forked from CS161/chickadee
-
Notifications
You must be signed in to change notification settings - Fork 0
/
p-lib.hh
320 lines (277 loc) · 10 KB
/
p-lib.hh
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#ifndef CHICKADEE_P_LIB_H
#define CHICKADEE_P_LIB_H
#include "lib.hh"
#include "x86-64.h"
#if CHICKADEE_KERNEL
#error "p-lib.hh should not be used by kernel code."
#endif
// p-lib.hh
//
// Support code for Chickadee processes.
// SYSTEM CALLS
inline uintptr_t syscall0(int syscallno) {
register uintptr_t rax asm("rax") = syscallno;
asm volatile ("syscall"
: "+a" (rax)
:
: "cc", "rcx", "rdx", "rsi", "rdi",
"r8", "r9", "r10", "r11");
return rax;
}
inline uintptr_t syscall0(int syscallno, uintptr_t arg0) {
register uintptr_t rax asm("rax") = syscallno;
asm volatile ("syscall"
: "+a" (rax), "+D" (arg0)
:
: "cc", "rcx", "rdx", "rsi",
"r8", "r9", "r10", "r11");
return rax;
}
inline uintptr_t syscall0(int syscallno, uintptr_t arg0,
uintptr_t arg1) {
register uintptr_t rax asm("rax") = syscallno;
asm volatile ("syscall"
: "+a" (rax), "+D" (arg0), "+S" (arg1)
:
: "cc", "rcx", "rdx", "r8", "r9", "r10", "r11");
return rax;
}
inline uintptr_t syscall0(int syscallno, uintptr_t arg0,
uintptr_t arg1, uintptr_t arg2) {
register uintptr_t rax asm("rax") = syscallno;
asm volatile ("syscall"
: "+a" (rax), "+D" (arg0), "+S" (arg1), "+d" (arg2)
:
: "cc", "rcx", "r8", "r9", "r10", "r11");
return rax;
}
inline uintptr_t syscall0(int syscallno, uintptr_t arg0,
uintptr_t arg1, uintptr_t arg2,
uintptr_t arg3) {
register uintptr_t rax asm("rax") = syscallno;
register uintptr_t r10 asm("r10") = arg3;
asm volatile ("syscall"
: "+a" (rax), "+D" (arg0), "+S" (arg1), "+d" (arg2),
"+r" (r10)
:
: "cc", "rcx", "r8", "r9", "r11");
return rax;
}
inline void clobber_memory(void* ptr) {
asm volatile ("" : "+m" (*(char (*)[]) ptr));
}
inline void access_memory(const void* ptr) {
asm volatile ("" : : "m" (*(const char (*)[]) ptr));
}
// sys_getpid
// Return current process ID.
static inline pid_t sys_getpid(void) {
return syscall0(SYSCALL_GETPID);
}
// sys_yield
// Yield control of the CPU to the kernel. The kernel will pick another
// process to run, if possible.
static inline void sys_yield(void) {
syscall0(SYSCALL_YIELD);
}
// sys_page_alloc(addr)
// Allocate a page of memory at address `addr`. `Addr` must be page-aligned
// (i.e., a multiple of PAGESIZE == 4096). Returns 0 on success and -1
// on failure.
static inline int sys_page_alloc(void* addr) {
return syscall0(SYSCALL_PAGE_ALLOC, reinterpret_cast<uintptr_t>(addr));
}
// sys_fork()
// Fork the current process. On success, return the child's process ID to
// the parent, and return 0 to the child. On failure, return -1.
static inline pid_t sys_fork(void) {
return syscall0(SYSCALL_FORK);
}
// sys_exit(status)
// Exit this process. Does not return.
static inline void __attribute__((noreturn)) sys_exit(int status) {
syscall0(SYSCALL_EXIT, status);
assert(false);
}
// sys_pause()
// A version of `sys_yield` that spins in the kernel long enough
// for kernel timer interrupts to occur.
static inline void sys_pause() {
syscall0(SYSCALL_PAUSE);
}
// sys_kdisplay(display_type)
// Set the display type (one of the KDISPLAY constants).
static inline int sys_kdisplay(int display_type) {
return syscall0(SYSCALL_KDISPLAY, display_type);
}
// sys_msleep(msec)
// Block for approximately `msec` milliseconds.
static inline int sys_msleep(unsigned msec) {
return E_NOSYS;
}
// sys_getppid()
// Return parent process ID.
static inline pid_t sys_getppid() {
return E_NOSYS;
}
// sys_waitpid(pid, status, options)
// Wait until process `pid` exits and report its status. The status
// is stored in `*status`, if `status != nullptr`. If `pid == 0`,
// waits for any child. If `options == W_NOHANG`, returns immediately.
static inline pid_t sys_waitpid(pid_t pid,
int* status = nullptr,
int options = 0) {
return E_NOSYS;
}
// sys_read(fd, buff, sz)
// Read bytes from `fd` into `buff`. Read at most `sz` bytes. Return
// the number of bytes read, which is 0 at EOF.
inline ssize_t sys_read(int fd, char* buff, size_t sz) {
clobber_memory(buff);
return syscall0(SYSCALL_READ, fd, reinterpret_cast<uintptr_t>(buff), sz);
}
// sys_write(fd, buff, sz)
// Write bytes to `fd` from `buff`. Write at most `sz` bytes. Return
// the number of bytes written.
inline ssize_t sys_write(int fd, const char* buff, size_t sz) {
access_memory(buff);
return syscall0(SYSCALL_WRITE, fd, reinterpret_cast<uintptr_t>(buff), sz);
}
// sys_dup2(oldfd, newfd)
// Make `newfd` a reference to the same file structure as `oldfd`.
inline int sys_dup2(int oldfd, int newfd) {
return syscall0(SYSCALL_DUP2, oldfd, newfd);
}
// sys_close(fd)
// Close `fd`.
inline int sys_close(int fd) {
return syscall0(SYSCALL_CLOSE, fd);
}
// sys_open(path, flags)
// Open a new file descriptor for pathname `path`. `flags` should
// contain at least one of `OF_READ` and `OF_WRITE`.
inline int sys_open(const char* path, int flags) {
access_memory(path);
return syscall0(SYSCALL_OPEN, reinterpret_cast<uintptr_t>(path),
flags);
}
// sys_pipe(pfd)
// Create a pipe.
inline int sys_pipe(int pfd[2]) {
uintptr_t r = syscall0(SYSCALL_PIPE);
if (!is_error(r)) {
pfd[0] = r;
pfd[1] = r >> 32;
r = 0;
}
return r;
}
// sys_execv(program_name, argv, argc)
// Replace this process image with a new image running `program_name`
// with `argc` arguments, stored in argument array `argv`. Returns
// only on failure.
inline int sys_execv(const char* program_name, const char* const* argv,
size_t argc) {
access_memory(program_name);
access_memory(argv);
return syscall0(SYSCALL_EXECV,
reinterpret_cast<uintptr_t>(program_name),
reinterpret_cast<uintptr_t>(argv), argc);
}
// sys_execv(program_name, argv)
// Replace this process image with a new image running `program_name`
// with arguments `argv`. `argv` is a null-terminated array. Returns
// only on failure.
inline int sys_execv(const char* program_name, const char* const* argv) {
size_t argc = 0;
while (argv && argv[argc] != nullptr) {
++argc;
}
return sys_execv(program_name, argv, argc);
}
// sys_unlink(pathname)
// Remove the file named `pathname`.
inline int sys_unlink(const char* pathname) {
access_memory(pathname);
return syscall0(SYSCALL_UNLINK, reinterpret_cast<uintptr_t>(pathname));
}
// sys_readdiskfile(filename, buff, sz, off)
// Read bytes from disk file `filename` into `buff`. Read at most `sz`
// bytes starting at file offset `off`. Return the number of bytes
// read, which is 0 at EOF.
inline ssize_t sys_readdiskfile(const char* filename,
char* buff, size_t sz, size_t off) {
clobber_memory(buff);
return syscall0(SYSCALL_READDISKFILE,
reinterpret_cast<uintptr_t>(filename),
reinterpret_cast<uintptr_t>(buff), sz, off);
}
// sys_sync(drop)
// Synchronize all modified buffer cache contents to disk. If
// `drop` is true, then additionally drop all buffer cache contents,
// so that future reads start from an empty cache.
inline int sys_sync(int drop = 0) {
return syscall0(SYSCALL_SYNC, drop);
}
// sys_lseek(fd, offset, origin)
// Set the current file position for `fd` to `off`, relative to
// `origin` (one of the `LSEEK_` constants). Returns the new file
// position (or, for `LSEEK_SIZE`, the file size).
inline ssize_t sys_lseek(int fd, ssize_t off, int origin) {
return syscall0(SYSCALL_LSEEK, fd, off, origin);
}
// sys_ftruncate(fd, len)
// Set the size of file `fd` to `sz`. If the file was previously
// larger, the extra data is lost; if it was shorter, it is extended
// with zero bytes.
inline int sys_ftruncate(int fd, size_t sz) {
return syscall0(SYSCALL_FTRUNCATE, fd, sz);
}
// sys_rename(oldpath, newpath)
// Rename the file with name `oldpath` to `newpath`.
inline int sys_rename(const char* oldpath, const char* newpath) {
access_memory(oldpath);
access_memory(newpath);
return syscall0(SYSCALL_RENAME, reinterpret_cast<uintptr_t>(oldpath),
reinterpret_cast<uintptr_t>(newpath));
}
// sys_gettid()
// Return the current thread ID.
inline pid_t sys_gettid() {
return syscall0(SYSCALL_GETTID);
}
// sys_clone(function, arg, stack_top)
// Create a new thread running `function` with `arg`, starting at
// stack address `stack_top`. Returns the new thread's thread ID.
//
// In the context of the new thread, when the `function` returns,
// the thread should call `sys_texit` with the function's return value
// as argument.
//
// Unlike most other system calls, we recommend you implement `sys_clone`
// in `p-lib.cc`.
pid_t sys_clone(int (*function)(void*), void* arg, char* stack_top);
// sys_texit(status)
// Exit the current thread with exit status `status`. If this is
// the last thread in the process, this will have the same effect
// as `sys_exit(status)`.
inline void __attribute__((noreturn)) sys_texit(int status) {
syscall0(SYSCALL_TEXIT, status);
assert(false);
}
// sys_panic(msg)
// Panic.
static inline pid_t __attribute__((noreturn)) sys_panic(const char* msg) {
syscall0(SYSCALL_PANIC, reinterpret_cast<uintptr_t>(msg));
while (1) {
}
}
// dprintf(fd, format, ...)
// Construct a string from `format` and pass it to `sys_write(fd)`.
// Returns the number of characters printed, or E_2BIG if the string
// could not be constructed.
int dprintf(int fd, const char* format, ...);
// printf(format, ...)
// Like `dprintf(1, format, ...)`.
int printf(const char* format, ...);
#endif