safa_api/syscalls/
call.rs

1use crate::syscalls::types::SyscallResult;
2
3use core::arch::asm;
4
5/// Invokes a syscall with the given number and arguments
6/// Number must be of type [`SyscallNum`]
7/// Arguments must be of type [`usize`]
8/// returns a [`SyscallResult`]
9#[macro_export]
10macro_rules! syscall {
11    ($num: expr, $($arg: expr),*) => {{
12        #[allow(unused_imports)]
13        use $crate::syscalls::call::JoinTuples;
14        use $crate::syscalls::call::SyscallCaller;
15        #[allow(unused_imports)]
16        use $crate::syscalls::types::IntoSyscallArg;
17
18        let args = ();
19        $(
20            let args = args.join_tuple($arg.into_syscall_arg());
21        )*
22        SyscallCaller::<{ $num as u16 }, _>::new(args).call()
23    }};
24}
25
26pub use syscall;
27
28pub struct SyscallCaller<const NUM: u16, T> {
29    args: T,
30}
31
32impl<const NUM: u16, T> SyscallCaller<NUM, T> {
33    pub const fn new(args: T) -> Self {
34        Self { args }
35    }
36}
37
38impl<const NUM: u16> SyscallCaller<NUM, ()> {
39    #[inline(always)]
40    pub fn call(self) -> SyscallResult {
41        syscall0::<NUM>()
42    }
43}
44
45impl<const NUM: u16> SyscallCaller<NUM, (usize,)> {
46    #[inline(always)]
47    pub fn call(self) -> SyscallResult {
48        syscall1::<NUM>(self.args.0)
49    }
50}
51
52impl<const NUM: u16> SyscallCaller<NUM, (usize, usize)> {
53    #[inline(always)]
54    pub fn call(self) -> SyscallResult {
55        syscall2::<NUM>(self.args.0, self.args.1)
56    }
57}
58
59impl<const NUM: u16> SyscallCaller<NUM, (usize, usize, usize)> {
60    #[inline(always)]
61    pub fn call(self) -> SyscallResult {
62        syscall3::<NUM>(self.args.0, self.args.1, self.args.2)
63    }
64}
65
66impl<const NUM: u16> SyscallCaller<NUM, (usize, usize, usize, usize)> {
67    #[inline(always)]
68    pub fn call(self) -> SyscallResult {
69        syscall4::<NUM>(self.args.0, self.args.1, self.args.2, self.args.3)
70    }
71}
72
73impl<const NUM: u16> SyscallCaller<NUM, (usize, usize, usize, usize, usize)> {
74    #[inline(always)]
75    pub fn call(self) -> SyscallResult {
76        syscall5::<NUM>(
77            self.args.0,
78            self.args.1,
79            self.args.2,
80            self.args.3,
81            self.args.4,
82        )
83    }
84}
85
86#[doc(hidden)]
87#[inline(always)]
88pub fn syscall0<const NUM: u16>() -> SyscallResult {
89    let result: u16;
90    unsafe {
91        #[cfg(target_arch = "x86_64")]
92        asm!(
93            "int 0x80",
94            in("rax") NUM as usize,
95            lateout("rax") result,
96        );
97        #[cfg(target_arch = "aarch64")]
98        asm!(
99            "svc #{num}",
100            num = const NUM,
101            lateout("x0") result
102        );
103        core::mem::transmute(result)
104    }
105}
106
107#[doc(hidden)]
108#[inline(always)]
109pub fn syscall1<const NUM: u16>(arg1: usize) -> SyscallResult {
110    let result: u16;
111    unsafe {
112        #[cfg(target_arch = "x86_64")]
113        asm!(
114            "int 0x80",
115            in("rax") NUM as usize,
116            in("rdi") arg1,
117            lateout("rax") result,
118        );
119        #[cfg(target_arch = "aarch64")]
120        asm!(
121            "svc #{num}",
122            num = const NUM,
123            in("x0") arg1,
124            lateout("x0") result
125        );
126        core::mem::transmute(result)
127    }
128}
129
130#[doc(hidden)]
131#[inline(always)]
132pub fn syscall2<const NUM: u16>(arg1: usize, arg2: usize) -> SyscallResult {
133    let result: u16;
134    unsafe {
135        #[cfg(target_arch = "x86_64")]
136        asm!(
137            "int 0x80",
138            in("rax") NUM as usize,
139            in("rdi") arg1,
140            in("rsi") arg2,
141            lateout("rax") result,
142        );
143        #[cfg(target_arch = "aarch64")]
144        asm!(
145            "svc #{num}",
146            num = const NUM,
147            in("x0") arg1,
148            in("x1") arg2,
149            lateout("x0") result
150        );
151        core::mem::transmute(result)
152    }
153}
154
155#[doc(hidden)]
156#[inline(always)]
157pub fn syscall3<const NUM: u16>(arg1: usize, arg2: usize, arg3: usize) -> SyscallResult {
158    let result: u16;
159    unsafe {
160        #[cfg(target_arch = "x86_64")]
161        asm!(
162            "int 0x80",
163            in("rax") NUM as usize,
164            in("rdi") arg1,
165            in("rsi") arg2,
166            in("rdx") arg3,
167            lateout("rax") result,
168        );
169        #[cfg(target_arch = "aarch64")]
170        asm!(
171            "svc #{num}",
172            num = const NUM,
173            in("x0") arg1,
174            in("x1") arg2,
175            in("x2") arg3,
176            lateout("x0") result
177        );
178        core::mem::transmute(result)
179    }
180}
181
182#[doc(hidden)]
183#[inline(always)]
184pub fn syscall4<const NUM: u16>(
185    arg1: usize,
186    arg2: usize,
187    arg3: usize,
188    arg4: usize,
189) -> SyscallResult {
190    let result: u16;
191    unsafe {
192        #[cfg(target_arch = "x86_64")]
193        asm!(
194            "int 0x80",
195            in("rax") NUM as usize,
196            in("rdi") arg1,
197            in("rsi") arg2,
198            in("rdx") arg3,
199            in("rcx") arg4,
200            lateout("rax") result,
201        );
202
203        #[cfg(target_arch = "aarch64")]
204        asm!(
205            "svc #{num}",
206            num = const NUM,
207            in("x0") arg1,
208            in("x1") arg2,
209            in("x2") arg3,
210            in("x3") arg4,
211            lateout("x0") result
212        );
213        core::mem::transmute(result)
214    }
215}
216
217#[doc(hidden)]
218#[inline(always)]
219pub fn syscall5<const NUM: u16>(
220    arg1: usize,
221    arg2: usize,
222    arg3: usize,
223    arg4: usize,
224    arg5: usize,
225) -> SyscallResult {
226    let result: u16;
227    unsafe {
228        #[cfg(target_arch = "x86_64")]
229        asm!(
230            "int 0x80",
231            in("rax") NUM as usize,
232            in("rdi") arg1,
233            in("rsi") arg2,
234            in("rdx") arg3,
235            in("rcx") arg4,
236            in("r8") arg5,
237            lateout("rax") result,
238        );
239        #[cfg(target_arch = "aarch64")]
240        asm!(
241            "svc #{num}",
242            num = const NUM,
243            in("x0") arg1,
244            in("x1") arg2,
245            in("x2") arg3,
246            in("x3") arg4,
247            in("x4") arg5,
248            lateout("x0") result
249        );
250        core::mem::transmute(result)
251    }
252}
253
254pub trait JoinTuples<JoinWith> {
255    type Output;
256    fn join_tuple(self, other: JoinWith) -> Self::Output;
257}
258
259macro_rules! impl_join_single {
260    ($($T:ident)*,$($O:ident)*) => {
261        impl<$($T,)* $($O,)*> JoinTuples<($($O,)*)> for ($($T,)*) {
262            type Output = ($($T,)* $($O,)*);
263            fn join_tuple(self, other: ($($O,)*) ) -> Self::Output {
264                #[allow(non_snake_case)]
265                let ($($T,)*) = self;
266                #[allow(non_snake_case)]
267                let ($($O,)*) = other;
268                ($($T,)* $($O,)*)
269            }
270        }
271    };
272}
273macro_rules! impl_join {
274    ($($T:ident)*,$($O:ident)*) => {
275        impl_join_single!($($T)*,$($O)*);
276        impl_join_single!($($O)*,$($T)*);
277    };
278}
279
280macro_rules! impl_join_nothing {
281    ($($T:ident)*) => {
282
283        impl<$($T,)*> JoinTuples<()> for ($($T,)*) {
284            type Output = ($($T,)*);
285            fn join_tuple(self, _other: ()) -> Self::Output {
286                self
287            }
288        }
289
290        impl<$($T,)*> JoinTuples<($($T,)*)> for () {
291            type Output = ($($T,)*);
292            fn join_tuple(self, other: ($($T,)*)) -> Self::Output {
293                _ = self;
294                other
295            }
296        }
297    };
298}
299
300// we only need to join up to 5 elements
301impl_join_nothing!(A);
302impl_join_single!(A, B);
303impl_join_nothing!(A B);
304impl_join_single!(A B, C D);
305// joining A, B, C
306impl_join!(A B, C);
307impl_join_nothing!(A B C);
308// ok we got A, B, C, joining A, B, C, D
309impl_join!(A B C, D);
310impl_join_nothing!(A B C D);
311// we got A, B, C, D, joining A, B, C, D, E == 5
312impl_join!(A B C D, E);
313impl_join_nothing!(A B C D E);
314// now joining A, B with C, D, E to get A, B, C, D, E == 5
315impl_join!(A B C, D E);