Userland reaches the kernel across one boundary: the sys instruction. This is every
call it exposes. The prelude wraps the common ones as ordinary
functions; everything else you invoke directly with __sys.
r7 and up to six arguments in
r1-r6; the result comes back in r1. From TBC that is
__sys(num, a, b, c, d, e, f). A negative return is an errno (e.g. -1 EPERM,
-2 ENOENT, -9 EBADF, -13 EACCES). Calls marked
root require an effective uid of 0. Resolving a path needs search
(execute) permission on every directory it descends through, and listing a directory needs read
permission on it. Unallocated numbers return
-38 ENOSYS. A handful of kernel-internal calls (shell↔kernel handshakes and
other plumbing) exist but are intentionally left off this list - if you're poking at those, you're
past needing docs.
| # | call | what it does |
|---|---|---|
| 0 | read(int fd, char* buf, int n) | Read up to n bytes into buf, advancing the offset. fd 0 / tty devices read the console. Returns bytes read; -9 if fd is invalid. |
| 78 | read_nb(int fd, char* buf, int len) | The non-blocking counterpart to read: pull up to len bytes of pending console input into buf without ever blocking. Returns the bytes ready now, or 0 if none. Reads the console stdin regardless of fd. |
| 1 | write(int fd, char* buf, int n) | Write n bytes. fd 1/2 go to the console. Returns bytes written; -9 if fd isn't open and writable. |
| 2 | open(char* path, int flags) | Open (or create) a file. Flags: O_WRONLY=1 O_RDWR=2 O_CREAT=0x40 O_TRUNC=0x200 O_APPEND=0x400. Returns an fd; -2/-13/-21/-28. |
| 3 | close(int fd) | Release the fd. Always returns 0. |
| 5 | stat(char* path, int* out) | Fill a 6-word stat: out[0]=mode, [4]=uid, [8]=size, [12]=type (1 file / 2 dir), [16]=gid, [20]=inode. -2 if missing. |
| 7 | listdir(char* path, char* buf, int cap) | Write directory entry names into buf. Returns bytes written; -2/-13/-20. |
| 9 | getcwd(char* buf, int cap) | Copy the working directory into buf. Returns its length. |
| 15 | unlink(char* path) | Delete a regular file. Returns 0; -2/-13/-21. |
| 16 | mkdir(char* path, int mode) | Create a directory (mode masked by the umask). Returns 0; -13/-17/-28. |
| 17 | rmdir(char* path) | Remove an empty directory. Returns 0; -2/-13/-20/-39. |
| 18 | rename(char* old, char* new) | Rename or move an entry, replacing an existing file or empty directory. Returns 0; -2, -13, -22 EINVAL (into its own subtree), -28, -39 ENOTEMPTY (target directory not empty). |
| 19 | chmod(char* path, int mode) | Set permission bits. Owner or root only. Returns 0; -1 EPERM / -2. |
| 23 | chown(char* path, int uid) | Set an entry's owner uid (leaves the gid; clears any setuid/setgid bit). Returns 0; -1 EPERM / -2. |
| 25 | chdir(char* path) | Change the working directory. Returns 0; -2/-20. |
| 29 | lseek(int fd, int off, int whence) | Reposition an fd. whence: 0 SET, 1 CUR, 2 END. Returns the new offset; -9. |
| 85 | pipe(int fds[2]) | Create a pipe: fds[0] is the read end, fds[1] the write end. Reading blocks until data or EOF (all writers closed); writing blocks until it fits, and raises SIGPIPE/-32 EPIPE once every reader has closed. Returns 0; -24 EMFILE. |
| 86 | dup(int oldfd) | Duplicate oldfd onto the lowest free fd, sharing the same open file (and offset). Returns the new fd; -9/-24. |
| 87 | dup2(int oldfd, int newfd) | Duplicate oldfd onto newfd (closing newfd first); newfd may be 0/1/2 to redirect stdio onto a file or pipe. Returns newfd; -9. |
| 88 | symlink(char* target, char* linkpath) | Create a symbolic link at linkpath pointing at target. Returns 0; -13/-17/-28. |
| 89 | readlink(char* path, char* buf, int cap) | Read a symlink's target into buf. Returns its length; -2/-22 EINVAL (not a symlink). |
| 90 | lstat(char* path, void* statbuf) | Like stat but does not follow a final symlink (type 3 = symlink). Returns 0; -2. |
| 91 | link(char* oldpath, char* newpath) | Create a hard link newpath to the same inode as oldpath. Returns 0; -1 EPERM (directory) / -13/-17. |
| 47 | umask(int mask) | Set the file-creation mask. Returns the previous mask. |
| 49 | chowng(char* path, int uid, int gid) | Change uid and/or gid (clears any setuid/setgid bit); pass -1 to leave a field alone. Changing uid needs root; changing gid needs root or (owner and group member). -1/-2. |
| # | call | what it does |
|---|---|---|
| 11 | exit(int code) | Terminate the process with an exit code. Does not return. |
| 22 | execve(char* path) | Replace the current image, keeping credentials; argv0 = path. No return on success; -2/-13. Deliberately single-argument. |
| 24 | srun(int argc, char** argv) | Run one command as a child: a fused fork + exec + wait. Honors setuid/setgid bits. Returns the child's exit code (127 not found, 126 not executable, 1 on error). The shell pipes via fork+pipe+dup2 now, so any stdin-feed / stdout-capture arguments are vestigial. |
| 26 | set_raw(int on) | Toggle raw (unbuffered, no-echo) keystroke input. Returns 0. |
| 46 | execvp(char* path, char** argv, int argc) | PATH-aware execve with an explicit argv vector (so argv0 can differ, e.g. -sh). No return on success; -2/-13. |
| 61 | fork() | Duplicate the process. Returns the child pid to the parent, 0 to the child; -11 EAGAIN if no free slot. |
| 62 | waitpid(int pid, int* status, int opts) | Reap a child (pid -1/0 = any). Writes its code to status. Returns the reaped pid, 0 with WNOHANG (opts bit 0), or -10 ECHILD. |
| 63 | getpid() | Return the process id. |
| 64 | getppid() | Return the parent process id. |
| 65 | procsnapshot(char* buf, int cap) | Write 32-byte records for live processes: [0]=pid, [4]=ppid, [8]=state, [12]=euid, [16..32]=name. Returns the count. |
| 79 | procsnap2(char* buf, int cap) | A richer snapshot (used by htop for CPU%/MEM%/TIME+): buf[0..8] holds clock_ms, then up to cap 48-byte records: [0]=pid, [4]=ppid, [8]=state, [12]=euid, [16]=insns (u64), [24]=start_ms, [28]=mem_bytes, [32..48]=name. Returns the count. |
| # | call | what it does |
|---|---|---|
| 13 | getuid() | Return the real uid. |
| 14 | geteuid() | Return the effective uid. |
| 30 | getgid() | Return the real gid. |
| 31 | getegid() | Return the effective gid. |
| 32 | setuid(int uid) | Root sets real+effective+saved uid; otherwise only to the real or saved uid. Returns 0 or -1 EPERM. |
| 33 | setgid(int gid) | Same rules as setuid, for the gid. Returns 0 or -1. |
| 35 | seteuid(int euid) | Set the effective uid (to the real/saved uid, or anything if root). -1 otherwise. |
| 36 | setegid(int egid) | Set the effective gid, same rules. -1 otherwise. |
| 37 | setreuid(int ruid, int euid) | Set real and effective uid together; -1 leaves a field. Saved uid follows the effective. -1 EPERM if not root. |
| 38 | setregid(int rgid, int egid) | Set real and effective gid together; -1 leaves a field. -1 EPERM if not root. |
| 39 | getgroups(int* list, int size) | Write up to size supplementary gids into list (size 0 = just count). Returns the number of groups. |
| 40 | setgroups(int* list, int n) | Replace the supplementary groups (up to 16). Returns 0 or -1 EPERM. |
| 48 | getlogin(char* out, int cap) | Copy the session's login name into out and put the login time in r2. Returns the name length. |
| # | call | what it does |
|---|---|---|
| 41 | getenv(char* name, char* out, int cap) | Copy a variable's value into out. Returns its length, or -1 if unset. |
| 42 | setenv(char* name, char* val) | Set a variable. Returns 0, or -1 if the store is full. |
| 43 | unsetenv(char* name) | Remove a variable. Always returns 0. |
| 44 | getenviron(char* out, int cap) | Copy the packed NAME=VAL\0 environment block into out. Returns its byte length. |
| # | call | what it does |
|---|---|---|
| 66 | signal(int sig, int handler) | Install a handler: 0 default, 1 ignore, else a function address. Returns the previous handler; -1 for signal 0, out-of-range, KILL, or STOP. |
| 67 | kill(int pid, int sig) | Send a signal (sig 0 = existence check). A negative pid signals process group -pid; pid 0 signals the caller's group. Returns 0; -3 ESRCH / -22 EINVAL. |
| 69 | sigprocmask(int how, int mask) | Adjust the blocked-signal mask. how: 0 BLOCK, 1 UNBLOCK, 2 SET. KILL/STOP are never blockable. Returns the old mask. |
| 70 | pause() | Block until a signal is delivered. |
| 92 | setpgid(int pid, int pgid) | Set a process's group (pid 0 = self, pgid 0 = its own pid). Returns 0; -3. |
| 93 | getpgid(int pid) | Return a process's group id (pid 0 = self). |
| 94 | setsid() | Start a new session; the caller becomes session and group leader. Returns the new session id. |
| 95 | getsid(int pid) | Return a process's session id (pid 0 = self). |
| 96 | tcsetpgrp(int fd, int pgrp) | Set the controlling terminal's foreground process group. Returns 0. |
| 97 | tcgetpgrp(int fd) | Return the controlling terminal's foreground process group. |
| 73 | msleep(int ms) | Sleep for ms milliseconds - real-time pacing for game and event loops. Returns 0 once the interval elapses. |
| 76 | sleep(int secs) | Sleep for secs seconds. Returns 0 if the full time elapsed, else the seconds left unslept (a signal cut it short). |
| 77 | alarm(int secs) | Arm a SIGALRM timer (secs 0 cancels). Returns the seconds remaining on any prior alarm. |
These back tbdbg and strace. The tracee runs de-privileged in a dedicated
memory window. Status codes are 0 exited, 1 breakpoint,
2 step, 3 syscall, 4 fault, 5 blocked,
6 subprocess. All return -1 when there is no active tracee.
| # | call | what it does |
|---|---|---|
| 50 | dbg_spawn(char* path, char** argv, int argc) | Load a fresh tracee, stopped at entry. -1 if already tracing or tracing a setuid-root binary as non-root; -2/-13. |
| 51 | dbg_step(int* out) | Single-step one instruction. out[0..1] = [status, info]. Returns the status. |
| 52 | dbg_cont(int max, int trace_sys, int* out) | Run up to max instructions (0 = 50M); trace_sys traps syscalls. Returns the stop status. |
| 53 | dbg_regs(int* buf) | Write the 16 registers, then pc (word 16) and flags (word 17: Z/N/C/V). Returns pc. |
| 54 | dbg_setreg(int idx, int val) | Set a tracee register (idx 0-15) or pc (idx 16). Returns 0. |
| 55 | dbg_read(int addr, int len, char* buf) | Read tracee memory into buf. Returns bytes read. |
| 56 | dbg_write(int addr, int len, char* buf) | Write buf into tracee memory. Returns bytes written. |
| 57 | dbg_break(int addr) | Set a breakpoint (max 16). Returns 0; -1 if the table is full. |
| 58 | dbg_unbreak(int addr) | Remove a breakpoint. Returns 0. |
| 59 | dbg_kill() | Detach and discard the tracee. Returns 0. |
| 60 | dbg_statget(int* out) | Read the current status/info without stepping. Returns the status. |
| # | call | what it does |
|---|---|---|
| 27 | time() | Return the current time in epoch seconds. |
| 80 | clock_gettime(int clk, void* ts) | Write {sec, nsec} to ts. clk 1 MONOTONIC (ms since boot), else REALTIME (epoch). Returns 0. |
| 81 | gettimeofday(void* tv) | Write {sec, usec} (epoch) to tv. Returns 0. |
| 82 | nanosleep(void* req, void* rem) | Sleep for the {sec, nsec} at req (millisecond granularity). Returns 0 once elapsed. |
| 83 | brk(void* addr) | Set the program break (heap top) to addr; brk(0) queries it. Returns 0; -1 if it would collide with the stack. |
| 84 | sbrk(int delta) | Grow the heap by delta bytes and return the previous break (used by malloc); (void*)-1 on overflow. |
| 100 | mmap(void* addr, int len, int prot, int flags, int fd, int off) | Map len bytes and return the mapping address. prot is PROT_READ 1 | PROT_WRITE 2 | PROT_EXEC 4; flags is MAP_FIXED 0x10 | MAP_ANON 0x20. Anonymous maps are demand-zero; file-backed maps populate pages from fd at off and enforce the same read permission as open. A writable MAP_SHARED file map is rejected (-95). -22 EINVAL / -9 EBADF / -12 ENOMEM. |
| 101 | munmap(void* addr, int len) | Unmap a whole prior mapping (frees its frames). Returns 0; -22 EINVAL if addr/len do not match a mapping. |
| 102 | mprotect(void* addr, int len, int prot) | Change the protection of a whole mapping. Returns 0; -22 EINVAL (not a whole mapping) / -13 EACCES (granting write beyond the file's permission). |
| 28 | getrandom(char* buf, int len) | Fill buf with len pseudo-random bytes (userland PRNG). Returns len. |
| 45 | crypt(char* pw, char* setting, char* out, int cap) | Hash pw with the salt from setting, writing a $5$salt$hash string (SHA-crypt style) into out. Returns its length. |
| 71 | klogread(char* buf, int cap) | Drain the kernel log ring into buf (blocks while empty). Returns bytes drained. (syslogd uses this.) |
| 72 | ioctl(int fd, int req, int arg) | Device control. fd 0/1/2 are the console tty (TIOCGWINSZ 0x5413, TCGETS 0x5401). -9 EBADF / -25 ENOTTY. |
| 74 | mount(char* source, char* target, char* fstype) | Mount a filesystem at target. Returns 0; -1/-2/-12/-16/-20. |
| 75 | umount(char* target) | Unmount a filesystem (/ never unmounts). Returns 0; -1/-16/-22. |
| 98 | reboot() | Request a session reboot; the host reseeds the ASLR slide and stack canary and resets the machine to a fresh boot. Returns 0. (The reboot command.) |