Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
141 lines
3.7 KiB
C
141 lines
3.7 KiB
C
#include "core/types.h"
|
|
#include "core/defs.h"
|
|
#include "core/param.h"
|
|
#include "arch/memlayout.h"
|
|
#include "arch/mmu.h"
|
|
#include "arch/traps.h"
|
|
#include "core/proc.h"
|
|
#include "arch/x86.h"
|
|
#include "core/syscall.h"
|
|
#include "core/uaccess.h"
|
|
#include "uapi/errno.h"
|
|
#include "uapi/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");
|
|
}
|