Skip to main content

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}