1use super::errors::ErrorStatus;
2
3#[cfg(not(feature = "rustc-dep-of-std"))]
4extern crate alloc;
5use super::raw::{RawSlice, RawSliceMut};
6use alloc::vec::Vec;
7use core::arch::asm;
8use core::{ops, ptr};
9use safa_abi::errors::SysResult;
10pub use safa_abi::syscalls::SyscallTable as SyscallNum;
11
12macro_rules! err_from_u16 {
13 ($result:expr) => {
14 unsafe {
15 Into::<Result<(), ErrorStatus>>::into(
16 TryInto::<SysResult>::try_into($result).unwrap_unchecked(),
17 )
18 }
19 };
20 ($result:expr, $ok:expr) => {
21 err_from_u16!($result).map(|()| $ok)
22 };
23}
24
25#[inline(always)]
26fn syscall1(num: SyscallNum, arg1: usize) -> u16 {
27 let result: u16;
28 unsafe {
29 asm!(
30 "int 0x80",
31 in("rax") num as usize,
32 in("rdi") arg1,
33 lateout("rax") result,
34 );
35 result
36 }
37}
38
39#[inline(always)]
40fn syscall2(num: SyscallNum, arg1: usize, arg2: usize) -> u16 {
41 let result: u16;
42 unsafe {
43 asm!(
44 "int 0x80",
45 in("rax") num as usize,
46 in("rdi") arg1,
47 in("rsi") arg2,
48 lateout("rax") result,
49 );
50 result
51 }
52}
53
54#[inline(always)]
55fn syscall3(num: SyscallNum, arg1: usize, arg2: usize, arg3: usize) -> u16 {
56 let result: u16;
57 unsafe {
58 asm!(
59 "int 0x80",
60 in("rax") num as usize,
61 in("rdi") arg1,
62 in("rsi") arg2,
63 in("rdx") arg3,
64 lateout("rax") result,
65 );
66 result
67 }
68}
69
70#[inline(always)]
71fn syscall5(
72 num: SyscallNum,
73 arg1: usize,
74 arg2: usize,
75 arg3: usize,
76 arg4: usize,
77 arg5: usize,
78) -> u16 {
79 let result: u16;
80 unsafe {
81 asm!(
82 "int 0x80",
83 in("rax") num as usize,
84 in("rdi") arg1,
85 in("rsi") arg2,
86 in("rdx") arg3,
87 in("rcx") arg4,
88 in("r8") arg5,
89 lateout("rax") result,
90 );
91 result
92 }
93}
94
95#[inline(always)]
96fn syscall4(num: SyscallNum, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> u16 {
97 let result: u16;
98 unsafe {
99 asm!(
100 "int 0x80",
101 in("rax") num as usize,
102 in("rdi") arg1,
103 in("rsi") arg2,
104 in("rdx") arg3,
105 in("rcx") arg4,
106 lateout("rax") result,
107 );
108 result
109 }
110}
111
112#[cfg_attr(
113 not(any(feature = "std", feature = "rustc-dep-of-std")),
114 unsafe(no_mangle)
115)]
116#[inline(always)]
117extern "C" fn syswrite(
118 fd: usize,
119 offset: isize,
120 buf: *const u8,
121 len: usize,
122 dest_wrote: &mut usize,
123) -> u16 {
124 syscall5(
125 SyscallNum::SysWrite,
126 fd,
127 offset as usize,
128 buf as usize,
129 len,
130 dest_wrote as *mut _ as usize,
131 )
132}
133
134#[inline]
135pub fn write(fd: usize, offset: isize, buf: &[u8]) -> Result<usize, ErrorStatus> {
136 let mut dest_wrote = 0;
137 err_from_u16!(
138 syswrite(fd, offset, buf.as_ptr(), buf.len(), &mut dest_wrote),
139 dest_wrote
140 )
141}
142#[cfg_attr(
143 not(any(feature = "std", feature = "rustc-dep-of-std")),
144 unsafe(no_mangle)
145)]
146#[inline(always)]
147extern "C" fn sysread(
148 fd: usize,
149 offset: isize,
150 buf: *mut u8,
151 len: usize,
152 dest_read: &mut usize,
153) -> u16 {
154 syscall5(
155 SyscallNum::SysRead,
156 fd,
157 offset as usize,
158 buf as usize,
159 len,
160 dest_read as *mut _ as usize,
161 )
162}
163
164#[inline]
165pub fn read(fd: usize, offset: isize, buf: &mut [u8]) -> Result<usize, ErrorStatus> {
166 let mut dest_read = 0;
167 err_from_u16!(
168 sysread(fd, offset, buf.as_mut_ptr(), buf.len(), &mut dest_read),
169 dest_read
170 )
171}
172
173#[cfg_attr(
174 not(any(feature = "std", feature = "rustc-dep-of-std")),
175 unsafe(no_mangle)
176)]
177#[inline(always)]
178extern "C" fn syssync(fd: usize) -> u16 {
179 syscall1(SyscallNum::SysSync, fd)
180}
181
182#[inline]
183pub fn sync(fd: usize) -> Result<(), ErrorStatus> {
184 err_from_u16!(syssync(fd))
185}
186#[cfg_attr(
187 not(any(feature = "std", feature = "rustc-dep-of-std")),
188 unsafe(no_mangle)
189)]
190#[inline(always)]
191extern "C" fn syssbrk(size: isize, target_ptr: &mut *mut u8) -> u16 {
192 syscall2(
193 SyscallNum::SysSbrk,
194 size as usize,
195 target_ptr as *mut _ as usize,
196 )
197}
198
199#[inline]
200pub fn sbrk(size: isize) -> Result<*mut u8, ErrorStatus> {
201 let mut target_ptr: *mut u8 = core::ptr::null_mut();
202 err_from_u16!(syssbrk(size, &mut target_ptr), target_ptr)
203}
204
205#[cfg_attr(
206 not(any(feature = "std", feature = "rustc-dep-of-std")),
207 unsafe(no_mangle)
208)]
209#[inline(always)]
210extern "C" fn sysexit(code: usize) -> ! {
211 syscall1(SyscallNum::SysExit, code);
212 unreachable!()
213}
214
215#[inline]
216pub fn exit(code: usize) -> ! {
217 sysexit(code)
218}
219#[cfg_attr(
220 not(any(feature = "std", feature = "rustc-dep-of-std")),
221 unsafe(no_mangle)
222)]
223#[inline(always)]
224extern "C" fn syschdir(buf_ptr: *const u8, buf_len: usize) -> u16 {
225 syscall2(SyscallNum::SysCHDir, buf_ptr as usize, buf_len)
226}
227
228#[inline]
229pub fn chdir(path: &str) -> Result<(), ErrorStatus> {
230 let path = path.as_bytes();
231 err_from_u16!(syschdir(path.as_ptr(), path.len()))
232}
233
234#[cfg_attr(
235 not(any(feature = "std", feature = "rustc-dep-of-std")),
236 unsafe(no_mangle)
237)]
238#[inline(always)]
241extern "C" fn sysgetcwd(cwd_buf_ptr: *mut u8, cwd_buf_len: usize, dest_len: &mut usize) -> u16 {
242 syscall3(
243 SyscallNum::SysGetCWD,
244 cwd_buf_ptr as usize,
245 cwd_buf_len,
246 dest_len as *mut _ as usize,
247 )
248}
249
250#[inline]
251pub fn getcwd() -> Result<Vec<u8>, ErrorStatus> {
252 let do_syscall = |cwd_buf: &mut [u8]| {
253 let mut dest_len = 0;
254 err_from_u16!(
255 sysgetcwd(cwd_buf.as_mut_ptr(), cwd_buf.len(), &mut dest_len),
256 dest_len
257 )
258 };
259
260 let extend = |cwd_buf: &mut Vec<u8>| unsafe {
261 cwd_buf.reserve(128);
262 cwd_buf.set_len(cwd_buf.capacity());
263 };
264
265 let mut cwd_buf = Vec::new();
266 extend(&mut cwd_buf);
267
268 loop {
269 match do_syscall(&mut cwd_buf) {
270 Ok(len) => unsafe {
271 cwd_buf.set_len(len);
272 return Ok(cwd_buf);
273 },
274 Err(err) => {
275 if err == ErrorStatus::Generic {
276 extend(&mut cwd_buf);
277 } else {
278 return Err(err);
279 }
280 }
281 }
282 }
283}
284
285#[derive(Debug, Clone, Copy)]
286#[repr(C)]
287pub struct SpawnFlags(u8);
288impl SpawnFlags {
289 pub const CLONE_RESOURCES: Self = Self(1 << 0);
290 pub const CLONE_CWD: Self = Self(1 << 1);
291}
292
293impl ops::BitOr for SpawnFlags {
294 type Output = Self;
295 fn bitor(self, rhs: Self) -> Self::Output {
296 Self(self.0 | rhs.0)
297 }
298}
299#[cfg_attr(
300 not(any(feature = "std", feature = "rustc-dep-of-std")),
301 unsafe(no_mangle)
302)]
303#[inline(always)]
304extern "C" fn syspspawn(
305 name_ptr: *const u8,
306 name_len: usize,
307 path_ptr: *const u8,
308 path_len: usize,
309 argv_ptr: *const RawSlice<u8>,
310 argv_len: usize,
311 flags: SpawnFlags,
312 dest_pid: &mut usize,
313) -> u16 {
314 #[repr(C)]
318 struct SpawnConfig {
319 name: RawSlice<u8>,
320 argv: RawSlice<RawSlice<u8>>,
321 flags: SpawnFlags,
322 }
323
324 let config = SpawnConfig {
325 name: unsafe { RawSlice::from_raw_parts(name_ptr, name_len) },
326 argv: unsafe { RawSlice::from_raw_parts(argv_ptr, argv_len) },
327 flags,
328 };
329 syscall4(
330 SyscallNum::SysPSpawn,
331 path_ptr as usize,
332 path_len,
333 (&raw const config) as usize,
334 dest_pid as *mut _ as usize,
335 )
336}
337
338#[inline]
343pub unsafe fn unsafe_pspawn(
344 name: Option<&str>,
345 path: &str,
346 argv: *mut [&str],
347 flags: SpawnFlags,
348) -> Result<usize, ErrorStatus> {
349 let mut pid = 0;
350
351 let name = name.map(|s| s.as_bytes());
352 let name_ptr = name.map(|s| s.as_ptr()).unwrap_or(ptr::null());
353 let name_len = name.map(|s| s.len()).unwrap_or(0);
354
355 let argv: *mut [&[u8]] = argv as *mut [&[u8]];
356 let argv = unsafe { RawSliceMut::from_slices(argv) };
357 err_from_u16!(
358 syspspawn(
359 name_ptr,
360 name_len,
361 path.as_ptr(),
362 path.len(),
363 argv.as_ptr(),
364 argv.len(),
365 flags,
366 &mut pid,
367 ),
368 pid
369 )
370}
371
372#[inline]
374pub fn pspawn(
375 name: Option<&str>,
376 path: &str,
377 mut argv: Vec<&str>,
378 flags: SpawnFlags,
379) -> Result<usize, ErrorStatus> {
380 let argv: &mut [&str] = &mut argv;
381 unsafe { unsafe_pspawn(name, path, argv as *mut _, flags) }
382}
383#[cfg_attr(
384 not(any(feature = "std", feature = "rustc-dep-of-std")),
385 unsafe(no_mangle)
386)]
387#[inline(always)]
388extern "C" fn syswait(pid: usize, exit_code: &mut usize) -> u16 {
389 syscall2(SyscallNum::SysWait, pid, exit_code as *mut _ as usize)
390}
391
392#[inline]
393pub fn wait(pid: usize) -> Result<usize, ErrorStatus> {
394 let mut dest_exit_code = 0;
395 err_from_u16!(syswait(pid, &mut dest_exit_code), dest_exit_code)
396}