Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

System Calls & ABI

This is a reference chapter. It documents two things and keeps them distinct:

  1. What dispatches today — the kernel calls the microkernel actually handles at the end of Phase 4, and the server request ranges minix.rs uses on the wire.
  2. The MINIX ABI minix.rs targets — the POSIX call catalog (PM and VFS) that the musl wrappers and file-system servers will wire up in Phase 5 and beyond. These numbers are the MINIX 3 reference ABI; they are not the request numbers minix.rs currently sends.

The two call paths

MINIX has two kinds of “system call,” and minix.rs keeps both.

POSIX calls (user → server). A user program’s open / read / fork becomes an IPC message to the responsible server, sent with SENDREC:

user program → SENDREC(server_endpoint, &msg) → kernel IPC → server → reply

The kernel routes the message but does not interpret the call. Today this path is driven directly through the minix-ipc crate (by init and worker, using the live PM request numbers below). The musl C wrappers that will make it transparent to C programs — read(fd, buf, n) constructing the message for you — arrive in Phase 5.

Kernel calls (server → kernel). A privileged server asks the kernel for a low-level operation by sending a SENDREC to the SYSTEM task (m_type = the call number). Each call is gated by the caller’s k_call_mask; a process without the bit gets an error.

Kernel calls (SYS_*) — live today

Kernel-call numbers are contiguous from KERNEL_CALL = 0x600 (kernel-shared/src/callnr.rs). Phase 4 defines 18. Twelve have real handlers; six are placeholder stubs whose consumers arrive later (grants in Phase 5, IRQ control in the driver era). The dispatch table is kernel/src/system/mod.rs.

NumberCallStatusPurpose
0x600SYS_GETINFOliveKernel introspection (e.g. GET_WHOAMI).
0x601SYS_PRIVCTLliveSet up a target’s privilege slot (PRIVCTL_SET_USER).
0x602SYS_FORKliveClone a process slot as a frozen child.
0x603SYS_EXECliveReplace a target’s image with a boot-embedded binary.
0x604SYS_EXITliveFull process teardown (address space, endpoint, slot).
0x605SYS_COPYstubInter-space copy — placeholder.
0x606SYS_SAFECOPYstubGrant-validated copy — real grants are Phase 5.
0x607SYS_IRQCTLstubIRQ handler registration — driver era.
0x608SYS_VMCTLliveVM’s paging-mechanism call (see subcalls below).
0x609SYS_SCHEDULEliveSet a process’s priority and quantum.
0x60ASYS_SETALARMliveArm/cancel a per-process one-shot alarm.
0x60BSYS_TIMESstubProcess accounting times — placeholder.
0x60CSYS_DIAGCTLlivePrint inline text to the console (see subcodes below).
0x60DSYS_SETGRANTstubRegister the caller’s grant table — Phase 5.
0x60ESYS_SCHEDCTLliveClaim/release a process for a user-space scheduler.
0x60FSYS_KILLliveRaise a signal on a target (queues toward PM).
0x610SYS_GETKSIGlivePM: fetch the next process with pending signals.
0x611SYS_ENDKSIGlivePM: acknowledge signal processing for a target.

SYS_VMCTL subcalls

SYS_VMCTL is VM’s single privileged lever over the kernel’s paging mechanism. The subcall selector is in the first payload word; the target process (endpoint, SELF allowed) in the next. Numbers start at 1 so a zeroed payload is invalid.

SubcallEffect
VMCTL_PT_MAP (1)Allocate a fresh zeroed frame, map it at vaddr, reply with the PA.
VMCTL_PT_UNMAP (2)Unmap vaddr and free the frame (EINVAL if nothing mapped).
VMCTL_CLEAR_PAGEFAULT (3)Clear a recorded fault and make the target runnable.
VMCTL_GET_PAGEFAULT (4)Read the target’s recorded fault coordinates.
VMCTL_VMINHIBIT_SET / _CLEAR (5/6)Gate scheduling while VM mutates the target’s AS.

See Memory Management for how VM uses these.

SYS_DIAGCTL subcodes

SYS_DIAGCTL is the servers’ debug channel. Servers run at EL0 with no console of their own, so without it their behavior is only observable indirectly, through kernel-side traces. server-rt::diag_print is the client side.

Unlike MINIX 3, which passes a (buf, len) user pointer and copies the text in, minix.rs carries the text inline in the message payload: the subcode in payload 0..4, the length in 4..8, and up to DIAG_TEXT_MAX (88) text bytes from DIAG_TEXT_OFF (8). The channel therefore needs no user-copy machinery and cannot fault — it has to keep working while the copy engine and grants are themselves under construction. diag_print splits longer strings across successive calls, one console line each.

SubcodeEffect
DIAGCTL_CODE_DIAG (1)Print the inline text as one [diag <name>] … line.
DIAGCTL_CODE_STACKTRACE (2)Reserved (MINIX 3) — EINVAL.
DIAGCTL_CODE_REGISTER / _UNREGISTER (3/4)Reserved (MINIX 3 kernel-message subscription) — EINVAL.

The <name> prefix is the caller’s name as the kernel knows it, never anything from the payload, so a server can only ever identify itself. Text is restricted to printable ASCII, which keeps one call to exactly one line — the boot-marker checks in tests/qemu-boot.expected depend on that framing. No extra privilege gate is needed: Priv::k_call_mask already limits kernel calls to server-grade privileges, and the shared USER privilege has an empty mask, so ordinary user processes cannot reach this call.

Server request ranges — live today

Server requests are ordinary IPC m_type values, not kernel calls. Each server occupies a distinct band below NOTIFY_MESSAGE (0x1000), const-asserted disjoint in kernel-shared/src/callnr.rs:

BaseValueServer / requests
PM_RQ_BASE0x700PM: GETPID / FORK / EXIT / WAIT / EXEC
VM_RQ_BASE0xC00VM: PAGEFAULT / BRK / MMAP / MUNMAP / FORK
SEF_RQ_BASE0xD00SEF control: INIT / SIGNAL
DS_RQ_BASE0xE00DS: PUBLISH / RETRIEVE / CHECK
SCHED_RQ_BASE0xF00SCHED: NO_QUANTUM / START / STOP / SET_NICE

The Servers chapter documents each request. These minix.rs-specific numbers are what actually travels on the wire today — distinct from the MINIX 3 POSIX ABI numbers catalogued below.

The MINIX ABI catalog (target)

Reference, not current behavior. The tables below are the MINIX 3 POSIX call ABI that minix.rs is heading toward — the numbering musl and the file-system servers will adopt. They describe the interface, not what is dispatched today: VFS is skeletal (it handles none of these yet), and PM’s live request numbers are the 0x700 band above, not these. Treat this as the map of Phase 5+ work.

PM calls (base 0x000, target)

The Process Manager handles process lifecycle, signals, credentials, and timing.

Call#POSIXDescription
PM_EXIT1_exitTerminate the caller
PM_FORK2forkCreate a child process
PM_WAIT43wait4Wait for a child to change state
PM_GETPID4getpidGet the caller’s PID
PM_SETUID/GETUID5/6setuid/getuidReal user ID
PM_KILL11killSend a signal
PM_SETGID/GETGID12/13setgid/getgidReal group ID
PM_EXEC14execveExecute a new program image
PM_SETSID/GETPGRP15/16setsid/getpgrpSession / process group
PM_ITIMER17setitimerInterval timer
PM_SIGACTIONPM_SIGRETURN20–24sigaction, sigsuspend, sigpending, sigprocmaskSignal machinery
PM_GETPRIORITY/SETPRIORITY26/27getpriority/setpriorityScheduling priority
PM_GETTIMEOFDAY28gettimeofdayTime of day
PM_CLOCK_GETRES/GETTIME/SETTIME33–35clock_*POSIX clocks
PM_GETRUSAGE36getrusageResource usage
PM_REBOOT37rebootReboot / halt
PM_SRV_FORKPM_GETSYSINFO41–47(MINIX)Service management for RS

Slots 25, 40 and a few others are unused; numbers ≥ 40 are MINIX-specific service infrastructure. (Full detail: minix/include/minix/callnr.h.)

VFS calls (base 0x100, target)

The Virtual File System server handles file I/O, directories, mounts, and — in MINIX 3.4 — BSD sockets.

Call#POSIXCall#POSIX
VFS_READ0readVFS_FCNTL25fcntl
VFS_WRITE1writeVFS_PIPE226pipe2
VFS_LSEEK2lseekVFS_UMASK27umask
VFS_OPEN3openVFS_CHROOT28chroot
VFS_CREAT4creatVFS_GETDENTS29getdents
VFS_CLOSE5closeVFS_SELECT30select
VFS_LINK/UNLINK6/7link/unlinkVFS_FCHDIR31fchdir
VFS_CHDIR8chdirVFS_FSYNC32fsync
VFS_MKDIR9mkdirVFS_TRUNCATE/FTRUNCATE33/34truncate/ftruncate
VFS_MKNOD10mknodVFS_FCHMOD/FCHOWN35/36fchmod/fchown
VFS_CHMOD/CHOWN11/12chmod/chownVFS_UTIMENS37utimensat
VFS_MOUNT/UMOUNT13/14mount/umountVFS_STATVFS1/FSTATVFS140/41statvfs/fstatvfs
VFS_ACCESS15accessVFS_SOCKETVFS_SHUTDOWN49–63BSD sockets
VFS_SYNC16sync
VFS_RENAME17rename
VFS_RMDIR18rmdir
VFS_SYMLINK/READLINK19/20symlink/readlink
VFS_STAT/FSTAT/LSTAT21–23stat/fstat/lstat
VFS_IOCTL24ioctl

The socket calls (49–63) route through VFS to a socket driver or network stack. (Full detail: minix/include/minix/callnr.h.)

Safe copy and grants (planned)

Because a message payload is only 96 bytes, larger transfers use MINIX’s grant mechanism rather than passing raw pointers the kernel would have to trust: a process publishes a grant describing a region and the permitted operation (read / write), passes the grant ID in a message, and the peer copies through SYS_SAFECOPY, which the kernel authorizes against the grant table. The call numbers (SYS_SETGRANT, SYS_SAFECOPY) exist as stubs today; a real grant table and validated copy are an opening Phase-5 slice — every interesting Phase-5 data path (VFS read/write, FS ↔ VFS) moves bytes across address spaces and needs them.

Generated C headers

The ABI above is described to C by headers generated from the live Rust constants and never committed (phase-5 decision D8):

HeaderContents
minix/ipc.hthe message struct, endpoint packing macros, IPC primitives
minix/com.hprocess numbers and the boot endpoints derived from them
minix/callnr.hkernel-call numbers and the server request bands
minix/errno.hthe MINIX 200-band errnos; an opt-in check on the C library’s POSIX ones
cargo gen-c-headers          # -> target/gen-c-headers/

Every value comes from kernel-shared, and the headers carry _Static_asserts pinning the message layout and the endpoint encode/decode against it — so an ABI change on the Rust side fails to compile on the C side rather than silently corrupting IPC. See Build & CI.

MINIX 3 source references

FilePurpose
include/minix/callnr.hPM and VFS call numbers
include/minix/com.hKernel-call numbers and IPC constants
lib/libc/sys/syscall.cUser-space _syscall()
lib/libsys/kernel_call.cServer-side _kernel_call()