1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * syscall_wrapper.h - x86 specific wrappers to syscall definitions
4 */
5
6#ifndef _ASM_X86_SYSCALL_WRAPPER_H
7#define _ASM_X86_SYSCALL_WRAPPER_H
8
9struct pt_regs;
10
11extern long __x64_sys_ni_syscall(const struct pt_regs *regs);
12extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
13
14/*
15 * Instead of the generic __SYSCALL_DEFINEx() definition, the x86 version takes
16 * struct pt_regs *regs as the only argument of the syscall stub(s) named as:
17 * __x64_sys_*()         - 64-bit native syscall
18 * __ia32_sys_*()        - 32-bit native syscall or common compat syscall
19 * __ia32_compat_sys_*() - 32-bit compat syscall
20 * __x32_compat_sys_*()  - 64-bit X32 compat syscall
21 *
22 * The registers are decoded according to the ABI:
23 * 64-bit: RDI, RSI, RDX, R10, R8, R9
24 * 32-bit: EBX, ECX, EDX, ESI, EDI, EBP
25 *
26 * The stub then passes the decoded arguments to the __se_sys_*() wrapper to
27 * perform sign-extension (omitted for zero-argument syscalls).  Finally the
28 * arguments are passed to the __do_sys_*() function which is the actual
29 * syscall.  These wrappers are marked as inline so the compiler can optimize
30 * the functions where appropriate.
31 *
32 * Example assembly (slightly re-ordered for better readability):
33 *
34 * <__x64_sys_recv>:		<-- syscall with 4 parameters
35 *	callq	<__fentry__>
36 *
37 *	mov	0x70(%rdi),%rdi	<-- decode regs->di
38 *	mov	0x68(%rdi),%rsi	<-- decode regs->si
39 *	mov	0x60(%rdi),%rdx	<-- decode regs->dx
40 *	mov	0x38(%rdi),%rcx	<-- decode regs->r10
41 *
42 *	xor	%r9d,%r9d	<-- clear %r9
43 *	xor	%r8d,%r8d	<-- clear %r8
44 *
45 *	callq	__sys_recvfrom	<-- do the actual work in __sys_recvfrom()
46 *				    which takes 6 arguments
47 *
48 *	cltq			<-- extend return value to 64-bit
49 *	retq			<-- return
50 *
51 * This approach avoids leaking random user-provided register content down
52 * the call chain.
53 */
54
55/* Mapping of registers to parameters for syscalls on x86-64 and x32 */
56#define SC_X86_64_REGS_TO_ARGS(x, ...)					\
57	__MAP(x,__SC_ARGS						\
58		,,regs->di,,regs->si,,regs->dx				\
59		,,regs->r10,,regs->r8,,regs->r9)			\
60
61
62/* SYSCALL_PT_ARGS is Adapted from s390x */
63#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6)			\
64	SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp))
65#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5)				\
66	SYSCALL_PT_ARG4(m, t1, t2, t3, t4),  m(t5, (regs->di))
67#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4)				\
68	SYSCALL_PT_ARG3(m, t1, t2, t3),  m(t4, (regs->si))
69#define SYSCALL_PT_ARG3(m, t1, t2, t3)					\
70	SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx))
71#define SYSCALL_PT_ARG2(m, t1, t2)					\
72	SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx))
73#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx))
74#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__)
75
76#define __SC_COMPAT_CAST(t, a)						\
77	(__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U)))	\
78	(unsigned int)a
79
80/* Mapping of registers to parameters for syscalls on i386 */
81#define SC_IA32_REGS_TO_ARGS(x, ...)					\
82	SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST,				\
83			__MAP(x, __SC_TYPE, __VA_ARGS__))		\
84
85#define __SYS_STUB0(abi, name)						\
86	long __##abi##_##name(const struct pt_regs *regs);		\
87	ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);			\
88	long __##abi##_##name(const struct pt_regs *regs)		\
89		__alias(__do_##name);
90
91#define __SYS_STUBx(abi, name, ...)					\
92	long __##abi##_##name(const struct pt_regs *regs);		\
93	ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);			\
94	long __##abi##_##name(const struct pt_regs *regs)		\
95	{								\
96		return __se_##name(__VA_ARGS__);			\
97	}
98
99#define __COND_SYSCALL(abi, name)					\
100	__weak long __##abi##_##name(const struct pt_regs *__unused)	\
101	{								\
102		return sys_ni_syscall();				\
103	}
104
105#define __SYS_NI(abi, name)						\
106	SYSCALL_ALIAS(__##abi##_##name, sys_ni_posix_timers);
107
108#ifdef CONFIG_X86_64
109#define __X64_SYS_STUB0(name)						\
110	__SYS_STUB0(x64, sys_##name)
111
112#define __X64_SYS_STUBx(x, name, ...)					\
113	__SYS_STUBx(x64, sys##name,					\
114		    SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
115
116#define __X64_COND_SYSCALL(name)					\
117	__COND_SYSCALL(x64, sys_##name)
118
119#define __X64_SYS_NI(name)						\
120	__SYS_NI(x64, sys_##name)
121#else /* CONFIG_X86_64 */
122#define __X64_SYS_STUB0(name)
123#define __X64_SYS_STUBx(x, name, ...)
124#define __X64_COND_SYSCALL(name)
125#define __X64_SYS_NI(name)
126#endif /* CONFIG_X86_64 */
127
128#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
129#define __IA32_SYS_STUB0(name)						\
130	__SYS_STUB0(ia32, sys_##name)
131
132#define __IA32_SYS_STUBx(x, name, ...)					\
133	__SYS_STUBx(ia32, sys##name,					\
134		    SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
135
136#define __IA32_COND_SYSCALL(name)					\
137	__COND_SYSCALL(ia32, sys_##name)
138
139#define __IA32_SYS_NI(name)						\
140	__SYS_NI(ia32, sys_##name)
141#else /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
142#define __IA32_SYS_STUB0(name)
143#define __IA32_SYS_STUBx(x, name, ...)
144#define __IA32_COND_SYSCALL(name)
145#define __IA32_SYS_NI(name)
146#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
147
148#ifdef CONFIG_IA32_EMULATION
149/*
150 * For IA32 emulation, we need to handle "compat" syscalls *and* create
151 * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
152 * ia32 regs in the proper order for shared or "common" syscalls. As some
153 * syscalls may not be implemented, we need to expand COND_SYSCALL in
154 * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
155 * case as well.
156 */
157#define __IA32_COMPAT_SYS_STUB0(name)					\
158	__SYS_STUB0(ia32, compat_sys_##name)
159
160#define __IA32_COMPAT_SYS_STUBx(x, name, ...)				\
161	__SYS_STUBx(ia32, compat_sys##name,				\
162		    SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
163
164#define __IA32_COMPAT_COND_SYSCALL(name)				\
165	__COND_SYSCALL(ia32, compat_sys_##name)
166
167#define __IA32_COMPAT_SYS_NI(name)					\
168	__SYS_NI(ia32, compat_sys_##name)
169
170#else /* CONFIG_IA32_EMULATION */
171#define __IA32_COMPAT_SYS_STUB0(name)
172#define __IA32_COMPAT_SYS_STUBx(x, name, ...)
173#define __IA32_COMPAT_COND_SYSCALL(name)
174#define __IA32_COMPAT_SYS_NI(name)
175#endif /* CONFIG_IA32_EMULATION */
176
177
178#ifdef CONFIG_X86_X32
179/*
180 * For the x32 ABI, we need to create a stub for compat_sys_*() which is aware
181 * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
182 * with x86_64 obviously do not need such care.
183 */
184#define __X32_COMPAT_SYS_STUB0(name)					\
185	__SYS_STUB0(x32, compat_sys_##name)
186
187#define __X32_COMPAT_SYS_STUBx(x, name, ...)				\
188	__SYS_STUBx(x32, compat_sys##name,				\
189		    SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
190
191#define __X32_COMPAT_COND_SYSCALL(name)					\
192	__COND_SYSCALL(x32, compat_sys_##name)
193
194#define __X32_COMPAT_SYS_NI(name)					\
195	__SYS_NI(x32, compat_sys_##name)
196#else /* CONFIG_X86_X32 */
197#define __X32_COMPAT_SYS_STUB0(name)
198#define __X32_COMPAT_SYS_STUBx(x, name, ...)
199#define __X32_COMPAT_COND_SYSCALL(name)
200#define __X32_COMPAT_SYS_NI(name)
201#endif /* CONFIG_X86_X32 */
202
203
204#ifdef CONFIG_COMPAT
205/*
206 * Compat means IA32_EMULATION and/or X86_X32. As they use a different
207 * mapping of registers to parameters, we need to generate stubs for each
208 * of them.
209 */
210#define COMPAT_SYSCALL_DEFINE0(name)					\
211	static long							\
212	__do_compat_sys_##name(const struct pt_regs *__unused);		\
213	__IA32_COMPAT_SYS_STUB0(name)					\
214	__X32_COMPAT_SYS_STUB0(name)					\
215	static long							\
216	__do_compat_sys_##name(const struct pt_regs *__unused)
217
218#define COMPAT_SYSCALL_DEFINEx(x, name, ...)					\
219	static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
220	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
221	__IA32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__)				\
222	__X32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__)				\
223	static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
224	{									\
225		return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\
226	}									\
227	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
228
229/*
230 * As some compat syscalls may not be implemented, we need to expand
231 * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
232 * kernel/time/posix-stubs.c to cover this case as well.
233 */
234#define COND_SYSCALL_COMPAT(name) 					\
235	__IA32_COMPAT_COND_SYSCALL(name)				\
236	__X32_COMPAT_COND_SYSCALL(name)
237
238#define COMPAT_SYS_NI(name)						\
239	__IA32_COMPAT_SYS_NI(name)					\
240	__X32_COMPAT_SYS_NI(name)
241
242#endif /* CONFIG_COMPAT */
243
244#define __SYSCALL_DEFINEx(x, name, ...)					\
245	static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
246	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
247	__X64_SYS_STUBx(x, name, __VA_ARGS__)				\
248	__IA32_SYS_STUBx(x, name, __VA_ARGS__)				\
249	static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
250	{								\
251		long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\
252		__MAP(x,__SC_TEST,__VA_ARGS__);				\
253		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
254		return ret;						\
255	}								\
256	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
257
258/*
259 * As the generic SYSCALL_DEFINE0() macro does not decode any parameters for
260 * obvious reasons, and passing struct pt_regs *regs to it in %rdi does not
261 * hurt, we only need to re-define it here to keep the naming congruent to
262 * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI()
263 * macros to work correctly.
264 */
265#define SYSCALL_DEFINE0(sname)						\
266	SYSCALL_METADATA(_##sname, 0);					\
267	static long __do_sys_##sname(const struct pt_regs *__unused);	\
268	__X64_SYS_STUB0(sname)						\
269	__IA32_SYS_STUB0(sname)						\
270	static long __do_sys_##sname(const struct pt_regs *__unused)
271
272#define COND_SYSCALL(name)						\
273	__X64_COND_SYSCALL(name)					\
274	__IA32_COND_SYSCALL(name)
275
276#define SYS_NI(name)							\
277	__X64_SYS_NI(name)						\
278	__IA32_SYS_NI(name)
279
280
281/*
282 * For VSYSCALLS, we need to declare these three syscalls with the new
283 * pt_regs-based calling convention for in-kernel use.
284 */
285long __x64_sys_getcpu(const struct pt_regs *regs);
286long __x64_sys_gettimeofday(const struct pt_regs *regs);
287long __x64_sys_time(const struct pt_regs *regs);
288
289#endif /* _ASM_X86_SYSCALL_WRAPPER_H */
290