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}