Skip to main content

rust_kernel_rt/
syscall.rs

1use core::{hint::unreachable_unchecked, mem::MaybeUninit};
2
3use arrayvec::ArrayString;
4use rust_kernel_shared_consts::{DirChild, Fd, PATH_MAX, SYSCALL_CLOSE, SYSCALL_EXEC, SYSCALL_EXIT, SYSCALL_GET_CHAR, SYSCALL_GET_CWD, SYSCALL_GET_DIR_CHILDREN, SYSCALL_OPEN, SYSCALL_PRINT, SYSCALL_SBRK, SYSCALL_SHUTDOWN, SYSCALL_STAT, SYSCALL_WAIT_PID, Stat};
5
6pub unsafe fn syscall0(syscall_nb : u64) -> u64 {
7    let ret : u64;
8    unsafe {
9        core::arch::asm!(
10            "int 0x80",
11            inlateout("rax") syscall_nb => ret,
12            options(nostack)
13        );
14    }
15    ret
16}
17
18pub unsafe fn syscall1(syscall_nb : u64, arg1 : u64) -> u64 {
19    let ret : u64;
20    unsafe {
21        core::arch::asm!(
22            "int 0x80",
23            inlateout("rax") syscall_nb => ret,
24            in("rdi") arg1,
25            options(nostack)
26        );
27    }
28    ret
29}
30
31pub unsafe fn syscall2(syscall_nb : u64, arg1 : u64, arg2 : u64) -> u64 {
32    let ret : u64;
33    unsafe {
34        core::arch::asm!(
35            "int 0x80",
36            inlateout("rax") syscall_nb => ret,
37            in("rdi") arg1,
38            in("rsi") arg2,
39            options(nostack)
40        );
41    }
42    ret
43}
44
45pub unsafe fn syscall3(syscall_nb : u64, arg1 : u64, arg2 : u64, arg3 : u64) -> u64 {
46    let ret : u64;
47    unsafe {
48        core::arch::asm!(
49            "int 0x80",
50            inlateout("rax") syscall_nb => ret,
51            in("rdi") arg1,
52            in("rsi") arg2,
53            in("rdx") arg3,
54            options(nostack)
55        );
56    }
57    ret
58}
59
60pub fn syscall_exit(status : i32) -> ! {
61    unsafe { 
62        syscall1(SYSCALL_EXIT, status as u64);
63        unreachable_unchecked()
64    }
65}
66
67fn str_to_ptr_and_len(s : &str) -> (u64, u64) {
68    (s.as_ptr() as u64, s.len() as u64)
69}
70
71pub fn syscall_print(message : &str) -> Option<()> {
72    let (message_ptr, message_len) = str_to_ptr_and_len(message);
73    unsafe {
74        let res = syscall2(SYSCALL_PRINT, message_ptr, message_len);
75        if res == u64::MAX {
76            return None;
77        }
78        Some(())
79    }
80}
81
82pub fn syscall_exec(path : &str) -> u64 {
83    let (path_ptr, path_len) = str_to_ptr_and_len(path);
84    unsafe {
85        syscall2(SYSCALL_EXEC, path_ptr, path_len)
86    }
87}
88
89pub fn syscall_get_char() -> char {
90    unsafe {
91        let c_u32 = syscall0(SYSCALL_GET_CHAR).try_into().unwrap();
92        char::from_u32_unchecked(c_u32) 
93    }
94}
95
96pub fn syscall_wait_pid(pid : u64){
97    unsafe {
98        syscall1(SYSCALL_WAIT_PID, pid); 
99    }
100}
101
102pub fn syscall_stat(path : &str) -> Option<Stat> {
103    let (path_ptr, path_len) = str_to_ptr_and_len(path);
104    let mut stat = MaybeUninit::uninit();
105    let ret = unsafe {
106        syscall3(SYSCALL_STAT, path_ptr, path_len, stat.as_mut_ptr() as u64)
107    };
108    match ret {
109        u64::MAX => None,
110        _ => unsafe { Some(stat.assume_init()) }
111    }
112}
113
114pub fn syscall_open(path : &str, mode : u64) -> Option<Fd> {
115    let (path_ptr, path_len) = str_to_ptr_and_len(path);
116    let ret = unsafe {
117        syscall3(SYSCALL_OPEN, path_ptr, path_len, mode)
118    };
119    match ret {
120        u64::MAX => None,
121        _ => Some(Fd(ret as usize))
122    }
123}
124
125pub fn syscall_close(fd : Fd) -> Option<()> {
126    let fd = fd.0 as u64;
127    let ret = unsafe {
128        syscall1(SYSCALL_CLOSE, fd)
129    };
130    
131    match ret {
132        u64::MAX => None,
133        _ => Some(()),
134    }
135}
136
137pub fn syscall_get_cwd() -> Option<ArrayString<PATH_MAX>> {
138    let mut ret = ArrayString::new();
139    let ret_ptr = ret.as_ptr() as u64;
140    let ret_len = ret.capacity() as u64;
141    let ret_syscall = unsafe {
142        syscall2(SYSCALL_GET_CWD, ret_ptr, ret_len)
143    };
144    match ret_syscall {
145        u64::MAX => None,
146        len => {
147            unsafe {
148                ret.set_len(len as usize);
149            }
150            Some(ret)
151        },
152    }
153}
154
155pub fn syscall_get_dir_children(fd : Fd, children : &mut [DirChild]) -> Option<usize> {
156    let fd = fd.0 as u64;
157    let children_ptr = children.as_mut_ptr() as u64;
158    let children_len = children.len() as u64;
159    
160    let ret = unsafe {
161        syscall3(SYSCALL_GET_DIR_CHILDREN, fd, children_ptr, children_len)
162    };
163
164    match ret {
165        u64::MAX => None,
166        ret => {
167            Some(ret as usize)
168        }
169    }
170}
171
172pub fn syscall_sbrk(increment : u64) -> Option<u64> {
173    let ret = unsafe {
174        syscall1(SYSCALL_SBRK, increment)
175    };
176    match ret {
177        u64::MAX => None,
178        ret => Some(ret),
179    }
180}
181
182pub fn syscall_shutdown(flags : u64) -> ! {
183    unsafe {
184        syscall1(SYSCALL_SHUTDOWN, flags);
185    }
186    panic!("shutdown syscall failed")
187}