xref: /aosp_15_r20/external/liburing/src/arch/x86/syscall.h (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 
3 #ifndef __INTERNAL__LIBURING_SYSCALL_H
4 	#error "This file should be included from src/syscall.h (liburing)"
5 #endif
6 
7 #ifndef LIBURING_ARCH_X86_SYSCALL_H
8 #define LIBURING_ARCH_X86_SYSCALL_H
9 
10 #if defined(__x86_64__)
11 /**
12  * Note for syscall registers usage (x86-64):
13  *   - %rax is the syscall number.
14  *   - %rax is also the return value.
15  *   - %rdi is the 1st argument.
16  *   - %rsi is the 2nd argument.
17  *   - %rdx is the 3rd argument.
18  *   - %r10 is the 4th argument (**yes it's %r10, not %rcx!**).
19  *   - %r8  is the 5th argument.
20  *   - %r9  is the 6th argument.
21  *
22  * `syscall` instruction will clobber %r11 and %rcx.
23  *
24  * After the syscall returns to userspace:
25  *   - %r11 will contain %rflags.
26  *   - %rcx will contain the return address.
27  *
28  * IOW, after the syscall returns to userspace:
29  *   %r11 == %rflags and %rcx == %rip.
30  */
31 
32 #define __do_syscall0(NUM) ({			\
33 	intptr_t rax;				\
34 						\
35 	__asm__ volatile(			\
36 		"syscall"			\
37 		: "=a"(rax)	/* %rax */	\
38 		: "a"(NUM)	/* %rax */	\
39 		: "rcx", "r11", "memory"	\
40 	);					\
41 	rax;					\
42 })
43 
44 #define __do_syscall1(NUM, ARG1) ({		\
45 	intptr_t rax;				\
46 						\
47 	__asm__ volatile(			\
48 		"syscall"			\
49 		: "=a"(rax)	/* %rax */	\
50 		: "a"((NUM)),	/* %rax */	\
51 		  "D"((ARG1))	/* %rdi */	\
52 		: "rcx", "r11", "memory"	\
53 	);					\
54 	rax;					\
55 })
56 
57 #define __do_syscall2(NUM, ARG1, ARG2) ({	\
58 	intptr_t rax;				\
59 						\
60 	__asm__ volatile(			\
61 		"syscall"			\
62 		: "=a"(rax)	/* %rax */	\
63 		: "a"((NUM)),	/* %rax */	\
64 		  "D"((ARG1)),	/* %rdi */	\
65 		  "S"((ARG2))	/* %rsi */	\
66 		: "rcx", "r11", "memory"	\
67 	);					\
68 	rax;					\
69 })
70 
71 #define __do_syscall3(NUM, ARG1, ARG2, ARG3) ({	\
72 	intptr_t rax;				\
73 						\
74 	__asm__ volatile(			\
75 		"syscall"			\
76 		: "=a"(rax)	/* %rax */	\
77 		: "a"((NUM)),	/* %rax */	\
78 		  "D"((ARG1)),	/* %rdi */	\
79 		  "S"((ARG2)),	/* %rsi */	\
80 		  "d"((ARG3))	/* %rdx */	\
81 		: "rcx", "r11", "memory"	\
82 	);					\
83 	rax;					\
84 })
85 
86 #define __do_syscall4(NUM, ARG1, ARG2, ARG3, ARG4) ({			\
87 	intptr_t rax;							\
88 	register __typeof__(ARG4) __r10 __asm__("r10") = (ARG4);	\
89 									\
90 	__asm__ volatile(						\
91 		"syscall"						\
92 		: "=a"(rax)	/* %rax */				\
93 		: "a"((NUM)),	/* %rax */				\
94 		  "D"((ARG1)),	/* %rdi */				\
95 		  "S"((ARG2)),	/* %rsi */				\
96 		  "d"((ARG3)),	/* %rdx */				\
97 		  "r"(__r10)	/* %r10 */				\
98 		: "rcx", "r11", "memory"				\
99 	);								\
100 	rax;								\
101 })
102 
103 #define __do_syscall5(NUM, ARG1, ARG2, ARG3, ARG4, ARG5) ({		\
104 	intptr_t rax;							\
105 	register __typeof__(ARG4) __r10 __asm__("r10") = (ARG4);	\
106 	register __typeof__(ARG5) __r8 __asm__("r8") = (ARG5);		\
107 									\
108 	__asm__ volatile(						\
109 		"syscall"						\
110 		: "=a"(rax)	/* %rax */				\
111 		: "a"((NUM)),	/* %rax */				\
112 		  "D"((ARG1)),	/* %rdi */				\
113 		  "S"((ARG2)),	/* %rsi */				\
114 		  "d"((ARG3)),	/* %rdx */				\
115 		  "r"(__r10),	/* %r10 */				\
116 		  "r"(__r8)	/* %r8 */				\
117 		: "rcx", "r11", "memory"				\
118 	);								\
119 	rax;								\
120 })
121 
122 #define __do_syscall6(NUM, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({	\
123 	intptr_t rax;							\
124 	register __typeof__(ARG4) __r10 __asm__("r10") = (ARG4);	\
125 	register __typeof__(ARG5) __r8 __asm__("r8") = (ARG5);		\
126 	register __typeof__(ARG6) __r9 __asm__("r9") = (ARG6);		\
127 									\
128 	__asm__ volatile(						\
129 		"syscall"						\
130 		: "=a"(rax)	/* %rax */				\
131 		: "a"((NUM)),	/* %rax */				\
132 		  "D"((ARG1)),	/* %rdi */				\
133 		  "S"((ARG2)),	/* %rsi */				\
134 		  "d"((ARG3)),	/* %rdx */				\
135 		  "r"(__r10),	/* %r10 */				\
136 		  "r"(__r8),	/* %r8 */				\
137 		  "r"(__r9)	/* %r9 */				\
138 		: "rcx", "r11", "memory"				\
139 	);								\
140 	rax;								\
141 })
142 
143 #include "../syscall-defs.h"
144 
145 #else /* #if defined(__x86_64__) */
146 
147 #ifdef CONFIG_NOLIBC
148 /**
149  * Note for syscall registers usage (x86, 32-bit):
150  *   - %eax is the syscall number.
151  *   - %eax is also the return value.
152  *   - %ebx is the 1st argument.
153  *   - %ecx is the 2nd argument.
154  *   - %edx is the 3rd argument.
155  *   - %esi is the 4th argument.
156  *   - %edi is the 5th argument.
157  *   - %ebp is the 6th argument.
158  */
159 
160 #define __do_syscall0(NUM) ({			\
161 	intptr_t eax;				\
162 						\
163 	__asm__ volatile(			\
164 		"int	$0x80"			\
165 		: "=a"(eax)	/* %eax */	\
166 		: "a"(NUM)	/* %eax */	\
167 		: "memory"			\
168 	);					\
169 	eax;					\
170 })
171 
172 #define __do_syscall1(NUM, ARG1) ({		\
173 	intptr_t eax;				\
174 						\
175 	__asm__ volatile(			\
176 		"int	$0x80"			\
177 		: "=a"(eax)	/* %eax */	\
178 		: "a"(NUM),	/* %eax */	\
179 		  "b"((ARG1))	/* %ebx */	\
180 		: "memory"			\
181 	);					\
182 	eax;					\
183 })
184 
185 #define __do_syscall2(NUM, ARG1, ARG2) ({	\
186 	intptr_t eax;				\
187 						\
188 	__asm__ volatile(			\
189 		"int	$0x80"			\
190 		: "=a" (eax)	/* %eax */	\
191 		: "a"(NUM),	/* %eax */	\
192 		  "b"((ARG1)),	/* %ebx */	\
193 		  "c"((ARG2))	/* %ecx */	\
194 		: "memory"			\
195 	);					\
196 	eax;					\
197 })
198 
199 #define __do_syscall3(NUM, ARG1, ARG2, ARG3) ({	\
200 	intptr_t eax;				\
201 						\
202 	__asm__ volatile(			\
203 		"int	$0x80"			\
204 		: "=a" (eax)	/* %eax */	\
205 		: "a"(NUM),	/* %eax */	\
206 		  "b"((ARG1)),	/* %ebx */	\
207 		  "c"((ARG2)),	/* %ecx */	\
208 		  "d"((ARG3))	/* %edx */	\
209 		: "memory"			\
210 	);					\
211 	eax;					\
212 })
213 
214 #define __do_syscall4(NUM, ARG1, ARG2, ARG3, ARG4) ({	\
215 	intptr_t eax;					\
216 							\
217 	__asm__ volatile(				\
218 		"int	$0x80"				\
219 		: "=a" (eax)	/* %eax */		\
220 		: "a"(NUM),	/* %eax */		\
221 		  "b"((ARG1)),	/* %ebx */		\
222 		  "c"((ARG2)),	/* %ecx */		\
223 		  "d"((ARG3)),	/* %edx */		\
224 		  "S"((ARG4))	/* %esi */		\
225 		: "memory"				\
226 	);						\
227 	eax;						\
228 })
229 
230 #define __do_syscall5(NUM, ARG1, ARG2, ARG3, ARG4, ARG5) ({	\
231 	intptr_t eax;						\
232 								\
233 	__asm__ volatile(					\
234 		"int	$0x80"					\
235 		: "=a" (eax)	/* %eax */			\
236 		: "a"(NUM),	/* %eax */			\
237 		  "b"((ARG1)),	/* %ebx */			\
238 		  "c"((ARG2)),	/* %ecx */			\
239 		  "d"((ARG3)),	/* %edx */			\
240 		  "S"((ARG4)),	/* %esi */			\
241 		  "D"((ARG5))	/* %edi */			\
242 		: "memory"					\
243 	);							\
244 	eax;							\
245 })
246 
247 
248 /*
249  * On i386, the 6th argument of syscall goes in %ebp. However, both Clang
250  * and GCC cannot use %ebp in the clobber list and in the "r" constraint
251  * without using -fomit-frame-pointer. To make it always available for
252  * any kind of compilation, the below workaround is implemented:
253  *
254  *  1) Push the 6-th argument.
255  *  2) Push %ebp.
256  *  3) Load the 6-th argument from 4(%esp) to %ebp.
257  *  4) Do the syscall (int $0x80).
258  *  5) Pop %ebp (restore the old value of %ebp).
259  *  6) Add %esp by 4 (undo the stack pointer).
260  *
261  * WARNING:
262  *   Don't use register variables for __do_syscall6(), there is a known
263  *   GCC bug that results in an endless loop.
264  *
265  * BugLink: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105032
266  *
267  */
268 #define __do_syscall6(NUM, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({	\
269 	intptr_t eax  = (intptr_t)(NUM);				\
270 	intptr_t arg6 = (intptr_t)(ARG6); /* Always in memory */	\
271 	__asm__ volatile (						\
272 		"pushl	%[_arg6]\n\t"					\
273 		"pushl	%%ebp\n\t"					\
274 		"movl	4(%%esp),%%ebp\n\t"				\
275 		"int	$0x80\n\t"					\
276 		"popl	%%ebp\n\t"					\
277 		"addl	$4,%%esp"					\
278 		: "+a"(eax)		/* %eax */			\
279 		: "b"(ARG1),		/* %ebx */			\
280 		  "c"(ARG2),		/* %ecx */			\
281 		  "d"(ARG3),		/* %edx */			\
282 		  "S"(ARG4),		/* %esi */			\
283 		  "D"(ARG5),		/* %edi */			\
284 		  [_arg6]"m"(arg6)	/* memory */			\
285 		: "memory", "cc"					\
286 	);								\
287 	eax;								\
288 })
289 
290 #include "../syscall-defs.h"
291 
292 #else /* #ifdef CONFIG_NOLIBC */
293 
294 #include "../generic/syscall.h"
295 
296 #endif /* #ifdef CONFIG_NOLIBC */
297 
298 #endif /* #if defined(__x86_64__) */
299 
300 #endif /* #ifndef LIBURING_ARCH_X86_SYSCALL_H */
301