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.
This commit is contained in:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
141
kernel/sys/syscall.c
Normal file
141
kernel/sys/syscall.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#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");
|
||||
}
|
||||
Loading…
Reference in a new issue