- Home
- ABI / Syscalls
- ABI Specification
ABI Specification¶
This overview document presents the rou2exOS (aka r2) kernel interface for external applications. Applications should use one of the language libraries from the apps repository and link it statically: libcr2 for C, libc++r2 for C++, or libgor2 for Go. See the SDK Overview for the rules every program has to follow.
Privilege Levels¶
The privilege levels are to be specified and defined in the Global Descriptor Table (GDT) in early boot sequence procedures.
| CPU Ring | Common Interrupt | Target purpose |
|---|---|---|
0 |
* | kernel space |
~~1~~ |
~~0x7d~~ |
kernel tasks, drivers, kernel services |
~~2~~ |
~~0x7e~~ |
privileged user space, services, privileged shell access |
3 |
0x7f |
user space, user programs, common shell |
*Kernel itself handles multiple software (CPU exceptions) and hardware interrupts (e.g. IRQs).
All common interrupts are callable from anywhere, but are handled only when called from the defined CPU ring, therefore are locked to such space.
Syscall Specification¶
The system call (syscall) is a procedure for requesting or modifying of kernel components, modules and drivers. Syscalls use the software interrupts (int 0x7f) under the hood to notify the CPU and kernel to take an action. Parameters of a syscall are passed using the CPU registers that are listed below.
All values passed into a syscall are 64-bit.
| Register | Usage | Example value (64bit) |
|---|---|---|
RAX |
syscall No. | 0x01 |
RDI |
argument No. 1 | 0x01 |
RSI |
argument No. 2 | 0x123abc |
RCX |
optional argument No. 3 | frame length for 0x44 operation 3 |
RAX |
return value | 0x00 |
Entry Stub¶
The ring-3 to ring-0 round trip. The dispatcher can be preempted after it re-enables interrupts; the caller resumes when the stub returns.
The interrupt gate for 0x7f is a naked stub (syscall_handler in src/abi/syscall.rs) that saves the general-purpose registers, calls the dispatcher syscall_inner(arg1, arg2, syscall_no, arg3) and returns with iretq:
cld ; Rust expects forward string operations
push rax ... r15 ; every GPR except R9
sub rsp, 8 ; align the stack for the Rust call
mov rdx, rax ; syscall number becomes the 3rd C argument
; RCX, untouched, is the 4th: the optional argument 3
call syscall_inner
mov r9, rax ; keep the result across the pops
add rsp, 8
pop r15 ... rax
mov rax, r9 ; result into RAX
iretq
Consequences for callers:
- The number is read from
RAX. SettingRDXalone is not enough; libc++r2 sets both to be safe. - Two arguments, and a third in
RCXfor calls that require it.RDXis overwritten with the number before the call, so it never reaches a syscall.0x1dreadsRCXas a metadata pointer only when bit 63 of argument 2 is set, because older wrappers may leave anything there.0x44always reads it: pass the frame length for operation 3, and zero for every other operation. The RNTP bridge0x47takes the format buffer length inRCXfor operation 5 and zero otherwise. Other syscalls use two arguments; calls that need more take a pointer to a request struct (e.g.0x39,0x3a). R9is clobbered by every syscall and must be declared as such in inline assembly. Every other register butRAXcomes back as it went in, so a compiler may keep a value inRCX,RDX,RSIorRDIacross the call.- Interrupts are re-enabled at the top of the dispatcher, so a long syscall can be preempted by the scheduler.
Pointer Arguments¶
Every syscall that takes a pointer checks the whole buffer it will touch, not just its first byte. The buffer must lie wholly inside one user region: the program image and the initial user stacks (0x400_000..0xA00_000: the stacks of slots 16–31, the image, then the stacks of slots 0–15; see Memory Overview), the userland heap (0xC00_000..0x1000_000, handed out by syscall 0x0a), or the heap's extension once the heap has grown into it (from 0xA000_000; see 0x0a). Otherwise the call fails with InvalidInput (or the call's own error value). A buffer may not straddle the gap between two regions. NUL-terminated strings are read up to the end of the region they start in.
Syscall Return Codes¶
Most syscalls return one of these codes. Syscalls that return a count, an address or a PID document their own return value; several of them use u64::MAX (-1 as int64_t) for an error.
| Code (uint64) | Meaning |
|---|---|
0x00 |
Okay |
0xf9 |
Unchanged — nothing new since the caller last asked; nothing was copied (0x1d with metadata) |
0xfa |
Busy — lock contention or a resource/ownership conflict; consult the call before retrying |
0xfb |
NotImplemented |
0xfc |
InvalidInput |
0xfd |
FilesystemError |
0xfe |
FileNotFound (also used for "no such process") |
0xff |
InvalidSyscall |
Syscall Map¶
| Range | Group | Page |
|---|---|---|
0x00–0x0f, 0x3b–0x3c, 0x3e, 0x41–0x43 |
Exit, system information, pipes, time, heap, kill (0x3b), memory information (0x3c), power (0x3e), command lines (0x41), desktop relaunch (0x42), shared heap range check (0x43) |
System, Processes & Memory |
0x10–0x1f, 0x3f |
Console, graphics, framebuffer capture (0x1c, 0x1d), audio (HD Audio PCM 0x3f) |
Video & Audio |
0x20–0x2f, 0x39–0x3a, 0x40 |
Files, directories, VFS, program execution, task list, mount sizes (0x40) |
Filesystem |
0x30–0x38, 0x3d, 0x44–0x47 |
I/O ports, serial, packets, IPC, network configuration (0x3d), userspace IPv4 tunnel and ICMP probes (0x44), NIC throughput counters (0x45), TCP port owners (0x46), RNTP block bridge (0x47) |
Ports & Networking |
Related documentation: SDK Overview, Type Definitions, Kernel Internals.