name: Pebbles Kernel System Call Specification description: ABI, semantics, and key corner cases for all required syscalls (from kspec.pdf) type: project
Single 32-bit param: placed in %esi.
Multiple params: construct a struct "packet" in memory; place its address in %esi.
Invoke: INT x where x is from spec/syscall_int.h.
Return value: in %eax. Zero on success, negative on error (unless spec says otherwise).
All other registers preserved (except those explicitly modified per-syscall spec).
Syscall stub library: one .o file per syscall, built into libsyscall.a. Must match spec/syscall.h exactly.
fork() - deep-copy address space; child gets 0, parent gets child's original tid. Exit status of new task starts at 0. Registered swexn handler is inherited.
thread_fork - new thread in same task; all registers identical except %eax (parent=new tid, child=0). No swexn handler in new thread. Runnable immediately. No %esi parameter (ignored).
exec(execname, argvec) - replaces program. Validates all args before deallocating old resources. On success does not return. argc/argv/stack_high/stack_low passed to new program's _main. New program has no swexn handler.
set_status(int status) - sets current task exit status.
vanish() - terminates calling thread. If last thread: deallocates all task resources, makes exit status available to parent via wait(). If parent is gone, status goes to init. Must never fail due to OOM.
wait(int *status_ptr) - blocks until a child task exits; stores exit status at *status_ptr (NULL is valid - means ignore status). Returns original tid (first thread) of exited task. Returns error if no collectable children will ever exist.
task_vanish(int status) - kills all threads in current task; threads must vanish "in a timely fashion."
gettid() - returns calling thread's ID.
yield(int tid) - yields to tid (-1 = scheduler chooses). Error if tid doesn't exist, is blocked, or is descheduled.
deschedule(int *reject) - atomically: if *reject != 0, return immediately (zero); else remove self from run queue until make_runnable() is called.
make_runnable(int tid) - makes descheduled thread runnable. Atomic with deschedule().
get_ticks() - returns timer tick count since boot.
sleep(int ticks) - deschedules until at least ticks timer interrupts have occurred. Returns immediately if ticks==0. Error if ticks<0.
swexn(void *esp3, swexn_handler_t eip, void *arg, ureg_t *newureg) - register/deregister software exception handler. If esp3/eip both zero: deregister. If both non-zero: register. newureg non-zero: adopt those register values before returning (atomically with handler registration). Handler is auto-deregistered when invoked. Handler invoked with (void *arg, ureg_t *ureg) on esp3 stack.
new_pages(void *base, int len) - allocates zeroed memory starting at base for len bytes. Fails if: base not page-aligned, len not positive multiple of page size, region overlaps existing mappings or kernel space, or OOM.
remove_pages(void *base) - deallocates region previously allocated by new_pages() using the same base value.
getchar() - reads one char from input stream; blocks if empty; does NOT echo. Returns char in low 8 bits, negative on error. Not required for P3; stub must return -1 without crashing.
readline(int len, char *buf) - reads line into buf (up to len chars); blocks if no line available; echoes typed chars to console; returns byte count. Error if buf invalid or len unreasonable.
print(int len, char *buf) - prints len bytes; concurrent prints not intermixed; blocks until done. Error if len too large or buf invalid.
set_term_color(int color), set_cursor_pos(int row, int col), get_cursor_pos(int *row, int *col).
readfile(char *filename, char *buf, int count, int offset) - reads from RAM disk.
halt() - calls sim_halt() + HLT. Required for grading.
misbehave(int mode) - kernel-defined semantics for debugging.
Thread terminates ONLY via: (1) vanish(), (2) task_vanish(), (3) unhandled exception. No other reason is legal.
Kernel must validate every pointer in every syscall argument against the invoking task's page tables. Return negative error code for any invalid pointer - never crash or kill the thread for bad args.
No fixed limit on number of tasks/threads - kernel must scale gracefully with available memory.
Task/thread IDs are monotonically increasing integers (never reused, never pointers).
Why: These are the authoritative behavioral specifications from kspec.pdf that the test suite tests against.
How to apply: When implementing any syscall handler, consult this spec for exact semantics and corner cases.
Table of Content