SchOS/kernel/sys/syscall.c
Nexoniarz d0f7acf9eb Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP,
a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF
rasteriser, and a Linux-numbered syscall ABI.

No history before this point -- the tree was never under version control.
This commit exists so the rename that follows has something to undo to.
2026-08-09 13:47:01 +02:00

141 lines
3.6 KiB
C

#include "types.h"
#include "defs.h"
#include "param.h"
#include "memlayout.h"
#include "mmu.h"
#include "traps.h"
#include "proc.h"
#include "x86.h"
#include "syscall.h"
#include "uaccess.h"
#include "errno.h"
#include "posix.h"
// -----------------------------------------------------------------------
// Argument helpers — read syscall args from the saved register frame.
// x86-64 SysV ABI: rdi, rsi, rdx, r10, r8, r9
// -----------------------------------------------------------------------
// Note: address validation goes through uaccess.h (page-table presence +
// user bit on every page of the range). There is deliberately no
// `addr < myproc()->sz` check: that would assume every valid user pointer
// lives in the heap — false for stack addresses and mmap()'d buffers
// (both live above myproc()->sz), which made syscalls fail whenever a
// Linux-ABI program passed a string/pointer from either region.
//
// Validated pointers are returned as raw user VAs — the process page
// table is live in kernel mode, so they dereference correctly across
// page boundaries (unlike a uva2ka() alias, which is only good within
// the one page it translated).
int
fetchint(addr_t addr, int *ip)
{
return copy_from_user(ip, addr, sizeof(*ip)) ? -1 : 0;
}
int
fetchaddr(addr_t addr, addr_t *ip)
{
return copy_from_user(ip, addr, sizeof(*ip)) ? -1 : 0;
}
int
fetchstr(addr_t addr, char **pp)
{
long len = strlen_user(addr);
if (len < 0)
return -1;
*pp = (char*)addr;
return len;
}
static addr_t
fetcharg(int n)
{
switch (n) {
case 0: return myproc()->tf->rdi;
case 1: return myproc()->tf->rsi;
case 2: return myproc()->tf->rdx;
case 3: return myproc()->tf->r10;
case 4: return myproc()->tf->r8;
case 5: return myproc()->tf->r9;
}
panic("fetcharg: bad n");
return 0;
}
int argint(int n, int *ip) { *ip = (int)fetcharg(n); return 0; }
int argaddr(int n, addr_t *ip) { *ip = fetcharg(n); return 0; }
int
argptr(int n, char **pp, int size)
{
addr_t i;
if (argaddr(n, &i) < 0)
return -1;
if (size < 0)
return -1;
char *p = user_ptr(i, (uint64)size);
if (!p)
return -1;
*pp = p;
return 0;
}
int
argstr(int n, char **pp)
{
addr_t addr;
if (argaddr(n, &addr) < 0)
return -1;
return fetchstr(addr, pp);
}
// -----------------------------------------------------------------------
// Dispatch table — auto-generated from table.inc
// -----------------------------------------------------------------------
#define SYSCALL(nr, lnr, name) extern addr_t sys_##name(void);
#define SYSCALL_ALIAS(lnr, name)
#include "table.inc"
#undef SYSCALL
#undef SYSCALL_ALIAS
static addr_t (*syscalls[NSYSCALLS])(void) = {
#define SYSCALL(nr, lnr, name) [SYS_##name] = sys_##name,
#define SYSCALL_ALIAS(lnr, name)
#include "table.inc"
#undef SYSCALL
#undef SYSCALL_ALIAS
};
// -----------------------------------------------------------------------
// Main entry point called from trap.c
// -----------------------------------------------------------------------
void
syscall(struct trapframe *tf)
{
kstack_check_canary("syscall entry");
myproc()->tf = tf;
uint64 orig = myproc()->tf->rax;
uint64 num = orig;
if (myproc()->syscall_map) {
num = (num < (uint64)myproc()->map_size) ? myproc()->syscall_map[num] : 0;
}
if (num > 0 && num < NSYSCALLS && syscalls[num]) {
tf->rax = syscalls[num]();
} else {
tf->rax = -ENOSYS;
}
if (myproc()->killed)
exit(W_EXITCODE(0, myproc()->killsig ? myproc()->killsig : SIGKILL));
deliver_signals(tf);
kstack_check_canary("syscall exit");
}