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();
- }
}