do not edit — generated by btf.
git.druid.rocksindexdruid520kaboomdocs/syscalls.btft

docs/syscalls.btft


[link rel="stylesheet" href="keyframes.css"][e]
 
[table class="topnav"]
[tr]
[td class="logotab"][see name="index"]kaboom[e][e]
[td][see name="kernel"]kernel[e][e]
[td][see name="fs"]fs[e][e]
[td][see name="syscalls"]syscalls[e][e]
[td][see name="userland"]userland[e][e]
[td][see name="build"]build[e][e]
[e]
[e]
 
[h1]syscalls[e]
 
this page is the table: all 24 syscalls kaboom currently has, their exact signatures, and what each one hands back on success and on failure. it's ported straight from [tt]idt.nsc[e]'s own numbered doc comment above [tt]syscall_dispatch[e], so the two can't quietly drift apart -- if this table and the running kernel ever disagree, the comment (and this page) is what's stale, not the other way around. read [see name="kernel"]kernel[e] for the dispatch mechanism itself: the int-gate at vector 0x80, the shared error-logging path ([tt]sys_doerror[e]), and how [tt]kaboom_errno[e] gets set. this page only covers the 24 individual calls.
 
the calling convention: syscall number goes in rax, which is also where the return value comes back. up to three arguments go in rdi, rsi, rdx -- a fourth, where one exists, goes in r10. that's the same register order and positions the real x86-64 sysv/syscall convention uses, kept purely for familiarity; the actual entry mechanism here is a classic int-gate, not the [tt]syscall[e] instruction. the failure convention is not uniform across calls -- some return a negative value, some a plain 0 or 1 boolean -- so check the returns column for each one rather than assuming.
 
[table]
[tr]
[th]#[e]
[th]call[e]
[th]returns[e]
[th]notes[e]
[e]
 
[tr]
[td]1[e]
[td][tt]print(str)[e][e]
[td]void[e]
[td]debug-prints a nul-terminated string (rdi) to vga and serial both. the original proof-of-mechanism syscall, kept around for back-compat rather than removed now that real i/o exists.[e]
[e]
 
[tr]
[td]2[e]
[td][tt]write(fd, buf, len)[e][e]
[td]bytes written, or -1[e]
[td][e]
[e]
 
[tr]
[td]3[e]
[td][tt]read(fd, buf, maxlen)[e][e]
[td]bytes read, or -1[e]
[td][e]
[e]
 
[tr]
[td]4[e]
[td][tt]open(path, path_len)[e][e]
[td]fd, or -1[e]
[td][e]
[e]
 
[tr]
[td]5[e]
[td][tt]close(fd)[e][e]
[td]0, or -1[e]
[td][e]
[e]
 
[tr]
[td]6[e]
[td][tt]listdir(names_out, max)[e][e]
[td]count of entries written[e]
[td]lists the current directory. see syscall 21 for the path-taking version.[e]
[e]
 
[tr]
[td]7[e]
[td][tt]exec(path, path_len, argc, argv)[e][e]
[td]the child's exit code (whatever it left in rax when it returned), or -1[e]
[td]four args -- the fourth, argv, comes in r10, not rdx. path resolution, the [tt]/bin[e] fallback, permission enforcement, and the shebang re-exec mechanism (including the paging window swap for sh nesting against itself) are all covered on [see name="kernel"]kernel[e]; this row is just the call's own contract. -1 is genuinely ambiguous here -- exec itself failing looks the same as a child whose own legitimate exit code happened to be -1 -- a known, pre-existing wart, not something this table is hiding.[e]
[e]
 
[tr]
[td]8[e]
[td][tt]klog_read(buf, maxlen)[e][e]
[td]bytes copied from the kernel log[e]
[td][e]
[e]
 
[tr]
[td]9[e]
[td][tt]mkdir(name, name_len, perm)[e][e]
[td]new inode number, or -1[e]
[td]the one create-style call that hands back something other than a plain 1/0 -- a caller that needs the inode it just made (rather than just knowing it worked) doesn't have to look it up again afterward.[e]
[e]
 
[tr]
[td]10[e]
[td][tt]rmdir(name, name_len)[e][e]
[td]1, or 0[e]
[td][e]
[e]
 
[tr]
[td]11[e]
[td][tt]rm(name, name_len)[e][e]
[td]1, or 0[e]
[td][e]
[e]
 
[tr]
[td]12[e]
[td][tt]cd(name, name_len)[e][e]
[td]1, or 0[e]
[td][e]
[e]
 
[tr]
[td]13[e]
[td][tt]pwd(buf)[e][e]
[td]path length[e]
[td][e]
[e]
 
[tr]
[td]14[e]
[td][tt]info(buf)[e][e]
[td]always 0[e]
[td]fills buf (room for 4 u64s) with total_blocks, blocks_used, inode_count, inodes_used. the return value is always 0 -- the actual result comes back through buf, not rax.[e]
[e]
 
[tr]
[td]15[e]
[td][tt]writefile(name, name_len, data, len)[e][e]
[td]1, or 0[e]
[td]four args -- len is the fourth, in r10, same convention as syscall 7. finds or creates name in the current directory and overwrites its entire content.[e]
[e]
 
[tr]
[td]16[e]
[td][tt]vga_clear()[e][e]
[td]void[e]
[td]no args. clears vga and serial both, despite the name only naming one of them.[e]
[e]
 
[tr]
[td]17[e]
[td][tt]chmod(name, name_len, perm)[e][e]
[td]1, or 0[e]
[td]see syscall 24 for the read-back counterpart.[e]
[e]
 
[tr]
[td]18[e]
[td][tt]alloc(size)[e][e]
[td]ptr, or 0 if the heap arena is exhausted[e]
[td]userspace's way to get memory dynamically instead of declaring a huge fixed-size global or stack buffer. wraps the same [tt]kalloc[e] every kernel-side subsystem already uses.[e]
[e]
 
[tr]
[td]19[e]
[td][tt]free(ptr)[e][e]
[td]void[e]
[td]no args used beyond the pointer, and always a no-op -- kaboom's arena allocator never frees. this exists as real api surface, so a program can call free without having to know that, not because it does anything yet.[e]
[e]
 
[tr]
[td]20[e]
[td][tt]stat(path, path_len)[e][e]
[td]-1 not found, 1 a file, 2 a directory[e]
[td][e]
[e]
 
[tr]
[td]21[e]
[td][tt]listdir_path(path, path_len, names_out, max)[e][e]
[td]count, or -1 if path doesn't resolve to a directory[e]
[td]four args -- max is the fourth, in r10, same convention as syscall 7. the path-taking version of syscall 6.[e]
[e]
 
[tr]
[td]22[e]
[td][tt]date(buf)[e][e]
[td]void[e]
[td]fills buf (room for 6 u64s) with second, minute, hour, day, month, and full year, read straight from the cmos rtc.[e]
[e]
 
[tr]
[td]23[e]
[td][tt]errno(void)[e][e]
[td][tt]kaboom_errno[e] -- 0 generic, 1 permission denied[e]
[td]no args. this is the userspace half of the same [tt]kaboom_errno[e]/[tt]sys_doerror[e] mechanism covered on [see name="kernel"]kernel[e]: [tt]klogs[e] already gets the real reason a syscall failed, but a command's own user-visible error message had no way to ask "was that permission denied, or something else" until this existed. reads whatever [tt]kaboom_errno[e] was left at by the most recent syscall this same process made -- check it right after a failing call, before making another one, or a later unrelated call's own reset overwrites it.[e]
[e]
 
[tr]
[td]24[e]
[td][tt]getperm(path, path_len)[e][e]
[td]the resolved inode's permission bitmask (r=1 w=2 x=4), or -1 if path doesn't resolve[e]
[td]chmod's read-back counterpart -- what a [tt]perms[e] command uses to show what's actually set.[e]
[e]
 
[tr]
[td]25[e]
[td][tt]fsize(fd)[e][e]
[td]the open file's full content size in bytes, or -1 if fd isn't an open file[e]
[td]lets a program size one buffer to the whole file before a single read, instead of assuming a fixed maximum -- what stdio's [tt]read_all[e] (and so [tt]cat[e]/[tt]cp[e]/[tt]mv[e]/[tt]sh[e]) uses.[e]
[e]
 
[tr]
[td]26[e]
[td][tt]ino(path, path_len)[e][e]
[td]the inode number path resolves to, or -1 if it doesn't resolve[e]
[td]file identity: two different spellings of the same file ([tt]/usr/k[e] and, from [tt]/usr[e], plain [tt]k[e]) give the same number. what [tt]mv[e] uses to make moving a file onto itself a no-op before anything is written or removed.[e]
[e]
[e]
 
grows further once real coreutils show what else they need.
 
[img src="made-with-nsc.gif"]made with nsc[e] [img src="powered-by-kaboom.gif"]powered by kaboom[e]
powered by btf.