Syscall API
The personality-aware syscall dispatcher and the kernel-ops callback table exposed to the Zig personality layer.
src/syscall_handler/time.rs
clock_gettime fn
fn clock_gettime(clock : usize, buf : UserSliceWo) -> Result<()>nanosleep fn
fn nanosleep(req_buf : UserSliceRo, rem_buf_opt : Option<UserSliceWo>) -> Result<()>Nanosleep will sleep by switching the current context
sched_yield fn
fn sched_yield() -> Result<()>src/syscall_handler/process.rs
exit_this_context fn
fn exit_this_context(excp : Option<kernel_syscall::Exception>) ->!mprotect fn
fn mprotect(address : usize, size : usize, flags : MapFlags) -> Result<()>usermode_bootstrap fn
unsafe fn usermode_bootstrap(bootstrap : &Bootstrap)bootstrap_mem fn
unsafe fn bootstrap_mem(bootstrap : &crate::Bootstrap) -> &'static [u8]src/syscall_handler/usercopy.rs
UserSlice struct
struct UserSlice { /* … */ }UserSliceRo type
pub type UserSliceRo = UserSlice<true, false>;UserSliceWo type
pub type UserSliceWo = UserSlice<false, true>;UserSliceRw type
pub type UserSliceRw = UserSlice<true, true>;UserSlice<READ, WRITE>::split_at fn
fn split_at(self, idx : usize) -> Option<(Self, Self)>Split [0, end) into [0, idx) and [idx, end)
UserSlice<READ, WRITE>::reinterpret_unchecked fn
fn reinterpret_unchecked<const NEW_READ : bool, const NEW_WRITE : bool>(self,) -> UserSlice<NEW_READ, NEW_WRITE>Not unsafe, because user memory is not covered by the memory model that decides if something is UB, but it can break logic invariants
validate_region fn
fn validate_region(address : usize, size : usize) -> Result<PageSpan>Convert [addr, addr+size) into (page, page_count).
This will fail if:
- the base address is not page-aligned,
- the length is not page-aligned,
- the region is empty (EINVAL), or
- any byte in the region exceeds USER_END_OFFSET (EFAULT).
src/syscall_handler/kernel_ops_table.rs
Kernel operation callback table for Zig personality layer
Convention: return i32 — non-negative = success value, negative = -errno. For M1 ("Hello World") only write and exit are wired.
open fn
unsafe extern "C" fn open(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32close fn
unsafe extern "C" fn close(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32read fn
unsafe extern "C" fn read(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32write fn
unsafe extern "C" fn write(fd : usize, buf : usize, count : usize, _d : usize, _e : usize, _f : usize) -> i32lseek fn
unsafe extern "C" fn lseek(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32fstat fn
unsafe extern "C" fn fstat(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32fcntl fn
unsafe extern "C" fn fcntl(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32dup fn
unsafe extern "C" fn dup(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32dup2 fn
unsafe extern "C" fn dup2(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32fpath fn
unsafe extern "C" fn fpath(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32fsync fn
unsafe extern "C" fn fsync(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32ftruncate fn
unsafe extern "C" fn ftruncate(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32mkdir fn
unsafe extern "C" fn mkdir(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32rmdir fn
unsafe extern "C" fn rmdir(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32unlink fn
unsafe extern "C" fn unlink(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32rename fn
unsafe extern "C" fn rename(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32link fn
unsafe extern "C" fn link(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32symlink fn
unsafe extern "C" fn symlink(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32readlink fn
unsafe extern "C" fn readlink(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32chmod fn
unsafe extern "C" fn chmod(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32chown fn
unsafe extern "C" fn chown(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32mmap fn
unsafe extern "C" fn mmap(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32munmap fn
unsafe extern "C" fn munmap(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32mprotect fn
unsafe extern "C" fn mprotect(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32exit fn
unsafe extern "C" fn exit(_code : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32getpid fn
unsafe extern "C" fn getpid(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32getppid fn
unsafe extern "C" fn getppid(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32getuid fn
unsafe extern "C" fn getuid(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32getgid fn
unsafe extern "C" fn getgid(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32geteuid fn
unsafe extern "C" fn geteuid(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32getegid fn
unsafe extern "C" fn getegid(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32yield_op fn
unsafe extern "C" fn yield_op(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32clock_gettime fn
unsafe extern "C" fn clock_gettime(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32nanosleep fn
unsafe extern "C" fn nanosleep(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32futex fn
unsafe extern "C" fn futex(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32unimplemented fn
unsafe extern "C" fn unimplemented(_a : usize, _b : usize, _c : usize, _d : usize, _e : usize, _f : usize) -> i32Stub for reserved / unimplemented slots.
src/syscall_handler/debug.rs
format_call fn
fn format_call(a : usize, b : usize, c : usize, d : usize, e : usize, f : usize) -> StringSyscallDebugInfo struct
struct SyscallDebugInfo { /* … */ }debug_start fn
fn debug_start([a, b, c, d, e, f] : [usize; 6])debug_end fn
fn debug_end([a, b, c, d, e, f] : [usize; 6], result : Result<usize>)src/syscall_handler/privilege.rs
mkns fn
fn mkns(mut user_buf : UserSliceRo) -> Result<usize>src/syscall_handler/fs.rs
Filesystem syscalls
file_op_generic fn
fn file_op_generic<T>(fd : FileHandle, op : impl FnOnce(&dyn KernelScheme, usize) -> Result<T>,) -> Result<T>file_op_generic_ext fn
fn file_op_generic_ext<T>(fd : FileHandle, op : impl FnOnce(&dyn KernelScheme, Arc<RwLock<FileDescription>>, FileDescription) -> Result<T>,) -> Result<T>copy_path_to_buf fn
fn copy_path_to_buf(raw_path : UserSliceRo, max_len : usize) -> Result<alloc::string::String>open fn
fn open(raw_path : UserSliceRo, flags : usize) -> Result<FileHandle>Open syscall
rmdir fn
fn rmdir(raw_path : UserSliceRo) -> Result<()>rmdir syscall
unlink fn
fn unlink(raw_path : UserSliceRo) -> Result<()>Unlink syscall
close fn
fn close(fd : FileHandle) -> Result<()>Close syscall
dup fn
fn dup(fd : FileHandle, buf : UserSliceRo) -> Result<FileHandle>Duplicate file descriptor
dup2 fn
fn dup2(fd : FileHandle, new_fd : FileHandle, buf : UserSliceRo) -> Result<FileHandle>Duplicate file descriptor, replacing another
call fn
fn call(fd : FileHandle, payload : UserSliceRw, flags : CallFlags, metadata : UserSliceRo,) -> Result<usize>sendfd fn
fn sendfd(socket : FileHandle, fd : FileHandle, flags_raw : usize, arg : u64) -> Result<usize>fcntl fn
fn fcntl(fd : FileHandle, cmd : usize, arg : usize) -> Result<usize>File descriptor controls
flink fn
fn flink(fd : FileHandle, raw_path : UserSliceRo) -> Result<()>frename fn
fn frename(fd : FileHandle, raw_path : UserSliceRo) -> Result<()>fstat fn
fn fstat(fd : FileHandle, user_buf : UserSliceWo) -> Result<()>File status
funmap fn
fn funmap(virtual_address : usize, length : usize) -> Result<usize>mremap fn
fn mremap(old_address : usize, old_size : usize, new_address : usize, new_size : usize, flags : usize,) -> Result<usize>lseek fn
fn lseek(fd : FileHandle, pos : i64, whence : usize) -> Result<usize>sys_read fn
fn sys_read(fd : FileHandle, buf : UserSliceWo) -> Result<usize>sys_write fn
fn sys_write(fd : FileHandle, buf : UserSliceRo) -> Result<usize>src/syscall_handler/futex.rs
Futex
Futex or Fast Userspace Mutex is "a method for waiting until a certain condition becomes true."
For more information about futexes, please read this blog post, and the futex(2) man page
FutexEntry struct
struct FutexEntry { /* … */ }futex fn
fn futex(addr : usize, op : usize, val : usize, val2 : usize, _addr2 : usize) -> Result<usize>src/syscall_handler/mod.rs
Multi-personality syscall handler
This module replaces the old single-dispatch syscall handler with a personality-aware dispatcher. It calls into the Zig personality library to handle syscall dispatch per OS personality.
Personality enum
enum Personality {
Kernel = 0,
Linux = 1,
Windows = 2,
Darwin = 3,
FreeBSD = 4,
NetBSD = 5,
OpenBSD = 6,
}Personality identifiers, matching personality/src/personality.zig.
KernelOp type
pub type KernelOp = unsafe extern "C" fn(a : usize, b : usize, c : usize, d : usize, e : usize, f : usize,) -> i32;KernelOps struct
struct KernelOps { /* … */ }init_personality fn
fn init_personality()Initialise the personality layer. Leaks the ops table for permanent lifetime.
syscall fn
fn syscall(a : usize, b : usize, c : usize, d : usize, e : usize, f : usize) -> usizeThe main syscall entry point, called from arch trap handlers.