safa_api/
syscalls.rs

1use crate::raw::DirEntry;
2
3use super::errors::ErrorStatus;
4
5#[cfg(not(feature = "rustc-dep-of-std"))]
6extern crate alloc;
7use super::raw::{RawSlice, RawSliceMut};
8use alloc::vec::Vec;
9use core::arch::asm;
10use core::{ops, ptr};
11use safa_abi::errors::SysResult;
12pub use safa_abi::syscalls::SyscallTable as SyscallNum;
13
14macro_rules! err_from_u16 {
15    ($result:expr) => {
16        unsafe {
17            Into::<Result<(), ErrorStatus>>::into(
18                TryInto::<SysResult>::try_into($result).unwrap_unchecked(),
19            )
20        }
21    };
22    ($result:expr, $ok:expr) => {
23        err_from_u16!($result).map(|()| $ok)
24    };
25}
26
27#[inline(always)]
28fn syscall0(num: SyscallNum) -> u16 {
29    let result: u16;
30    unsafe {
31        asm!(
32            "int 0x80",
33            in("rax") num as usize,
34            lateout("rax") result,
35        );
36        result
37    }
38}
39
40#[inline(always)]
41fn syscall1(num: SyscallNum, arg1: usize) -> u16 {
42    let result: u16;
43    unsafe {
44        asm!(
45            "int 0x80",
46            in("rax") num as usize,
47            in("rdi") arg1,
48            lateout("rax") result,
49        );
50        result
51    }
52}
53
54#[inline(always)]
55fn syscall2(num: SyscallNum, arg1: usize, arg2: 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            lateout("rax") result,
64        );
65        result
66    }
67}
68
69#[inline(always)]
70fn syscall3(num: SyscallNum, arg1: usize, arg2: usize, arg3: usize) -> u16 {
71    let result: u16;
72    unsafe {
73        asm!(
74            "int 0x80",
75            in("rax") num as usize,
76            in("rdi") arg1,
77            in("rsi") arg2,
78            in("rdx") arg3,
79            lateout("rax") result,
80        );
81        result
82    }
83}
84
85#[inline(always)]
86fn syscall5(
87    num: SyscallNum,
88    arg1: usize,
89    arg2: usize,
90    arg3: usize,
91    arg4: usize,
92    arg5: usize,
93) -> u16 {
94    let result: u16;
95    unsafe {
96        asm!(
97            "int 0x80",
98            in("rax") num as usize,
99            in("rdi") arg1,
100            in("rsi") arg2,
101            in("rdx") arg3,
102            in("rcx") arg4,
103            in("r8") arg5,
104            lateout("rax") result,
105        );
106        result
107    }
108}
109
110#[inline(always)]
111fn syscall4(num: SyscallNum, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> u16 {
112    let result: u16;
113    unsafe {
114        asm!(
115            "int 0x80",
116            in("rax") num as usize,
117            in("rdi") arg1,
118            in("rsi") arg2,
119            in("rdx") arg3,
120            in("rcx") arg4,
121            lateout("rax") result,
122        );
123        result
124    }
125}
126
127#[cfg_attr(
128    not(any(feature = "std", feature = "rustc-dep-of-std")),
129    unsafe(no_mangle)
130)]
131#[inline(always)]
132extern "C" fn sysgetdirentry(
133    path_ptr: *const u8,
134    path_len: usize,
135    dest_direntry: *mut DirEntry,
136) -> u16 {
137    syscall3(
138        SyscallNum::SysGetDirEntry,
139        path_ptr as usize,
140        path_len,
141        dest_direntry as usize,
142    )
143}
144
145#[inline]
146pub fn getdirentry(path: &str) -> Result<DirEntry, ErrorStatus> {
147    let mut dest_direntry: DirEntry = unsafe { core::mem::zeroed() };
148    err_from_u16!(
149        sysgetdirentry(path.as_ptr(), path.len(), &raw mut dest_direntry),
150        dest_direntry
151    )
152}
153
154#[cfg_attr(
155    not(any(feature = "std", feature = "rustc-dep-of-std")),
156    unsafe(no_mangle)
157)]
158#[inline(always)]
159extern "C" fn sysopen(path_ptr: *const u8, path_len: usize, dest_fd: *mut usize) -> u16 {
160    syscall3(
161        SyscallNum::SysOpen,
162        path_ptr as usize,
163        path_len,
164        dest_fd as usize,
165    )
166}
167
168#[cfg_attr(
169    not(any(feature = "std", feature = "rustc-dep-of-std")),
170    unsafe(no_mangle)
171)]
172#[inline(always)]
173extern "C" fn syscreate_file(path_ptr: *const u8, path_len: usize) -> u16 {
174    syscall2(SyscallNum::SysCreate, path_ptr as usize, path_len)
175}
176
177#[inline]
178pub fn create(path: &str) -> Result<(), ErrorStatus> {
179    err_from_u16!(syscreate_file(path.as_ptr(), path.len()))
180}
181
182#[cfg_attr(
183    not(any(feature = "std", feature = "rustc-dep-of-std")),
184    unsafe(no_mangle)
185)]
186#[inline(always)]
187extern "C" fn syscreate_dir(path_ptr: *const u8, path_len: usize) -> u16 {
188    syscall2(SyscallNum::SysCreateDir, path_ptr as usize, path_len)
189}
190
191#[inline]
192pub fn createdir(path: &str) -> Result<(), ErrorStatus> {
193    err_from_u16!(syscreate_dir(path.as_ptr(), path.len()))
194}
195
196#[inline]
197pub fn open(path: &str) -> Result<usize, ErrorStatus> {
198    let mut dest_fd = 0xAAAAAAAAAAAAAAAAusize;
199    err_from_u16!(
200        sysopen(path.as_ptr(), path.len(), &raw mut dest_fd),
201        dest_fd
202    )
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 sysclose(fd: usize) -> u16 {
211    syscall1(SyscallNum::SysClose, fd)
212}
213
214#[inline]
215pub fn close(fd: usize) -> Result<(), ErrorStatus> {
216    err_from_u16!(sysclose(fd))
217}
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 sysdiriter_close(fd: usize) -> u16 {
225    syscall1(SyscallNum::SysDirIterClose, fd)
226}
227
228#[inline]
229pub fn diriter_close(fd: usize) -> Result<(), ErrorStatus> {
230    err_from_u16!(sysdiriter_close(fd))
231}
232
233#[cfg_attr(
234    not(any(feature = "std", feature = "rustc-dep-of-std")),
235    unsafe(no_mangle)
236)]
237#[inline(always)]
238extern "C" fn sysdiriter_open(path_ptr: *const u8, path_len: usize, dest_fd: *mut usize) -> u16 {
239    syscall3(
240        SyscallNum::SysDirIterOpen,
241        path_ptr as usize,
242        path_len,
243        dest_fd as usize,
244    )
245}
246
247#[inline]
248pub fn diriter_open(path: &str) -> Result<usize, ErrorStatus> {
249    let mut dest_fd: usize = 0xAAAAAAAAAAAAAAAAusize;
250    err_from_u16!(
251        sysdiriter_open(path.as_ptr(), path.len(), &raw mut dest_fd),
252        dest_fd
253    )
254}
255
256#[cfg_attr(
257    not(any(feature = "std", feature = "rustc-dep-of-std")),
258    unsafe(no_mangle)
259)]
260#[inline(always)]
261extern "C" fn sysdiriter_next(dir_ri: usize, dest_direntry: *mut DirEntry) -> u16 {
262    syscall2(SyscallNum::SysDirIterNext, dir_ri, dest_direntry as usize)
263}
264
265#[inline]
266pub fn diriter_next(dir_ri: usize) -> Result<DirEntry, ErrorStatus> {
267    let mut dest_direntry: DirEntry = unsafe { core::mem::zeroed() };
268    err_from_u16!(
269        sysdiriter_next(dir_ri, &raw mut dest_direntry),
270        dest_direntry
271    )
272}
273
274#[cfg_attr(
275    not(any(feature = "std", feature = "rustc-dep-of-std")),
276    unsafe(no_mangle)
277)]
278#[inline(always)]
279extern "C" fn syswrite(
280    fd: usize,
281    offset: isize,
282    buf: *const u8,
283    len: usize,
284    dest_wrote: &mut usize,
285) -> u16 {
286    syscall5(
287        SyscallNum::SysWrite,
288        fd,
289        offset as usize,
290        buf as usize,
291        len,
292        dest_wrote as *mut _ as usize,
293    )
294}
295
296#[inline]
297pub fn write(fd: usize, offset: isize, buf: &[u8]) -> Result<usize, ErrorStatus> {
298    let mut dest_wrote = 0;
299    err_from_u16!(
300        syswrite(fd, offset, buf.as_ptr(), buf.len(), &mut dest_wrote),
301        dest_wrote
302    )
303}
304
305#[cfg_attr(
306    not(any(feature = "std", feature = "rustc-dep-of-std")),
307    unsafe(no_mangle)
308)]
309#[inline(always)]
310extern "C" fn systruncate(fd: usize, len: usize) -> u16 {
311    syscall2(SyscallNum::SysTruncate, fd, len)
312}
313
314#[inline]
315pub fn truncate(fd: usize, len: usize) -> Result<(), ErrorStatus> {
316    err_from_u16!(systruncate(fd, len))
317}
318
319#[cfg_attr(
320    not(any(feature = "std", feature = "rustc-dep-of-std")),
321    unsafe(no_mangle)
322)]
323#[inline(always)]
324pub fn sysfsize(fd: usize, dest_size: *mut usize) -> u16 {
325    syscall2(SyscallNum::SysFSize, fd, dest_size as usize)
326}
327
328pub fn fsize(fd: usize) -> Result<usize, ErrorStatus> {
329    let mut dest_size = 0;
330    err_from_u16!(sysfsize(fd, &raw mut dest_size), dest_size)
331}
332
333#[cfg_attr(
334    not(any(feature = "std", feature = "rustc-dep-of-std")),
335    unsafe(no_mangle)
336)]
337#[inline(always)]
338extern "C" fn sysread(
339    fd: usize,
340    offset: isize,
341    buf: *mut u8,
342    len: usize,
343    dest_read: &mut usize,
344) -> u16 {
345    syscall5(
346        SyscallNum::SysRead,
347        fd,
348        offset as usize,
349        buf as usize,
350        len,
351        dest_read as *mut _ as usize,
352    )
353}
354
355#[inline]
356pub fn read(fd: usize, offset: isize, buf: &mut [u8]) -> Result<usize, ErrorStatus> {
357    let mut dest_read = 0;
358    err_from_u16!(
359        sysread(fd, offset, buf.as_mut_ptr(), buf.len(), &mut dest_read),
360        dest_read
361    )
362}
363
364#[cfg_attr(
365    not(any(feature = "std", feature = "rustc-dep-of-std")),
366    unsafe(no_mangle)
367)]
368#[inline(always)]
369extern "C" fn syssync(fd: usize) -> u16 {
370    syscall1(SyscallNum::SysSync, fd)
371}
372
373#[inline]
374pub fn sync(fd: usize) -> Result<(), ErrorStatus> {
375    err_from_u16!(syssync(fd))
376}
377#[cfg_attr(
378    not(any(feature = "std", feature = "rustc-dep-of-std")),
379    unsafe(no_mangle)
380)]
381#[inline(always)]
382extern "C" fn syssbrk(size: isize, target_ptr: &mut *mut u8) -> u16 {
383    syscall2(
384        SyscallNum::SysSbrk,
385        size as usize,
386        target_ptr as *mut _ as usize,
387    )
388}
389
390#[inline]
391pub fn sbrk(size: isize) -> Result<*mut u8, ErrorStatus> {
392    let mut target_ptr: *mut u8 = core::ptr::null_mut();
393    err_from_u16!(syssbrk(size, &mut target_ptr), target_ptr)
394}
395
396#[cfg_attr(
397    not(any(feature = "std", feature = "rustc-dep-of-std")),
398    unsafe(no_mangle)
399)]
400#[inline(always)]
401extern "C" fn sysexit(code: usize) -> ! {
402    syscall1(SyscallNum::SysExit, code);
403    unreachable!()
404}
405
406#[cfg_attr(
407    not(any(feature = "std", feature = "rustc-dep-of-std")),
408    unsafe(no_mangle)
409)]
410#[inline(always)]
411extern "C" fn sysyield() -> u16 {
412    syscall0(SyscallNum::SysYield)
413}
414
415#[inline]
416pub fn yield_now() {
417    debug_assert!(sysyield() == 0)
418}
419
420#[cfg_attr(
421    not(any(feature = "std", feature = "rustc-dep-of-std")),
422    unsafe(no_mangle)
423)]
424#[inline(always)]
425extern "C" fn sysshutdown() -> ! {
426    syscall0(SyscallNum::SysShutdown);
427    unreachable!()
428}
429
430#[inline]
431pub fn shutdown() -> ! {
432    sysshutdown()
433}
434
435#[cfg_attr(
436    not(any(feature = "std", feature = "rustc-dep-of-std")),
437    unsafe(no_mangle)
438)]
439#[inline(always)]
440extern "C" fn sysreboot() -> ! {
441    syscall0(SyscallNum::SysReboot);
442    unreachable!()
443}
444
445#[inline]
446pub fn reboot() -> ! {
447    sysreboot()
448}
449
450#[inline]
451pub fn exit(code: usize) -> ! {
452    sysexit(code)
453}
454#[cfg_attr(
455    not(any(feature = "std", feature = "rustc-dep-of-std")),
456    unsafe(no_mangle)
457)]
458#[inline(always)]
459extern "C" fn syschdir(buf_ptr: *const u8, buf_len: usize) -> u16 {
460    syscall2(SyscallNum::SysCHDir, buf_ptr as usize, buf_len)
461}
462
463#[inline]
464pub fn chdir(path: &str) -> Result<(), ErrorStatus> {
465    let path = path.as_bytes();
466    err_from_u16!(syschdir(path.as_ptr(), path.len()))
467}
468
469#[cfg_attr(
470    not(any(feature = "std", feature = "rustc-dep-of-std")),
471    unsafe(no_mangle)
472)]
473/// Gets the current working directory
474/// returns Err(ErrorStatus::Generic) if the buffer is too small to hold the cwd
475#[inline(always)]
476extern "C" fn sysgetcwd(cwd_buf_ptr: *mut u8, cwd_buf_len: usize, dest_len: &mut usize) -> u16 {
477    syscall3(
478        SyscallNum::SysGetCWD,
479        cwd_buf_ptr as usize,
480        cwd_buf_len,
481        dest_len as *mut _ as usize,
482    )
483}
484
485#[inline]
486pub fn getcwd() -> Result<Vec<u8>, ErrorStatus> {
487    let do_syscall = |cwd_buf: &mut [u8]| {
488        let mut dest_len = 0;
489        err_from_u16!(
490            sysgetcwd(cwd_buf.as_mut_ptr(), cwd_buf.len(), &mut dest_len),
491            dest_len
492        )
493    };
494
495    let extend = |cwd_buf: &mut Vec<u8>| unsafe {
496        cwd_buf.reserve(128);
497        cwd_buf.set_len(cwd_buf.capacity());
498    };
499
500    let mut cwd_buf = Vec::new();
501    extend(&mut cwd_buf);
502
503    loop {
504        match do_syscall(&mut cwd_buf) {
505            Ok(len) => unsafe {
506                cwd_buf.set_len(len);
507                return Ok(cwd_buf);
508            },
509            Err(err) => {
510                if err == ErrorStatus::Generic {
511                    extend(&mut cwd_buf);
512                } else {
513                    return Err(err);
514                }
515            }
516        }
517    }
518}
519
520#[derive(Debug, Clone, Copy)]
521#[repr(C)]
522pub struct SpawnFlags(u8);
523impl SpawnFlags {
524    pub const CLONE_RESOURCES: Self = Self(1 << 0);
525    pub const CLONE_CWD: Self = Self(1 << 1);
526}
527
528impl ops::BitOr for SpawnFlags {
529    type Output = Self;
530    fn bitor(self, rhs: Self) -> Self::Output {
531        Self(self.0 | rhs.0)
532    }
533}
534#[cfg_attr(
535    not(any(feature = "std", feature = "rustc-dep-of-std")),
536    unsafe(no_mangle)
537)]
538#[inline(always)]
539extern "C" fn syspspawn(
540    name_ptr: *const u8,
541    name_len: usize,
542    path_ptr: *const u8,
543    path_len: usize,
544    argv_ptr: *const RawSlice<u8>,
545    argv_len: usize,
546    flags: SpawnFlags,
547    dest_pid: &mut usize,
548) -> u16 {
549    /// the temporary config struct for the spawn syscall, passed to the syscall
550    /// because if it was passed as a bunch of arguments it would be too big to fit
551    /// inside the registers
552    #[repr(C)]
553    struct SpawnConfig {
554        name: RawSlice<u8>,
555        argv: RawSlice<RawSlice<u8>>,
556        flags: SpawnFlags,
557    }
558
559    let config = SpawnConfig {
560        name: unsafe { RawSlice::from_raw_parts(name_ptr, name_len) },
561        argv: unsafe { RawSlice::from_raw_parts(argv_ptr, argv_len) },
562        flags,
563    };
564    syscall4(
565        SyscallNum::SysPSpawn,
566        path_ptr as usize,
567        path_len,
568        (&raw const config) as usize,
569        dest_pid as *mut _ as usize,
570    )
571}
572
573/// spawns a new process
574/// # Safety
575/// `argv` must be a valid pointer to a slice of slices of `&str`
576/// `argv` will become invaild after use, using it is UB
577#[inline]
578pub unsafe fn unsafe_pspawn(
579    name: Option<&str>,
580    path: &str,
581    argv: *mut [&str],
582    flags: SpawnFlags,
583) -> Result<usize, ErrorStatus> {
584    let mut pid = 0;
585
586    let name = name.map(|s| s.as_bytes());
587    let name_ptr = name.map(|s| s.as_ptr()).unwrap_or(ptr::null());
588    let name_len = name.map(|s| s.len()).unwrap_or(0);
589
590    let argv: *mut [&[u8]] = argv as *mut [&[u8]];
591    let argv = unsafe { RawSliceMut::from_slices(argv) };
592    err_from_u16!(
593        syspspawn(
594            name_ptr,
595            name_len,
596            path.as_ptr(),
597            path.len(),
598            argv.as_ptr(),
599            argv.len(),
600            flags,
601            &mut pid,
602        ),
603        pid
604    )
605}
606
607/// same as [`pspawn`] but safe because it makes it clear that `argv` is consumed`
608#[inline]
609pub fn pspawn(
610    name: Option<&str>,
611    path: &str,
612    mut argv: Vec<&str>,
613    flags: SpawnFlags,
614) -> Result<usize, ErrorStatus> {
615    let argv: &mut [&str] = &mut argv;
616    unsafe { unsafe_pspawn(name, path, argv as *mut _, flags) }
617}
618#[cfg_attr(
619    not(any(feature = "std", feature = "rustc-dep-of-std")),
620    unsafe(no_mangle)
621)]
622#[inline(always)]
623extern "C" fn syswait(pid: usize, exit_code: &mut usize) -> u16 {
624    syscall2(SyscallNum::SysWait, pid, exit_code as *mut _ as usize)
625}
626
627#[inline]
628pub fn wait(pid: usize) -> Result<usize, ErrorStatus> {
629    let mut dest_exit_code = 0;
630    err_from_u16!(syswait(pid, &mut dest_exit_code), dest_exit_code)
631}