linux_syscalls/inline/
x86.rs

1use crate::Sysno;
2
3use core::arch::asm;
4
5#[inline(always)]
6unsafe fn callee() -> usize {
7    (*crate::env::vdso::VDSO.get()).0.vsyscall as usize
8}
9
10#[inline(always)]
11unsafe fn vsyscall0(sysno: Sysno) -> usize {
12    let ret;
13    asm!(
14        "call {callee}",
15        callee = in(reg) callee(),
16        inlateout("rax") sysno as usize => ret,
17        options(preserves_flags)
18    );
19    ret
20}
21
22#[inline(always)]
23unsafe fn vsyscall1(sysno: Sysno, arg0: usize) -> usize {
24    let ret: usize;
25    asm!(
26        "call {callee}",
27        callee = in(reg) callee(),
28        inlateout("eax") sysno as usize => ret,
29        in("ebx") arg0,
30        options(preserves_flags)
31    );
32    ret
33}
34
35#[inline(always)]
36unsafe fn vsyscall1_noreturn(sysno: Sysno, arg0: usize) -> ! {
37    asm!(
38        "call {callee}",
39        "ud2",
40        callee = in(reg) callee(),
41        in("eax") sysno as usize,
42        in("ebx") arg0,
43        options(noreturn)
44    )
45}
46
47#[inline(always)]
48unsafe fn vsyscall2(sysno: Sysno, arg0: usize, arg1: usize) -> usize {
49    let ret: usize;
50    asm!(
51        "call {callee}",
52        callee = in(reg) callee(),
53        inlateout("eax") sysno as usize => ret,
54        in("ebx") arg0,
55        in("ecx") arg1,
56        options(preserves_flags)
57    );
58    ret
59}
60
61#[inline(always)]
62unsafe fn vsyscall3(sysno: Sysno, arg0: usize, arg1: usize, arg2: usize) -> usize {
63    let ret: usize;
64    asm!(
65        "call {callee}",
66        callee = in(reg) callee(),
67        inlateout("eax") sysno as usize => ret,
68        in("ebx") arg0,
69        in("ecx") arg1,
70        in("edx") arg2,
71        options(preserves_flags)
72    );
73    ret
74}
75
76#[inline(always)]
77unsafe fn vsyscall4(sysno: Sysno, arg0: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
78    let ret: usize;
79    asm!(
80        "xchg esi, {arg3}",
81        "call edi",
82        "xchg esi, {arg3}",
83        arg3 = in(reg) arg3,
84        in("edi") callee(),
85        inlateout("eax") sysno as usize => ret,
86        in("ebx") arg0,
87        in("ecx") arg1,
88        in("edx") arg2,
89        options(preserves_flags)
90    );
91    ret
92}
93
94#[inline(always)]
95unsafe fn vsyscall5(
96    sysno: Sysno,
97    arg0: usize,
98    arg1: usize,
99    arg2: usize,
100    arg3: usize,
101    arg4: usize,
102) -> usize {
103    // NOTE: We don't have enough registers to handle this and we can't
104    // use stack so we pass a slice as a secondary stack.
105    let ret: usize;
106    asm!(
107        // save register
108        "push esi",
109
110        // push syscall parameter
111        "push DWORD PTR [eax]",
112        "mov esi, DWORD PTR [eax+4]",
113        "mov eax, DWORD PTR [eax+8]",
114        "call DWORD PTR [esp]",
115
116        // delete pushed parameter
117        "pop esi",
118
119        // restore register
120        "pop esi",
121        inout("eax") &[callee(), arg3, sysno as usize] => ret,
122        in("ebx") arg0,
123        in("ecx") arg1,
124        in("edx") arg2,
125        in("edi") arg4,
126        options(preserves_flags)
127    );
128    ret
129}
130
131#[inline(always)]
132unsafe fn vsyscall6(
133    sysno: Sysno,
134    arg0: usize,
135    arg1: usize,
136    arg2: usize,
137    arg3: usize,
138    arg4: usize,
139    arg5: usize,
140) -> usize {
141    // NOTE: Same as syscall5 but we have to fight for ebp too.
142
143    let ret: usize;
144    asm!(
145        // save registers
146        "push ebp",
147        "push esi",
148
149        // push syscall parameter
150        "push DWORD PTR [eax]",
151        "mov esi, DWORD PTR [eax+4]",
152        "mov ebp, DWORD PTR [eax+8]",
153        "mov eax, DWORD PTR [eax+12]",
154        "call DWORD PTR [esp]",
155
156        // delete pushed parameter
157        "pop esi",
158
159        // restore registers
160        "pop esi",
161        "pop ebp",
162        inout("eax") &[callee(), arg3, arg5, sysno as usize] => ret,
163        in("ebx") arg0,
164        in("ecx") arg1,
165        in("edx") arg2,
166        in("edi") arg4,
167        options(preserves_flags)
168    );
169    ret
170}
171
172#[allow(clippy::missing_safety_doc)]
173#[inline(always)]
174pub unsafe fn raw_syscall0(sysno: Sysno) -> usize {
175    if callee() == 0 {
176        let ret;
177        asm!(
178            "int $$0x80",
179            inlateout("eax") sysno as usize => ret,
180            options(nostack, preserves_flags, readonly)
181        );
182        ret
183    } else {
184        vsyscall0(sysno)
185    }
186}
187
188pub use raw_syscall0 as raw_syscall0_readonly;
189
190#[allow(clippy::missing_safety_doc)]
191pub unsafe fn raw_syscall1(sysno: Sysno, arg0: usize) -> usize {
192    if callee() == 0 {
193        let ret;
194        asm!(
195            "int $$0x80",
196            inlateout("eax") sysno as usize => ret,
197            in("ebx") arg0,
198            options(nostack, preserves_flags)
199        );
200        ret
201    } else {
202        vsyscall1(sysno, arg0)
203    }
204}
205
206#[allow(clippy::missing_safety_doc)]
207pub unsafe fn raw_syscall1_readonly(sysno: Sysno, arg0: usize) -> usize {
208    if callee() == 0 {
209        let ret;
210        asm!(
211            "int $$0x80",
212            inlateout("eax") sysno as usize => ret,
213            in("ebx") arg0,
214            options(nostack, preserves_flags, readonly)
215        );
216        ret
217    } else {
218        vsyscall1(sysno, arg0)
219    }
220}
221
222#[allow(clippy::missing_safety_doc)]
223pub unsafe fn syscall1_noreturn(sysno: Sysno, arg0: usize) -> ! {
224    if callee() == 0 {
225        asm!(
226            "int $$0x80",
227            "ud2",
228            in("eax") sysno as usize,
229            in("ebx") arg0,
230            options(noreturn)
231        )
232    } else {
233        vsyscall1_noreturn(sysno, arg0)
234    }
235}
236
237#[allow(clippy::missing_safety_doc)]
238pub unsafe fn raw_syscall2(sysno: Sysno, arg0: usize, arg1: usize) -> usize {
239    if callee() == 0 {
240        let ret;
241        asm!(
242            "int $$0x80",
243            inlateout("eax") sysno as usize => ret,
244            in("ebx") arg0,
245            in("ecx") arg1,
246            options(nostack, preserves_flags)
247        );
248        ret
249    } else {
250        vsyscall2(sysno, arg0, arg1)
251    }
252}
253
254#[allow(clippy::missing_safety_doc)]
255pub unsafe fn raw_syscall2_readonly(sysno: Sysno, arg0: usize, arg1: usize) -> usize {
256    if callee() == 0 {
257        let ret;
258        asm!(
259            "int $$0x80",
260            inlateout("eax") sysno as usize => ret,
261            in("ebx") arg0,
262            in("ecx") arg1,
263            options(nostack, preserves_flags, readonly)
264        );
265        ret
266    } else {
267        vsyscall2(sysno, arg0, arg1)
268    }
269}
270
271#[allow(clippy::missing_safety_doc)]
272pub unsafe fn raw_syscall3(sysno: Sysno, arg0: usize, arg1: usize, arg2: usize) -> usize {
273    if callee() == 0 {
274        let ret;
275        asm!(
276            "int $$0x80",
277            inlateout("eax") sysno as usize => ret,
278            in("ebx") arg0,
279            in("ecx") arg1,
280            in("edx") arg2,
281            options(nostack, preserves_flags)
282        );
283        ret
284    } else {
285        vsyscall3(sysno, arg0, arg1, arg2)
286    }
287}
288
289#[allow(clippy::missing_safety_doc)]
290pub unsafe fn raw_syscall3_readonly(sysno: Sysno, arg0: usize, arg1: usize, arg2: usize) -> usize {
291    if callee() == 0 {
292        let ret;
293        asm!(
294            "int $$0x80",
295            inlateout("eax") sysno as usize => ret,
296            in("ebx") arg0,
297            in("ecx") arg1,
298            in("edx") arg2,
299            options(nostack, preserves_flags, readonly)
300        );
301        ret
302    } else {
303        vsyscall3(sysno, arg0, arg1, arg2)
304    }
305}
306
307#[allow(clippy::missing_safety_doc)]
308pub unsafe fn raw_syscall4(
309    sysno: Sysno,
310    arg0: usize,
311    arg1: usize,
312    arg2: usize,
313    arg3: usize,
314) -> usize {
315    if callee() == 0 {
316        let ret;
317        // We need to put arg3 in esi but asm macro won't let us do it directly.
318        // So swap it prior to interrupt and swap again afterward.
319        asm!(
320            "xchg esi, {arg3}",
321            "int $$0x80",
322            "xchg esi, {arg3}",
323            arg3 = in(reg) arg3,
324            inlateout("eax") sysno as usize => ret,
325            in("ebx") arg0,
326            in("ecx") arg1,
327            in("edx") arg2,
328            options(nostack, preserves_flags)
329        );
330        ret
331    } else {
332        vsyscall4(sysno, arg0, arg1, arg2, arg3)
333    }
334}
335
336#[allow(clippy::missing_safety_doc)]
337pub unsafe fn raw_syscall4_readonly(
338    sysno: Sysno,
339    arg0: usize,
340    arg1: usize,
341    arg2: usize,
342    arg3: usize,
343) -> usize {
344    if callee() == 0 {
345        let ret;
346        asm!(
347            "xchg esi, {arg3}",
348            "int $$0x80",
349            "xchg esi, {arg3}",
350            arg3 = in(reg) arg3,
351            inlateout("eax") sysno as usize => ret,
352            in("ebx") arg0,
353            in("ecx") arg1,
354            in("edx") arg2,
355            options(nostack, preserves_flags, readonly)
356        );
357        ret
358    } else {
359        vsyscall4(sysno, arg0, arg1, arg2, arg3)
360    }
361}
362
363#[allow(clippy::missing_safety_doc)]
364pub unsafe fn raw_syscall5(
365    sysno: Sysno,
366    arg0: usize,
367    arg1: usize,
368    arg2: usize,
369    arg3: usize,
370    arg4: usize,
371) -> usize {
372    if callee() == 0 {
373        let ret;
374        asm!(
375            "xchg esi, {arg3}",
376            "int $$0x80",
377            "xchg esi, {arg3}",
378            arg3 = in(reg) arg3,
379            inlateout("eax") sysno as usize => ret,
380            in("ebx") arg0,
381            in("ecx") arg1,
382            in("edx") arg2,
383            in("edi") arg4,
384            options(nostack, preserves_flags)
385        );
386        ret
387    } else {
388        vsyscall5(sysno, arg0, arg1, arg2, arg3, arg4)
389    }
390}
391
392#[allow(clippy::missing_safety_doc)]
393pub unsafe fn raw_syscall5_readonly(
394    sysno: Sysno,
395    arg0: usize,
396    arg1: usize,
397    arg2: usize,
398    arg3: usize,
399    arg4: usize,
400) -> usize {
401    if callee() == 0 {
402        let ret;
403        asm!(
404            "xchg esi, {arg3}",
405            "int $$0x80",
406            "xchg esi, {arg3}",
407            arg3 = in(reg) arg3,
408            inlateout("eax") sysno as usize => ret,
409            in("ebx") arg0,
410            in("ecx") arg1,
411            in("edx") arg2,
412            in("edi") arg4,
413            options(nostack, preserves_flags, readonly)
414        );
415        ret
416    } else {
417        vsyscall5(sysno, arg0, arg1, arg2, arg3, arg4)
418    }
419}
420
421#[allow(clippy::missing_safety_doc)]
422pub unsafe fn raw_syscall6(
423    sysno: Sysno,
424    arg0: usize,
425    arg1: usize,
426    arg2: usize,
427    arg3: usize,
428    arg4: usize,
429    arg5: usize,
430) -> usize {
431    if callee() == 0 {
432        let ret;
433        // Similary to syscall4/5, we need to put arg3 in esi and arg5 in ebp but
434        // asm macro doesn't allow us to do it and we can't alloc memory on stack
435        // and there are no other registers free.
436        // So we create a temporary slice and pass its pointer to eax, now we can
437        // copy data from slice to stack. Don't forget to preserve ebp and esi regs.
438        asm!(
439            "push ebp",
440            "push esi",
441            "mov esi, DWORD PTR [eax]",
442            "mov ebp, DWORD PTR [eax+4]",
443            "mov eax, DWORD PTR [eax+8]",
444            "int $$0x80",
445            "pop esi",
446            "pop ebp",
447            inlateout("eax") &[arg3, arg5, sysno as usize] => ret,
448            in("ebx") arg0,
449            in("ecx") arg1,
450            in("edx") arg2,
451            in("edi") arg4,
452            options(preserves_flags)
453        );
454        ret
455    } else {
456        vsyscall6(sysno, arg0, arg1, arg2, arg3, arg4, arg5)
457    }
458}
459
460#[allow(clippy::missing_safety_doc)]
461pub unsafe fn raw_syscall6_readonly(
462    sysno: Sysno,
463    arg0: usize,
464    arg1: usize,
465    arg2: usize,
466    arg3: usize,
467    arg4: usize,
468    arg5: usize,
469) -> usize {
470    if callee() == 0 {
471        let ret;
472        asm!(
473            "push ebp",
474            "push esi",
475            "mov esi, DWORD PTR [eax]",
476            "mov ebp, DWORD PTR [eax+4]",
477            "mov eax, DWORD PTR [eax+8]",
478            "int $$0x80",
479            "pop esi",
480            "pop ebp",
481            inlateout("eax") &[arg3, arg5, sysno as usize] => ret,
482            in("ebx") arg0,
483            in("ecx") arg1,
484            in("edx") arg2,
485            in("edi") arg4,
486            options(preserves_flags, readonly)
487        );
488        ret
489    } else {
490        vsyscall6(sysno, arg0, arg1, arg2, arg3, arg4, arg5)
491    }
492}
493
494include!("_syscalls.rs");
495
496#[inline(always)]
497pub(crate) fn init() {}