azathoth_core/os/linux/
syscalls.rs

1/// Performs a raw system call with 1 argument.
2///
3/// This function directly invokes the Linux `syscall` instruction with the
4/// specified system call number (`n`) and one argument (`a1`). It returns the
5/// result of the syscall as an `isize`, which may be a negative error code
6/// (following Linux conventions).
7///
8/// # Safety
9///
10/// - The caller must ensure that the provided syscall number and arguments
11///   are valid for the target platform.
12/// - Passing invalid pointers or arguments may cause undefined behavior,
13///   including crashes or data corruption.
14/// - This function does not perform any error translation. Negative return
15///   values correspond to `-errno`.
16///
17/// # Examples
18/// ```
19/// use azathoth_utils::platform::linux::syscalls::syscall1;
20///
21/// // Example: `getpid` (syscall number 39 on x86_64 Linux)
22/// let pid = unsafe { syscall1(39, 0) };
23/// assert!(pid > 0);
24/// ```
25#[inline(always)]
26#[unsafe(link_section = ".text")]
27pub fn syscall1(n: usize, a1: usize) -> isize {
28    let ret: isize;
29    unsafe {
30        core::arch::asm!(
31        "syscall",
32        inout("rax") n => ret,
33        in("rdi") a1
34        )
35    }
36    ret
37}
38
39/// Performs a raw system call with 2 arguments.
40///
41/// Similar to [`syscall1`], but accepts
42/// two arguments (`a1`, `a2`). Returns the raw result of the syscall.
43///
44/// # Safety
45/// Same as `syscall1`.
46///
47/// # Examples
48/// ```
49/// use azathoth_utils::platform::linux::{syscalls::syscall2, consts::SYS_OPEN};
50///
51/// let fd = unsafe { syscall2(SYS_OPEN, b"/etc/passwd\0".as_ptr() as usize, 0) };
52/// assert!(fd >= 0);
53/// ```
54#[inline(always)]
55#[unsafe(link_section = ".text")]
56pub fn syscall2(n: usize, a1: usize, a2: usize) -> isize {
57    let ret: isize;
58    unsafe {
59        core::arch::asm!(
60        "syscall",
61        inout("rax") n => ret,
62        in("rdi") a1,
63        in("rsi") a2,
64        lateout("rcx") _,
65        lateout("r11") _,
66        options(nostack, preserves_flags),
67        )
68    }
69    ret
70}
71
72/// Performs a raw system call with 3 arguments.
73///
74/// This is commonly used for syscalls such as `read` or `write`.
75///
76/// # Safety
77/// Same as `syscall1`.
78///
79/// # Examples
80/// ```
81/// use azathoth_utils::platform::linux::syscalls::syscall3;
82///
83/// let buf = [0u8; 64];
84/// let n = unsafe { syscall3(0, 0, buf.as_ptr() as usize, buf.len()) }; // read(stdin)
85/// assert!(n >= 0);
86/// ```
87#[inline(always)]
88#[unsafe(link_section = ".text")]
89pub fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) -> isize {
90    let ret: isize;
91    unsafe {
92        core::arch::asm!(
93        "syscall",
94        inout("rax") n => ret,
95        in("rdi") a1,
96        in("rsi") a2,
97        in("rdx") a3,
98        );
99    }
100    ret
101}
102
103/// Performs a raw system call with 4 arguments.
104///
105/// # Safety
106/// Same as `syscall1`.
107///
108/// # Examples
109/// ```
110/// use azathoth_utils::platform::linux::syscalls::syscall4;
111///
112/// let fd = unsafe { syscall4(17, 1, 0, 0, 0) }; // Example syscall
113/// ```
114#[allow(unused)]
115#[inline(always)]
116#[unsafe(link_section = ".text")]
117pub fn syscall4(n: usize, a1: usize, a2: usize, a3: usize, a4: usize) -> isize {
118    let ret: isize;
119    unsafe {
120        core::arch::asm!(
121        "syscall",
122        inout("rax") n => ret,
123        in("rdi") a1,
124        in("rsi") a2,
125        in("rdx") a3,
126        in("r10") a4,
127        )
128    }
129    ret
130}
131
132/// Performs a raw system call with 5 arguments.
133///
134/// # Safety
135/// Same as `syscall1`.
136///
137/// # Examples
138/// ```
139/// use azathoth_utils::platform::linux::syscalls::syscall5;
140///
141/// let fd = unsafe { syscall5(5, 0, 0, 0, 0, 0) };
142/// ```
143#[inline(always)]
144#[unsafe(link_section = ".text")]
145pub fn syscall5(n: usize, a1: usize, a2: usize, a3: usize, a4: usize, a5: usize) -> isize {
146    let ret: isize;
147    unsafe {
148        core::arch::asm!(
149        "syscall",
150        inout("rax") n => ret,
151        in("rdi") a1,
152        in("rsi") a2,
153        in("rdx") a3,
154        in("r10") a4,
155        in("r8") a5,
156        )
157    }
158    ret
159}
160
161
162/// Performs a raw system call with 6 arguments.
163///
164/// This is used for syscalls that require up to six parameters, such as `mmap`.
165///
166/// # Safety
167/// Same as `syscall1`.
168///
169/// # Examples
170/// ```
171/// use azathoth_utils::platform::linux::{syscalls::syscall6, consts::SYS_MMAP};
172///
173/// let ptr = unsafe { syscall6(SYS_MMAP, 0, 4096, 3, 0x22, -1isize as usize, 0) };
174/// assert!(ptr >= 0);
175/// ```
176#[inline(always)]
177#[unsafe(link_section = ".text")]
178pub fn syscall6(
179    n: usize,
180    a1: usize,
181    a2: usize,
182    a3: usize,
183    a4: usize,
184    a5: usize,
185    a6: usize,
186) -> isize {
187    let ret: isize;
188    unsafe {
189        core::arch::asm!(
190        "syscall",
191        inlateout("rax") n => ret,
192        in("rdi") a1,
193        in("rsi") a2,
194        in("rdx") a3,
195        in("r10") a4,
196        in("r8") a5,
197        in("r9") a6,
198        lateout("rcx") _, lateout("r11") _,
199        );
200    }
201    ret
202}