// POSIX / Linux-ABI compatibility syscalls. // These are stubs or thin wrappers that make musl and ksh happy // without implementing full semantics. #include "types.h" #include "defs.h" #include "param.h" #include "memlayout.h" #include "mmu.h" #include "traps.h" #include "proc.h" #include "x86.h" #include "syscall.h" #include "posix.h" #include "uaccess.h" #include "errno.h" extern int linux_syscall_map[]; extern int linux_syscall_map_size; // enable_linux_abi: switch this process to Linux syscall numbering. addr_t sys_enable_linux_abi(void) { myproc()->syscall_map = linux_syscall_map; myproc()->map_size = linux_syscall_map_size; return 0; } // set_tid_address: musl calls this at startup to register its TID location. addr_t sys_set_tid_address(void) { addr_t tidp; argaddr(0, &tidp); if (tidp) put_user(myproc()->pid, tidp); return myproc()->pid; } // set_robust_list: robust mutex cleanup on exit — stub. addr_t sys_set_robust_list(void) { return 0; } // futex: used by musl for single-threaded lock primitives. addr_t sys_futex(void) { int op; argint(1, &op); op &= ~(FUTEX_WAIT_PRIVATE - FUTEX_WAIT); if (op == FUTEX_WAKE || op == FUTEX_WAKE_PRIVATE) return 0; return -EAGAIN; // no blocking, musl retries } // arch_prctl: save FS_BASE for TLS. addr_t sys_arch_prctl(void) { int code; addr_t addr; argint(0, &code); argaddr(1, &addr); if (code == ARCH_SET_FS) { myproc()->fs_base = addr; return 0; } if (code == ARCH_GET_FS) { if (put_user(myproc()->fs_base, addr) < 0) return -EFAULT; return 0; } return -EINVAL; } addr_t sys_getrlimit(void) { int resource; struct rlimit *rlp; argint(0, &resource); if (argptr(1, (char**)&rlp, sizeof(*rlp)) < 0) return -1; rlp->rlim_cur = (uint64)-1; rlp->rlim_max = (uint64)-1; return 0; } addr_t sys_prlimit(void) { struct rlimit *oldrlp; if (argptr(3, (char**)&oldrlp, sizeof(*oldrlp)) == 0 && oldrlp) { oldrlp->rlim_cur = (uint64)-1; oldrlp->rlim_max = (uint64)-1; } return 0; } // uname: return fake but plausible kernel/host info addr_t sys_uname(void) { struct utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; char domainname[65]; }; addr_t ubuf; argaddr(0, &ubuf); struct utsname *u = (struct utsname*)user_ptr(ubuf, sizeof(*u)); if (!u) return -EFAULT; memset(u, 0, sizeof(*u)); memmove(u->sysname, "Schunix", 8); memmove(u->nodename, "schunix", 8); memmove(u->release, "0.1.0", 6); memmove(u->version, "#1", 3); memmove(u->machine, "x86_64", 7); memmove(u->domainname, "(none)", 7); return 0; } // socket/bind/listen/accept/connect live in sys_net.c now that they do // something. // syslog: kernel logging facility — no-op for user processes. addr_t sys_syslog(void) { return 0; } // getrandom: fill buffer with pseudo-random bytes. addr_t sys_getrandom(void) { addr_t bufaddr; int len, flags; argaddr(0, &bufaddr); argint(1, &len); argint(2, &flags); if (len <= 0) return 0; uint8 *buf = (uint8*)user_ptr(bufaddr, (uint64)len); if (!buf) return -EFAULT; // LCG seeded from proc pointer + pid; no lock needed (read-only fields). uint rseed = (uint)(uintptr_t)myproc() ^ (uint)myproc()->pid; for (int i = 0; i < len; i++) { rseed = rseed * 1664525u + 1013904223u; buf[i] = (uint8)(rseed >> 16); } return len; } // pselect6 / ppoll live in sys_poll.c alongside select/poll. // epoll: not implemented. addr_t sys_epoll_create1(void) { return -ENOSYS; } addr_t sys_epoll_ctl(void) { return -ENOSYS; } addr_t sys_epoll_wait(void) { return -ENOSYS; } // signalfd / eventfd / timerfd: not implemented. addr_t sys_signalfd4(void) { return -ENOSYS; } addr_t sys_eventfd2(void) { return -ENOSYS; } addr_t sys_timerfd_create(void) { return -ENOSYS; } addr_t sys_timerfd_settime(void){ return -ENOSYS; } addr_t sys_timerfd_gettime(void){ return -ENOSYS; }