xv6, line by line
kernel/syscall.c

kernel/syscall.c

C · 151 lines · annotated 100% · kernel · upstream

About this file

The system call dispatcher, and the helpers every system call uses to read its arguments.

When a user program executes ecall, usertrap recognizes a system call and calls syscall here. By then uservec has saved all of the program’s registers in its trapframe, so the kernel finds there what the program left in its registers: the system call number in a7 and up to six system call arguments in a0–a5. syscall uses the number to pick a function from the table syscalls, calls it, and writes its return value into the trapframe’s a0, which userret loads into the program’s a0 on the way back.

The first half of the file is the argument helpers: argint, argaddr and argstr read argument n; fetchaddr and fetchstr read a value or a string from a user address. They exist because arguments come from an untrusted program: an “address” may point anywhere, so the kernel never dereferences it directly, and copies through the process’s page table instead.

Read before: kernel/trap.c. Read next: kernel/sysproc.c and kernel/sysfile.c, where the sys_* functions live.

1#include "types.h"
2#include "param.h"
4#include "riscv.h"
5#include "spinlock.h"
6#include "proc.h"
7#include "syscall.h"
8#include "defs.h"
10// Fetch the uint64 at addr from the current process.
11int
14 struct proc *p = myproc();
15 if (addr >= p->sz ||
16 addr + sizeof(uint64) > p->sz) // both tests needed, in case of overflow
17 return -1;
18 if (copyin(p->pagetable, p->sz, (char *)ip, addr, sizeof(*ip)) != 0)
19 return -1;
20 return 0;
23// Fetch the nul-terminated string at addr from the current process.
24// Returns length of string, not including nul, or -1 for error.
25int
28 struct proc *p = myproc();
29 if (copyinstr(p->pagetable, p->sz, buf, addr, max) < 0)
30 return -1;
31 return strlen(buf);
34static uint64
35argraw(int n)
37 struct proc *p = myproc();
38 switch (n) {
39 case 0:
40 return p->trapframe->a0;
41 case 1:
42 return p->trapframe->a1;
43 case 2:
44 return p->trapframe->a2;
45 case 3:
46 return p->trapframe->a3;
47 case 4:
48 return p->trapframe->a4;
49 case 5:
50 return p->trapframe->a5;
51 }
52 panic("argraw");
53 return -1;
56// Fetch the nth 32-bit system call argument.
57void
58argint(int n, int *ip)
60 *ip = argraw(n);
63// Retrieve an argument as a pointer.
64// Doesn't check for legality, since
65// copyin/copyout will do that.
66void
69 *ip = argraw(n);
72// Fetch the nth word-sized system call argument as a null-terminated string.
73// Copies into buf, at most max.
74// Returns string length if OK (not including nul), -1 if error.
75int
76argstr(int n, char *buf, int max)
80 return fetchstr(addr, buf, max);
83// Prototypes for the functions that handle system calls.
84extern uint64 sys_fork(void);
85extern uint64 sys_exit(void);
86extern uint64 sys_wait(void);
87extern uint64 sys_pipe(void);
88extern uint64 sys_read(void);
89extern uint64 sys_kill(void);
90extern uint64 sys_exec(void);
91extern uint64 sys_fstat(void);
92extern uint64 sys_chdir(void);
93extern uint64 sys_dup(void);
94extern uint64 sys_getpid(void);
95extern uint64 sys_sbrk(void);
96extern uint64 sys_pause(void);
97extern uint64 sys_uptime(void);
98extern uint64 sys_open(void);
99extern uint64 sys_write(void);
100extern uint64 sys_mknod(void);
101extern uint64 sys_unlink(void);
102extern uint64 sys_link(void);
103extern uint64 sys_mkdir(void);
104extern uint64 sys_close(void);
105extern uint64 sys_sync(void);
107// An array mapping syscall numbers from syscall.h
108// to the function that handles the system call.
109static uint64 (*syscalls[])(void) = {
110 // clang-format off
133 // clang-format on
134};
136void
139 int num;
140 struct proc *p = myproc();
143 if (num > 0 && num < NELEM(syscalls) && syscalls[num]) {
144 // Use num to lookup the system call function for num, call it,
145 // and store its return value in p->trapframe->a0
147 } else {
148 printk("%d %s: unknown sys call %d\n", p->pid, p->name, num);
149 p->trapframe->a0 = -1;
150 }