1//! Architecture-specific syscall code.
2//!
3//! `rustix` has inline assembly sequences using `asm!`, but that requires
4//! Rust 1.59, so it also has out-of-line ("outline") assembly sequences in .s
5//! files. And 32-bit x86 is special (see comments below).
6//!
7//! This module also has a `choose` submodule which chooses a scheme and is
8//! what most of the `rustix` syscalls use.
9//!
10//! # Safety
11//!
12//! This contains the inline `asm` statements performing the syscall
13//! instructions and FFI declarations declaring the out-of-line ("outline")
14//! syscall instructions.
15
16#![allow(unsafe_code)]
17#![cfg_attr(not(feature = "all-apis"), allow(unused_imports))]
18// We'll use as many arguments as syscalls need.
19#![allow(clippy::too_many_arguments)]
20
21// When inline asm is available, use it. Otherwise, use out-of-line asm. These
22// functions always use the machine's syscall instruction, even when it isn't
23// the fastest option available.
24#[cfg_attr(asm, path = "inline/mod.rs")]
25#[cfg_attr(not(asm), path = "outline/mod.rs")]
26pub(in crate::backend) mod asm;
27
28// On most architectures, the architecture syscall instruction is fast, so use
29// it directly.
30#[cfg(any(
31 target_arch = "arm",
32 target_arch = "aarch64",
33 target_arch = "mips",
34 target_arch = "mips64",
35 target_arch = "powerpc64",
36 target_arch = "riscv64",
37 target_arch = "x86_64",
38))]
39pub(in crate::backend) use self::asm as choose;
40
41// On 32-bit x86, use vDSO wrappers for all syscalls. We could use the
42// architecture syscall instruction (`int 0x80`), but the vDSO kernel_vsyscall
43// mechanism is much faster.
44#[cfg(target_arch = "x86")]
45pub(in crate::backend) use super::vdso_wrappers::x86_via_vdso as choose;
46
47// This would be the code for always using `int 0x80` on 32-bit x86.
48//#[cfg(target_arch = "x86")]
49//pub(in crate::backend) use self::asm as choose;
50
51// Macros for invoking system calls.
52//
53// These factor out:
54// - Calling `nr` on the syscall number to convert it into `SyscallNumber`.
55// - Calling `.into()` on each of the arguments to convert them into `ArgReg`.
56// - Qualifying the `syscall*` and `__NR_*` identifiers.
57// - Counting the number of arguments.
58macro_rules! syscall {
59 ($nr:ident) => {
60 $crate::backend::arch::choose::syscall0($crate::backend::reg::nr(
61 linux_raw_sys::general::$nr,
62 ))
63 };
64
65 ($nr:ident, $a0:expr) => {
66 $crate::backend::arch::choose::syscall1(
67 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
68 $a0.into(),
69 )
70 };
71
72 ($nr:ident, $a0:expr, $a1:expr) => {
73 $crate::backend::arch::choose::syscall2(
74 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
75 $a0.into(),
76 $a1.into(),
77 )
78 };
79
80 ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => {
81 $crate::backend::arch::choose::syscall3(
82 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
83 $a0.into(),
84 $a1.into(),
85 $a2.into(),
86 )
87 };
88
89 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {
90 $crate::backend::arch::choose::syscall4(
91 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
92 $a0.into(),
93 $a1.into(),
94 $a2.into(),
95 $a3.into(),
96 )
97 };
98
99 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
100 $crate::backend::arch::choose::syscall5(
101 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
102 $a0.into(),
103 $a1.into(),
104 $a2.into(),
105 $a3.into(),
106 $a4.into(),
107 )
108 };
109
110 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
111 $crate::backend::arch::choose::syscall6(
112 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
113 $a0.into(),
114 $a1.into(),
115 $a2.into(),
116 $a3.into(),
117 $a4.into(),
118 $a5.into(),
119 )
120 };
121
122 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
123 $crate::backend::arch::choose::syscall7(
124 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
125 $a0.into(),
126 $a1.into(),
127 $a2.into(),
128 $a3.into(),
129 $a4.into(),
130 $a5.into(),
131 $a6.into(),
132 )
133 };
134}
135
136/// Like `syscall`, but adds the `readonly` attribute to the inline asm, which
137/// indicates that the syscall does not mutate any memory.
138macro_rules! syscall_readonly {
139 ($nr:ident) => {
140 $crate::backend::arch::choose::syscall0_readonly($crate::backend::reg::nr(
141 linux_raw_sys::general::$nr,
142 ))
143 };
144
145 ($nr:ident, $a0:expr) => {
146 $crate::backend::arch::choose::syscall1_readonly(
147 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
148 $a0.into(),
149 )
150 };
151
152 ($nr:ident, $a0:expr, $a1:expr) => {
153 $crate::backend::arch::choose::syscall2_readonly(
154 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
155 $a0.into(),
156 $a1.into(),
157 )
158 };
159
160 ($nr:ident, $a0:expr, $a1:expr, $a2:expr) => {
161 $crate::backend::arch::choose::syscall3_readonly(
162 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
163 $a0.into(),
164 $a1.into(),
165 $a2.into(),
166 )
167 };
168
169 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {
170 $crate::backend::arch::choose::syscall4_readonly(
171 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
172 $a0.into(),
173 $a1.into(),
174 $a2.into(),
175 $a3.into(),
176 )
177 };
178
179 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
180 $crate::backend::arch::choose::syscall5_readonly(
181 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
182 $a0.into(),
183 $a1.into(),
184 $a2.into(),
185 $a3.into(),
186 $a4.into(),
187 )
188 };
189
190 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
191 $crate::backend::arch::choose::syscall6_readonly(
192 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
193 $a0.into(),
194 $a1.into(),
195 $a2.into(),
196 $a3.into(),
197 $a4.into(),
198 $a5.into(),
199 )
200 };
201
202 ($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
203 $crate::backend::arch::choose::syscall7_readonly(
204 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
205 $a0.into(),
206 $a1.into(),
207 $a2.into(),
208 $a3.into(),
209 $a4.into(),
210 $a5.into(),
211 $a6.into(),
212 )
213 };
214}
215
216/// Like `syscall`, but indicates that the syscall does not return.
217#[cfg(feature = "runtime")]
218macro_rules! syscall_noreturn {
219 ($nr:ident, $a0:expr) => {
220 $crate::backend::arch::choose::syscall1_noreturn(
221 $crate::backend::reg::nr(linux_raw_sys::general::$nr),
222 $a0.into(),
223 )
224 };
225}
226