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(dir_ri: usize, dest_ri: *mut usize) -> u16 {
240    syscall2(SyscallNum::SysDirIterOpen, dir_ri, dest_ri as usize)
241}
242
243#[inline]
244pub fn diriter_open(dir_ri: usize) -> Result<usize, ErrorStatus> {
245    let mut dest_fd: usize = 0xAAAAAAAAAAAAAAAAusize;
246    err_from_u16!(sysdiriter_open(dir_ri, &raw mut dest_fd), dest_fd)
247}
248
249#[cfg_attr(
250    not(any(feature = "std", feature = "rustc-dep-of-std")),
251    unsafe(no_mangle)
252)]
253#[inline(always)]
254extern "C" fn sysdiriter_next(dir_ri: usize, dest_direntry: *mut DirEntry) -> u16 {
255    syscall2(SyscallNum::SysDirIterNext, dir_ri, dest_direntry as usize)
256}
257
258#[inline]
259pub fn diriter_next(dir_ri: usize) -> Result<DirEntry, ErrorStatus> {
260    let mut dest_direntry: DirEntry = unsafe { core::mem::zeroed() };
261    err_from_u16!(
262        sysdiriter_next(dir_ri, &raw mut dest_direntry),
263        dest_direntry
264    )
265}
266
267#[cfg_attr(
268    not(any(feature = "std", feature = "rustc-dep-of-std")),
269    unsafe(no_mangle)
270)]
271#[inline(always)]
272extern "C" fn syswrite(
273    fd: usize,
274    offset: isize,
275    buf: *const u8,
276    len: usize,
277    dest_wrote: &mut usize,
278) -> u16 {
279    syscall5(
280        SyscallNum::SysWrite,
281        fd,
282        offset as usize,
283        buf as usize,
284        len,
285        dest_wrote as *mut _ as usize,
286    )
287}
288
289#[inline]
290pub fn write(fd: usize, offset: isize, buf: &[u8]) -> Result<usize, ErrorStatus> {
291    let mut dest_wrote = 0;
292    err_from_u16!(
293        syswrite(fd, offset, buf.as_ptr(), buf.len(), &mut dest_wrote),
294        dest_wrote
295    )
296}
297
298#[cfg_attr(
299    not(any(feature = "std", feature = "rustc-dep-of-std")),
300    unsafe(no_mangle)
301)]
302#[inline(always)]
303extern "C" fn systruncate(fd: usize, len: usize) -> u16 {
304    syscall2(SyscallNum::SysTruncate, fd, len)
305}
306
307#[inline]
308pub fn truncate(fd: usize, len: usize) -> Result<(), ErrorStatus> {
309    err_from_u16!(systruncate(fd, len))
310}
311
312#[cfg_attr(
313    not(any(feature = "std", feature = "rustc-dep-of-std")),
314    unsafe(no_mangle)
315)]
316#[inline(always)]
317pub fn sysfsize(fd: usize, dest_size: *mut usize) -> u16 {
318    syscall2(SyscallNum::SysFSize, fd, dest_size as usize)
319}
320
321#[inline]
322pub fn fsize(fd: usize) -> Result<usize, ErrorStatus> {
323    let mut dest_size = 0;
324    err_from_u16!(sysfsize(fd, &raw mut dest_size), dest_size)
325}
326
327#[cfg_attr(
328    not(any(feature = "std", feature = "rustc-dep-of-std")),
329    unsafe(no_mangle)
330)]
331#[inline(always)]
332extern "C" fn sysfattrs(fd: usize, dest_attrs: *mut FileAttr) -> u16 {
333    syscall2(SyscallNum::SysFAttrs, fd, dest_attrs as usize)
334}
335
336#[inline]
337pub fn fattrs(fd: usize) -> Result<FileAttr, ErrorStatus> {
338    let mut attrs: FileAttr = unsafe { core::mem::zeroed() };
339    err_from_u16!(sysfattrs(fd, &raw mut attrs), attrs)
340}
341
342#[cfg_attr(
343    not(any(feature = "std", feature = "rustc-dep-of-std")),
344    unsafe(no_mangle)
345)]
346#[inline(always)]
347extern "C" fn sysread(
348    fd: usize,
349    offset: isize,
350    buf: *mut u8,
351    len: usize,
352    dest_read: &mut usize,
353) -> u16 {
354    syscall5(
355        SyscallNum::SysRead,
356        fd,
357        offset as usize,
358        buf as usize,
359        len,
360        dest_read as *mut _ as usize,
361    )
362}
363
364#[inline]
365pub fn read(fd: usize, offset: isize, buf: &mut [u8]) -> Result<usize, ErrorStatus> {
366    let mut dest_read = 0;
367    err_from_u16!(
368        sysread(fd, offset, buf.as_mut_ptr(), buf.len(), &mut dest_read),
369        dest_read
370    )
371}
372
373#[cfg_attr(
374    not(any(feature = "std", feature = "rustc-dep-of-std")),
375    unsafe(no_mangle)
376)]
377#[inline(always)]
378extern "C" fn syssync(fd: usize) -> u16 {
379    syscall1(SyscallNum::SysSync, fd)
380}
381
382#[inline]
383pub fn sync(fd: usize) -> Result<(), ErrorStatus> {
384    err_from_u16!(syssync(fd))
385}
386#[cfg_attr(
387    not(any(feature = "std", feature = "rustc-dep-of-std")),
388    unsafe(no_mangle)
389)]
390#[inline(always)]
391extern "C" fn syssbrk(size: isize, target_ptr: &mut *mut u8) -> u16 {
392    syscall2(
393        SyscallNum::SysSbrk,
394        size as usize,
395        target_ptr as *mut _ as usize,
396    )
397}
398
399#[inline]
400pub fn sbrk(size: isize) -> Result<*mut u8, ErrorStatus> {
401    let mut target_ptr: *mut u8 = core::ptr::null_mut();
402    err_from_u16!(syssbrk(size, &mut target_ptr), target_ptr)
403}
404
405#[cfg_attr(
406    not(any(feature = "std", feature = "rustc-dep-of-std")),
407    unsafe(no_mangle)
408)]
409#[inline(always)]
410extern "C" fn sysexit(code: usize) -> ! {
411    syscall1(SyscallNum::SysExit, code);
412    unreachable!()
413}
414
415#[cfg_attr(
416    not(any(feature = "std", feature = "rustc-dep-of-std")),
417    unsafe(no_mangle)
418)]
419#[inline(always)]
420extern "C" fn sysyield() -> u16 {
421    syscall0(SyscallNum::SysYield)
422}
423
424#[inline]
425pub fn yield_now() {
426    debug_assert!(sysyield() == 0)
427}
428
429#[cfg_attr(
430    not(any(feature = "std", feature = "rustc-dep-of-std")),
431    unsafe(no_mangle)
432)]
433#[inline(always)]
434extern "C" fn sysshutdown() -> ! {
435    syscall0(SyscallNum::SysShutdown);
436    unreachable!()
437}
438
439#[inline]
440pub fn shutdown() -> ! {
441    sysshutdown()
442}
443
444#[cfg_attr(
445    not(any(feature = "std", feature = "rustc-dep-of-std")),
446    unsafe(no_mangle)
447)]
448#[inline(always)]
449extern "C" fn sysreboot() -> ! {
450    syscall0(SyscallNum::SysReboot);
451    unreachable!()
452}
453
454#[inline]
455pub fn reboot() -> ! {
456    sysreboot()
457}
458
459#[inline]
460pub fn exit(code: usize) -> ! {
461    sysexit(code)
462}
463#[cfg_attr(
464    not(any(feature = "std", feature = "rustc-dep-of-std")),
465    unsafe(no_mangle)
466)]
467#[inline(always)]
468extern "C" fn syschdir(buf_ptr: *const u8, buf_len: usize) -> u16 {
469    syscall2(SyscallNum::SysCHDir, buf_ptr as usize, buf_len)
470}
471
472#[inline]
473pub fn chdir(path: &str) -> Result<(), ErrorStatus> {
474    let path = path.as_bytes();
475    err_from_u16!(syschdir(path.as_ptr(), path.len()))
476}
477
478#[cfg_attr(
479    not(any(feature = "std", feature = "rustc-dep-of-std")),
480    unsafe(no_mangle)
481)]
482/// Gets the current working directory
483/// returns Err(ErrorStatus::Generic) if the buffer is too small to hold the cwd
484#[inline(always)]
485extern "C" fn sysgetcwd(cwd_buf_ptr: *mut u8, cwd_buf_len: usize, dest_len: &mut usize) -> u16 {
486    syscall3(
487        SyscallNum::SysGetCWD,
488        cwd_buf_ptr as usize,
489        cwd_buf_len,
490        dest_len as *mut _ as usize,
491    )
492}
493
494#[inline]
495pub fn getcwd() -> Result<Vec<u8>, ErrorStatus> {
496    let do_syscall = |cwd_buf: &mut [u8]| {
497        let mut dest_len = 0;
498        err_from_u16!(
499            sysgetcwd(cwd_buf.as_mut_ptr(), cwd_buf.len(), &mut dest_len),
500            dest_len
501        )
502    };
503
504    let extend = |cwd_buf: &mut Vec<u8>| unsafe {
505        cwd_buf.reserve(128);
506        cwd_buf.set_len(cwd_buf.capacity());
507    };
508
509    let mut cwd_buf = Vec::new();
510    extend(&mut cwd_buf);
511
512    loop {
513        match do_syscall(&mut cwd_buf) {
514            Ok(len) => unsafe {
515                cwd_buf.set_len(len);
516                return Ok(cwd_buf);
517            },
518            Err(err) => {
519                if err == ErrorStatus::Generic {
520                    extend(&mut cwd_buf);
521                } else {
522                    return Err(err);
523                }
524            }
525        }
526    }
527}
528
529#[derive(Debug, Clone, Copy)]
530#[repr(C)]
531pub struct SpawnFlags(u8);
532impl SpawnFlags {
533    pub const CLONE_RESOURCES: Self = Self(1 << 0);
534    pub const CLONE_CWD: Self = Self(1 << 1);
535}
536
537impl ops::BitOr for SpawnFlags {
538    type Output = Self;
539    fn bitor(self, rhs: Self) -> Self::Output {
540        Self(self.0 | rhs.0)
541    }
542}
543#[cfg_attr(
544    not(any(feature = "std", feature = "rustc-dep-of-std")),
545    unsafe(no_mangle)
546)]
547#[inline(always)]
548extern "C" fn syspspawn(
549    name_ptr: *const u8,
550    name_len: usize,
551    path_ptr: *const u8,
552    path_len: usize,
553    argv_ptr: *const RawSlice<u8>,
554    argv_len: usize,
555    flags: SpawnFlags,
556    dest_pid: &mut usize,
557) -> u16 {
558    /// the temporary config struct for the spawn syscall, passed to the syscall
559    /// because if it was passed as a bunch of arguments it would be too big to fit
560    /// inside the registers
561    #[repr(C)]
562    struct SpawnConfig {
563        name: RawSlice<u8>,
564        argv: RawSlice<RawSlice<u8>>,
565        flags: SpawnFlags,
566    }
567
568    let config = SpawnConfig {
569        name: unsafe { RawSlice::from_raw_parts(name_ptr, name_len) },
570        argv: unsafe { RawSlice::from_raw_parts(argv_ptr, argv_len) },
571        flags,
572    };
573    syscall4(
574        SyscallNum::SysPSpawn,
575        path_ptr as usize,
576        path_len,
577        (&raw const config) as usize,
578        dest_pid as *mut _ as usize,
579    )
580}
581
582/// spawns a new process
583/// # Safety
584/// `argv` must be a valid pointer to a slice of slices of `&str`
585/// `argv` will become invaild after use, using it is UB
586#[inline]
587pub unsafe fn unsafe_pspawn(
588    name: Option<&str>,
589    path: &str,
590    argv: *mut [&str],
591    flags: SpawnFlags,
592) -> Result<usize, ErrorStatus> {
593    let mut pid = 0;
594
595    let name = name.map(|s| s.as_bytes());
596    let name_ptr = name.map(|s| s.as_ptr()).unwrap_or(ptr::null());
597    let name_len = name.map(|s| s.len()).unwrap_or(0);
598
599    let argv: *mut [&[u8]] = argv as *mut [&[u8]];
600    let argv = unsafe { RawSliceMut::from_slices(argv) };
601    err_from_u16!(
602        syspspawn(
603            name_ptr,
604            name_len,
605            path.as_ptr(),
606            path.len(),
607            argv.as_ptr(),
608            argv.len(),
609            flags,
610            &mut pid,
611        ),
612        pid
613    )
614}
615
616/// same as [`pspawn`] but safe because it makes it clear that `argv` is consumed`
617#[inline]
618pub fn pspawn(
619    name: Option<&str>,
620    path: &str,
621    mut argv: Vec<&str>,
622    flags: SpawnFlags,
623) -> Result<usize, ErrorStatus> {
624    let argv: &mut [&str] = &mut argv;
625    unsafe { unsafe_pspawn(name, path, argv as *mut _, flags) }
626}
627#[cfg_attr(
628    not(any(feature = "std", feature = "rustc-dep-of-std")),
629    unsafe(no_mangle)
630)]
631#[inline(always)]
632extern "C" fn syswait(pid: usize, exit_code: &mut usize) -> u16 {
633    syscall2(SyscallNum::SysWait, pid, exit_code as *mut _ as usize)
634}
635
636#[inline]
637pub fn wait(pid: usize) -> Result<usize, ErrorStatus> {
638    let mut dest_exit_code = 0;
639    err_from_u16!(syswait(pid, &mut dest_exit_code), dest_exit_code)
640}