diff --git a/output/dll/uzem.wbx.gz b/output/dll/uzem.wbx.gz index 891fecea26..8477315a70 100644 Binary files a/output/dll/uzem.wbx.gz and b/output/dll/uzem.wbx.gz differ diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs index d463f34c9b..e543930fd0 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs @@ -29,6 +29,7 @@ namespace BizHawk.Emulation.Cores.Waterbox SealedHeapSizeKB = 1024 * 16, InvisibleHeapSizeKB = 1024 * 16, PlainHeapSizeKB = 1024 * 16, + MmapHeapSizeKB = 1024 * 16, StartAddress = WaterboxHost.CanonicalStart, SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Errno.cs b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Errno.cs new file mode 100644 index 0000000000..1aea091957 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Errno.cs @@ -0,0 +1,140 @@ +namespace BizHawk.Emulation.Cores.Waterbox +{ + partial class Syscalls + { + internal const int EPERM = 1; + internal const int ENOENT = 2; + internal const int ESRCH = 3; + internal const int EINTR = 4; + internal const int EIO = 5; + internal const int ENXIO = 6; + internal const int E2BIG = 7; + internal const int ENOEXEC = 8; + internal const int EBADF = 9; + internal const int ECHILD = 10; + internal const int EAGAIN = 11; + internal const int ENOMEM = 12; + internal const int EACCES = 13; + internal const int EFAULT = 14; + internal const int ENOTBLK = 15; + internal const int EBUSY = 16; + internal const int EEXIST = 17; + internal const int EXDEV = 18; + internal const int ENODEV = 19; + internal const int ENOTDIR = 20; + internal const int EISDIR = 21; + internal const int EINVAL = 22; + internal const int ENFILE = 23; + internal const int EMFILE = 24; + internal const int ENOTTY = 25; + internal const int ETXTBSY = 26; + internal const int EFBIG = 27; + internal const int ENOSPC = 28; + internal const int ESPIPE = 29; + internal const int EROFS = 30; + internal const int EMLINK = 31; + internal const int EPIPE = 32; + internal const int EDOM = 33; + internal const int ERANGE = 34; + internal const int EDEADLK = 35; + internal const int ENAMETOOLONG = 36; + internal const int ENOLCK = 37; + internal const int ENOSYS = 38; + internal const int ENOTEMPTY = 39; + internal const int ELOOP = 40; + internal const int EWOULDBLOCK = EAGAIN; + internal const int ENOMSG = 42; + internal const int EIDRM = 43; + internal const int ECHRNG = 44; + internal const int EL2NSYNC = 45; + internal const int EL3HLT = 46; + internal const int EL3RST = 47; + internal const int ELNRNG = 48; + internal const int EUNATCH = 49; + internal const int ENOCSI = 50; + internal const int EL2HLT = 51; + internal const int EBADE = 52; + internal const int EBADR = 53; + internal const int EXFULL = 54; + internal const int ENOANO = 55; + internal const int EBADRQC = 56; + internal const int EBADSLT = 57; + internal const int EDEADLOCK = EDEADLK; + internal const int EBFONT = 59; + internal const int ENOSTR = 60; + internal const int ENODATA = 61; + internal const int ETIME = 62; + internal const int ENOSR = 63; + internal const int ENONET = 64; + internal const int ENOPKG = 65; + internal const int EREMOTE = 66; + internal const int ENOLINK = 67; + internal const int EADV = 68; + internal const int ESRMNT = 69; + internal const int ECOMM = 70; + internal const int EPROTO = 71; + internal const int EMULTIHOP = 72; + internal const int EDOTDOT = 73; + internal const int EBADMSG = 74; + internal const int EOVERFLOW = 75; + internal const int ENOTUNIQ = 76; + internal const int EBADFD = 77; + internal const int EREMCHG = 78; + internal const int ELIBACC = 79; + internal const int ELIBBAD = 80; + internal const int ELIBSCN = 81; + internal const int ELIBMAX = 82; + internal const int ELIBEXEC = 83; + internal const int EILSEQ = 84; + internal const int ERESTART = 85; + internal const int ESTRPIPE = 86; + internal const int EUSERS = 87; + internal const int ENOTSOCK = 88; + internal const int EDESTADDRREQ = 89; + internal const int EMSGSIZE = 90; + internal const int EPROTOTYPE = 91; + internal const int ENOPROTOOPT = 92; + internal const int EPROTONOSUPPORT = 93; + internal const int ESOCKTNOSUPPORT = 94; + internal const int EOPNOTSUPP = 95; + internal const int ENOTSUP = EOPNOTSUPP; + internal const int EPFNOSUPPORT = 96; + internal const int EAFNOSUPPORT = 97; + internal const int EADDRINUSE = 98; + internal const int EADDRNOTAVAIL = 99; + internal const int ENETDOWN = 100; + internal const int ENETUNREACH = 101; + internal const int ENETRESET = 102; + internal const int ECONNABORTED = 103; + internal const int ECONNRESET = 104; + internal const int ENOBUFS = 105; + internal const int EISCONN = 106; + internal const int ENOTCONN = 107; + internal const int ESHUTDOWN = 108; + internal const int ETOOMANYREFS = 109; + internal const int ETIMEDOUT = 110; + internal const int ECONNREFUSED = 111; + internal const int EHOSTDOWN = 112; + internal const int EHOSTUNREACH = 113; + internal const int EALREADY = 114; + internal const int EINPROGRESS = 115; + internal const int ESTALE = 116; + internal const int EUCLEAN = 117; + internal const int ENOTNAM = 118; + internal const int ENAVAIL = 119; + internal const int EISNAM = 120; + internal const int EREMOTEIO = 121; + internal const int EDQUOT = 122; + internal const int ENOMEDIUM = 123; + internal const int EMEDIUMTYPE = 124; + internal const int ECANCELED = 125; + internal const int ENOKEY = 126; + internal const int EKEYEXPIRED = 127; + internal const int EKEYREVOKED = 128; + internal const int EKEYREJECTED = 129; + internal const int EOWNERDEAD = 130; + internal const int ENOTRECOVERABLE = 131; + internal const int ERFKILL = 132; + internal const int EHWPOISON = 133; + } +} diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/MMan.cs b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/MMan.cs new file mode 100644 index 0000000000..eaa71ad7a1 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/MMan.cs @@ -0,0 +1,194 @@ +using System; +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + partial class Syscalls + { + internal const long MAP_FAILED = -1; + + internal const ulong MAP_SHARED = 0x01; + internal const ulong MAP_PRIVATE = 0x02; + internal const ulong MAP_SHARED_VALIDATE = 0x03; + internal const ulong MAP_TYPE = 0x0f; + internal const ulong MAP_FIXED = 0x10; + internal const ulong MAP_ANON = 0x20; + internal const ulong MAP_ANONYMOUS = MAP_ANON; + internal const ulong MAP_NORESERVE = 0x4000; + internal const ulong MAP_GROWSDOWN = 0x0100; + internal const ulong MAP_DENYWRITE = 0x0800; + internal const ulong MAP_EXECUTABLE = 0x1000; + internal const ulong MAP_LOCKED = 0x2000; + internal const ulong MAP_POPULATE = 0x8000; + internal const ulong MAP_NONBLOCK = 0x10000; + internal const ulong MAP_STACK = 0x20000; + internal const ulong MAP_HUGETLB = 0x40000; + internal const ulong MAP_SYNC = 0x80000; + internal const ulong MAP_FIXED_NOREPLACE = 0x100000; + internal const ulong MAP_FILE = 0; + + internal const ulong MAP_HUGE_SHIFT = 26; + internal const ulong MAP_HUGE_MASK = 0x3f; + internal const ulong MAP_HUGE_64KB = (16 << 26); + internal const ulong MAP_HUGE_512KB = (19 << 26); + internal const ulong MAP_HUGE_1MB = (20 << 26); + internal const ulong MAP_HUGE_2MB = (21 << 26); + internal const ulong MAP_HUGE_8MB = (23 << 26); + internal const ulong MAP_HUGE_16MB = (24 << 26); + internal const ulong MAP_HUGE_32MB = (25 << 26); + internal const ulong MAP_HUGE_256MB = (28 << 26); + internal const ulong MAP_HUGE_512MB = (29 << 26); + internal const ulong MAP_HUGE_1GB = (30 << 26); + internal const ulong MAP_HUGE_2GB = (31 << 26); + internal const ulong MAP_HUGE_16GB = (34U << 26); + + internal const ulong PROT_NONE = 0; + internal const ulong PROT_READ = 1; + internal const ulong PROT_WRITE = 2; + internal const ulong PROT_EXEC = 4; + internal const ulong PROT_GROWSDOWN = 0x01000000; + internal const ulong PROT_GROWSUP = 0x02000000; + + internal const ulong MS_ASYNC = 1; + internal const ulong MS_INVALIDATE = 2; + internal const ulong MS_SYNC = 4; + + internal const ulong MCL_CURRENT = 1; + internal const ulong MCL_FUTURE = 2; + internal const ulong MCL_ONFAULT = 4; + + internal const ulong POSIX_MADV_NORMAL = 0; + internal const ulong POSIX_MADV_RANDOM = 1; + internal const ulong POSIX_MADV_SEQUENTIAL = 2; + internal const ulong POSIX_MADV_WILLNEED = 3; + internal const ulong POSIX_MADV_DONTNEED = 4; + + internal const ulong MADV_NORMAL = 0; + internal const ulong MADV_RANDOM = 1; + internal const ulong MADV_SEQUENTIAL = 2; + internal const ulong MADV_WILLNEED = 3; + internal const ulong MADV_DONTNEED = 4; + internal const ulong MADV_FREE = 8; + internal const ulong MADV_REMOVE = 9; + internal const ulong MADV_DONTFORK = 10; + internal const ulong MADV_DOFORK = 11; + internal const ulong MADV_MERGEABLE = 12; + internal const ulong MADV_UNMERGEABLE = 13; + internal const ulong MADV_HUGEPAGE = 14; + internal const ulong MADV_NOHUGEPAGE = 15; + internal const ulong MADV_DONTDUMP = 16; + internal const ulong MADV_DODUMP = 17; + internal const ulong MADV_WIPEONFORK = 18; + internal const ulong MADV_KEEPONFORK = 19; + internal const ulong MADV_COLD = 20; + internal const ulong MADV_PAGEOUT = 21; + internal const ulong MADV_HWPOISON = 100; + internal const ulong MADV_SOFT_OFFLINE = 101; + + internal const ulong MREMAP_MAYMOVE = 1; + internal const ulong MREMAP_FIXED = 2; + + internal const ulong MLOCK_ONFAULT = 0x01; + + internal const ulong MFD_CLOEXEC = 0x0001U; + internal const ulong MFD_ALLOW_SEALING = 0x0002U; + internal const ulong MFD_HUGETLB = 0x0004U; + + [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[9]")] + public IntPtr MMap(IntPtr address, UIntPtr size, ulong prot, ulong flags, int fd, IntPtr offs) + { + if (address != IntPtr.Zero) + { + // waterbox cores generally don't know about hardcoded addresses + // we could support this, so long as the address is in our heap's range + return Z.SS(MAP_FAILED); + } + MemoryBlock.Protection mprot; + switch (prot) + { + case PROT_NONE: + mprot = MemoryBlock.Protection.None; + break; + default: + case PROT_WRITE | PROT_EXEC: // W^X + case PROT_READ | PROT_WRITE | PROT_EXEC: // W^X + case PROT_EXEC: // exec only???? + case PROT_WRITE: + return Z.SS(MAP_FAILED); // write only???? + case PROT_READ | PROT_WRITE: + mprot = MemoryBlock.Protection.RW; + break; + case PROT_READ: + mprot = MemoryBlock.Protection.R; + break; + case PROT_READ | PROT_EXEC: + mprot = MemoryBlock.Protection.RX; + break; + } + if ((flags & MAP_ANONYMOUS) == 0) + { + // anonymous + private is easy + // anonymous by itself is hard + // nothing needs either right now + return Z.SS(MAP_FAILED); + } + if ((flags & 0xf00) != 0) + { + // various unsupported flags + return Z.SS(MAP_FAILED); + } + + var ret = _parent._mmapheap.Map((ulong)size, mprot); + return ret == 0 ? Z.SS(MAP_FAILED) : Z.US(ret); + } + [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[25]")] + public IntPtr MRemap(UIntPtr oldAddress, UIntPtr oldSize, + UIntPtr newSize, ulong flags) + { + if ((flags & MREMAP_FIXED) != 0) + { + // just like mmap. + // waterbox cores generally don't know about hardcoded addresses + // we could support this, so long as the address is in our heap's range + return Z.SS(MAP_FAILED); + } + var ret = _parent._mmapheap.Remap((ulong)oldAddress, (ulong)oldSize, (ulong)newSize, + (flags & MREMAP_MAYMOVE) != 0); + return ret == 0 ? Z.SS(MAP_FAILED) : Z.US(ret); + } + [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[11]")] + public long MUnmap(UIntPtr address, UIntPtr size) + { + return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : MAP_FAILED; + } + + [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[10]")] + public long MProtect(UIntPtr address, UIntPtr size, ulong prot) + { + MemoryBlock.Protection mprot; + switch (prot) + { + case PROT_NONE: + mprot = MemoryBlock.Protection.None; + break; + default: + case PROT_WRITE | PROT_EXEC: // W^X + case PROT_READ | PROT_WRITE | PROT_EXEC: // W^X + case PROT_EXEC: // exec only???? + case PROT_WRITE: + return MAP_FAILED; // write only???? + case PROT_READ | PROT_WRITE: + mprot = MemoryBlock.Protection.RW; + break; + case PROT_READ: + mprot = MemoryBlock.Protection.R; + break; + case PROT_READ | PROT_EXEC: + mprot = MemoryBlock.Protection.RX; + break; + } + return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : MAP_FAILED; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/NotImplementedSyscalls.cs b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/NotImplementedSyscalls.cs new file mode 100644 index 0000000000..1d82a3338c --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/NotImplementedSyscalls.cs @@ -0,0 +1,422 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using BizHawk.BizInvoke; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + /// + /// Provides useful traps for any syscalls that are not implemented by libc + /// + internal class NotImplementedSyscalls : IImportResolver + { + private static readonly Dictionary SyscallNames = new Dictionary() + { + { 0, "read" }, + { 1, "write" }, + { 2, "open" }, + { 3, "close" }, + { 4, "stat" }, + { 5, "fstat" }, + { 6, "lstat" }, + { 7, "poll" }, + { 8, "lseek" }, + { 9, "mmap" }, + { 10, "mprotect" }, + { 11, "munmap" }, + { 12, "brk" }, + { 13, "rt_sigaction" }, + { 14, "rt_sigprocmask" }, + { 15, "rt_sigreturn" }, + { 16, "ioctl" }, + { 17, "pread64" }, + { 18, "pwrite64" }, + { 19, "readv" }, + { 20, "writev" }, + { 21, "access" }, + { 22, "pipe" }, + { 23, "select" }, + { 24, "sched_yield" }, + { 25, "mremap" }, + { 26, "msync" }, + { 27, "mincore" }, + { 28, "madvise" }, + { 29, "shmget" }, + { 30, "shmat" }, + { 31, "shmctl" }, + { 32, "dup" }, + { 33, "dup2" }, + { 34, "pause" }, + { 35, "nanosleep" }, + { 36, "getitimer" }, + { 37, "alarm" }, + { 38, "setitimer" }, + { 39, "getpid" }, + { 40, "sendfile" }, + { 41, "socket" }, + { 42, "connect" }, + { 43, "accept" }, + { 44, "sendto" }, + { 45, "recvfrom" }, + { 46, "sendmsg" }, + { 47, "recvmsg" }, + { 48, "shutdown" }, + { 49, "bind" }, + { 50, "listen" }, + { 51, "getsockname" }, + { 52, "getpeername" }, + { 53, "socketpair" }, + { 54, "setsockopt" }, + { 55, "getsockopt" }, + { 56, "clone" }, + { 57, "fork" }, + { 58, "vfork" }, + { 59, "execve" }, + { 60, "exit" }, + { 61, "wait4" }, + { 62, "kill" }, + { 63, "uname" }, + { 64, "semget" }, + { 65, "semop" }, + { 66, "semctl" }, + { 67, "shmdt" }, + { 68, "msgget" }, + { 69, "msgsnd" }, + { 70, "msgrcv" }, + { 71, "msgctl" }, + { 72, "fcntl" }, + { 73, "flock" }, + { 74, "fsync" }, + { 75, "fdatasync" }, + { 76, "truncate" }, + { 77, "ftruncate" }, + { 78, "getdents" }, + { 79, "getcwd" }, + { 80, "chdir" }, + { 81, "fchdir" }, + { 82, "rename" }, + { 83, "mkdir" }, + { 84, "rmdir" }, + { 85, "creat" }, + { 86, "link" }, + { 87, "unlink" }, + { 88, "symlink" }, + { 89, "readlink" }, + { 90, "chmod" }, + { 91, "fchmod" }, + { 92, "chown" }, + { 93, "fchown" }, + { 94, "lchown" }, + { 95, "umask" }, + { 96, "gettimeofday" }, + { 97, "getrlimit" }, + { 98, "getrusage" }, + { 99, "sysinfo" }, + { 100, "times" }, + { 101, "ptrace" }, + { 102, "getuid" }, + { 103, "syslog" }, + { 104, "getgid" }, + { 105, "setuid" }, + { 106, "setgid" }, + { 107, "geteuid" }, + { 108, "getegid" }, + { 109, "setpgid" }, + { 110, "getppid" }, + { 111, "getpgrp" }, + { 112, "setsid" }, + { 113, "setreuid" }, + { 114, "setregid" }, + { 115, "getgroups" }, + { 116, "setgroups" }, + { 117, "setresuid" }, + { 118, "getresuid" }, + { 119, "setresgid" }, + { 120, "getresgid" }, + { 121, "getpgid" }, + { 122, "setfsuid" }, + { 123, "setfsgid" }, + { 124, "getsid" }, + { 125, "capget" }, + { 126, "capset" }, + { 127, "rt_sigpending" }, + { 128, "rt_sigtimedwait" }, + { 129, "rt_sigqueueinfo" }, + { 130, "rt_sigsuspend" }, + { 131, "sigaltstack" }, + { 132, "utime" }, + { 133, "mknod" }, + { 134, "uselib" }, + { 135, "personality" }, + { 136, "ustat" }, + { 137, "statfs" }, + { 138, "fstatfs" }, + { 139, "sysfs" }, + { 140, "getpriority" }, + { 141, "setpriority" }, + { 142, "sched_setparam" }, + { 143, "sched_getparam" }, + { 144, "sched_setscheduler" }, + { 145, "sched_getscheduler" }, + { 146, "sched_get_priority_max" }, + { 147, "sched_get_priority_min" }, + { 148, "sched_rr_get_interval" }, + { 149, "mlock" }, + { 150, "munlock" }, + { 151, "mlockall" }, + { 152, "munlockall" }, + { 153, "vhangup" }, + { 154, "modify_ldt" }, + { 155, "pivot_root" }, + { 156, "_sysctl" }, + { 157, "prctl" }, + { 158, "arch_prctl" }, + { 159, "adjtimex" }, + { 160, "setrlimit" }, + { 161, "chroot" }, + { 162, "sync" }, + { 163, "acct" }, + { 164, "settimeofday" }, + { 165, "mount" }, + { 166, "umount2" }, + { 167, "swapon" }, + { 168, "swapoff" }, + { 169, "reboot" }, + { 170, "sethostname" }, + { 171, "setdomainname" }, + { 172, "iopl" }, + { 173, "ioperm" }, + { 174, "create_module" }, + { 175, "init_module" }, + { 176, "delete_module" }, + { 177, "get_kernel_syms" }, + { 178, "query_module" }, + { 179, "quotactl" }, + { 180, "nfsservctl" }, + { 181, "getpmsg" }, + { 182, "putpmsg" }, + { 183, "afs_syscall" }, + { 184, "tuxcall" }, + { 185, "security" }, + { 186, "gettid" }, + { 187, "readahead" }, + { 188, "setxattr" }, + { 189, "lsetxattr" }, + { 190, "fsetxattr" }, + { 191, "getxattr" }, + { 192, "lgetxattr" }, + { 193, "fgetxattr" }, + { 194, "listxattr" }, + { 195, "llistxattr" }, + { 196, "flistxattr" }, + { 197, "removexattr" }, + { 198, "lremovexattr" }, + { 199, "fremovexattr" }, + { 200, "tkill" }, + { 201, "time" }, + { 202, "futex" }, + { 203, "sched_setaffinity" }, + { 204, "sched_getaffinity" }, + { 205, "set_thread_area" }, + { 206, "io_setup" }, + { 207, "io_destroy" }, + { 208, "io_getevents" }, + { 209, "io_submit" }, + { 210, "io_cancel" }, + { 211, "get_thread_area" }, + { 212, "lookup_dcookie" }, + { 213, "epoll_create" }, + { 214, "epoll_ctl_old" }, + { 215, "epoll_wait_old" }, + { 216, "remap_file_pages" }, + { 217, "getdents64" }, + { 218, "set_tid_address" }, + { 219, "restart_syscall" }, + { 220, "semtimedop" }, + { 221, "fadvise64" }, + { 222, "timer_create" }, + { 223, "timer_settime" }, + { 224, "timer_gettime" }, + { 225, "timer_getoverrun" }, + { 226, "timer_delete" }, + { 227, "clock_settime" }, + { 228, "clock_gettime" }, + { 229, "clock_getres" }, + { 230, "clock_nanosleep" }, + { 231, "exit_group" }, + { 232, "epoll_wait" }, + { 233, "epoll_ctl" }, + { 234, "tgkill" }, + { 235, "utimes" }, + { 236, "vserver" }, + { 237, "mbind" }, + { 238, "set_mempolicy" }, + { 239, "get_mempolicy" }, + { 240, "mq_open" }, + { 241, "mq_unlink" }, + { 242, "mq_timedsend" }, + { 243, "mq_timedreceive" }, + { 244, "mq_notify" }, + { 245, "mq_getsetattr" }, + { 246, "kexec_load" }, + { 247, "waitid" }, + { 248, "add_key" }, + { 249, "request_key" }, + { 250, "keyctl" }, + { 251, "ioprio_set" }, + { 252, "ioprio_get" }, + { 253, "inotify_init" }, + { 254, "inotify_add_watch" }, + { 255, "inotify_rm_watch" }, + { 256, "migrate_pages" }, + { 257, "openat" }, + { 258, "mkdirat" }, + { 259, "mknodat" }, + { 260, "fchownat" }, + { 261, "futimesat" }, + { 262, "newfstatat" }, + { 263, "unlinkat" }, + { 264, "renameat" }, + { 265, "linkat" }, + { 266, "symlinkat" }, + { 267, "readlinkat" }, + { 268, "fchmodat" }, + { 269, "faccessat" }, + { 270, "pselect6" }, + { 271, "ppoll" }, + { 272, "unshare" }, + { 273, "set_robust_list" }, + { 274, "get_robust_list" }, + { 275, "splice" }, + { 276, "tee" }, + { 277, "sync_file_range" }, + { 278, "vmsplice" }, + { 279, "move_pages" }, + { 280, "utimensat" }, + { 281, "epoll_pwait" }, + { 282, "signalfd" }, + { 283, "timerfd_create" }, + { 284, "eventfd" }, + { 285, "fallocate" }, + { 286, "timerfd_settime" }, + { 287, "timerfd_gettime" }, + { 288, "accept4" }, + { 289, "signalfd4" }, + { 290, "eventfd2" }, + { 291, "epoll_create1" }, + { 292, "dup3" }, + { 293, "pipe2" }, + { 294, "inotify_init1" }, + { 295, "preadv" }, + { 296, "pwritev" }, + { 297, "rt_tgsigqueueinfo" }, + { 298, "perf_event_open" }, + { 299, "recvmmsg" }, + { 300, "fanotify_init" }, + { 301, "fanotify_mark" }, + { 302, "prlimit64" }, + { 303, "name_to_handle_at" }, + { 304, "open_by_handle_at" }, + { 305, "clock_adjtime" }, + { 306, "syncfs" }, + { 307, "sendmmsg" }, + { 308, "setns" }, + { 309, "getcpu" }, + { 310, "process_vm_readv" }, + { 311, "process_vm_writev" }, + { 312, "kcmp" }, + { 313, "finit_module" }, + { 314, "sched_setattr" }, + { 315, "sched_getattr" }, + { 316, "renameat2" }, + { 317, "seccomp" }, + { 318, "getrandom" }, + { 319, "memfd_create" }, + { 320, "kexec_file_load" }, + { 321, "bpf" }, + { 322, "execveat" }, + { 323, "userfaultfd" }, + { 324, "membarrier" }, + { 325, "mlock2" }, + { 326, "copy_file_range" }, + { 327, "preadv2" }, + { 328, "pwritev2" }, + { 329, "pkey_mprotect" }, + { 330, "pkey_alloc" }, + { 331, "pkey_free" }, + { 332, "statx" }, + { 333, "io_pgetevents" }, + { 334, "rseq" }, + { 424, "pidfd_send_signal" }, + { 425, "io_uring_setup" }, + { 426, "io_uring_enter" }, + { 427, "io_uring_register" }, + { 428, "open_tree" }, + { 429, "move_mount" }, + { 430, "fsopen" }, + { 431, "fsconfig" }, + { 432, "fsmount" }, + { 433, "fspick" }, + { 434, "pidfd_open" }, + { 435, "clone3" }, + }; + + private class Trap + { + private readonly int _index; + private readonly string _message; + private readonly IImportResolver _resolver; + public Trap(int index) + { + _index = index; + _resolver = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox); + if (!SyscallNames.TryGetValue(_index, out var name)) + name = "???"; + _message = $"Trapped on unimplemented syscall {name} (#{_index})"; + } + [BizExport(CallingConvention.Cdecl, EntryPoint="@@")] + public void RunTrap() + { + System.Diagnostics.Debug.WriteLine(_message); + // TODO: this unwind never works, so debugbrk instead + System.Diagnostics.Debugger.Break(); + throw new InvalidOperationException(_message); + } + public IntPtr FunctionPointer => _resolver.GetProcAddrOrThrow("@@"); + } + private readonly List _traps; + private NotImplementedSyscalls() + { + _traps = Enumerable.Range(0, 512) + .Select(i => new Trap(i)) + .ToList(); + } + + private static readonly Regex ExportRegex = new Regex("__wsyscalltab\\[(\\d+)\\]"); + + public IntPtr GetProcAddrOrZero(string entryPoint) + { + var m = ExportRegex.Match(entryPoint); + if (m.Success) + { + return _traps[int.Parse(m.Groups[1].Value)].FunctionPointer; + } + return IntPtr.Zero; + } + + public IntPtr GetProcAddrOrThrow(string entryPoint) + { + var m = ExportRegex.Match(entryPoint); + if (m.Success) + { + return _traps[int.Parse(m.Groups[1].Value)].FunctionPointer; + } + throw new InvalidOperationException($"{entryPoint} was not of the format __wsyscalltab[#]"); + } + + public static NotImplementedSyscalls Instance { get; } = new NotImplementedSyscalls(); + } +} diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Stat.cs b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Stat.cs new file mode 100644 index 0000000000..a2f4e22802 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Stat.cs @@ -0,0 +1,120 @@ +using System; +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + unsafe partial class Syscalls + { + internal const uint S_IFMT = 61440; + + internal const uint S_IFDIR = 16384; + internal const uint S_IFCHR = 8192; + internal const uint S_IFBLK = 24576; + internal const uint S_IFREG = 32768; + internal const uint S_IFIFO = 4096; + internal const uint S_IFLNK = 40960; + internal const uint S_IFSOCK = 49152; + + internal const uint S_ISUID = 2048; + internal const uint S_ISGID = 1024; + internal const uint S_ISVTX = 512; + internal const uint S_IRUSR = 0400; + internal const uint S_IWUSR = 256; + internal const uint S_IXUSR = 64; + internal const uint S_IRWXU = 448; + internal const uint S_IRGRP = 32; + internal const uint S_IWGRP = 16; + internal const uint S_IXGRP = 8; + internal const uint S_IRWXG = 56; + internal const uint S_IROTH = 4; + internal const uint S_IWOTH = 2; + internal const uint S_IXOTH = 1; + internal const uint S_IRWXO = 7; + + + [StructLayout(LayoutKind.Sequential)] + public struct KStat + { + public ulong st_dev; + public ulong st_ino; + public ulong st_nlink; + + public uint st_mode; + public uint st_uid; + public uint st_gid; + public uint __pad0; + public ulong st_rdev; + public long st_size; + public long st_blksize; + public long st_blocks; + + public long st_atime_sec; + public long st_atime_nsec; + public long st_mtime_sec; + public long st_mtime_nsec; + public long st_ctime_sec; + public long st_ctime_nsec; + public long __unused0; + public long __unused1; + public long __unused2; + } + + private void StatInternal(KStat* s, IFileObject o) + { + s->st_dev = 1; + s->st_ino = 1; + s->st_nlink = 0; + + uint flags = 0; + if (o.Stream.CanRead) + flags |= S_IRUSR | S_IRGRP | S_IROTH; + if (o.Stream.CanWrite) + flags |= S_IWUSR | S_IWGRP | S_IWOTH; + if (o.Stream.CanSeek) + flags |= S_IFREG; + else + flags |= S_IFIFO; + s->st_mode = flags; + s->st_uid = 0; + s->st_gid = 0; + s->__pad0 = 0; + s->st_rdev = 0; + if (o.Stream.CanSeek) + s->st_size = o.Stream.Length; + else + s->st_size = 0; + s->st_blksize = 4096; + s->st_blocks = (s->st_size + 511) / 512; + + s->st_atime_sec = 1262304000000; + s->st_atime_nsec = 1000000000 / 2; + s->st_mtime_sec = 1262304000000; + s->st_mtime_nsec = 1000000000 / 2; + s->st_ctime_sec = 1262304000000; + s->st_ctime_nsec = 1000000000 / 2; + } + + [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[4]")] + public long Stat(string path, KStat* statbuf) + { + if (!_availableFiles.TryGetValue(path, out var o)) + return -ENOENT; + + StatInternal(statbuf, o); + return 0; + } + + [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[5]")] + public long Fstat(int fd, KStat* statbuf) + { + if (fd < 0 || fd >= _openFiles.Count) + return -EBADF; + var o = _openFiles[fd]; + if (o == null) + return -EBADF; + StatInternal(statbuf, o); + return 0; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Syscalls.cs similarity index 67% rename from src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs rename to src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Syscalls.cs index fd8428a0ca..8f9b467e97 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls/Syscalls.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Text.RegularExpressions; using BizHawk.BizInvoke; using BizHawk.Common; using BizHawk.Emulation.Common; @@ -13,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// /// syscall emulation layer /// - internal class Syscalls : IBinaryStateable + internal partial class Syscalls : IBinaryStateable { public interface IFileObject : IBinaryStateable { @@ -287,12 +286,12 @@ namespace BizHawk.Emulation.Cores.Waterbox } [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[2]")] - public int Open(string path, int flags, int mode) + public long Open(string path, int flags, int mode) { if (!_availableFiles.TryGetValue(path, out var o)) - return -1; + return -ENOENT; if (_openFiles.Contains(o)) - return -1; + return -EACCES; FileAccess access; switch (flags & 3) { @@ -306,10 +305,10 @@ namespace BizHawk.Emulation.Cores.Waterbox access = FileAccess.ReadWrite; break; default: - return -1; + return -EINVAL; } if (!o.Open(access)) - return -1; + return -EACCES; int fd; for (fd = 0; fd < _openFiles.Count; fd++) if (_openFiles[fd] == null) @@ -321,13 +320,15 @@ namespace BizHawk.Emulation.Cores.Waterbox return fd; } [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[3]")] - public int Close(int fd) + public long Close(int fd) { if (fd < 0 || fd >= _openFiles.Count) - return -1; + return -EBADF; var o = _openFiles[fd]; - if (o == null || !o.Close()) - return -1; + if (o == null) + return -EBADF; + if (!o.Close()) + return -EIO; _openFiles[fd] = null; return 0; } @@ -335,8 +336,10 @@ namespace BizHawk.Emulation.Cores.Waterbox public long Seek(int fd, long offset, int type) { var s = StreamForFd(fd); - if (s == null || !s.CanSeek) - return -1; + if (s == null) + return -EBADF; + if (!s.CanSeek) + return -ESPIPE; SeekOrigin o; switch (type) { @@ -350,23 +353,20 @@ namespace BizHawk.Emulation.Cores.Waterbox o = SeekOrigin.End; break; default: - return -1; + return -EINVAL; + } + try + { + return s.Seek(offset, o); + } + catch (IOException) + { + // usually means bad offset, since we already filtered out on CanSeek + return -EINVAL; } - return s.Seek(offset, o); - } - - [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[4]")] - public int Stat(string path, IntPtr statbuf) - { - return -1; - } - - [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[5]")] - public int Fstat(int fd, IntPtr statbuf) - { - return -1; } + // TODO: Remove this entirely once everything is compiled against the new libc [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[205]")] public long SetThreadArea(IntPtr uinfo) { @@ -376,6 +376,7 @@ namespace BizHawk.Emulation.Cores.Waterbox [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[218]")] public long SetTidAddress(IntPtr address) { + // pretend we succeeded return 8675309; // arbitrary thread id } @@ -394,76 +395,6 @@ namespace BizHawk.Emulation.Cores.Waterbox return 0; } - [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[9]")] - public IntPtr MMap(IntPtr address, UIntPtr size, int prot, int flags, int fd, IntPtr offs) - { - if (address != IntPtr.Zero) - return Z.SS(-1); - MemoryBlock.Protection mprot; - switch (prot) - { - case 0: mprot = MemoryBlock.Protection.None; break; - default: - case 6: // W^X - case 7: // W^X - case 4: // exec only???? - case 2: return Z.SS(-1); // write only???? - case 3: mprot = MemoryBlock.Protection.RW; break; - case 1: mprot = MemoryBlock.Protection.R; break; - case 5: mprot = MemoryBlock.Protection.RX; break; - } - if ((flags & 0x20) == 0) - { - // MAP_ANONYMOUS is required - return Z.SS(-1); - } - if ((flags & 0xf00) != 0) - { - // various unsupported flags - return Z.SS(-1); - } - - var ret = _parent._mmapheap.Map((ulong)size, mprot); - return ret == 0 ? Z.SS(-1) : Z.US(ret); - } - [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[25]")] - public IntPtr MRemap(UIntPtr oldAddress, UIntPtr oldSize, - UIntPtr newSize, int flags) - { - if ((flags & 2) != 0) - { - // don't support MREMAP_FIXED - return Z.SS(-1); - } - var ret = _parent._mmapheap.Remap((ulong)oldAddress, (ulong)oldSize, (ulong)newSize, - (flags & 1) != 0); - return ret == 0 ? Z.SS(-1) : Z.US(ret); - } - [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[11]")] - public int MUnmap(UIntPtr address, UIntPtr size) - { - return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : -1; - } - - [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[10]")] - public int MProtect(UIntPtr address, UIntPtr size, int prot) - { - MemoryBlock.Protection mprot; - switch (prot) - { - case 0: mprot = MemoryBlock.Protection.None; break; - default: - case 6: // W^X - case 7: // W^X - case 4: // exec only???? - case 2: return -1; // write only???? - case 3: mprot = MemoryBlock.Protection.RW; break; - case 1: mprot = MemoryBlock.Protection.R; break; - case 5: mprot = MemoryBlock.Protection.RX; break; - } - return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : -1; - } - public void SaveStateBinary(BinaryWriter bw) { bw.Write(_availableFiles.Count); @@ -531,60 +462,4 @@ namespace BizHawk.Emulation.Cores.Waterbox return RemoveFileInternal(name).GetContents(); } } - - /// - /// Provides useful traps for any syscalls that are not implemented by libc - /// - internal class NotImplementedSyscalls : IImportResolver - { - private class Trap - { - private readonly int _index; - private readonly IImportResolver _resolver; - public Trap(int index) - { - _index = index; - _resolver = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox); - } - [BizExport(CallingConvention.Cdecl, EntryPoint="@@")] - public void RunTrap() - { - var s = $"Trapped on unimplemented syscall {_index}"; - Console.WriteLine(s); - throw new InvalidOperationException(s); - } - public IntPtr FunctionPointer => _resolver.GetProcAddrOrThrow("@@"); - } - private readonly List _traps; - private NotImplementedSyscalls() - { - _traps = Enumerable.Range(0, 512) - .Select(i => new Trap(i)) - .ToList(); - } - - private static readonly Regex ExportRegex = new Regex("__wsyscalltab\\[(\\d+)\\]"); - - public IntPtr GetProcAddrOrZero(string entryPoint) - { - var m = ExportRegex.Match(entryPoint); - if (m.Success) - { - return _traps[int.Parse(m.Groups[1].Value)].FunctionPointer; - } - return IntPtr.Zero; - } - - public IntPtr GetProcAddrOrThrow(string entryPoint) - { - var m = ExportRegex.Match(entryPoint); - if (m.Success) - { - return _traps[int.Parse(m.Groups[1].Value)].FunctionPointer; - } - throw new InvalidOperationException($"{entryPoint} was not of the format __wsyscalltab[#]"); - } - - public static NotImplementedSyscalls Instance { get; } = new NotImplementedSyscalls(); - } }