1#![deny(clippy::all, clippy::pedantic)]
2#![allow(
3 clippy::cast_possible_truncation,
4 clippy::cast_possible_wrap,
5 clippy::cast_sign_loss,
6 clippy::inline_always,
7 clippy::missing_errors_doc,
8 clippy::module_name_repetitions,
9 clippy::must_use_candidate,
10 clippy::needless_pass_by_value,
11 clippy::ptr_as_ptr,
12 clippy::unsafe_derive_deserialize
13)]
14#![cfg_attr(not(feature = "std"), no_std)]
15#![cfg_attr(
16 any(
19 target_arch = "mips",
20 target_arch = "mips64",
21 target_arch = "s390x",
22 target_arch = "powerpc",
23 target_arch = "powerpc64",
24 ),
25 feature(asm_experimental_arch)
26)]
27
28#[macro_use]
29mod macros;
30
31mod arch;
32mod args;
33mod errno;
34mod map;
35mod set;
36mod syscall;
37
38pub use arch::*;
39pub use args::SyscallArgs;
40pub use errno::{Errno, ErrnoSentinel};
41pub use map::*;
42pub use set::*;
43pub use syscall::SyscallWord;
44
45pub mod raw {
46 pub use super::syscall::syscall0;
49 pub use super::syscall::syscall1;
50 pub use super::syscall::syscall2;
51 pub use super::syscall::syscall3;
52 pub use super::syscall::syscall4;
53 pub use super::syscall::syscall5;
54 pub use super::syscall::syscall6;
55}
56
57#[inline]
83pub unsafe fn syscall0(nr: Sysno) -> Result<SyscallWord, Errno> {
84 let ret = unsafe { raw::syscall0(nr as SyscallWord) };
85
86 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
88 return Errno::from_ret_u64(ret as u64);
89
90 #[cfg(all(
91 not(all(target_arch = "x86_64", target_pointer_width = "32")),
92 target_pointer_width = "64"
93 ))]
94 return Errno::from_ret_u64(ret as u64);
95
96 #[cfg(all(
97 not(all(target_arch = "x86_64", target_pointer_width = "32")),
98 target_pointer_width = "32"
99 ))]
100 return Errno::from_ret_u32(ret as u32);
101}
102
103#[inline]
110pub unsafe fn syscall1(
111 nr: Sysno,
112 a1: SyscallWord,
113) -> Result<SyscallWord, Errno> {
114 let ret = unsafe { raw::syscall1(nr as SyscallWord, a1) };
115
116 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
118 return Errno::from_ret_u64(ret as u64);
119
120 #[cfg(all(
121 not(all(target_arch = "x86_64", target_pointer_width = "32")),
122 target_pointer_width = "64"
123 ))]
124 return Errno::from_ret_u64(ret as u64);
125
126 #[cfg(all(
127 not(all(target_arch = "x86_64", target_pointer_width = "32")),
128 target_pointer_width = "32"
129 ))]
130 return Errno::from_ret_u32(ret as u32);
131}
132
133#[inline]
140pub unsafe fn syscall2(
141 nr: Sysno,
142 a1: SyscallWord,
143 a2: SyscallWord,
144) -> Result<SyscallWord, Errno> {
145 let ret = unsafe { raw::syscall2(nr as SyscallWord, a1, a2) };
146
147 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
149 return Errno::from_ret_u64(ret as u64);
150
151 #[cfg(all(
152 not(all(target_arch = "x86_64", target_pointer_width = "32")),
153 target_pointer_width = "64"
154 ))]
155 return Errno::from_ret_u64(ret as u64);
156
157 #[cfg(all(
158 not(all(target_arch = "x86_64", target_pointer_width = "32")),
159 target_pointer_width = "32"
160 ))]
161 return Errno::from_ret_u32(ret as u32);
162}
163
164#[inline]
171pub unsafe fn syscall3(
172 nr: Sysno,
173 a1: SyscallWord,
174 a2: SyscallWord,
175 a3: SyscallWord,
176) -> Result<SyscallWord, Errno> {
177 let ret = unsafe { raw::syscall3(nr as SyscallWord, a1, a2, a3) };
178
179 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
181 return Errno::from_ret_u64(ret as u64);
182
183 #[cfg(all(
184 not(all(target_arch = "x86_64", target_pointer_width = "32")),
185 target_pointer_width = "64"
186 ))]
187 return Errno::from_ret_u64(ret as u64);
188
189 #[cfg(all(
190 not(all(target_arch = "x86_64", target_pointer_width = "32")),
191 target_pointer_width = "32"
192 ))]
193 return Errno::from_ret_u32(ret as u32);
194}
195
196#[inline]
203pub unsafe fn syscall4(
204 nr: Sysno,
205 a1: SyscallWord,
206 a2: SyscallWord,
207 a3: SyscallWord,
208 a4: SyscallWord,
209) -> Result<SyscallWord, Errno> {
210 let ret = unsafe { raw::syscall4(nr as SyscallWord, a1, a2, a3, a4) };
211
212 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
214 return Errno::from_ret_u64(ret as u64);
215
216 #[cfg(all(
217 not(all(target_arch = "x86_64", target_pointer_width = "32")),
218 target_pointer_width = "64"
219 ))]
220 return Errno::from_ret_u64(ret as u64);
221
222 #[cfg(all(
223 not(all(target_arch = "x86_64", target_pointer_width = "32")),
224 target_pointer_width = "32"
225 ))]
226 return Errno::from_ret_u32(ret as u32);
227}
228
229#[inline]
236pub unsafe fn syscall5(
237 nr: Sysno,
238 a1: SyscallWord,
239 a2: SyscallWord,
240 a3: SyscallWord,
241 a4: SyscallWord,
242 a5: SyscallWord,
243) -> Result<SyscallWord, Errno> {
244 let ret = unsafe { raw::syscall5(nr as SyscallWord, a1, a2, a3, a4, a5) };
245
246 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
248 return Errno::from_ret_u64(ret as u64);
249
250 #[cfg(all(
251 not(all(target_arch = "x86_64", target_pointer_width = "32")),
252 target_pointer_width = "64"
253 ))]
254 return Errno::from_ret_u64(ret as u64);
255
256 #[cfg(all(
257 not(all(target_arch = "x86_64", target_pointer_width = "32")),
258 target_pointer_width = "32"
259 ))]
260 return Errno::from_ret_u32(ret as u32);
261}
262
263#[inline]
270pub unsafe fn syscall6(
271 nr: Sysno,
272 a1: SyscallWord,
273 a2: SyscallWord,
274 a3: SyscallWord,
275 a4: SyscallWord,
276 a5: SyscallWord,
277 a6: SyscallWord,
278) -> Result<SyscallWord, Errno> {
279 let ret =
280 unsafe { raw::syscall6(nr as SyscallWord, a1, a2, a3, a4, a5, a6) };
281
282 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
284 return Errno::from_ret_u64(ret as u64);
285
286 #[cfg(all(
287 not(all(target_arch = "x86_64", target_pointer_width = "32")),
288 target_pointer_width = "64"
289 ))]
290 return Errno::from_ret_u64(ret as u64);
291
292 #[cfg(all(
293 not(all(target_arch = "x86_64", target_pointer_width = "32")),
294 target_pointer_width = "32"
295 ))]
296 return Errno::from_ret_u32(ret as u32);
297}
298
299pub unsafe fn syscall(
314 nr: Sysno,
315 args: &SyscallArgs,
316) -> Result<SyscallWord, Errno> {
317 unsafe {
318 syscall6(
319 nr, args.arg0, args.arg1, args.arg2, args.arg3, args.arg4,
320 args.arg5,
321 )
322 }
323}
324#[cfg(test)]
326mod tests {
327 use super::*;
328
329 #[test]
330 fn test_syscall1_syscall4() {
331 let fd = unsafe {
332 let at_fdcwd = -100isize;
333 syscall!(Sysno::openat, at_fdcwd, "/dev/zero\0".as_ptr(), 0)
334 }
335 .unwrap();
336
337 let mut buffer1: [u8; 64] = unsafe { core::mem::zeroed() };
338 let mut buffer2: [u8; 64] = unsafe { core::mem::zeroed() };
339
340 let r1 =
341 unsafe { libc::read(fd as i32, buffer1.as_mut_ptr() as _, 64) };
342
343 let s1 = unsafe {
344 core::slice::from_raw_parts(
345 buffer1.as_mut_ptr() as *const u8,
346 r1 as usize,
347 )
348 };
349 let r2 = unsafe { syscall!(Sysno::read, fd, buffer2.as_mut_ptr(), 64) };
350 let s2 = unsafe {
351 core::slice::from_raw_parts(
352 buffer1.as_mut_ptr() as *const u8,
353 r2.unwrap_or(0) as usize,
354 )
355 };
356
357 assert_eq!(r2, Ok(r1 as SyscallWord));
358 assert_eq!(s1, s2);
359
360 let closed = unsafe { syscall!(Sysno::close, fd) };
361 assert!(closed.is_ok());
362 }
363
364 #[test]
365 fn test_syscall1_syscall4_2() {
366 let fd = unsafe {
367 let at_fdcwd = -100isize;
368 syscall!(Sysno::openat, at_fdcwd, "/dev/zero\0".as_ptr(), 0)
369 }
370 .unwrap();
371
372 let mut buffer1: [u8; 64] = unsafe { core::mem::zeroed() };
373 let mut buffer2: [u8; 64] = unsafe { core::mem::zeroed() };
374
375 let args = SyscallArgs::from(&[
376 fd as SyscallWord,
377 buffer1.as_mut_ptr() as _,
378 64,
379 ]);
380 let r1 = unsafe { syscall(Sysno::read, &args) }.expect("read failed");
381
382 let s1 = unsafe {
383 core::slice::from_raw_parts(
384 buffer1.as_mut_ptr() as *const u8,
385 r1 as usize,
386 )
387 };
388 let r2 = unsafe { syscall!(Sysno::read, fd, buffer2.as_mut_ptr(), 64) };
389 let s2 = unsafe {
390 core::slice::from_raw_parts(
391 buffer1.as_mut_ptr() as *const u8,
392 r2.unwrap_or(0) as usize,
393 )
394 };
395
396 assert_eq!(r2, Ok(r1));
397 assert_eq!(s1, s2);
398
399 let closed = unsafe { syscall!(Sysno::close, fd) };
400 assert!(closed.is_ok());
401 }
402
403 #[test]
404 fn test_name() {
405 assert_eq!(Sysno::write.name(), "write");
406 assert_eq!(Sysno::fsopen.name(), "fsopen");
407 }
408
409 #[cfg(target_arch = "x86_64")]
410 #[test]
411 fn test_syscallno() {
412 assert_eq!(Sysno::from(2), Sysno::open);
413 assert_eq!(Sysno::new(2), Some(Sysno::open));
414 assert_eq!(Sysno::new(-1i32 as usize), None);
415 assert_eq!(Sysno::new(1024), None);
416 }
417
418 #[test]
419 fn test_first() {
420 #[cfg(target_arch = "x86_64")]
421 assert_eq!(Sysno::first(), Sysno::read);
422
423 #[cfg(target_arch = "x86")]
424 assert_eq!(Sysno::first(), Sysno::restart_syscall);
425 }
426
427 #[test]
428 fn test_syscall_len() {
429 assert!(Sysno::table_size() > 300);
430 assert!(Sysno::table_size() < 1000);
431 }
432}