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::{
6	sched::GLOBAL_SCHEDULER,
7	task::{Task, TaskState},
8	PIDMEISTER,
9};
10use core::slice;
11
12/// syscall numbers
13/// TODO: use a syscall lookup table
14const SYS_WRITE: u64 = 1;
15const SYS_GETPID: u64 = 37;
16const SYS_FORK: u64 = 57;
17const SYS_EXIT: u64 = 60;
18
19/// dispatch a syscall.
20/// TODO: re-enable interrupts to make the kernel preemptive
21/// TODO: add constants for errnos
22pub fn dispatch(fp: u64, nr: u64, a0: u64, a1: u64, a2: u64) -> u64 {
23	match nr {
24		SYS_WRITE => unsafe { sys_write(a0, a1 as *const u8, a2) },
25		SYS_FORK => sys_fork(fp),
26		SYS_GETPID => sys_getpid(),
27		SYS_EXIT => {
28			// TODO push the exit code to waiting thread (parents)
29			sys_exit(a0);
30			return 0;
31		}
32		_ => {
33			println!("[syscall] unknown syscall {}", nr);
34			// -ENOSYS
35			!0
36		}
37	}
38}
39
40pub fn sys_fork(fp: u64) -> u64 {
41	let t = Task::current().unwrap();
42	let pid = PIDMEISTER.nya();
43	let tid_child = t.clone_task_user(fp, pid);
44	GLOBAL_SCHEDULER.lock().insert_task(tid_child);
45	pid
46}
47
48// TODO: getpid returns u64 here ... but the userland expects int.
49pub fn sys_getpid() -> u64 { Task::current().unwrap().pid }
50
51/// sys_write(fd, buf, len) -> number of bytes written
52/// currently only support fd==1 (stdout).
53pub unsafe fn sys_write(fd: u64, usr_ptr: *const u8, len: u64) -> u64 {
54	if fd != 1 {
55		return !0;
56	}
57	if len == 0 {
58		return 0;
59	}
60	// this is kinda unsafe ... do user ptr sanitization at some point.
61	let buf = unsafe { slice::from_raw_parts(usr_ptr, len as usize) };
62	for &b in buf {
63		print!("{}", b as char);
64	}
65	len
66}
67
68/// sys_exit(code)
69///
70/// Mark the current task Dead so that it will never be scheduled again. We do
71/// not reclaim its memory yet. The scheduler (or a kernel worker thread) will
72/// clean up zombie tasks later. The trap_gate will check for the task state,
73/// and will never return to user context if the task has been marked as Dead.
74pub fn sys_exit(code: u64) {
75	println!("[syscall] sys_exit({})", code);
76	let task = Task::current().unwrap();
77	task.state = TaskState::Dead;
78	// TODO push the exit code to waiting thread (parents)
79	return;
80}