diff options
author | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2019-03-09 20:37:54 +0100 |
---|---|---|
committer | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2019-03-09 20:37:54 +0100 |
commit | fc3571602f19d86ca86c25dd204f8662782e62d6 (patch) | |
tree | c9dad1178486fe87c4f452f08eb9de5e4998d40f /qtmips_osemu | |
parent | 3360c7a27865f16441d744fd4559a30e5b5dd7db (diff) | |
download | qtmips-fc3571602f19d86ca86c25dd204f8662782e62d6.tar.gz qtmips-fc3571602f19d86ca86c25dd204f8662782e62d6.tar.bz2 qtmips-fc3571602f19d86ca86c25dd204f8662782e62d6.zip |
Updated read and write, added open, close, ftruncate syscalls and fs_root option.
When operating system emulation root directory (fs_root) are selected
then open() syscall opens real host system files in this limited
subtree. When fs_root is not set then console is mapped to all
read, write, open and close calls.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Diffstat (limited to 'qtmips_osemu')
-rw-r--r-- | qtmips_osemu/ossyscall.cpp | 828 | ||||
-rw-r--r-- | qtmips_osemu/ossyscall.h | 27 |
2 files changed, 815 insertions, 40 deletions
diff --git a/qtmips_osemu/ossyscall.cpp b/qtmips_osemu/ossyscall.cpp index fed4548..50d275c 100644 --- a/qtmips_osemu/ossyscall.cpp +++ b/qtmips_osemu/ossyscall.cpp @@ -37,6 +37,13 @@ #include "core.h" #include "ossyscall.h" #include "syscall_nr.h" +#include "errno.h" +#include "target_errno.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> using namespace machine; using namespace osemu; @@ -54,6 +61,482 @@ struct mips_syscall_desc_t { syscall_handler_t handler; }; +// The copyied from musl-libc + +#define TARGET_O_CREAT 0400 +#define TARGET_O_EXCL 02000 +#define TARGET_O_NOCTTY 04000 +#define TARGET_O_TRUNC 01000 +#define TARGET_O_APPEND 0010 +#define TARGET_O_NONBLOCK 0200 +#define TARGET_O_DSYNC 0020 +#define TARGET_O_SYNC 040020 +#define TARGET_O_RSYNC 040020 +#define TARGET_O_DIRECTORY 0200000 +#define TARGET_O_NOFOLLOW 0400000 +#define TARGET_O_CLOEXEC 02000000 + +#define TARGET_O_PATH 010000000 + +#define TARGET_O_SYNC1 040000 + +#define TARGET_O_ACCMODE (03|TARGET_O_PATH) +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 + +static const QMap<int, int> map_target_o_flags_to_o_flags = { + #ifdef O_CREAT + {TARGET_O_CREAT, O_CREAT}, + #endif + #ifdef O_EXCL + {TARGET_O_EXCL, O_EXCL}, + #endif + #ifdef O_NOCTTY + {TARGET_O_NOCTTY, O_NOCTTY}, + #endif + #ifdef O_TRUNC + {TARGET_O_TRUNC, O_TRUNC}, + #endif + #ifdef O_APPEND + {TARGET_O_APPEND, O_APPEND}, + #endif + #ifdef O_NONBLOCK + {TARGET_O_NONBLOCK, O_NONBLOCK}, + #endif + #ifdef O_DSYNC + {TARGET_O_DSYNC, O_DSYNC}, + #endif + #ifdef O_SYNC + {TARGET_O_SYNC1, O_SYNC}, + #endif + #ifdef O_RSYNC + {TARGET_O_SYNC1, O_RSYNC}, + #endif + #ifdef O_DIRECTORY + {TARGET_O_DIRECTORY, O_DIRECTORY}, + #endif + #ifdef O_NOFOLLOW + {TARGET_O_NOFOLLOW, O_NOFOLLOW}, + #endif + #ifdef O_CLOEXEC + {TARGET_O_CLOEXEC, O_CLOEXEC}, + #endif +}; + +#if defined(S_IRUSR) & defined(S_IWUSR) & defined(S_IRGRP) & defined(S_IWGRP) & defined(S_IROTH) & defined(S_IWOTH) +#define OPEN_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) +#else +#define OPEN_MODE 0 +#endif + +// The list copyied from musl-libc + +static const QMap<int, int> errno_map = { + #ifdef EPERM + {EPERM, TARGET_EPERM}, + #endif + #ifdef ENOENT + {ENOENT, TARGET_ENOENT}, + #endif + #ifdef ESRCH + {ESRCH, TARGET_ESRCH}, + #endif + #ifdef EINTR + {EINTR, TARGET_EINTR}, + #endif + #ifdef EIO + {EIO, TARGET_EIO}, + #endif + #ifdef ENXIO + {ENXIO, TARGET_ENXIO}, + #endif + #ifdef E2BIG + {E2BIG, TARGET_E2BIG}, + #endif + #ifdef ENOEXEC + {ENOEXEC, TARGET_ENOEXEC}, + #endif + #ifdef EBADF + {EBADF, TARGET_EBADF}, + #endif + #ifdef ECHILD + {ECHILD, TARGET_ECHILD}, + #endif + #ifdef EAGAIN + {EAGAIN, TARGET_EAGAIN}, + #endif + #ifdef ENOMEM + {ENOMEM, TARGET_ENOMEM}, + #endif + #ifdef EACCES + {EACCES, TARGET_EACCES}, + #endif + #ifdef EFAULT + {EFAULT, TARGET_EFAULT}, + #endif + #ifdef ENOTBLK + {ENOTBLK, TARGET_ENOTBLK}, + #endif + #ifdef EBUSY + {EBUSY, TARGET_EBUSY}, + #endif + #ifdef EEXIST + {EEXIST, TARGET_EEXIST}, + #endif + #ifdef EXDEV + {EXDEV, TARGET_EXDEV}, + #endif + #ifdef ENODEV + {ENODEV, TARGET_ENODEV}, + #endif + #ifdef ENOTDIR + {ENOTDIR, TARGET_ENOTDIR}, + #endif + #ifdef EISDIR + {EISDIR, TARGET_EISDIR}, + #endif + #ifdef EINVAL + {EINVAL, TARGET_EINVAL}, + #endif + #ifdef ENFILE + {ENFILE, TARGET_ENFILE}, + #endif + #ifdef EMFILE + {EMFILE, TARGET_EMFILE}, + #endif + #ifdef ENOTTY + {ENOTTY, TARGET_ENOTTY}, + #endif + #ifdef ETXTBSY + {ETXTBSY, TARGET_ETXTBSY}, + #endif + #ifdef EFBIG + {EFBIG, TARGET_EFBIG}, + #endif + #ifdef ENOSPC + {ENOSPC, TARGET_ENOSPC}, + #endif + #ifdef ESPIPE + {ESPIPE, TARGET_ESPIPE}, + #endif + #ifdef EROFS + {EROFS, TARGET_EROFS}, + #endif + #ifdef EMLINK + {EMLINK, TARGET_EMLINK}, + #endif + #ifdef EPIPE + {EPIPE, TARGET_EPIPE}, + #endif + #ifdef EDOM + {EDOM, TARGET_EDOM}, + #endif + #ifdef ERANGE + {ERANGE, TARGET_ERANGE}, + #endif + #ifdef ENOMSG + {ENOMSG, TARGET_ENOMSG}, + #endif + #ifdef EIDRM + {EIDRM, TARGET_EIDRM}, + #endif + #ifdef ECHRNG + {ECHRNG, TARGET_ECHRNG}, + #endif + #ifdef EL2NSYNC + {EL2NSYNC, TARGET_EL2NSYNC}, + #endif + #ifdef EL3HLT + {EL3HLT, TARGET_EL3HLT}, + #endif + #ifdef EL3RST + {EL3RST, TARGET_EL3RST}, + #endif + #ifdef ELNRNG + {ELNRNG, TARGET_ELNRNG}, + #endif + #ifdef EUNATCH + {EUNATCH, TARGET_EUNATCH}, + #endif + #ifdef ENOCSI + {ENOCSI, TARGET_ENOCSI}, + #endif + #ifdef EL2HLT + {EL2HLT, TARGET_EL2HLT}, + #endif + #ifdef EDEADLK + {EDEADLK, TARGET_EDEADLK}, + #endif + #ifdef ENOLCK + {ENOLCK, TARGET_ENOLCK}, + #endif + #ifdef EBADE + {EBADE, TARGET_EBADE}, + #endif + #ifdef EBADR + {EBADR, TARGET_EBADR}, + #endif + #ifdef EXFULL + {EXFULL, TARGET_EXFULL}, + #endif + #ifdef ENOANO + {ENOANO, TARGET_ENOANO}, + #endif + #ifdef EBADRQC + {EBADRQC, TARGET_EBADRQC}, + #endif + #ifdef EBADSLT + {EBADSLT, TARGET_EBADSLT}, + #endif + #ifdef EDEADLOCK + {EDEADLOCK, TARGET_EDEADLOCK}, + #endif + #ifdef EBFONT + {EBFONT, TARGET_EBFONT}, + #endif + #ifdef ENOSTR + {ENOSTR, TARGET_ENOSTR}, + #endif + #ifdef ENODATA + {ENODATA, TARGET_ENODATA}, + #endif + #ifdef ETIME + {ETIME, TARGET_ETIME}, + #endif + #ifdef ENOSR + {ENOSR, TARGET_ENOSR}, + #endif + #ifdef ENONET + {ENONET, TARGET_ENONET}, + #endif + #ifdef ENOPKG + {ENOPKG, TARGET_ENOPKG}, + #endif + #ifdef EREMOTE + {EREMOTE, TARGET_EREMOTE}, + #endif + #ifdef ENOLINK + {ENOLINK, TARGET_ENOLINK}, + #endif + #ifdef EADV + {EADV, TARGET_EADV}, + #endif + #ifdef ESRMNT + {ESRMNT, TARGET_ESRMNT}, + #endif + #ifdef ECOMM + {ECOMM, TARGET_ECOMM}, + #endif + #ifdef EPROTO + {EPROTO, TARGET_EPROTO}, + #endif + #ifdef EDOTDOT + {EDOTDOT, TARGET_EDOTDOT}, + #endif + #ifdef EMULTIHOP + {EMULTIHOP, TARGET_EMULTIHOP}, + #endif + #ifdef EBADMSG + {EBADMSG, TARGET_EBADMSG}, + #endif + #ifdef ENAMETOOLONG + {ENAMETOOLONG, TARGET_ENAMETOOLONG}, + #endif + #ifdef EOVERFLOW + {EOVERFLOW, TARGET_EOVERFLOW}, + #endif + #ifdef ENOTUNIQ + {ENOTUNIQ, TARGET_ENOTUNIQ}, + #endif + #ifdef EBADFD + {EBADFD, TARGET_EBADFD}, + #endif + #ifdef EREMCHG + {EREMCHG, TARGET_EREMCHG}, + #endif + #ifdef ELIBACC + {ELIBACC, TARGET_ELIBACC}, + #endif + #ifdef ELIBBAD + {ELIBBAD, TARGET_ELIBBAD}, + #endif + #ifdef ELIBSCN + {ELIBSCN, TARGET_ELIBSCN}, + #endif + #ifdef ELIBMAX + {ELIBMAX, TARGET_ELIBMAX}, + #endif + #ifdef ELIBEXEC + {ELIBEXEC, TARGET_ELIBEXEC}, + #endif + #ifdef EILSEQ + {EILSEQ, TARGET_EILSEQ}, + #endif + #ifdef ENOSYS + {ENOSYS, TARGET_ENOSYS}, + #endif + #ifdef ELOOP + {ELOOP, TARGET_ELOOP}, + #endif + #ifdef ERESTART + {ERESTART, TARGET_ERESTART}, + #endif + #ifdef ESTRPIPE + {ESTRPIPE, TARGET_ESTRPIPE}, + #endif + #ifdef ENOTEMPTY + {ENOTEMPTY, TARGET_ENOTEMPTY}, + #endif + #ifdef EUSERS + {EUSERS, TARGET_EUSERS}, + #endif + #ifdef ENOTSOCK + {ENOTSOCK, TARGET_ENOTSOCK}, + #endif + #ifdef EDESTADDRREQ + {EDESTADDRREQ, TARGET_EDESTADDRREQ}, + #endif + #ifdef EMSGSIZE + {EMSGSIZE, TARGET_EMSGSIZE}, + #endif + #ifdef EPROTOTYPE + {EPROTOTYPE, TARGET_EPROTOTYPE}, + #endif + #ifdef ENOPROTOOPT + {ENOPROTOOPT, TARGET_ENOPROTOOPT}, + #endif + #ifdef EPROTONOSUPPORT + {EPROTONOSUPPORT, TARGET_EPROTONOSUPPORT}, + #endif + #ifdef ESOCKTNOSUPPORT + {ESOCKTNOSUPPORT, TARGET_ESOCKTNOSUPPORT}, + #endif + #ifdef EOPNOTSUPP + {EOPNOTSUPP, TARGET_EOPNOTSUPP}, + #endif + #ifdef ENOTSUP + {ENOTSUP, TARGET_ENOTSUP}, + #endif + #ifdef EPFNOSUPPORT + {EPFNOSUPPORT, TARGET_EPFNOSUPPORT}, + #endif + #ifdef EAFNOSUPPORT + {EAFNOSUPPORT, TARGET_EAFNOSUPPORT}, + #endif + #ifdef EADDRINUSE + {EADDRINUSE, TARGET_EADDRINUSE}, + #endif + #ifdef EADDRNOTAVAIL + {EADDRNOTAVAIL, TARGET_EADDRNOTAVAIL}, + #endif + #ifdef ENETDOWN + {ENETDOWN, TARGET_ENETDOWN}, + #endif + #ifdef ENETUNREACH + {ENETUNREACH, TARGET_ENETUNREACH}, + #endif + #ifdef ENETRESET + {ENETRESET, TARGET_ENETRESET}, + #endif + #ifdef ECONNABORTED + {ECONNABORTED, TARGET_ECONNABORTED}, + #endif + #ifdef ECONNRESET + {ECONNRESET, TARGET_ECONNRESET}, + #endif + #ifdef ENOBUFS + {ENOBUFS, TARGET_ENOBUFS}, + #endif + #ifdef EISCONN + {EISCONN, TARGET_EISCONN}, + #endif + #ifdef ENOTCONN + {ENOTCONN, TARGET_ENOTCONN}, + #endif + #ifdef EUCLEAN + {EUCLEAN, TARGET_EUCLEAN}, + #endif + #ifdef ENOTNAM + {ENOTNAM, TARGET_ENOTNAM}, + #endif + #ifdef ENAVAIL + {ENAVAIL, TARGET_ENAVAIL}, + #endif + #ifdef EISNAM + {EISNAM, TARGET_EISNAM}, + #endif + #ifdef EREMOTEIO + {EREMOTEIO, TARGET_EREMOTEIO}, + #endif + #ifdef ESHUTDOWN + {ESHUTDOWN, TARGET_ESHUTDOWN}, + #endif + #ifdef ETOOMANYREFS + {ETOOMANYREFS, TARGET_ETOOMANYREFS}, + #endif + #ifdef ETIMEDOUT + {ETIMEDOUT, TARGET_ETIMEDOUT}, + #endif + #ifdef ECONNREFUSED + {ECONNREFUSED, TARGET_ECONNREFUSED}, + #endif + #ifdef EHOSTDOWN + {EHOSTDOWN, TARGET_EHOSTDOWN}, + #endif + #ifdef EHOSTUNREACH + {EHOSTUNREACH, TARGET_EHOSTUNREACH}, + #endif + #ifdef EWOULDBLOCK + {EWOULDBLOCK, TARGET_EWOULDBLOCK}, + #endif + #ifdef EALREADY + {EALREADY, TARGET_EALREADY}, + #endif + #ifdef EINPROGRESS + {EINPROGRESS, TARGET_EINPROGRESS}, + #endif + #ifdef ESTALE + {ESTALE, TARGET_ESTALE}, + #endif + #ifdef ECANCELED + {ECANCELED, TARGET_ECANCELED}, + #endif + #ifdef ENOMEDIUM + {ENOMEDIUM, TARGET_ENOMEDIUM}, + #endif + #ifdef EMEDIUMTYPE + {EMEDIUMTYPE, TARGET_EMEDIUMTYPE}, + #endif + #ifdef ENOKEY + {ENOKEY, TARGET_ENOKEY}, + #endif + #ifdef EKEYEXPIRED + {EKEYEXPIRED, TARGET_EKEYEXPIRED}, + #endif + #ifdef EKEYREVOKED + {EKEYREVOKED, TARGET_EKEYREVOKED}, + #endif + #ifdef EKEYREJECTED + {EKEYREJECTED, TARGET_EKEYREJECTED}, + #endif + #ifdef EOWNERDEAD + {EOWNERDEAD, TARGET_EOWNERDEAD}, + #endif + #ifdef ENOTRECOVERABLE + {ENOTRECOVERABLE, TARGET_ENOTRECOVERABLE}, + #endif + #ifdef ERFKILL + {ERFKILL, TARGET_ERFKILL}, + #endif + #ifdef EHWPOISON + {EHWPOISON, TARGET_EHWPOISON}, + #endif + #ifdef EDQUOT + {EDQUOT, TARGET_EDQUOT}, + #endif +}; + // The list copyied from QEMU # define MIPS_SYS(name, args, handler) {#name, args, \ @@ -64,8 +547,8 @@ static const mips_syscall_desc_t mips_syscall_args[] = { MIPS_SYS(sys_fork , 0, syscall_default_handler) MIPS_SYS(sys_read , 3, do_sys_read) MIPS_SYS(sys_write , 3, do_sys_write) - MIPS_SYS(sys_open , 3, syscall_default_handler) /* 4005 */ - MIPS_SYS(sys_close , 1, syscall_default_handler) + MIPS_SYS(sys_open , 3, do_sys_open) /* 4005 */ + MIPS_SYS(sys_close , 1, do_sys_close) MIPS_SYS(sys_waitpid , 3, syscall_default_handler) MIPS_SYS(sys_creat , 2, syscall_default_handler) MIPS_SYS(sys_link , 2, syscall_default_handler) @@ -152,7 +635,7 @@ static const mips_syscall_desc_t mips_syscall_args[] = { MIPS_SYS(old_mmap , 6, syscall_default_handler) /* 4090 */ MIPS_SYS(sys_munmap , 2, syscall_default_handler) MIPS_SYS(sys_truncate , 2, syscall_default_handler) - MIPS_SYS(sys_ftruncate , 2, syscall_default_handler) + MIPS_SYS(sys_ftruncate , 2, do_sys_ftruncate) MIPS_SYS(sys_fchmod , 2, syscall_default_handler) MIPS_SYS(sys_fchown , 3, syscall_default_handler) /* 4095 */ MIPS_SYS(sys_getpriority, 2, syscall_default_handler) @@ -428,12 +911,15 @@ const unsigned mips_syscall_args_size = sizeof(mips_syscall_args)/sizeof(*mips_syscall_args); OsSyscallExceptionHandler::OsSyscallExceptionHandler(bool known_syscall_stop, - bool unknown_syscall_stop) { + bool unknown_syscall_stop, + QString fs_root) : + fd_mapping(3, FD_TERMINAL) { brk_limit = 0; anonymous_base = 0x60000000; anonymous_last = anonymous_base; this->known_syscall_stop = known_syscall_stop; this->unknown_syscall_stop = unknown_syscall_stop; + this->fs_root = fs_root; } bool OsSyscallExceptionHandler::handle_exception(Core *core, Registers *regs, @@ -511,6 +997,163 @@ bool OsSyscallExceptionHandler::handle_exception(Core *core, Registers *regs, return true; }; +std::int32_t OsSyscallExceptionHandler::write_mem(machine::MemoryAccess *mem, std::uint32_t addr, + const QVector<std::uint8_t> &data, std::uint32_t count) { + if ((std::uint32_t)data.size() < count) + count = data.size(); + + for (std::uint32_t i = 0; i < count; i++) { + mem->write_byte(addr++, data[i]); + } + return count; +} + +std::int32_t OsSyscallExceptionHandler::read_mem(machine::MemoryAccess *mem, std::uint32_t addr, + QVector<std::uint8_t> &data, std::uint32_t count) { + data.resize(count); + for (std::uint32_t i = 0; i < count; i++) { + data[i] = mem->read_byte(addr++); + } + return count; +} + +std::int32_t OsSyscallExceptionHandler::write_io(int fd, const QVector<std::uint8_t> &data, + std::uint32_t count) { + if ((std::uint32_t)data.size() < count) + count = data.size(); + if (fd == FD_UNUSED) { + return -1; + } else if (fd == FD_TERMINAL) { + for (std::uint32_t i = 0; i < count; i++) + emit char_written(fd, data[i]); + } else { + count = write(fd, data.data(), count); + } + return count; +} + +std::int32_t OsSyscallExceptionHandler::read_io(int fd, QVector<std::uint8_t> &data, + std::uint32_t count, bool add_nl_at_eof) { + data.resize(count); + if ((std::uint32_t)data.size() < count) + count = data.size(); + if (fd == FD_UNUSED) { + return -1; + } else if (fd == FD_TERMINAL) { + for (std::uint32_t i = 0; i < count; i++) { + unsigned int byte; + bool available = false; + emit rx_byte_pool(fd, byte, available); + if (!available) { + // add final newline if there are no more data + if (add_nl_at_eof) + data[i] = '\n'; + count = i + 1; + break; + } + data[i] = byte; + } + } else { + count = read(fd, data.data(), count); + } + data.resize(count); + return count; +} + +int OsSyscallExceptionHandler::allocate_fd(int val) { + int i; + for (i = 0 ; i < fd_mapping.size(); i++) { + if (fd_mapping[i] == FD_UNUSED) { + fd_mapping[i] = val; + return i; + } + } + i = fd_mapping.size(); + fd_mapping.resize(i + 1); + fd_mapping[i] = val; + return i; +} + +int OsSyscallExceptionHandler::file_open(QString fname, int flags, int mode) { + int targetfd, fd; + int hostflags = 0; + (void)mode; + for (auto i = map_target_o_flags_to_o_flags.begin(); + i != map_target_o_flags_to_o_flags.end(); i++) + if (flags & i.key()) + hostflags |= i.value(); + + switch (flags & TARGET_O_ACCMODE) { + case TARGET_O_RDONLY: + hostflags |= O_RDONLY; + break; + case TARGET_O_WRONLY: + hostflags |= O_WRONLY; + break; + case TARGET_O_RDWR: + hostflags |= O_RDWR; + break; + } + + if (fs_root.size() == 0) { + return allocate_fd(FD_TERMINAL); + } + + fname = filepath_to_host(fname); + + fd = open(fname.toLatin1().data(), hostflags, OPEN_MODE); + if (fd >= 0) { + targetfd = allocate_fd(fd); + } else { + perror("file_open"); + targetfd = -1; + } + return targetfd; +} + +int OsSyscallExceptionHandler::targetfd_to_fd(int targetfd) { + if (targetfd < 0) + return FD_INVALID; + if (targetfd >= fd_mapping.size()) + return FD_INVALID; + return fd_mapping.at(targetfd); +} + +void OsSyscallExceptionHandler::close_fd(int targetfd) { + if (targetfd <= fd_mapping.size()) + fd_mapping[targetfd] = FD_UNUSED; +} + +QString OsSyscallExceptionHandler::filepath_to_host(QString path) { + int pos = 0; + int prev = 0; + while(1) { + if (((path.size() - pos == 2) && (path.mid(pos, -1) == "..")) || + ((path.size() - pos > 2) && (path.mid(pos, 3) == "../"))) { + if (pos == 0) { + prev = 0; + } else { + if (pos == 1) + prev = 0; + else + prev = path.lastIndexOf('/', pos - 2) + 1; + } + path.remove(prev, pos + 3 - prev); + pos = prev; + continue; + } + pos = path.indexOf('/', pos); + if (pos == -1) + break; + pos += 1; + } + if ((path.size() >= 1) && path.at(0) == '/') + path = fs_root + path; + else + path = fs_root + '/' + path; + return path; +} + int OsSyscallExceptionHandler::syscall_default_handler(std::uint32_t &result, Core *core, std::uint32_t syscall_num, std::uint32_t a1, std::uint32_t a2, std::uint32_t a3, @@ -577,19 +1220,32 @@ int OsSyscallExceptionHandler::do_sys_writev(std::uint32_t &result, Core *core, std::uint32_t iov = a2; int iovcnt = a3; MemoryAccess *mem = core->get_mem_data(); + std::int32_t count; + QVector<std::uint8_t> data; printf("sys_writev to fd %d\n", fd); + fd = targetfd_to_fd(fd); + if (fd == FD_INVALID) { + result = -TARGET_EINVAL; + return 0; + } + while (iovcnt-- > 0) { std::uint32_t iov_base = mem->read_word(iov); std::uint32_t iov_len = mem->read_word(iov + 4); iov += 8; - for (std::uint32_t i = 0; i < iov_len; i++) { - int ch = mem->read_byte(iov_base++); - printf("%c", ch); - emit char_written(fd, ch); + + read_mem(mem, iov_base, data, iov_len); + count = write_io(fd, data, iov_len); + if (count >= 0) { + result += count; + } else { + if (result == 0) + result = count; } - result += iov_len; + if (count < (std::int32_t)iov_len) + break; } return 0; @@ -609,16 +1265,22 @@ int OsSyscallExceptionHandler::do_sys_write(std::uint32_t &result, Core *core, std::uint32_t buf = a2; int size = a3; MemoryAccess *mem = core->get_mem_data(); + std::int32_t count; + QVector<std::uint8_t> data; printf("sys_write to fd %d\n", fd); - result += size; - while (size-- > 0) { - int ch = mem->read_byte(buf++); - printf("%c", ch); - emit char_written(fd, ch); + fd = targetfd_to_fd(fd); + if (fd == FD_INVALID) { + result = -TARGET_EINVAL; + return 0; } + read_mem(mem, buf, data, size); + count = write_io(fd, data, size); + + result = count; + return 0; } @@ -636,28 +1298,31 @@ int OsSyscallExceptionHandler::do_sys_readv(std::uint32_t &result, Core *core, std::uint32_t iov = a2; int iovcnt = a3; MemoryAccess *mem = core->get_mem_data(); - bool available; - unsigned int byte; + std::int32_t count; + QVector<std::uint8_t> data; printf("sys_readv to fd %d\n", fd); + fd = targetfd_to_fd(fd); + if (fd == FD_INVALID) { + result = -TARGET_EINVAL; + return 0; + } + while (iovcnt-- > 0) { std::uint32_t iov_base = mem->read_word(iov); std::uint32_t iov_len = mem->read_word(iov + 4); iov += 8; - available = true; - for (std::uint32_t i = 0; i < iov_len; i++) { - emit rx_byte_pool(fd, byte, available); - if (!available) { - // add final newline if there are no more data - mem->write_byte(iov_base++, '\n'); - result += 1; - break; - } - mem->write_byte(iov_base++, byte); - result += 1; + + count = read_io(fd, data, iov_len, true); + if (count >= 0) { + write_mem(mem, iov_base, data, count); + result += count; + } else { + if (result == 0) + result =count; } - if (!available) + if (count < (std::int32_t)iov_len) break; } @@ -678,24 +1343,109 @@ int OsSyscallExceptionHandler::do_sys_read(std::uint32_t &result, Core *core, std::uint32_t buf = a2; int size = a3; MemoryAccess *mem = core->get_mem_data(); - bool available; - unsigned int byte; + std::int32_t count; + QVector<std::uint8_t> data; printf("sys_read to fd %d\n", fd); + fd = targetfd_to_fd(fd); + if (fd == FD_INVALID) { + result = -TARGET_EINVAL; + return 0; + } + + result = 0; + + count = read_io(fd, data, size, true); + if (count >= 0) { + write_mem(mem, buf, data, size); + } + result = count; + + return 0; +} + +// int open(const char *pathname, int flags, mode_t mode); +int OsSyscallExceptionHandler::do_sys_open(std::uint32_t &result, Core *core, + std::uint32_t syscall_num, + std::uint32_t a1, std::uint32_t a2, std::uint32_t a3, + std::uint32_t a4, std::uint32_t a5, std::uint32_t a6, + std::uint32_t a7, std::uint32_t a8) { + (void)core; (void)syscall_num; + (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; (void)a7; (void)a8; + result = 0; - while (size-- > 0) { - emit rx_byte_pool(fd, byte, available); - if (!available) { - // add final newline if there are no more data - mem->write_byte(buf++, '\n'); - result += 1; + std::uint32_t pathname = a1; + int flags = a2; + int mode = a3; + std::uint32_t ch; + MemoryAccess *mem = core->get_mem_data(); + + printf("sys_open filename\n"); + + QString fname; + while (true) { + ch = mem->read_byte(pathname++); + if (ch == 0) break; - } - mem->write_byte(buf++, byte); - result += 1; + fname.append(QChar(ch)); + } + + result = file_open(fname, flags, mode); + + return 0; +} + +// int close(int fd); +int OsSyscallExceptionHandler::do_sys_close(std::uint32_t &result, Core *core, + std::uint32_t syscall_num, + std::uint32_t a1, std::uint32_t a2, std::uint32_t a3, + std::uint32_t a4, std::uint32_t a5, std::uint32_t a6, + std::uint32_t a7, std::uint32_t a8) { + (void)core; (void)syscall_num; + (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; (void)a7; (void)a8; + + result = 0; + int fd = a1; + + printf("sys_close fd %d\n", fd); + + int targetfd = fd; + fd = targetfd_to_fd(fd); + if (fd == FD_INVALID) { + result = -TARGET_EINVAL; + return 0; + } + + close(fd); + close_fd(targetfd); + + return 0; +} + +// int ftruncate(int fd, off_t length); +int OsSyscallExceptionHandler::do_sys_ftruncate(std::uint32_t &result, Core *core, + std::uint32_t syscall_num, + std::uint32_t a1, std::uint32_t a2, std::uint32_t a3, + std::uint32_t a4, std::uint32_t a5, std::uint32_t a6, + std::uint32_t a7, std::uint32_t a8) { + (void)core; (void)syscall_num; + (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; (void)a7; (void)a8; + + result = 0; + int fd = a1; + std::uint64_t length = ((std::uint64_t)a2 << 32) | a3; + + printf("sys_ftruncate fd %d\n", fd); + + fd = targetfd_to_fd(fd); + if (fd == FD_INVALID) { + result = -TARGET_EINVAL; + return 0; } + ftruncate(fd, length); + return 0; } diff --git a/qtmips_osemu/ossyscall.h b/qtmips_osemu/ossyscall.h index bcb202f..2f8f54a 100644 --- a/qtmips_osemu/ossyscall.h +++ b/qtmips_osemu/ossyscall.h @@ -37,6 +37,8 @@ #define OSSYCALL_H #include <QObject> +#include <QString> +#include <QVector> #include <qtmipsexception.h> #include <machineconfig.h> #include <registers.h> @@ -57,7 +59,8 @@ int name(std::uint32_t &result, machine::Core *core, \ class OsSyscallExceptionHandler : public machine::ExceptionHandler { Q_OBJECT public: - OsSyscallExceptionHandler(bool known_syscall_stop = false, bool unknown_syscall_stop = false); + OsSyscallExceptionHandler(bool known_syscall_stop = false, bool unknown_syscall_stop = false, + QString fs_root = ""); bool handle_exception(machine::Core *core, machine::Registers *regs, machine::ExceptionCause excause, std::uint32_t inst_addr, std::uint32_t next_addr, std::uint32_t jump_branch_pc, @@ -69,17 +72,39 @@ public: OSSYCALL_HANDLER_DECLARE(do_sys_write); OSSYCALL_HANDLER_DECLARE(do_sys_readv); OSSYCALL_HANDLER_DECLARE(do_sys_read); + OSSYCALL_HANDLER_DECLARE(do_sys_open); + OSSYCALL_HANDLER_DECLARE(do_sys_close); + OSSYCALL_HANDLER_DECLARE(do_sys_ftruncate); OSSYCALL_HANDLER_DECLARE(do_sys_brk); OSSYCALL_HANDLER_DECLARE(do_sys_mmap2); signals: void char_written(int fd, unsigned int val); void rx_byte_pool(int fd, unsigned int &data, bool &available); private: + enum FdMapping { + FD_UNUSED = -1, + FD_INVALID = -1, + FD_TERMINAL = -2, + }; + std::int32_t write_mem(machine::MemoryAccess *mem, std::uint32_t addr, + const QVector<std::uint8_t> &data, std::uint32_t count); + std::int32_t read_mem(machine::MemoryAccess *mem, std::uint32_t addr, + QVector<std::uint8_t> &data, std::uint32_t count); + std::int32_t write_io(int fd, const QVector<std::uint8_t> &data, std::uint32_t count); + std::int32_t read_io(int fd, QVector<std::uint8_t> &data, std::uint32_t count, bool add_nl_at_eof); + int allocate_fd(int val = FD_UNUSED); + int file_open(QString fname, int flags, int mode); + int targetfd_to_fd(int targetfd); + void close_fd(int targetfd); + QString filepath_to_host(QString path); + + QVector<int> fd_mapping; std::uint32_t brk_limit; std::uint32_t anonymous_base; std::uint32_t anonymous_last; bool known_syscall_stop; bool unknown_syscall_stop; + QString fs_root; }; #undef OSSYCALL_HANDLER_DECLARE |