x86/bits64/
syscall.rs

1//! Invokes an OS system-call handler at privilege level 0.
2//!
3//! It does so by loading RIP from the IA32_LSTAR MSR (after saving the address of the instruction
4//! following SYSCALL into RCX).
5//!
6//! The code follows "A.2 AMD64 Linux Kernel Conventions" of System V Application
7//! Binary Interface AMD64 Architecture Processor Supplement:
8//!
9//! * The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9.
10//! * A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11.
11//! * The number of the syscall has to be passed in register %rax.
12//! * System-calls are limited to six arguments, no argument is passed directly on the stack.
13//! * Returning from the syscall, register %rax contains the result of the system-call.
14//! * Only values of class INTEGER or class MEMORY are passed to the kernel.
15//!
16//! This code is inspired by the syscall.rs (https://github.com/kmcallister/syscall.rs/) project.
17
18#[cfg(target_arch = "x86_64")]
19use core::arch::asm;
20
21#[macro_export]
22macro_rules! syscall {
23    ($arg0:expr) => {
24        x86::bits64::syscall::syscall0($arg0 as u64)
25    };
26
27    ($arg0:expr, $arg1:expr) => {
28        x86::bits64::syscall::syscall1($arg0 as u64, $arg1 as u64)
29    };
30
31    ($arg0:expr, $arg1:expr, $arg2:expr) => {
32        x86::bits64::syscall::syscall2($arg0 as u64, $arg1 as u64, $arg2 as u64)
33    };
34
35    ($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr) => {
36        x86::bits64::syscall::syscall3($arg0 as u64, $arg1 as u64, $arg2 as u64, $arg3 as u64)
37    };
38
39    ($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr) => {
40        x86::bits64::syscall::syscall4(
41            $arg0 as u64,
42            $arg1 as u64,
43            $arg2 as u64,
44            $arg3 as u64,
45            $arg4 as u64,
46        )
47    };
48
49    ($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => {
50        x86::bits64::syscall::syscall5(
51            $arg0 as u64,
52            $arg1 as u64,
53            $arg2 as u64,
54            $arg3 as u64,
55            $arg4 as u64,
56            $arg5 as u64,
57        )
58    };
59
60    ($arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr) => {
61        x86::bits64::syscall::syscall6(
62            $arg0 as u64,
63            $arg1 as u64,
64            $arg2 as u64,
65            $arg3 as u64,
66            $arg4 as u64,
67            $arg5 as u64,
68            $arg6 as u64,
69        )
70    };
71
72    (
73        $arg0:expr,
74        $arg1:expr,
75        $arg2:expr,
76        $arg3:expr,
77        $arg4:expr,
78        $arg5:expr,
79        $arg6:expr,
80        $arg7:expr
81    ) => {
82        x86::bits64::syscall::syscall7(
83            $arg0 as u64,
84            $arg1 as u64,
85            $arg2 as u64,
86            $arg3 as u64,
87            $arg4 as u64,
88            $arg5 as u64,
89            $arg6 as u64,
90            $arg7 as u64,
91        )
92    };
93}
94
95/// Invoke a syscall.
96///
97/// # Safety
98/// Throws `#UD` if IA32_EFER.SCE = 0.
99#[cfg(target_arch = "x86_64")]
100#[inline(always)]
101#[allow(unused_mut)]
102pub unsafe fn syscall0(arg0: u64) -> u64 {
103    let mut ret: u64;
104    asm!("syscall", lateout("rax") ret, in("rax") arg0, options(att_syntax));
105    ret
106}
107
108/// Invoke a syscall.
109///
110/// # Safety
111/// Throws `#UD` if IA32_EFER.SCE = 0.
112#[cfg(target_arch = "x86_64")]
113#[inline(always)]
114#[allow(unused_mut)]
115pub unsafe fn syscall1(arg0: u64, arg1: u64) -> u64 {
116    let mut ret: u64;
117    asm!(
118        "syscall",
119        lateout("rax") ret, in("rax") arg0, in("rdi") arg1,
120        out("rcx") _, out("r11") _, options(att_syntax),
121    );
122    ret
123}
124
125/// Invoke a syscall.
126///
127/// # Safety
128/// Throws `#UD` if IA32_EFER.SCE = 0.
129#[cfg(target_arch = "x86_64")]
130#[inline(always)]
131#[allow(unused_mut)]
132pub unsafe fn syscall2(arg0: u64, arg1: u64, arg2: u64) -> u64 {
133    let mut ret: u64;
134    asm!(
135        "syscall",
136        lateout("rax") ret,
137        in("rax") arg0, in("rdi") arg1, in("rsi") arg2,
138        out("rcx") _, out("r11") _, options(att_syntax),
139    );
140    ret
141}
142
143/// Invoke a syscall.
144///
145/// # Safety
146/// Throws `#UD` if IA32_EFER.SCE = 0.
147#[cfg(target_arch = "x86_64")]
148#[inline(always)]
149#[allow(unused_mut)]
150pub unsafe fn syscall3(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> u64 {
151    let mut ret: u64;
152    asm!(
153        "syscall",
154        lateout("rax") ret,
155        in("rax") arg0, in("rdi") arg1, in("rsi") arg2, in("rdx") arg3,
156        out("rcx") _, out("r11") _, options(att_syntax),
157    );
158    ret
159}
160
161/// Invoke a syscall.
162///
163/// # Safety
164/// Throws `#UD` if IA32_EFER.SCE = 0.
165#[cfg(target_arch = "x86_64")]
166#[inline(always)]
167#[allow(unused_mut)]
168pub unsafe fn syscall4(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> u64 {
169    let mut ret: u64;
170    asm!(
171        "syscall",
172        lateout("rax") ret,
173        in("rax") arg0, in("rdi") arg1, in("rsi") arg2, in("rdx") arg3, in("r10") arg4,
174        out("rcx") _, out("r11") _, options(att_syntax),
175    );
176    ret
177}
178
179/// Invoke a syscall.
180///
181/// # Safety
182/// Throws `#UD` if IA32_EFER.SCE = 0.
183#[cfg(target_arch = "x86_64")]
184#[inline(always)]
185#[allow(unused_mut)]
186pub unsafe fn syscall5(arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
187    let mut ret: u64;
188    asm!(
189        "syscall",
190        lateout("rax") ret,
191        in("rax") arg0, in("rdi") arg1, in("rsi") arg2, in("rdx") arg3, in("r10") arg4, in("r8") arg5,
192        out("rcx") _, out("r11") _, options(att_syntax),
193    );
194    ret
195}
196
197/// Invoke a syscall.
198///
199/// # Safety
200/// Throws `#UD` if IA32_EFER.SCE = 0.
201#[cfg(target_arch = "x86_64")]
202#[inline(always)]
203#[allow(unused_mut)]
204pub unsafe fn syscall6(
205    arg0: u64,
206    arg1: u64,
207    arg2: u64,
208    arg3: u64,
209    arg4: u64,
210    arg5: u64,
211    arg6: u64,
212) -> u64 {
213    let mut ret: u64;
214    asm!(
215        "syscall",
216        lateout("rax") ret,
217        in("rax") arg0, in("rdi") arg1, in("rsi") arg2, in("rdx") arg3,
218        in("r10") arg4, in("r8") arg5, in("r9") arg6,
219        out("rcx") _, out("r11") _, options(att_syntax),
220    );
221    ret
222}