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