rustubs/syscalls.rs
1//! syscall interface:
2//! x86 convention via int80. syscall nr in rax, up to 3 parameters in rdi, rsi,
3//! rdx. Return value in rax
4
5use crate::proc::task::{Task, TaskState};
6use core::slice;
7
8/// syscall numbers
9/// TODO: use a syscall loockup table
10const SYS_WRITE: u64 = 1;
11const SYS_EXIT: u64 = 60;
12
13/// dispatch a syscall.
14/// TODO: re-enable interrupts to make the kernel preemptive
15/// TODO: add constants for errnos
16pub fn dispatch(nr: u64, a0: u64, a1: u64, a2: u64) -> u64 {
17 match nr {
18 SYS_WRITE => unsafe { sys_write(a0, a1 as *const u8, a2) },
19 SYS_EXIT => {
20 // TODO push the exit code to waiting thread (parents)
21 sys_exit(a0);
22 return 0;
23 }
24 _ => {
25 println!("[syscall] unknown syscall {}", nr);
26 // -ENOSYS
27 !0
28 }
29 }
30}
31
32/// sys_write(fd, buf, len) -> number of bytes written
33/// currently only support fd==1 (stdout).
34pub unsafe fn sys_write(fd: u64, usr_ptr: *const u8, len: u64) -> u64 {
35 if fd != 1 {
36 return !0;
37 }
38 if len == 0 {
39 return 0;
40 }
41 // this is kinda unsafe ... do user ptr sanitization at some point.
42 let buf = unsafe { slice::from_raw_parts(usr_ptr, len as usize) };
43 for &b in buf {
44 print!("{}", b as char);
45 }
46 len
47}
48
49/// sys_exit(code)
50///
51/// Mark the current task Dead so that it will never be scheduled again. We do
52/// not reclaim its memory yet. The scheduler (or a kernel worker thread) will
53/// clean up zombie tasks later. The trap_gate will check for the task state,
54/// and will never return to user context if the task has been marked as Dead.
55pub fn sys_exit(code: u64) {
56 println!("[syscall] sys_exit({})", code);
57 let task = Task::current().unwrap();
58 task.state = TaskState::Dead;
59 // TODO push the exit code to waiting thread (parents)
60 return;
61}