aboutsummaryrefslogtreecommitdiff
path: root/qtmips_osemu
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-03-09 20:37:54 +0100
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-03-09 20:37:54 +0100
commitfc3571602f19d86ca86c25dd204f8662782e62d6 (patch)
treec9dad1178486fe87c4f452f08eb9de5e4998d40f /qtmips_osemu
parent3360c7a27865f16441d744fd4559a30e5b5dd7db (diff)
downloadqtmips-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.cpp828
-rw-r--r--qtmips_osemu/ossyscall.h27
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