System Call Interface Progress
Status: In Progress (Linux process semantics verified from ring 3) Last review: 2026-08-25
Implemented
- Portable, host-tested handlers (docs/abi/ A2, 2026-09-29).
kernel/abi/linux/reaches the kernel only throughinclude/vibeos/ksvc.h, a services interface written for every personality rather than for Linux; the architecture implements it inkernel/arch/x86_64/ksvc.cand the host tests intests/kernel/ksvc_fake.c.tests/kernel/linux_abi_tests.cruns the handlers throughlinux_syscall, and every PARTIAL row of the registry carries a gap expectation that fails until its phase closes it.check-abi-layering.pykeeps it so. The details are in docs/abi/phases.md, A2. - Descriptors as Linux has them (docs/abi/ A3, 2026-09-30). A descriptor names a counted open file description (
include/vibeos/file.h), sodup,dup2,dup3andforkshare its offset and flags; a process has up to 1024 of them, 0-2 included, withFD_CLOEXEChonoured at exec;fcntl(no record locks) andclose_rangeare served. Each file type - regular file, directory, pipe end, socket, console - has its own operations inkernel/abi/files/, which any personality uses. Details in docs/abi/phases.md, A3. - Paths (docs/abi/ A4, 2026-09-30). Each process has a working directory and a root; a path is normalised against them and walked through the mount table by
kernel/fs/path.c, which every personality shares.chdir,fchdir,getcwd,mkdiratandunlinkatare served, every *at call honours its directory descriptor, exec resolves relative paths, and the dynamic loader is opened at the path PT_INTERP names - the substitution toEFI/BOOT/LDMUSL.SOis gone. Details in docs/abi/phases.md, A4. - Layouts and numbers from Linux's headers (docs/abi/ A5, 2026-09-30). The structures the Linux handlers copy to and from user memory, and the constants they compare arguments against, are declared once in
include/vibeos/linux_layout.hinstead of as byte offsets and bare numbers in each handler.tests/kernel/linux_layout_tests.ccompares every field, size, errno value and constant with the host's uapi headers (the C library's for what uapi does not export), andcheck-linux-layout.pyfails the build when a declaration has no comparison. Details in docs/abi/phases.md, A5. - IPC, L7 (closed 2026-10-12). Six steps (docs/abi/phases.md), measured against
tests/corpus/ltp-l7.txt(0 of 81 on the parent). Steps 1 to 5, the 21 calls in five files under one lock:ipc.c- Linux's numbering (an index handed out cyclically, as since 5.4, and a sequence that moves when the cycle restarts;msg_next_idand its kin), ipcperms, the STAT and INFO commands, message queues by type;sem.c- semop whole or not at all, waiter counts, SEM_UNDO given back at the process's end;shm.c- a segment is an unnamed /tmp file, an attachment a shared mapping whose regions carry the segment's number, so the attach count is read off every process's regions rather than kept;mqueue.c- messages by priority in pages the sender allocates, mq_notify by signal;splice.c- through a kernel page andvibeos_pipe_peek, so a short write loses nothing. /proc takes files from its owner and its tunables are written as Linux's are. The registry's sixteen tables became 32 (a seventeenth was a panic at boot). Step 6:tests/corpus/sysvipc.c, a producer and consumer over SysV shared memory and semaphores and a round trip through each kind of queue, under musl and glibc, compared with Linux; the run found vmsplice waiting to put in everything, where Linux puts in what fits. LTP 64 of 81. Left: SIGEV_THREAD (netlink), a 4 KiB pipe, a sleep of at least a tick, fields x86-64 does not have, shmctl01's fork refused with EAGAIN (unexplained). Open and not L7's: THREADS.ELF's C6_SCHED failed once in about eighteen boots, a pinned child not moved to its core in three seconds; the stage now prints where it was. - Threads and scheduling, L6 (closed 2026-10-12). Four steps (docs/abi/phases.md), measured against
tests/corpus/ltp-l6.txt(16 of 67 on the parent). Step 1: futex finished - bitsets, requeue, WAKE_OP on a fault-tolerant user compare-exchange (vibeos_uaccess_cmpxchg32), the futex2 calls with a sleeper on up to 128 words, robust lists walked at exit; THREADS.ELF's C6_ROBUST and C6_COND at boot. Step 2: thesched_*family over a REALTIME class added to the scheduler's policy (priority before virtual time; the torture's model learned it), affinity over the pickers' mask, getcpu, sched_rr_get_interval, ioprio, membarrier through the shootdown IPI; C6_SCHED. Step 3: clone makes a process on its parent's memory - posix_spawn and vfork work - with CLONE_VFORK, CLONE_PARENT and the tid words for a forking clone, and the task table is 64 slots; C6_VFORK. Step 4: a thread pool under musl and glibc in the corpus, compared with Linux, which found three defects: a fatal signal ended one thread rather than the process (nowhw_task_kill_group, C6_ABORT), the TLB quarantine leaked frames when full (a shootdown releases them), and the mm lock's waiters did not answer a flush under TCG. LTP 53 of 67; what is left needs more than 64 tasks, SCHED_DEADLINE, or another phase. - Sockets, L5 (closed 2026-10-06). Four steps (docs/abi/phases.md). Steps 1 to 3: a socket type carries a neutral table of socket operations (
include/vibeos/sockops.h) - bind, listen, connect, accept, sendmsg, recvmsg, shutdown, names, options - filled by IP (kernel/abi/files/socket.c, over a stack that learned addressed binds, EADDRINUSE and SO_REUSEADDR, ephemeral ports, connected UDP, MSG_PEEK and MSG_TRUNC) and by local sockets (kernel/abi/files/unixsock.c: stream and datagram, a socket node in the filesystem through a new VFSmknodor a name in the abstract namespace, SO_PEERCRED, SCM_RIGHTS carrying A3's counted descriptions); the options every socket keeps alike live in the description (sockopt.c);kernel/abi/linux/net.conly translates sockaddr, msghdr, cmsg and mmsghdr. readv and writev on a socket are one receive or send. Step 4: BusyBox wget against the host, a DNS lookup through musl's resolver and QEMU's, and SOCKETS.ELF's checks - a Unix-socket server and client among them - at boot (tests/corpus/run-l5.sh). Its LTP run found there was no loopback: the stack has one now (a ring the timer's poll feeds back to the input path), and a SYN to a closed port is reset; its boots found that a half-closed connection was reclaimed under an open descriptor (L4's nc check had been green on timing), and it waits for the close now. LTP for the phase 44 of 64 (26 before the fixes); the rest network namespaces, IPv6/SCTP/RDS, SysV semaphores, O_PATH, MSG_MORE corking. - Event loops, L4 (closed 2026-10-06). The plan, in seven steps (docs/abi/phases.md): one readiness engine for poll, ppoll, select and pselect6, with sockets saying what they can do; eventfd; timerfd; signalfd; epoll; inotify; and the programs - BusyBox httpd serving from the guest, nc, tail -f - with LTP's 78 tests for L4's calls (tests/corpus/ltp-l4.txt). No wait queue: every wait here looks, gives up the core and looks again, and the event loops ask each description's ready(). Step 1 (2026-10-05): poll, ppoll, select and pselect6 on one engine (kernel/abi/linux/poll.c), sockets that say what they can do (vibeos_inet_ready), a wait never shorter than asked, and EVENTS.ELF at boot. Steps 2 to 4 (2026-10-05): eventfd (a counter in the description, changed by compare-exchange), timerfd (a deadline and a period counted by whoever looks - nothing fires it) and signalfd (pending signals taken as Linux's records), each a file type with a ready() and a pipe's wait; LTP 16 of 20, the rest a time namespace, libaio and a fuzzy-sync race that needs L6. Step 5 (2026-10-05): epoll (kernel/abi/linux/epoll.c) - poll with a set that outlives the call: entries belong to the description and go with its last reference (vibeos_file_on_release), level, edge (a rise in ready), one-shot, nested up to five, ELOOP for a cycle; LTP 16 of 25, then epoll_ctl04 fixed (the nesting chain counted only below), the rest socketpair (L5), listen unbound and F_SETPIPE_SZ. Step 6 (2026-10-05): inotify (kernel/abi/linux/inotify.c) on vibeos_fs_notify, which the file layer calls once per operation on a name and the regular-file type for open, read, write and close; a watch names a node. Its LTP run found that a process renaming its own working directory lost it (cwd is a path here): a renamed directory now takes working directories, roots and open descriptions along. Step 7 (2026-10-06): the programs at boot (tests/corpus/run-l4.sh) - tail -f, BusyBox httpd fetched from the host through a forwarded port, nc both ways - with setsockopt (SO_REUSEADDR, SO_KEEPALIVE) and shutdown taken from L5; the TCP flush no longer counts a FIN as data (it looped for ever with the network lock held), and a wait on a socket hears a signal. LTP for the phase 58 of 83.
- Processes, credentials and time, L2 (closed 2026-10-04). All seven steps. Step 1: a process has real, effective, saved and filesystem ids and supplementary groups (
include/vibeos/cred.h,kernel/sched/cred.c); the sixteen get and set calls; and L1's file operations ask who is asking - search permission in the walk, read/write on open, the directory's permission and the sticky bit for names, ownership forchmod/chown/times, withaccessanswering for the real user. Registry: 143 done, 23 partial. LTP's L1 list after it: 154 passed (131 before it), 16 failed, 144 broken, 65 not applicable, 2 did not run. What is left is mostly a loop device,alarm, and files under /proc and /dev. Step 2: signals as Linux delivers them - asiginfo_tanducontextframe with the vector registers, read back byrt_sigreturn; a fault given to a handler that asked for it;sigaltstack,rt_sigpending,rt_sigsuspend,pause,rt_sigtimedwait,rt_sigqueueinfo,rt_tgsigqueueinfo; SIGCHLD when a child ends. LTP after it: not measured in this step. The first test of the signal list, pause01, waits for its child to show as sleeping in /proc//stat (step 6), and LTP's own timeout is setitimer (step 3), so the first test that waits forever takes the rest of its boot: 3 of 48 reported (kill08 passed; kill05 needs System V shared memory; kill06 failed with ESRCH killing a process group, not yet looked into). Measured again with step 3, when the timeout works. Step 3: timers - alarm, the three interval timers and POSIX timers on the machine's and the CPU's clocks, fired by the tick from a portable table (kernel/sched/ptimer.c);clock_getres,gettimeofday,times. LTP after it: the timer tests and step 2's signal tests together (tests/corpus/ltp-l2.txt's subset, 70 tests): 37 passed, 1 failed (times03: no system time), 24 broken, 7 did not run (kill10 takes the rest of its boot: step 5). Before this step the same list ran 3 of 48. Of the broken: /proc//stat and /proc/cpuinfo (step 6), setrlimit (step 4), clock_settime refused, System V shared memory, signal 64, and LTP's musl restorer. Step 4: resource limits in the process state, NOFILE, FSIZE, DATA, NPROC and CPU enforced; getrusage, getpriority/setpriority, personality - and the scheduler's policy, never initialised on the machine since it was written, now runs (M-084). LTP after it: the limit tests (22): 17 passed; the rest need 512 MB free (getrusage03), /proc/cpuinfo (getrusage04, step 6), sched_getaffinity (nice05, L6), select (personality02), /bin/true on the volume (setrlimit04), and useradd (setpriority01, which then waits out its timeout - not looked into). With step 3's 70 alongside: 54 of 94 passed. Step 5: one engine under wait4 and waitid (by pid, group or pidfd; WNOWAIT), pidfds (kernel/abi/files/pidfd.c), clone3 and execveat. LTP after it: the step's own 41 ( build-gcc-Release/ltp-l2s5.txt): 12 passed, 2 failed, 26 broken, 1 not applicable. It found two defects in this step's clone3 - the exit signal a caller names is ignored and SIGCHLD sent instead (clone301), and five of the argument checks Linux makes are missing (clone302) - and two in older layers that decide most of the rest. Eight tests waited out their timeout; waitid04, the one read, passed its checks and then hung in LTP's checkpoint, a futex shared between processes through a MAP_SHARED page, which the futex table keys per process. And an orphan is never given to init here, so the children of a test killed by its timeout stay zombies nobody reaps: the task table filled, and every fork after that was EAGAIN (seven tests). All three are fixed in the next commits. The rest want /proc (step 6), unshare, cgroups, a loop device, core dumps, ns_last_pid, or LTP resources that are not staged (execveat01, execveat02). Step 6: /proc about processes (self,/stat, status, cmdline, maps, fd/, exe; cpuinfo, mounts), /dev (null, zero, full, random, urandom, tty), a ChaCha20 pool behind getrandom; and the three defects step 5's LTP found - a futex shared through a MAP_SHARED page, orphans never adopted by init, clone's exit signal. LTP after it: 41 of 79 passed ( ltp-l2s6.txt), step 5's 41 alone 23 (12 before); it found orphaned process groups never sent SIGHUP and SIGCONT, which step 7 takes. Step 7, the programs: eight BusyBox workloads more in the corpus - traps, kill and wait, timeout, time, ps, /proc, /dev, limits - compared with Linux; kill's session rule replaced by Linux's (BusyBox's timeout); a stop holds until SIGCONT or SIGKILL; orphaned process groups with a stopped member hung up; /proc/gives the leader's state, and /proc/ and task/ exist. LTP for L2's own 188: 106 passed, none left unrun. - Memory, L3 (closed 2026-10-02). Step 6, the programs: SQLite's shell and Lua built against glibc and dynamically linked run with the host's own
ld-linux-x86-64.so.2andlibc.so.6staged on the boot volume; SQLite runs in write-ahead-log mode withmmap_sizeset, which needs a shared mapping of a file. Eighteen corpus workloads, compared with Linux's answers. LTP for L3's syscalls: 31 of 63 pass, with two left out because they hang (mincore04,mmap18). It found three more wrong answers, fixed:MAP_SHARED_VALIDATEdid not refuse an unknown flag,MAP_LOCKEDwas ignored, andmsync(MS_INVALIDATE)of a locked page was not EBUSY. Not fixed and said: a fault in ring 3 kills the task instead of delivering SIGSEGV or SIGBUS to a handler that asked for it (mmap05,mmap13, and whymmap18hangs);mincore03expects an untouched page not to be resident;mremap01aborts aftermremaprefuses to grow a shared mapping of a file - most likely in its own cleanup, which was not confirmed. The rest wantsetrlimit,/proc/self/mapsandstatus,shmget, seals,mountor a loop device. Steps 1 to 5: Step 4:madvise(a discarded private page reads zeros; speed advice is a no-op; advice this kernel cannot keep is EINVAL),mincore,mlock/mlock2/munlock/mlockall/munlockall(a mark in the entry that page-out refuses),mremap(shrink, grow in place, move - entries moved, not copied) andmemfd_create(a /tmp file that goes with its last descriptor). Registry: 132 done, 24 partial; the four new partial rows name their gaps. Step 3: LTP's 382 tests for L1's syscalls run throughscripts/dev/ltp-run.sh(131 passed, 10 failed, 177 broken, 57 not applicable, 7 did not run). To start at all they needed/proc(kernel/fs/procfs.c: meminfo, sys/kernel/pid_max),/etc/passwdand/etc/group,nanosleep/clock_nanosleep, and interrupted calls run again underSA_RESTART. They found and this fixed:F_GETLK's choice of lock, an unjudged read of a path's first byte (M-082), ENOENT for an empty path, EINVAL and EISDIR inpreadv, EFBIG infallocate, the description pool,socket's errno. What is left is mostly L2's: credentials,alarm,/dev. Registry: 127 done, 20 partial. Step 2:MAP_SHARED- a shared page is marked in its entry and a fork maps the same frame into the child instead of making it copy-on-write; a shared mapping of a file maps the filesystem's own pages (share_page, tmpfs only; FAT answers ENODEV), so the mapping andread/writeare one memory;msyncvalidates and returns; a shared page is never paged out. Registry: 125 done, 20 partial. Step 5, taken early: the user stack grows - four pages at exec, a zeroed page for any address in the two megabytes below that the program or the kernel reaches, a guard page under them; the range check accepts an untouched stack page; the gate assertsstack_grownand a ring-3 self-test with a hundred-kilobyte frame. It replaced the 64 pages L1 step 8 mapped at exec, which had made the open swap defect M-070 frequent enough to make the gate flaky. Step 1:mmapplaces a mapping at a fixed address (MAP_FIXED,MAP_FIXED_NOREPLACE), honours a free hint, steps its arena over what is already mapped, and maps a file privately - the file's bytes in the process's own pages. The fake kernel gained real page tables (kernel/mmover static memory), so the memory handlers are host-tested for the first time. Shared mappings are step 2, and are what LTP's harness waits for. On the way: a race in fork - a read-only page evicted between fork's read of its entry and fork's reference - found and fixed inkernel/mm/vmspace.c; and M-070, the swap-slot double release, seen three times in about sixty boots since L1 step 8 and still open, now with instrumentation that says why a page-in failed. - Files and paths, L1 (closed 2026-10-01, LTP pending L3). All eight steps. Step 8:
tests/corpus/run-l1.shruns fifteen corpus workloads in the guest - twelve BusyBox ones, SQLite on a file and in memory, a Lua script - and the gate compares every line with what the same script printed on Linux (tests/corpus/l1-expected.txt, written byscripts/dev/corpus-expect.sh). Running them found four defects outside the step's syscalls:execverefused/proc/self/exe(how BusyBox's shell runs its applets), a forked child kept the slot's previous program path, the user stack was 16 KiB (now 256, still not growing), and FAT files were reported non-executable. LTP is staged byscripts/dev/ltp-run.shand every test breaks at its harness'smmap(MAP_SHARED)of a file: L3. Step 7: the console is a terminal (include/vibeos/tty.h): modes in Linux's numbering, ICANON, ECHO, ICRNL and ONLCR honoured, a line discipline that waits for a finished line or hands over bytes as typed; TCGETS, the TCSETS forms, the window size, and FIOCLEX/FIONCLEX/FIONBIO/FIONREAD. A terminal made BusyBox's shell interactive, which neededpoll(minimal, PARTIAL, L4's) and awritevgathered into one write. Found on the way: the native shell'swritehad made an empty file since step 4 and nothing asserted its contents - nownotes_file_not_read_back. Step 6: advisory locks in a personality-neutral table (kernel/fs/filelock.c) -fcntl's record locks owned by a process, the OFD forms andflockowned by a description, EDEADLK for a wait that could not end, POSIX's close-drops-everything rule - tortured nightly against a model; directories read by position through onereaddiroperation and formatted by the personality, sogetdents64lists whole names with their real type and inode andgetdentsis the same reader in the older record; the twelve xattr calls;close_range's UNSHARE for a single-threaded process. 124 done, 19 partial. Step 5: names and metadata inkernel/abi/linux/names.c-stat/lstat/statx, theaccessfamily,rename*,rmdir,link*,symlink*,readlink, thechmod,chownandutimefamilies,statfs/fstatfs,mknod*,openat2- thirty-two rows, the registry at 108 done and 21 partial. What Linux decides before a filesystem is asked (EXDEV, EBUSY for a mount's root, a directory into itself) is decided in the handler;st_devis the mount, so two filesystems are two devices; the shell's mv, ln, chmod and stat are gated at boot. Step 4: the FAT driver (kernel/fs/fat.c, out of the architecture) writes at an offset, truncates, creates long names, renames, removes directories and grows them; a node is identified by where its directory entry sits; the 512-byte whole-file path inkernel/abi/files/regular.cis deleted andpwrite64,pwritev,truncate,ftruncateare done (79 done, 18 partial). Proved by host tests, by mtools reading a volume the driver worked on (scripts/dev/verify-fat-mtools.sh), byscripts/dev/fat-fsck.py, and at boot: the shell writes on the boot volume and the gate checks the image once the machine has stopped. (Step 3: writes through a descriptor at an offset, O_CREAT/O_EXCL/O_TRUNC/O_APPEND/O_RDWR, the umask, and twenty rows from pread64 to copy_file_range; the registry is at 75 done and 22 partial). Steps 1 and 2: the filesystem interface carries what stat reports and has write-at-offset, truncate, create, rmdir, rename, link, symlink, readlink, setattr, statfs and sync as optional operations;vibeos_path_walkfollows symbolic links; andkernel/fs/tmpfs.cis a complete in-memory filesystem at/tmp, host-tested and tortured nightly against a model. The syscalls themselves come from step 3 on. Details in docs/abi/phases.md, L1. - Real on-metal ring-3 -> ring-0 syscall entry (
kernel/arch/x86_64/arch_hw.c+isr.S), two paths into one Linux-ABI dispatcher (vibeos_x86_64_linux_syscall):- Native
syscall/sysret(the real Linux x86-64 fast path): EFER.SCE enabled, STAR/LSTAR/SFMASK programmed, and an LSTAR trampoline that switches to a kernel stack, marshals the Linux ABI (nr in rax; args in rdi/rsi/rdx) into the C ABI, dispatches, andsysretqs back to ring 3. int 0x80gate (DPL 3) as a legacy/bring-up path into the same dispatcher.- User GDT segments ordered data-then-code (for SYSRET) + a TSS with RSP0.
- Linux syscall translation covers the runtime subset used by the user programs, including console I/O, process lifecycle and FAT-backed file operations; unsupported calls return
-ENOSYSand are named in the serial log, so a missing number is visible rather than silent. - The opening sequence of a C runtime. A static libc runs a fixed set of syscalls before it reaches
mainand dies if any of them fails. Implemented:arch_prctl(ARCH_SET_FS/ARCH_GET_FS),set_tid_address,set_robust_list,gettid,ioctl,writev,readv,uname,clock_gettime,prlimit64,futex,sched_yield,rt_sigprocmask,rt_sigaction, and thegetuid/getgidfamily.rseqandgetrandomreturn-ENOSYSdeliberately: both have mandatory fallbacks, and a fake success would be worse than a refusal. - Thread-local storage is real.
arch_prctl(ARCH_SET_FS)writesMSR_FS_BASE, the value is per task, and it is reloaded on every context switch - without that, one program reads another's thread state. A base outside user memory is refused before the write, because a non-canonical value would fault in ring 0. Verified from ring 3 by reading the TLS self-pointer back through%fs:0after the task has been preempted and rescheduled many times, not by checking that the syscall returned zero. mmap,mprotectandmunmapact on the page tables.mprotectgrants and revokes write permission on the real entries and flushes the TLB;munmapunmaps and frees the frames, so a use-after-unmap faults here as it would on Linux.MAP_FIXEDand file-backed mappings are refused rather than quietly ignored - a program that asks for a specific address and silently gets another one corrupts itself later, far from the call.- What a program does once it is running, beyond the startup sequence:
fstat,newfstatat,openat,getcwd,readlinkat,prctl,setuid/setgid,getppid,time, andclonefor the flags that meanfork. These are the calls that separate "a libc starts" from "a program works": BusyBox reaches the filesystem throughopenat,fstat,readandgetdents64, and the boot fails onbusybox_file_operations_failedif any of them regresses. - Signal delivery is implemented, not stubbed.
rt_sigactionandrt_sigprocmaskinstall real dispositions and masks;kill,tkillandtgkillraise; a raise sets a pending bit and wakes a task blocked inread(). Delivery happens on the way back to user space, where the process's own stack exists: the frame goes below the 128-byte red zone, aligned as a call site, with the C library'sSA_RESTORERtrampoline as the return address.rt_sigreturnrestores that frame but forcescs,ssandrflagsback to safe values and checks a magic word first, because the frame is user-writable and nothing read out of it may decide privilege.SIGKILLandSIGSTOPare neither catchable nor blockable. Linuxsigset_tbits are numbered from zero (bit 0 is signal 1) and are converted only inhw_sigset_from_user/hw_sigset_to_user. A wait status is not an exit code: exit code in the high byte, signal in the low seven bits. Gated - the boot fails onsignal_delivery_brokeniftests/linux/musl_signal.c, built bymusl-gccagainst a real libc, does not reportSIG_OK. - Pipes and descriptor plumbing:
pipe,pipe2,dup,dup2, inheritance acrossforkwith the pipe's reader/writer counts adjusted, release on exit, andSIGPIPEplusEPIPEfor a write with no reader. A pipe outlives its last writer so a reader can drain it.dup2onto 0, 1 or 2 records a standard-descriptor redirection, since the console is not an entry in the descriptor table. Gated:ls /EFI/BOOT | wc -lruns in BusyBox's shell and the boot fails onpipeline_did_not_complete. - Verified in QEMU (GCC and Clang): a real user ELF is loaded (parsed by the portable, host-tested
kernel/core/elf.c), run in ring 3, and prints via a nativesyscall, thenexitreturns cleanly to the kernel. This hardware front end will route into the portable dispatcher and the Linux personality (user/compat/linux) next.
- Native
- Central syscall dispatcher in
kernel/core/syscall.c(portable model). - ABI helper mappings in
include/vibeos/syscall_abi.h. - Rights/policy lookup layer in
kernel/core/syscall_policy.c. - Process/thread lifecycle syscall family.
- Scheduler observability and runtime-control syscall family.
- Waitset ownership/stats/wake-policy syscall paths.
- Security/audit/policy control syscalls with kernel-vs-user authorization checks.
- ABI version/compatibility syscalls (
VIBEOS_SYSCALL_ABI_VERSION_GET,VIBEOS_SYSCALL_ABI_COMPAT_CHECK) with compatibility helpers insyscall_abi.h. - The on-metal dispatcher validates user pointers before dereference for the implemented Linux-ABI subset.
Pending
nanosleepandpoll. A shell that waits on several descriptors at once needspoll; the pipeline path currently blocks on one at a time.clonewithCLONE_VM/CLONE_THREADreturns-ENOSYS, and real futexes belong with real threads rather than before them.- Signal gaps: no
SA_SIGINFOsiginfo_t, no alternate signal stack (sigaltstack), nort_sigsuspend/rt_sigpending, and a handler installed withoutSA_RESTORERcannot be entered at all - the process is terminated instead of being given a kernel-supplied trampoline. A three-argumentSA_SIGINFOhandler is entered with its second and third arguments zeroed. openataccepts onlyAT_FDCWDand there is no per-process working directory, so relative paths resolve against the volume root.sendfileis refused; callers are expected to take their read-and-write fallback.- Copy-on-write statistics are printed (
[MM] COW_STATS) but no gate asserts them. - An entropy source, so
getrandomcan answer andAT_RANDOMcan carry something better than nothing. - Stronger multi-tenant authorization model beyond relation-based checks.
- Syscall ABI versioning strategy with compatibility negotiation.
- Per-syscall latency telemetry and regression thresholds.
- Consolidate the hardware Linux-ABI dispatcher and portable syscall policy dispatcher behind one audited authorization boundary.
Next checkpoint
pollandnanosleep, so a shell can wait on more than one descriptor and a program can sleep without spinning.- Consolidate the runtime and portable dispatch paths, then add negative pointer/permission tests for every exposed syscall.