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