Syscalls
Userspace enters the kernel through SYSCALL, and the kernel returns through SYSRET.
There is no interrupt gate for system calls and no argument block on the stack: the call
number goes in rax, and up to six arguments go in registers.
| Register | Carries |
|---|---|
rax |
the call number on the way in, the result on the way out |
rdi, rsi, rdx, r10, r8, r9 |
arguments one through six |
rcx, r11 |
clobbered by the instruction itself: return address and RFLAGS |
The fourth argument is in r10 rather than rcx for the reason the last row gives:
SYSCALL puts the return address in rcx before any handler runs, so an argument left
there would be gone.
// The whole of the userspace side, from programs/edos_lib/src/sys.rs.pub unsafe fn syscall2(num: u64, arg1: u64, arg2: u64) -> u64 { let ret: u64; unsafe { asm!( "syscall", in("rax") num, in("rdi") arg1, in("rsi") arg2, lateout("rax") ret, lateout("rcx") _, lateout("r11") _, options(nostack), ); } ret}Reporting failure
Section titled “Reporting failure”There is no errno global and no negative-value convention shared across the table. A call
that returns a u64 signals failure with u64::MAX; one that returns a signed value
signals it with -1. Either way the number itself carries no detail, so the failing
handler stores a code on the calling thread and userspace reads it back with call 0x400.
The code is per thread, and every handler that can fail clears it before doing any work, so a stale value from an earlier call cannot be mistaken for a fresh one. A call that succeeds leaves it cleared.
Paths are NUL-terminated and are rejected past 1024 bytes. Every pointer userspace hands
over is copied through checked helpers rather than dereferenced: a bad address is
EFAULT, not a kernel fault.
The table
Section titled “The table”0readRead from a descriptor into a user buffer, advancing its offset.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsibuf*mut u8Destination buffer. rdxcountusizeBytes to read. Returnsi64 — bytes read, 0 at end of file, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorBlocks on a pipe, a pty or a tty with nothing buffered. Files are served from the page cache, so a hit never reaches the disk.
1writeWrite a user buffer to a descriptor.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsibuf*const u8Source buffer. rdxcountusizeBytes to write. A zero-length write returns 0 without touching the descriptor.
3closeRelease a descriptor.I/O
Reg Argument Type Meaning rdifdu64File descriptor. 4list_dirPack a directory listing into a user buffer.Filesystem
Reg Argument Type Meaning rdipath*const u8Directory to list. rsibuf*mut u8Destination buffer. rdxbuf_sizeusizeBuffer capacity in bytes. Returnsi64 — bytes written, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorEntries are fixed-size headers each followed by a name; the return value is a byte count, not an entry count.
5getcwdCopy the working directory out as a NUL-terminated path.Filesystem
Reg Argument Type Meaning rdibuf*mut u8Destination buffer. rsisizeusizeBuffer capacity in bytes. 6chdirChange the working directory of the calling process.Filesystem
Reg Argument Type Meaning rdipath*const u8Directory to move to. 7pollWait until one of a set of descriptors is ready.I/O
Reg Argument Type Meaning rdifds*mut SelectFdArray of descriptors and interests; results are written back in place. rsicountusizeNumber of entries. rdxtimeout_msu64Timeout in milliseconds. SelectFd is { fd: u64, interests: PollState, result: PollState }, and PollState is five bools: readable, writable, error, hangup, invalid.
8fstatMetadata for an open descriptor.Filesystem
Reg Argument Type Meaning rdifdu64File descriptor. rsistatbuf*mut FstatEntryDestination struct. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError9mmapMap anonymous, file-backed or physical memory into the address space.Memory
Reg Argument Type Meaning rdiaddru64Requested address, or 0 to let the kernel choose. rsilengthu64Length in bytes. rdxprotu32PROT_READ 0x1, PROT_WRITE 0x2, PROT_EXEC 0x4. r10flagsu32MAP_SHARED 0x01, MAP_PRIVATE 0x02, MAP_FIXED 0x10, MAP_ANONYMOUS 0x20, MAP_PHYSICAL 0x40, MAP_WRITE_COMBINING 0x80. r8phys_or_fdu64Physical address for MAP_PHYSICAL, descriptor for a file-backed mapping. r9file_offsetu64Offset into the file; file-backed mappings only. Pages are faulted in on demand. MAP_PHYSICAL is how a driver in userspace reaches device memory, and it is the reason this call can return EPERM.
10statMetadata for a path.Filesystem
Reg Argument Type Meaning rdipath*const u8Path to inspect. rsipath_lenusizeLength of the path in bytes. rdxstatbuf*mut FstatEntryDestination struct. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError11munmapRemove a mapping and shoot down the stale TLB entries.Memory
Reg Argument Type Meaning rdiaddru64Start of the mapping. rsilengthu64Length in bytes. 12lseekMove the offset of a file descriptor.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsioffseti64Signed displacement. rdxwhenceu320 SEEK_SET, 1 SEEK_CUR, 2 SEEK_END. Only regular files carry an offset; anything else is rejected.
13ftruncateSet the length of an open file.Filesystem
Reg Argument Type Meaning rdifdu64File descriptor. rsisizeu64New length in bytes. 14fsyncFlush one file, data and metadata, to stable storage.Filesystem
Reg Argument Type Meaning rdifdu64File descriptor. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError15isattyReport whether a descriptor is a terminal.I/O
Reg Argument Type Meaning rdifdu64File descriptor. 16ioctlDevice-specific control, for ptys and for devfs nodes.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsirequestu64Device-defined request code. rdxargu64Inline value, or a pointer when arg_len is non-zero. r10arg_lenusizeSize of the buffer arg points at. r8flagsu64IOCTL_FLAG_READ 1 copies the buffer in, IOCTL_FLAG_WRITE 2 copies it back out. Returnsi64 — the device’s own value, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorThe buffer is bounced through the kernel rather than handed to the driver, so a device never touches a user pointer. devfs nodes are dispatched directly instead of through the filesystem mailbox.
17preadRead at an explicit offset, leaving the descriptor offset alone.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsibuf*mut u8Destination buffer. rdxcountusizeBytes to read. r10offsetu64Absolute file offset. Returnsi64 — bytes read, 0 at end of file, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorThreads of one process share a descriptor table, so they share one offset per descriptor: lseek followed by read races by construction. This call is the fix, and it is ESPIPE on anything without an offset.
18pwriteWrite at an explicit offset, leaving the descriptor offset alone.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsibuf*const u8Source buffer. rdxcountusizeBytes to write. r10offsetu64Absolute file offset. O_APPEND is deliberately not consulted: a positional write that silently lands somewhere else is worse than no call at all.
19readvRead into a list of buffers, filling each before moving to the next.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsiiov*const IoVecArray of { base, len } pairs. rdxiovcntusizeNumber of entries, at most IOV_MAX (1024). Returnsi64 — total bytes read, 0 at end of file, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorEach buffer is a separate underlying read, so the buffers fill in order but the sequence is not atomic against a concurrent reader. A short read ends the sequence, and an error after a partial transfer returns the partial count with errno cleared, as POSIX requires.
20writevWrite a list of buffers in order.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsiiov*const IoVecArray of { base, len } pairs. rdxiovcntusizeNumber of entries, at most IOV_MAX (1024). Returnsi64 — total bytes written, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorA zero-length entry is skipped rather than ending the run. A total length past i64::MAX is rejected before anything is written.
21accessTest a path for existence and readability.Filesystem
Reg Argument Type Meaning rdipath*const u8Path, not NUL-terminated. rsipath_lenusizeLength in bytes. rdxmodeu32F_OK 0, X_OK 1, W_OK 2, R_OK 4. Returnsi32 — 0 if the access would be permitted, -1 otherwiseErrorsplus any filesystem failure, mapped fromFsErrorDelegates to faccessat with AT_FDCWD. There is one user id, so only the read-only attribute can actually deny anything; undefined mode bits are EINVAL rather than ignored.
22pipeCreate a pipe and return both ends.I/O
Reg Argument Type Meaning rdipipefd*mut [u64; 2]Receives [read_fd, write_fd]. If the copy back to userspace faults, both descriptors are closed rather than leaked.
32dupDuplicate a descriptor onto the lowest free number.I/O
Reg Argument Type Meaning rdioldfdu64Descriptor to duplicate. 33dup2Duplicate a descriptor onto a chosen number, closing whatever was there.I/O
Reg Argument Type Meaning rdioldfdu64Descriptor to duplicate. rsinewfdu64Target number. 34msyncFlush the dirty pages of a MAP_SHARED range to storage.Memory
Reg Argument Type Meaning rdiaddru64Start of the range. rsilenu64Length in bytes. rdxflagsu32MS_ASYNC 0x1, MS_SYNC 0x2, MS_INVALIDATE 0x4. The VMA lock collects the work and is dropped before any disk I/O runs.
35nanosleepSleep for a duration given in nanoseconds.Time
Reg Argument Type Meaning rdireq*const TimespecRequested duration; tv_nsec must be under 1e9. rsirem*mut TimespecAccepted and validated, never written. A sleep ends on any wake, so the kernel loops until the deadline passes. `rem` stays unwritten because there are no userspace signal handlers yet, which makes an early return unobservable.
39getpidProcess ID of the caller.Process
Takes no arguments.
40waitpidWait for a child to exit and collect its status.Process
Reg Argument Type Meaning rdipidu64Child to wait for. rsiblocku641 parks until the child exits, anything else polls. rdxstatus*mut i32Receives the exit code; may be null. Returnsu64 — the pid, 0 if it has not exited and block was 0, u64::MAX on errorErrors57spawnLoad a program as a new process with three inherited descriptors.Process
Reg Argument Type Meaning rdipath*const u8Program to load. rsiargv*const *const u8NULL-terminated argument vector. rdxstdin_fdu64Descriptor to install as stdin. r10stdout_fdu64Descriptor to install as stdout. r8stderr_fdu64Descriptor to install as stderr. Registers are scarce, so anything richer than three descriptors goes through spawn2.
59execveReplace this process’s image, keeping its pid.Process
Reg Argument Type Meaning rdipath*const u8Program to load. rsiargv*const *const u8NULL-terminated argument vector. rdxenvp*const *const u8NULL-terminated environment. One rule dictates the order of the whole implementation: nothing observable changes until the point of no return, and nothing after that point may fail.
60exitTerminate the calling thread.Process
Reg Argument Type Meaning rdicodei32Exit status. 72fcntlDescriptor flags, status flags and duplication.I/O
Reg Argument Type Meaning rdifdu64File descriptor. rsicmdu64F_DUPFD 0, F_GETFD 1, F_SETFD 2, F_GETFL 3, F_SETFL 4, F_DUPFD_CLOEXEC 1030. rdxargu64Command-specific argument. F_GETFL reports the access mode, O_APPEND and O_NONBLOCK. F_SETFL can change only O_NONBLOCK; the access mode and the creation flags are ignored there rather than refused, so a caller that reads flags and writes them back does not fail.
76truncateSet a file length by path.Filesystem
Reg Argument Type Meaning rdipath*const u8Path, not NUL-terminated. rsipath_lenusizeLength in bytes. rdxsizeu64New length in bytes. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorGrowing a file creates a hole: the blocks it names are never allocated and read back as zeros. Shrinking zeroes the surviving tail of the last cached page, so a later grow cannot resurrect the old bytes.
78getdentsStream a directory listing from an entry index.Filesystem
Reg Argument Type Meaning rdipath*const u8Directory to list. rsipath_lenusizeLength in bytes. rdxbuf*mut u8Destination buffer. r10buf_sizeusizeBuffer capacity in bytes. r8startusizeIndex of the first entry to pack. Returnsi64 — bytes written, 0 once `start` is past the last entry, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorThe caller advances `start` by the number of entries it decoded, so there is no in/out cursor to keep. An entry that cannot fit on its own is EINVAL, not 0, because 0 means end of directory and would silently drop the tail.
82renameRename or move an entry.Filesystem
Reg Argument Type Meaning rdiold_path*const u8Existing path. rsinew_path*const u8Destination path. 88symlinkCreate a symbolic link.Filesystem
Reg Argument Type Meaning rditarget*const u8What the link points at, stored verbatim. rsitarget_lenusizeLength in bytes. rdxpath*const u8Where the link is created. r10path_lenusizeLength in bytes. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorDelegates to symlinkat with AT_FDCWD. Targets are stored inline in the inode on EFS. Path resolution follows links up to eight hops before returning ELOOP; unlinking a link frees its inode in the same transaction as the detach, since nothing can hold a reference to one.
89readlinkRead a symbolic link target without following it.Filesystem
Reg Argument Type Meaning rdipath*const u8The link itself. rsipath_lenusizeLength in bytes. rdxbuf*mut u8Destination buffer. r10buf_lenusizeBuffer capacity in bytes. Returnsi64 — bytes written, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorTruncates rather than failing when the buffer is short, and no terminator is written. A path that is not a link is an error, not an empty read.
102getuidReal user id of the calling process.System
Takes no arguments.
104getgidReal group id of the calling process.System
Takes no arguments.
109setpgidPlace a process in a process group.Process
Reg Argument Type Meaning rdipidu64The process to move; 0 means the caller. rsipgidu64The group to join; 0 means lead a new group of its own. How a shell puts each pipeline in a group of its own: the first stage leads with a pgid of 0 and the rest join it. That group is then what the terminal hands Ctrl+C and Ctrl+Z to, which is why killing a pipeline kills every stage rather than only the one the shell named.
121getpgidThe process group a process belongs to.Process
Reg Argument Type Meaning rdipidu64The process to ask about; 0 means the caller. 162syncFlush every dirty block cache page to disk.Filesystem
Takes no arguments.
Errors are the writeback thread’s to log; the caller is told nothing because it can do nothing.
169rebootSync every filesystem, then stop or restart the machine.System
Reg Argument Type Meaning rdicmdu640 power off, 1 reset, 2 halt. Soft-off with no AML interpreter: PM1a/PM1b_CNT come from the FADT and SLP_TYPa is decoded structurally out of the DSDT’s \_S5_ package, with emulator ports as a fallback. Reset drives RST_CNT then pulses the 8042. Progress prints to the serial port rather than the log ring, because the kthread that drains the ring will not run again.
186gettidThread ID of the caller.Process
Takes no arguments.
The same value as `getpid` only when the process has one thread. `futex_wait_pi` names an owner by tid, so a userspace lock that lends priority reads it here.
202mountMount a partition at a path.Filesystem
Reg Argument Type Meaning rdidevice_idu64Block device index. rsipartition_idxu64Partition within that device. rdxpath*const u8Mount point. r10fs_type*const u8Filesystem name, e.g. efs or fat32. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError203list_partitionsDescribe every partition the kernel enumerated, as text.Filesystem
Reg Argument Type Meaning rdibuf*mut u8Destination buffer. rsisizeu64Buffer capacity in bytes. 204mkdirCreate a directory.Filesystem
Reg Argument Type Meaning rdipath*const u8Directory to create. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError205rmdirRemove an empty directory.Filesystem
Reg Argument Type Meaning rdipath*const u8Directory to remove. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError206rmdir_allRemove a directory and everything under it.Filesystem
Reg Argument Type Meaning rdipath*const u8Root of the subtree to remove. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorThe recursion lives in the kernel because a userspace walk would race with anyone else writing into the tree.
207unlinkRemove a file.Filesystem
Reg Argument Type Meaning rdipath*const u8File to remove. Returnsi64 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsError208list_mountsDescribe the mount table as text.Filesystem
Reg Argument Type Meaning rdibuf*mut u8Destination buffer. rsisizeusizeBuffer capacity in bytes. 209sleep_msPark the calling thread for a duration.Time
Reg Argument Type Meaning rdimillisecondsu64How long to sleep. 210monotonic_timeNanoseconds since boot, from the HPET.Time
Takes no arguments.
Monotonic with microsecond resolution, scaled to nanoseconds. It never goes backwards and never jumps with the wall clock.
211cloneStart a thread in the calling process’s address space.Process
Reg Argument Type Meaning rdifuncu64Entry point. rsiargu64Value passed to the entry point. rdxflagsu64Clone flags. r10child_stacku64Top of the stack the child runs on. The child shares the address space, the descriptor table and the heap break, and gets its own TLS block and stack.
212futex_waitSleep while a word in memory still holds an expected value.Sync
Reg Argument Type Meaning rdiaddr*const u32Word to watch. rsiexpectedu32Value to sleep on. rdxtimeout_nsu64Timeout in nanoseconds; u64::MAX waits forever. Returnsu64 — 0 woken with the value changed, 1 value did not match or a spurious wake, 2 timed out, u64::MAX on errorErrorsKeyed by the address space plus the address, so two processes sharing a mapping share a queue. The wait queue is dropped when its last waiter leaves.
213futex_wakeWake waiters parked on a word.Sync
Reg Argument Type Meaning rdiaddr*const u32Word waiters are parked on. rsicountu32How many to wake. 214getrandomFill a buffer with random bytes.System
Reg Argument Type Meaning rdibuf*mut u8Destination buffer. rsilenusizeBytes to generate, at most 1 MiB. rdxflagsu64Must be 0. 215shm_createCreate a shared memory region.Shared memory
Reg Argument Type Meaning rdisizeu64Size in bytes. 216shm_mapMap a shared region into the calling process.Shared memory
Reg Argument Type Meaning rdishm_idu64Region id. rsiaddr_hintu64Suggested address, or 0 to let the kernel choose. rdxprotu64PROT_READ 0x1, PROT_WRITE 0x2, PROT_EXEC 0x4. This is what a window buffer is: the client draws into the region and the compositor reads the same frames.
217shm_unmapUnmap a shared region from the calling process.Shared memory
Reg Argument Type Meaning rdiaddru64Address the region was mapped at. 218shm_destroyDestroy a shared region.Shared memory
Reg Argument Type Meaning rdishm_idu64Region id. Refused while any mapping is still live.
219window_createRegister a window with the kernel.Window
Reg Argument Type Meaning rdixi64Position, x. rsiyi64Position, y. rdxwidthu64Width in pixels. r10heightu64Height in pixels. The kernel owns the registry and routes input to it. Decoration, stacking and everything else people call a window manager is userspace.
220window_destroyRemove a window from the registry.Window
Reg Argument Type Meaning rdiwindow_idu64Window id. 221window_setSet a window property.Window
Reg Argument Type Meaning rdiwindow_idu64Window id. rsipropu64VISIBLE 1, X 2, Y 3, WIDTH 4, HEIGHT 5, TITLE_PTR 6, BUFFER_SHM 7, FLAGS 8. rdxvalueu64The value, or a pointer for TITLE_PTR. FLAGS carries FLAG_DOCK 1, the undecorated, undraggable window the taskbar uses.
222window_getRead a window property.Window
Reg Argument Type Meaning rdiwindow_idu64Window id. rsipropu64Property id, as for window_set. 223window_pollDrain pending events for a window.Window
Reg Argument Type Meaning rdiwindow_idu64Window id. rsievents*mut WindowEventDestination array. rdxmaxu64Capacity of that array. 224window_listList every window, for the compositor.Window
Reg Argument Type Meaning rdibuf*mut WindowListEntryDestination array. rsimaxu64Capacity of that array. rdxflagsu64Bit 0 (WINDOW_LIST_CONSUME_DAMAGE) clears each listed window’s damage as it is read. Consuming damage in the same call that reports it is what keeps the compositor from redrawing a window twice or missing a repaint: the caller that acts on the damage is the one that takes it. The list is snapshotted under the registry lock and copied out after it is released, because a copy to a user pointer can demand-fault and parking on a page fill under that lock would leave every other CPU spinning behind it.
225window_send_eventPost an event to a window the caller does not own.Window
Reg Argument Type Meaning rdiwindow_idu64Target window. rsievent*const WindowEventEvent to deliver. How the window manager asks a client to close itself.
226clock_gettimeNanoseconds since the Unix epoch.Time
Reg Argument Type Meaning rdibuf*mut u8Eight-byte buffer receiving a little-endian u64. Answered from the monotonic counter plus a wall-clock offset sampled at boot, so it costs a counter read rather than several RTC port round-trips.
227openptyOpen a pty master and slave pair.I/O
Reg Argument Type Meaning rdifds*mut [u64; 2]Receives [master_fd, slave_fd]. What the terminal emulator opens before it spawns a shell.
228spawn2Spawn with arguments, an environment and three descriptors.Process
Reg Argument Type Meaning rdiargs*const SpawnArgsStruct of { path, argv, envp, stdin_fd, stdout_fd, stderr_fd }. 229killSend a signal to a process.Process
Reg Argument Type Meaning rdipidu64Target process. rsisignumu32Signal number, 1 to 31. 230sigactionInstall a signal disposition.Process
Reg Argument Type Meaning rdisignumu32Signal number, 1 to 31; SIGKILL is rejected. rsihandleru320 SIG_DFL, 1 SIG_IGN, otherwise a handler address. 231shm_sizeSize of a shared region.Shared memory
Reg Argument Type Meaning rdishm_idu64Region id. 232window_damageTell the compositor which part of a window has repainted.Window
Reg Argument Type Meaning rdiwindow_idu64Window id. rsixu32Left edge of the repainted region, in window coordinates. rdxyu32Top edge of that region. r10wu32Its width. Zero means the whole window. r8hu32Its height. Zero means the whole window. Only the window’s own process may declare it repainted, or any process could make the compositor redraw the screen every frame. The region is clamped to the window, since one outside it would grow the union the compositor redraws without describing a pixel it can draw. A client that does not track its own damage passes a zero size and gets the whole window.
233sigprocmaskRead and change the calling thread’s blocked signal mask.Process
Reg Argument Type Meaning rdihowu32SIG_BLOCK 0, SIG_UNBLOCK 1, SIG_SETMASK 2. rsimasku32The set to apply. Sets are 32 bits, so the mask goes in and the old one comes back by value rather than through pointers, matching sigaction. A signal sent while blocked is recorded pending without killing or waking the target; widening the mask delivers it immediately, and SIGKILL is dropped from the mask rather than making the call fail.
234window_grant_shellAppoint another process as part of the shell.Window
Reg Argument Type Meaning rdipidu64Process to appoint. Moving, resizing, framing, minimizing and posting events to a window belong to a shell, not to the window’s owner, so they cannot be gated on ownership. They are gated on this instead. Only a process that already holds the privilege may grant it, and the kernel seeds exactly one: `bin/edos-init`, the only process it starts, which appoints the compositor and the panel. The grant is per pid, follows a process’s threads, and is dropped when the process exits.
235trace_ctlStart or stop syscall tracing on a thread.System
Reg Argument Type Meaning rdiopu64What to do: begin a trace generation, attach a thread, or stop. rsiargu64The thread id for an attach; 0 means the caller. The control half of what `strace` is built on. Tracing is a per-thread generation counter rather than a flag, so a stale attach from a previous run cannot resurrect itself.
236trace_readDrain buffered syscall trace records.System
Reg Argument Type Meaning rdibuf*mut TraceRecordArray receiving the records. rsimaxu64How many records the array holds. rdxtimeout_msu64How long to wait for at least one record. Records carry the call number, not its name: the table in `syscalls/table.rs` is what turns one into the other, and a call added without a row there prints as `syscall_NNN`.
237tcsetpgrpHand the terminal to a process group.I/O
Reg Argument Type Meaning rdifdu64A descriptor on either side of the PTY. rsipgidu64The group that becomes the foreground job. This is what makes a job “foreground”. The line discipline aims Ctrl+C and Ctrl+Z at whichever group holds the terminal, so a shell resuming a job gives it the terminal first and takes it back when the job stops or exits.
238tcgetpgrpThe process group currently holding the terminal.I/O
Reg Argument Type Meaning rdifdu64A descriptor on either side of the PTY. 239sigreturnReturn from a signal handler.Process
Takes no arguments.
Never called directly. The kernel builds a frame on the handler’s stack whose return address points here, so a handler that simply returns lands in this call and the kernel restores the context the signal interrupted.
240socketCreate a socket and install it in the descriptor table.Network
Reg Argument Type Meaning rdidomainu64AF_INET 2. rsitypeu64SOCK_STREAM 1, SOCK_DGRAM 2. rdxprotocolu64Ignored; implied by the type. 241bindBind a socket to a local address.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsiaddr*const SockAddrInLocal address. rdxaddr_lenu64Size of that struct. 242connectOpen a connection to a remote address.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsiaddr*const SockAddrInRemote address. rdxaddr_lenu64Size of that struct. Blocks through the TCP handshake.
243listenMark a bound socket as accepting connections.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsibacklogu32Pending connection queue depth. 244acceptTake the next established connection off a listening socket.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsiaddr*mut SockAddrInReceives the peer address; may be null. rdxaddr_len*mut u32In and out length for that struct. Returnsu64 — descriptor for the new connection, u64::MAX on errorErrors245sendtoSend on a socket, with an explicit destination for datagrams.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsibuf*const u8Payload. rdxlenu64Payload length. r10flagsu64Unused. r8addr*const SockAddrInDestination; null on a connected socket. r9addr_lenu64Size of that struct. 246recvfromReceive on a socket, optionally reporting the sender.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsibuf*mut u8Destination buffer. rdxlenu64Buffer capacity. r10flagsu64Unused. r8addr*mut SockAddrInReceives the sender address; may be null. r9addr_len*mut u32In and out length for that struct. 247shutdownClose one or both directions of a connection.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsihowu640 read, 1 write, 2 both. 248setsockoptSet a socket option.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsileveli32Option level. rdxoptnamei32Option name. r10val*const u8Option value. r8val_lenu32Length of that value. 249pingSend an ICMP echo request and wait for the reply.Network
Reg Argument Type Meaning rdidst_ip*const [u8; 4]Destination address. rsiidu16ICMP identifier. rdxsequ16ICMP sequence number. r10timeout_msu64Timeout in milliseconds; 0 means 5000. Returnsu64 — round-trip time in microseconds, u64::MAX on timeout or errorErrorsA raw socket API would be the general answer; this is the one ICMP case userspace actually needs.
250netinfoDescribe the network interfaces as text.Network
Reg Argument Type Meaning rdibuf*mut u8Destination buffer. rsilenusizeBuffer capacity in bytes. 251getsockoptRead a socket option.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsileveli32Option level. rdxoptnamei32Option name. r10val*mut u8Receives the value. r8val_len*mut u32In and out length for that buffer. 252getpeernameAddress of the remote end of a connection.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsiaddr*mut SockAddrInReceives the peer address. rdxaddr_len*mut u32In and out length for that struct. 253getsocknameLocal address a socket is bound to.Network
Reg Argument Type Meaning rdifdu64File descriptor. rsiaddr*mut SockAddrInReceives the local address. rdxaddr_len*mut u32In and out length for that struct. 254statfsFilesystem statistics for the mount that holds a path.Filesystem
Reg Argument Type Meaning rdipath*const u8Any path on the filesystem. rsibuf*mut RawStatFsDestination struct. rdxbuf_lenusizeSize of that struct. 255forkDuplicate the calling process, copy-on-write.Process
Takes no arguments.
Returnsi64 — the child pid in the parent, 0 in the child, -1 on errorErrorsPrivate mappings are marked read-only in both processes and split on the first write fault.
256getdnsThe resolver address the stack learned from DHCP.Network
Reg Argument Type Meaning rdiaddr*mut [u8; 4]Receives the resolver address. A resolver is configuration, and there is no /etc/resolv.conf convention here, so userspace asks the stack that learned it.
257openatOpen a path resolved against a directory descriptor.I/O
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. r10flagsu64Access mode and creation flags. Returnsi64 — new descriptor, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorThe only way in: a plain open is this call against AT_FDCWD. The low two bits are the access mode — 0 O_RDONLY, 1 O_WRONLY, 2 O_RDWR — and 0x40 is O_CREAT, 0x200 O_TRUNC, 0x400 O_APPEND, 0x800 O_NONBLOCK. An append offset is resolved per write rather than at open time. Taking pointer and length rather than a NUL-terminated string means userspace does not have to allocate a CString per open.
258mkdiratCreate a directory relative to a directory descriptor.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorNo mode argument: there are no permission bits to observe yet.
262fstatatStat a path resolved against a directory descriptor.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. r10statbuf*mut FstatEntryReceives the metadata. r8flagsu64Must be zero. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorstat is this call against the cwd. A nonzero flags word is rejected rather than ignored: AT_SYMLINK_NOFOLLOW cannot be honoured while the lookup follows links.
263unlinkatRemove a file or directory relative to a directory descriptor.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. r10flagsu640, or AT_REMOVEDIR (0x200) to remove a directory. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorAT_REMOVEDIR is the only accepted flag; anything else is EINVAL.
264renameatRename, resolving each side against its own directory descriptor.Filesystem
Reg Argument Type Meaning rdiolddirfdi64Base for the old path, or AT_FDCWD (-100). rsioldpath*const u8Existing name. rdxoldpath_lenusizeLength in bytes. r10newdirfdi64Base for the new path, or AT_FDCWD (-100). r8newpath*const u8New name. r9newpath_lenusizeLength in bytes. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorrename routes through the same body, which is what gives it real filesystem error codes instead of a flat EINVAL.
266symlinkatCreate a symbolic link relative to a directory descriptor.Filesystem
Reg Argument Type Meaning rditarget*const u8What the link points at, stored verbatim. rsitarget_lenusizeLength in bytes. rdxnewdirfdi64Base for the link path, or AT_FDCWD (-100). r10linkpath*const u8Where the link is created. r8linkpath_lenusizeLength in bytes. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorThe descriptor places the link only. The target is never resolved at creation time, so it may dangle, and a dangling link still takes the name.
267readlinkatRead a link target relative to a directory descriptor.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8The link itself. rdxpath_lenusizeLength in bytes. r10buf*mut u8Destination buffer. r8buf_lenusizeBuffer capacity in bytes. Returnsi64 — bytes written, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorreadlink is this call against the cwd.
269faccessatTest access to a path relative to a directory descriptor.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. r10modeu32F_OK 0, X_OK 1, W_OK 2, R_OK 4. r8flagsu64Must be zero. Returnsi32 — 0 if the access would be permitted, -1 otherwiseErrorsplus any filesystem failure, mapped fromFsErrorFlags are rejected rather than ignored. AT_EACCESS names the only set of ids there is, and AT_SYMLINK_NOFOLLOW cannot be honoured while the lookup follows links.
280utimensatSet a file’s access and modification times.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. r10times*const [Timespec; 2]Access time then modification time; null means both now. r8flagsu64Must be zero. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorUTIME_NOW stamps the current time and UTIME_OMIT leaves that field alone. EFS applies both in one journal transaction. AT_SYMLINK_NOFOLLOW is rejected, since the underlying set_times follows links.
281clock_settimeStep the wall clock to a known time.Time
Reg Argument Type Meaning rdibuf*const u8Eight-byte buffer holding little-endian nanoseconds since the Unix epoch. The RTC is sampled once at boot and every later answer is that reading plus HPET ticks, so the clock is only ever as good as one one-second-resolution sample. `sntp` corrects it through here. The step is stored as an offset, so the monotonic counter durations are measured against is untouched.
282sched_yieldGive up the rest of this thread’s timeslice.Process
Takes no arguments.
Cannot fail: the thread stays runnable and is put back on its run queue behind anything else ready at the same priority. With nothing else ready it returns having done nothing but pay the syscall boundary, which is why `switchbench` measures the idle case separately.
283mkfifoatCreate a named pipe relative to a directory descriptor.Filesystem
Reg Argument Type Meaning rdidirfdi64Directory the path is resolved against, or AT_FDCWD (-100) for the cwd. Ignored when the path is absolute. rsipath*const u8Path, not NUL-terminated. rdxpath_lenusizeLength in bytes. Returnsi32 — 0 on success, -1 on errorErrorsplus any filesystem failure, mapped fromFsErrorCreates the name only; the pipe behind it is allocated on the first open and freed when the last descriptor closes. No mode argument, for the same reason mkdirat has none.
284clipboard_getRead a clipboard buffer.Window
Reg Argument Type Meaning rdiwhichu640 for the clipboard, 1 for the primary selection. rsibuffer*mut u8Where to copy the contents. May be null to ask only for the length. rdxlenusizeRoom in the buffer, in bytes. Returns the whole length rather than the number of bytes copied, so a caller with a short buffer learns how big to make it. The copy happens after the clipboard lock is released, for the reason window_list copies outside the registry lock.
285clipboard_setReplace a clipboard buffer.Window
Reg Argument Type Meaning rdiwhichu640 for the clipboard, 1 for the primary selection. rsibuffer*const u8Contents to store. Ignored when len is 0. rdxlenusizeLength in bytes, at most 64 KiB. The clipboard lives in the kernel so a copy outlives the process that made it: closing the window you copied from does not empty it. A length of 0 clears the buffer and reads no user pointer. The bytes are copied in before the lock is taken, since a copy from a user pointer can demand-fault and parking on a page fill under a spin lock would leave every other CPU spinning behind it.
286window_waitBlock until a window has events queued or the screen has been presented.Window
Reg Argument Type Meaning rdiwindow_idu64Window id. rsiseen_frameu64The frame count the caller last acted on, taken from a previous return. rdxtimeout_msu64Milliseconds to wait, or 0 to wait indefinitely. Returnsu64 — reason bits in the low 32 (1 events, 2 frame) and the current frame count in the high 32; 0 if the wait timed out with nothing to reportErrorsCannot fail.A client with no way to block guesses an interval and sleeps: it either wakes with nothing to do or leaves an event sitting for the rest of that interval. window_poll cannot block, so this exists alongside it rather than replacing it — the caller still polls to collect the events once this says there are some. The frame count is passed back in rather than remembered per window, because a window can be waited on from more than one thread and a kernel-held count would let whichever called first consume the signal.
287window_presentReport that a frame has been put on the display.Window
Takes no arguments.
Called by whatever owns the screen, once per presented frame. It wakes every client blocked in window_wait so they draw into the frame after this one instead of guessing when it happened. Deliberately not a side effect of consuming damage: that happens before the frame is drawn, and a client woken then would be racing the compositor it is trying to keep step with.
288window_grab_keyClaim or release a key chord, so the focused window does not see it.Window
Reg Argument Type Meaning rdicodeu32pc_keyboard key code. rsimodsu32Modifier mask: shift, ctrl, alt. rdxclaimu64Non-zero to claim the chord, zero to release it. The mask is matched exactly, so Alt+Tab and Ctrl+Alt+Tab are different chords and claiming one leaves the other with the focused window. Restricted to the session shell for the same reason window management is: a chord claimable by any process would let one program read another’s keys by taking them away from it. A grab dies with the process that holds it, like a file descriptor, so there is no reclaim path to get wrong.
289mprotectChange the protection of an existing mapping.Memory
Reg Argument Type Meaning rdiaddru64Start of the range; must be page aligned. rsilengthu64Length in bytes, rounded up to a page. rdxprotu32PROT_READ 0x1, PROT_WRITE 0x2, PROT_EXEC 0x4. The range is split at both edges so it is a whole number of VMAs, then each is retagged and its page table entries updated. A hole anywhere in the range changes nothing and reports ENOMEM, so a partly applied protection is never observable. A page already marked copy-on-write is not made writable here: the fault path still owns that transition, and dropping the COW bit on a retag would share a private page.
314sched_setattrSet a thread’s priority and the service it asks for per pick.Process
Reg Argument Type Meaning rditidu64The thread to change; 0 means the caller. rsiattr*const SchedAttru32 priority, u32 padding, u64 slice_ns. Both fields are clamped rather than rejected: the priority saturates at the top of the table and the slice is held to MIN_SLICE..=MAX_SLICE, which is 250 us to 10 ms. There is no privilege check because this system has no user model to check against, and EEVDF is what makes that tolerable — the worst a thread can do to another by taking the top of the table is claim about 6x its share, which is a share and not a lockout.
315sched_getattrRead back a thread’s scheduling attributes.Process
Reg Argument Type Meaning rditidu64The thread to ask about; 0 means the caller. rsiattr*mut SchedAttrFilled in with the current priority and slice. Reports what was actually set rather than what was asked for, so a caller learns where its slice landed after the clamp.
316setdnsPoint the resolver at an address, or clear the override.Network
Reg Argument Type Meaning rdiaddr*const [u8; 4]Resolver address, or 0.0.0.0 to go back to the one DHCP learned. This is what lets a caching resolver redirect every program on the machine to itself without any of them being rebuilt: they already ask `getdns` for the address to query. The override is held against the calling thread and dies with it.
317futex_wait_pi`futex_wait`, plus the thread the caller believes holds the lock.Sync
Reg Argument Type Meaning rdiaddr*const u32Word to watch. rsiexpectedu32Value to sleep on. rdxtimeout_nsu64Timeout in nanoseconds; u64::MAX waits forever. r10owner_tidu64Thread believed to hold the word, or 0 to ask for no lending. Returnsu64 — as futex_wait: 0 woken with the value changed, 1 no match or a spurious wake, 2 timed out, u64::MAX on errorErrorsA futex word is opaque to the kernel, so unlike a blocking mutex there is nothing in it to read an owner out of; the waiter names one and the kernel lends its priority for exactly as long as the wait lasts. The loan ends with the wait rather than with the release, because the release is a userspace store the kernel never sees.
318profile_ctlStart, stop, or report on the sampling profiler.System
Reg Argument Type Meaning rdiopu64START, STOP or STATS. rsiargu64The requested period for START, or a *mut Stats for STATS. Returnsu64 — for START the period actually in force, otherwise 0; u64::MAX on errorErrorsOne session at a time, owned by the thread that started it, so only that thread may stop it or drain samples. The period comes back clamped to what the sampler accepts rather than being refused.
319profile_readDrain samples from the running session.System
Reg Argument Type Meaning rdidst*mut SampleDestination buffer. rsimaxu64How many samples to take, clamped to the batch limit. rdxtimeout_msu64Park for this long if none are waiting; 0 does not wait. Returnsu64 — samples written, 0 on timeout, u64::MAX on errorErrorsThe session owner’s alone. Anyone else draining would take samples the profiler then never sees, and anyone else parking would add a second waiter to a queue that is kept at depth one.
1024errnoThe error code the caller’s last failing syscall stored.System
Takes no arguments.
Per thread, and cleared at the start of every handler that can fail. The value is the discriminant below, not a POSIX number.
Nothing matches that.
Error codes
Section titled “Error codes”Errno is a plain Rust enum, and what userspace reads is its discriminant. These are
not the POSIX numbers; a program that hardcodes 2 for ENOENT is reading ENOMEM.
| Value | Name | Meaning |
|---|---|---|
| 0 | Clear | No error. Every handler stores this before it does any work. |
| 1 | EINVAL | Invalid argument passed to a syscall. |
| 2 | ENOMEM | Memory allocation failed or memory exhausted. |
| 3 | EFAULT | Bad memory address provided by userspace. |
| 4 | EBADF | Invalid or closed file descriptor. |
| 5 | EACCES | Operation requires permissions the caller lacks. |
| 6 | EPERM | Operation not permitted for the current caller. |
| 7 | ENOENT | Requested file or directory does not exist. |
| 8 | EEXIST | Attempted to create an entry that already exists. |
| 9 | ENOTDIR | Expected a directory but encountered a non-directory entry. |
| 10 | EISDIR | Operation required a regular file but encountered a directory. |
| 11 | ENOSPC | Device or filesystem has no space left for the operation. |
| 12 | EROFS | Write attempted on a read-only filesystem or device. |
| 13 | EIO | Generic I/O failure from the filesystem or storage layer. |
| 14 | EINTR | System call interrupted, e.g. by a signal or a kill. |
| 15 | ENOEXEC | File format is not recognized as an executable. |
| 16 | EAGAIN | Resource temporarily unavailable; the operation would block. |
| 17 | ENOTCONN | Socket is not connected. |
| 18 | ECONNREFUSED | Connection was refused by the remote host. |
| 19 | EADDRINUSE | Address already in use. |
| 20 | EPIPE | Broken pipe: a write to a closed connection. |
| 21 | EAFNOSUPPORT | Address family not supported. |
| 22 | ESPIPE | Seek on a descriptor with no file offset: pipe, socket, tty. |
| 23 | EBUSY | Device or resource in use, e.g. a disk backing a live mount. |
| 24 | UNKNOWN | Placeholder for unmapped kernel error codes. |
Filesystem failures reach userspace through a mapping rather than as their own codes:
FileNotFound becomes ENOENT, NotAFile becomes EISDIR, NotADir becomes
ENOTDIR, Busy becomes EBUSY, InvalidFs and InvalidArgument become EINVAL, and
everything else, including a corrupt filesystem and an AHCI error, becomes EIO.
Adding one
Section titled “Adding one”Four edits, in this order:
- A number constant and a dispatch arm in
kernel/src/syscalls/mod.rs. The arm unpacks registers and calls the implementation; it does not contain logic. - The implementation in the matching
syscalls/*.rs, taking real types rather than registers, clearing the caller’s error code first and copying user memory through the checked helpers. - A wrapper in
programs/edos_lib/, or in theedos_rtcrate and the std fork if it has to be reachable throughstd. - A row here, since this page is transcribed from that table.