forked from mit-pdos/xv6-public
-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathsyscall.c
165 lines (152 loc) · 3.57 KB
/
syscall.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "types.h"
#include "defs.h"
#include "param.h"
#include "memlayout.h"
#include "mmu.h"
#include "proc.h"
#include "x86.h"
#include "syscall.h"
// Fetch the int at addr from the current process.
int
fetchint(addr_t addr, int *ip)
{
if(addr < PGSIZE || addr >= proc->sz || addr+sizeof(int) > proc->sz)
return -1;
*ip = *(int*)(addr);
return 0;
}
int
fetchaddr(addr_t addr, addr_t *ip)
{
if(addr < PGSIZE || addr >= proc->sz || addr+sizeof(addr_t) > proc->sz)
return -1;
*ip = *(addr_t*)(addr);
return 0;
}
// Fetch the nul-terminated string at addr from the current process.
// Doesn't actually copy the string - just sets *pp to point at it.
// Returns length of string, not including nul.
int
fetchstr(addr_t addr, char **pp)
{
char *s, *ep;
if(addr < PGSIZE || addr >= proc->sz)
return -1;
*pp = (char*)addr;
ep = (char*)proc->sz;
for(s = *pp; s < ep; s++)
if(*s == 0)
return s - *pp;
return -1;
}
static addr_t
fetcharg(int n)
{
switch (n) {
case 0: return proc->tf->rdi;
case 1: return proc->tf->rsi;
case 2: return proc->tf->rdx;
case 3: return proc->tf->r10;
case 4: return proc->tf->r8;
case 5: return proc->tf->r9;
}
panic("failed fetch");
}
int
argint(int n, int *ip)
{
*ip = fetcharg(n);
return 0;
}
addr_t
argaddr(int n, addr_t *ip)
{
*ip = fetcharg(n);
return 0;
}
// Fetch the nth word-sized system call argument as a pointer
// to a block of memory of size bytes. Check that the pointer
// lies within the process address space.
addr_t
argptr(int n, char **pp, int size)
{
addr_t i;
if(argaddr(n, &i) < 0)
return -1;
if(size < 0 || (uint)i >= proc->sz || (uint)i+size > proc->sz)
return -1;
*pp = (char*)i;
return 0;
}
// Fetch the nth word-sized system call argument as a string pointer.
// Check that the pointer is valid and the string is nul-terminated.
// (There is no shared writable memory, so the string can't change
// between this check and being used by the kernel.)
int
argstr(int n, char **pp)
{
int addr;
if(argint(n, &addr) < 0)
return -1;
return fetchstr(addr, pp);
}
extern addr_t sys_chdir(void);
extern addr_t sys_close(void);
extern addr_t sys_dup(void);
extern addr_t sys_exec(void);
extern addr_t sys_exit(void);
extern addr_t sys_fork(void);
extern addr_t sys_fstat(void);
extern addr_t sys_getpid(void);
extern addr_t sys_kill(void);
extern addr_t sys_link(void);
extern addr_t sys_mkdir(void);
extern addr_t sys_mknod(void);
extern addr_t sys_open(void);
extern addr_t sys_pipe(void);
extern addr_t sys_read(void);
extern addr_t sys_sbrk(void);
extern addr_t sys_sleep(void);
extern addr_t sys_unlink(void);
extern addr_t sys_wait(void);
extern addr_t sys_write(void);
extern addr_t sys_uptime(void);
// PAGEBREAK!
static addr_t (*syscalls[])(void) = {
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
[SYS_pipe] sys_pipe,
[SYS_read] sys_read,
[SYS_kill] sys_kill,
[SYS_exec] sys_exec,
[SYS_fstat] sys_fstat,
[SYS_chdir] sys_chdir,
[SYS_dup] sys_dup,
[SYS_getpid] sys_getpid,
[SYS_sbrk] sys_sbrk,
[SYS_sleep] sys_sleep,
[SYS_uptime] sys_uptime,
[SYS_open] sys_open,
[SYS_write] sys_write,
[SYS_mknod] sys_mknod,
[SYS_unlink] sys_unlink,
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
};
void
syscall(struct trapframe *tf)
{
proc->tf = tf;
uint64 num = proc->tf->rax;
if (num > 0 && num < NELEM(syscalls) && syscalls[num]) {
tf->rax = syscalls[num]();
} else {
cprintf("%d %s: unknown sys call %d\n",
proc->pid, proc->name, num);
tf->rax = -1;
}
if (proc->killed)
exit();
}