-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A lot of syscalls glue code is very repetitive and adheres to the same pattern. It's easily generatable from a very simple and concise source of truth. That source of truth is now in include/syscalls.hh, and the scripts/gen-syscalls.py generates the following files from it: * include/syscallnums.h * include/syscalldecls.h * src/syscalls.c * user/inc/usyscalls.h * user/src/usyscalls.S All these files are still tracked in git, both for accountability, and for easier readability of complete code. A new syscall should now be added only to include/syscalls.hh, the rest will get dealt with by the Makefile.
- Loading branch information
Showing
12 changed files
with
390 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// This file is generated by scripts/gen-syscalls.py from include/syscalls.hh. | ||
// To add a new system call, edit syscalls.hh. gen-syscalls.py will be rerun on | ||
// the next build and this file will be modified. Commit in the changed file for | ||
// easier readability. | ||
#ifndef _SYSCALLDECLS_H_ | ||
#define _SYSCALLDECLS_H_ | ||
|
||
regsize_t sys_exit(); | ||
regsize_t sys_fork(); | ||
regsize_t sys_read(); | ||
regsize_t sys_write(); | ||
regsize_t sys_open(); | ||
regsize_t sys_close(); | ||
regsize_t sys_wait(); | ||
regsize_t sys_execv(); | ||
regsize_t sys_getpid(); | ||
regsize_t sys_dup(); | ||
regsize_t sys_pipe(); | ||
regsize_t sys_sysinfo(); | ||
regsize_t sys_sleep(); | ||
regsize_t sys_plist(); | ||
regsize_t sys_pinfo(); | ||
regsize_t sys_pgalloc(); | ||
regsize_t sys_pgfree(); | ||
regsize_t sys_gpio(); | ||
regsize_t sys_detach(); | ||
regsize_t sys_isopen(); | ||
regsize_t sys_pipeattch(); | ||
regsize_t sys_lsdir(); | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,28 @@ | ||
// This file is to be included both in usyscalls.S and in C code, so let's keep | ||
// it neat and minimal. | ||
// This file is generated by scripts/gen-syscalls.py from include/syscalls.hh. | ||
// To add a new system call, edit syscalls.hh. gen-syscalls.py will be rerun on | ||
// the next build and this file will be modified. Commit in the changed file for | ||
// easier readability. | ||
#define SYS_NR_exit 1 | ||
#define SYS_NR_fork 2 | ||
#define SYS_NR_read 3 | ||
#define SYS_NR_write 4 | ||
#define SYS_NR_open 5 | ||
#define SYS_NR_close 6 | ||
#define SYS_NR_wait 7 | ||
#define SYS_NR_execv 11 | ||
#define SYS_NR_getpid 20 | ||
#define SYS_NR_dup 28 | ||
#define SYS_NR_pipe 29 | ||
#define SYS_NR_sysinfo 30 | ||
#define SYS_NR_sleep 31 | ||
#define SYS_NR_plist 32 | ||
#define SYS_NR_pinfo 33 | ||
#define SYS_NR_pgalloc 34 | ||
#define SYS_NR_pgfree 35 | ||
#define SYS_NR_gpio 36 | ||
#define SYS_NR_detach 37 | ||
#define SYS_NR_isopen 38 | ||
#define SYS_NR_pipeattch 39 | ||
#define SYS_NR_lsdir 40 | ||
|
||
#define SYS_NR_restart 0 | ||
#define SYS_NR_exit 1 | ||
#define SYS_NR_fork 2 | ||
#define SYS_NR_read 3 | ||
#define SYS_NR_write 4 | ||
#define SYS_NR_open 5 | ||
#define SYS_NR_close 6 | ||
#define SYS_NR_wait 7 | ||
#define SYS_NR_execv 11 | ||
#define SYS_NR_getpid 20 | ||
|
||
// The numbers below differ from Linux, may need to renumber one day if we ever | ||
// want to achieve ABI compatibility. But for now, I don't want to make | ||
// trap_vector too big while very sparsely populated. | ||
#define SYS_NR_dup 28 // __NR_dup is 41 on Linux | ||
#define SYS_NR_pipe 29 // __NR_pipe is 42 on Linux | ||
#define SYS_NR_sysinfo 30 // __NR_sysinfo is 116 on Linux | ||
#define SYS_NR_sleep 31 // __NR_nanosleep is 162 on Linux | ||
|
||
// These are non-standard syscalls | ||
#define SYS_NR_plist 32 | ||
#define SYS_NR_pinfo 33 | ||
#define SYS_NR_pgalloc 34 | ||
#define SYS_NR_pgfree 35 | ||
#define SYS_NR_gpio 36 | ||
#define SYS_NR_detach 37 | ||
#define SYS_NR_isopen 38 | ||
#define SYS_NR_pipeattch 39 | ||
#define SYS_NR_lsdir 40 | ||
#define SYSCALL_VECTOR_LEN 40 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// This file is an input to scripts/gen-syscalls.py, not meant to be directly | ||
// #included in a .c file. | ||
|
||
1: exit(int status); | ||
2: fork(); | ||
3: read(uint32_t fd, char* buf, uint32_t size); | ||
|
||
// write writes the given data to file descriptor fd. The three special file | ||
// descriptors are stdin=0, stdout=1 and stderr=2. Other descriptors should be obtained | ||
// via open(). The size parameter is optional: it specifies how many bytes to | ||
// write from data, but it can be -1 if data contains a zero-terminated string, | ||
// then data will be written until the first zero byte is encountered. | ||
4: write(uint32_t fd, void* data, uint32_t size); | ||
5: open(char const *filepath, uint32_t flags); | ||
6: close(uint32_t fd); | ||
7: wait(wait_cond_t *cond); | ||
11: execv(char const* filename, char const* argv[]); | ||
20: getpid(); | ||
|
||
// The numbers below differ from Linux, may need to renumber one day if we ever | ||
// want to achieve ABI compatibility. But for now, I don't want to make | ||
// syscall_vector too big while very sparsely populated. | ||
// __NR_dup is 41 on Linux | ||
28: dup(uint32_t fd); | ||
// __NR_pipe is 42 on Linux | ||
29: pipe(uint32_t fd[2]); | ||
// __NR_sysinfo is 116 on Linux | ||
30: sysinfo(sysinfo_t* info); | ||
// __NR_nanosleep is 162 on Linux | ||
31: sleep(uint64_t milliseconds); | ||
|
||
// These are non-standard syscalls | ||
32: plist(uint32_t *pids, uint32_t size); | ||
33: pinfo(uint32_t pid, pinfo_t *pinfo); | ||
34: pgalloc(); | ||
35: pgfree(void *page); | ||
36: gpio(uint32_t pin_num, uint32_t enable, uint32_t value); | ||
37: detach(); | ||
38: isopen(int32_t fd); | ||
39: pipeattch(uint32_t pid, int32_t src_fd); | ||
40: lsdir(char const *dir, dirent_t *dirents, int size); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from dataclasses import dataclass | ||
from io import StringIO | ||
from typing import Callable | ||
|
||
|
||
@dataclass | ||
class Param: | ||
input: str | ||
type: str | ||
name: str | ||
array_qual: str | ||
|
||
|
||
@dataclass | ||
class SyscallDecl: | ||
full_input: str | ||
ret_type: str | ||
decl: str | ||
func_name: str | ||
syscall_num: str | ||
params: list[Param] | ||
|
||
|
||
@dataclass | ||
class GenFile: | ||
filename: str | ||
generator: Callable[[list[SyscallDecl]], str] | ||
|
||
|
||
def parse_params(input: str) -> list[Param]: | ||
if input == '': | ||
return [] | ||
plist = input.split(',') | ||
result = [] | ||
for p in plist: | ||
array_qual = '' | ||
type, _, name = p.strip().rpartition(' ') | ||
if name.startswith('*'): | ||
type += '*' | ||
name = name[1:] | ||
if name.startswith('*'): | ||
type += '*' | ||
name = name[1:] | ||
if name.endswith(']'): | ||
open_sq_br = name.find('[') | ||
array_qual = name[open_sq_br:] | ||
name = name[:open_sq_br] | ||
result.append(Param(p, type, name, array_qual)) | ||
return result | ||
|
||
|
||
def parse(input: str) -> SyscallDecl: | ||
syscall_num, _, decl = input.partition(': ') | ||
decl = decl.strip() | ||
# ret_type, decl = input.split(maxsplit=1) | ||
ret_type = 'regsize_t' | ||
func_name, _, temp = decl.partition('(') | ||
params_str, _, _ = temp.partition(')') | ||
params = parse_params(params_str) | ||
return SyscallDecl(input, ret_type, decl, func_name, syscall_num, params) | ||
|
||
|
||
def gen_usyscalls_h(data: list[SyscallDecl]) -> str: | ||
f = StringIO() | ||
f.write('#include "syscalls.h"\n') | ||
for d in data: | ||
f.write(f'extern {d.ret_type} {d.decl}\n') | ||
return f.getvalue() | ||
|
||
|
||
def gen_usyscalls_s(data: list[SyscallDecl]) -> str: | ||
f = StringIO() | ||
f.write('''#include "syscallnums.h" | ||
// for fun let\'s pretend syscall is kinda like Linux: syscall nr in a7, other | ||
// arguments in a0..a6') | ||
.macro macro_syscall nr | ||
li a7, \\nr | ||
ecall | ||
.endm | ||
''') | ||
f.write('\n.balign 4\n') | ||
f.write('.section .user_text\n') | ||
for d in data: | ||
f.write(f'\n.globl {d.func_name}\n') | ||
f.write(f'{d.func_name}:\n') | ||
f.write(f' macro_syscall SYS_NR_{d.func_name}\n') | ||
f.write(f' ret\n') | ||
return f.getvalue() | ||
|
||
|
||
def gen_syscallnums(data: list[SyscallDecl]) -> str: | ||
f = StringIO() | ||
for d in data: | ||
f.write(f'#define SYS_NR_{d.func_name}'.ljust(32) + f'{d.syscall_num}\n') | ||
greatest_syscall_num = max(map(lambda d: int(d.syscall_num), data)) | ||
f.write(f'\n#define SYSCALL_VECTOR_LEN {greatest_syscall_num}\n') | ||
return f.getvalue() | ||
|
||
|
||
def gen_syscalls(data: list[SyscallDecl]) -> None: | ||
f = StringIO() | ||
f.write(''' | ||
#include "proc.h" | ||
#include "syscalls.h" | ||
// for fun let's pretend syscall table is kinda like 32bit Linux on x86, | ||
// /usr/include/asm/unistd_32.h: __NR_restart_syscall 0, __NR_exit 1, _NR_fork 2, __NR_read 3, __NR_write 4 | ||
// | ||
// Note that we place syscall_vector in a .text segment in order to have it in | ||
// ROM, since it's read-only after all. | ||
''') | ||
f.write('void *syscall_vector[] _text = {\n') | ||
for d in data: | ||
f.write(f' [SYS_NR_{d.func_name}]'.ljust(32) + f'sys_{d.func_name},\n') | ||
f.write('};\n') | ||
for d in data: | ||
f.write(f'\n{d.ret_type} sys_{d.func_name}() {{\n') | ||
for i, p in enumerate(d.params): | ||
type = p.type | ||
if p.array_qual != '': | ||
type += '*' | ||
f.write(f' {type} {p.name} = ({type})trap_frame.regs[REG_A{i}];\n') | ||
calllist = ', '.join([p.name for p in d.params]) | ||
f.write(f' return proc_{d.func_name}({calllist});\n') | ||
f.write('}\n') | ||
return f.getvalue() | ||
|
||
|
||
def gen_syscalldecls(data: list[SyscallDecl]) -> str: | ||
f = StringIO() | ||
f.write('''#ifndef _SYSCALLDECLS_H_ | ||
#define _SYSCALLDECLS_H_ | ||
''') | ||
for d in data: | ||
f.write(f'regsize_t sys_{d.func_name}();\n') | ||
f.write('#endif\n') | ||
return f.getvalue() | ||
|
||
|
||
def load_data(filename: str) -> list[SyscallDecl]: | ||
ilines = open(filename).readlines() | ||
data = [] | ||
for line in ilines: | ||
if line.strip() == '': | ||
continue | ||
if line.startswith('//'): | ||
continue | ||
data.append(parse(line)) | ||
return data | ||
|
||
|
||
def main(): | ||
data = load_data('include/syscalls.hh') | ||
gens = [ | ||
GenFile('user/inc/usyscalls.h', gen_usyscalls_h), | ||
GenFile('user/src/usyscalls.S', gen_usyscalls_s), | ||
GenFile('include/syscallnums.h', gen_syscallnums), | ||
GenFile('src/syscalls.c', gen_syscalls), | ||
GenFile('include/syscalldecls.h', gen_syscalldecls), | ||
] | ||
for g in gens: | ||
fo = open(g.filename, 'w') | ||
fo.write('''// This file is generated by scripts/gen-syscalls.py from include/syscalls.hh. | ||
// To add a new system call, edit syscalls.hh. gen-syscalls.py will be rerun on | ||
// the next build and this file will be modified. Commit in the changed file for | ||
// easier readability. | ||
''') | ||
fo.write(g.generator(data)) | ||
fo.flush() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.