hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/x86/include/asm/syscall_wrapper.h
....@@ -8,140 +8,28 @@
88
99 struct pt_regs;
1010
11
-/* Mapping of registers to parameters for syscalls on x86-64 and x32 */
12
-#define SC_X86_64_REGS_TO_ARGS(x, ...) \
13
- __MAP(x,__SC_ARGS \
14
- ,,regs->di,,regs->si,,regs->dx \
15
- ,,regs->r10,,regs->r8,,regs->r9) \
16
-
17
-/* Mapping of registers to parameters for syscalls on i386 */
18
-#define SC_IA32_REGS_TO_ARGS(x, ...) \
19
- __MAP(x,__SC_ARGS \
20
- ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \
21
- ,,(unsigned int)regs->dx,,(unsigned int)regs->si \
22
- ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
23
-
24
-#ifdef CONFIG_IA32_EMULATION
25
-/*
26
- * For IA32 emulation, we need to handle "compat" syscalls *and* create
27
- * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
28
- * ia32 regs in the proper order for shared or "common" syscalls. As some
29
- * syscalls may not be implemented, we need to expand COND_SYSCALL in
30
- * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
31
- * case as well.
32
- */
33
-#define __IA32_COMPAT_SYS_STUBx(x, name, ...) \
34
- asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs);\
35
- ALLOW_ERROR_INJECTION(__ia32_compat_sys##name, ERRNO); \
36
- asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs)\
37
- { \
38
- return __se_compat_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\
39
- } \
40
-
41
-#define __IA32_SYS_STUBx(x, name, ...) \
42
- asmlinkage long __ia32_sys##name(const struct pt_regs *regs); \
43
- ALLOW_ERROR_INJECTION(__ia32_sys##name, ERRNO); \
44
- asmlinkage long __ia32_sys##name(const struct pt_regs *regs) \
45
- { \
46
- return __se_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\
47
- }
11
+extern long __x64_sys_ni_syscall(const struct pt_regs *regs);
12
+extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
4813
4914 /*
50
- * To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias
51
- * named __ia32_sys_*()
52
- */
53
-
54
-#define SYSCALL_DEFINE0(sname) \
55
- SYSCALL_METADATA(_##sname, 0); \
56
- asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
57
- ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO); \
58
- SYSCALL_ALIAS(__ia32_sys_##sname, __x64_sys_##sname); \
59
- asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
60
-
61
-#define COND_SYSCALL(name) \
62
- asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \
63
- { \
64
- return sys_ni_syscall(); \
65
- } \
66
- asmlinkage __weak long __ia32_sys_##name(const struct pt_regs *__unused)\
67
- { \
68
- return sys_ni_syscall(); \
69
- }
70
-
71
-#define SYS_NI(name) \
72
- SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers); \
73
- SYSCALL_ALIAS(__ia32_sys_##name, sys_ni_posix_timers)
74
-
75
-#else /* CONFIG_IA32_EMULATION */
76
-#define __IA32_COMPAT_SYS_STUBx(x, name, ...)
77
-#define __IA32_SYS_STUBx(x, fullname, name, ...)
78
-#endif /* CONFIG_IA32_EMULATION */
79
-
80
-
81
-#ifdef CONFIG_X86_X32
82
-/*
83
- * For the x32 ABI, we need to create a stub for compat_sys_*() which is aware
84
- * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
85
- * with x86_64 obviously do not need such care.
86
- */
87
-#define __X32_COMPAT_SYS_STUBx(x, name, ...) \
88
- asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs);\
89
- ALLOW_ERROR_INJECTION(__x32_compat_sys##name, ERRNO); \
90
- asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs)\
91
- { \
92
- return __se_compat_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\
93
- } \
94
-
95
-#else /* CONFIG_X86_X32 */
96
-#define __X32_COMPAT_SYS_STUBx(x, name, ...)
97
-#endif /* CONFIG_X86_X32 */
98
-
99
-
100
-#ifdef CONFIG_COMPAT
101
-/*
102
- * Compat means IA32_EMULATION and/or X86_X32. As they use a different
103
- * mapping of registers to parameters, we need to generate stubs for each
104
- * of them.
105
- */
106
-#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \
107
- static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
108
- static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
109
- __IA32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__) \
110
- __X32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__) \
111
- static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
112
- { \
113
- return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\
114
- } \
115
- static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
116
-
117
-/*
118
- * As some compat syscalls may not be implemented, we need to expand
119
- * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
120
- * kernel/time/posix-stubs.c to cover this case as well.
121
- */
122
-#define COND_SYSCALL_COMPAT(name) \
123
- asmlinkage __weak long __ia32_compat_sys_##name( \
124
- const struct pt_regs *__unused) \
125
- { \
126
- return sys_ni_syscall(); \
127
- } \
128
- cond_syscall(__x32_compat_sys_##name)
129
-
130
-#define COMPAT_SYS_NI(name) \
131
- SYSCALL_ALIAS(__ia32_compat_sys_##name, sys_ni_posix_timers); \
132
- SYSCALL_ALIAS(__x32_compat_sys_##name, sys_ni_posix_timers)
133
-
134
-#endif /* CONFIG_COMPAT */
135
-
136
-
137
-/*
138
- * Instead of the generic __SYSCALL_DEFINEx() definition, this macro takes
139
- * struct pt_regs *regs as the only argument of the syscall stub named
140
- * __x64_sys_*(). It decodes just the registers it needs and passes them on to
141
- * the __se_sys_*() wrapper performing sign extension and then to the
142
- * __do_sys_*() function doing the actual job. These wrappers and functions
143
- * are inlined (at least in very most cases), meaning that the assembly looks
144
- * as follows (slightly re-ordered for better readability):
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):
14533 *
14634 * <__x64_sys_recv>: <-- syscall with 4 parameters
14735 * callq <__fentry__>
....@@ -162,20 +50,184 @@
16250 *
16351 * This approach avoids leaking random user-provided register content down
16452 * the call chain.
165
- *
166
- * If IA32_EMULATION is enabled, this macro generates an additional wrapper
167
- * named __ia32_sys_*() which decodes the struct pt_regs *regs according
168
- * to the i386 calling convention (bx, cx, dx, si, di, bp).
16953 */
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
+/* Mapping of registers to parameters for syscalls on i386 */
62
+#define SC_IA32_REGS_TO_ARGS(x, ...) \
63
+ __MAP(x,__SC_ARGS \
64
+ ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \
65
+ ,,(unsigned int)regs->dx,,(unsigned int)regs->si \
66
+ ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
67
+
68
+#define __SYS_STUB0(abi, name) \
69
+ long __##abi##_##name(const struct pt_regs *regs); \
70
+ ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO); \
71
+ long __##abi##_##name(const struct pt_regs *regs) \
72
+ __alias(__do_##name);
73
+
74
+#define __SYS_STUBx(abi, name, ...) \
75
+ long __##abi##_##name(const struct pt_regs *regs); \
76
+ ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO); \
77
+ long __##abi##_##name(const struct pt_regs *regs) \
78
+ { \
79
+ return __se_##name(__VA_ARGS__); \
80
+ }
81
+
82
+#define __COND_SYSCALL(abi, name) \
83
+ __weak long __##abi##_##name(const struct pt_regs *__unused) \
84
+ { \
85
+ return sys_ni_syscall(); \
86
+ }
87
+
88
+#define __SYS_NI(abi, name) \
89
+ SYSCALL_ALIAS(__##abi##_##name, sys_ni_posix_timers);
90
+
91
+#ifdef CONFIG_X86_64
92
+#define __X64_SYS_STUB0(name) \
93
+ __SYS_STUB0(x64, sys_##name)
94
+
95
+#define __X64_SYS_STUBx(x, name, ...) \
96
+ __SYS_STUBx(x64, sys##name, \
97
+ SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
98
+
99
+#define __X64_COND_SYSCALL(name) \
100
+ __COND_SYSCALL(x64, sys_##name)
101
+
102
+#define __X64_SYS_NI(name) \
103
+ __SYS_NI(x64, sys_##name)
104
+#else /* CONFIG_X86_64 */
105
+#define __X64_SYS_STUB0(name)
106
+#define __X64_SYS_STUBx(x, name, ...)
107
+#define __X64_COND_SYSCALL(name)
108
+#define __X64_SYS_NI(name)
109
+#endif /* CONFIG_X86_64 */
110
+
111
+#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
112
+#define __IA32_SYS_STUB0(name) \
113
+ __SYS_STUB0(ia32, sys_##name)
114
+
115
+#define __IA32_SYS_STUBx(x, name, ...) \
116
+ __SYS_STUBx(ia32, sys##name, \
117
+ SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
118
+
119
+#define __IA32_COND_SYSCALL(name) \
120
+ __COND_SYSCALL(ia32, sys_##name)
121
+
122
+#define __IA32_SYS_NI(name) \
123
+ __SYS_NI(ia32, sys_##name)
124
+#else /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
125
+#define __IA32_SYS_STUB0(name)
126
+#define __IA32_SYS_STUBx(x, name, ...)
127
+#define __IA32_COND_SYSCALL(name)
128
+#define __IA32_SYS_NI(name)
129
+#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
130
+
131
+#ifdef CONFIG_IA32_EMULATION
132
+/*
133
+ * For IA32 emulation, we need to handle "compat" syscalls *and* create
134
+ * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
135
+ * ia32 regs in the proper order for shared or "common" syscalls. As some
136
+ * syscalls may not be implemented, we need to expand COND_SYSCALL in
137
+ * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
138
+ * case as well.
139
+ */
140
+#define __IA32_COMPAT_SYS_STUB0(name) \
141
+ __SYS_STUB0(ia32, compat_sys_##name)
142
+
143
+#define __IA32_COMPAT_SYS_STUBx(x, name, ...) \
144
+ __SYS_STUBx(ia32, compat_sys##name, \
145
+ SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
146
+
147
+#define __IA32_COMPAT_COND_SYSCALL(name) \
148
+ __COND_SYSCALL(ia32, compat_sys_##name)
149
+
150
+#define __IA32_COMPAT_SYS_NI(name) \
151
+ __SYS_NI(ia32, compat_sys_##name)
152
+
153
+#else /* CONFIG_IA32_EMULATION */
154
+#define __IA32_COMPAT_SYS_STUB0(name)
155
+#define __IA32_COMPAT_SYS_STUBx(x, name, ...)
156
+#define __IA32_COMPAT_COND_SYSCALL(name)
157
+#define __IA32_COMPAT_SYS_NI(name)
158
+#endif /* CONFIG_IA32_EMULATION */
159
+
160
+
161
+#ifdef CONFIG_X86_X32
162
+/*
163
+ * For the x32 ABI, we need to create a stub for compat_sys_*() which is aware
164
+ * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
165
+ * with x86_64 obviously do not need such care.
166
+ */
167
+#define __X32_COMPAT_SYS_STUB0(name) \
168
+ __SYS_STUB0(x32, compat_sys_##name)
169
+
170
+#define __X32_COMPAT_SYS_STUBx(x, name, ...) \
171
+ __SYS_STUBx(x32, compat_sys##name, \
172
+ SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
173
+
174
+#define __X32_COMPAT_COND_SYSCALL(name) \
175
+ __COND_SYSCALL(x32, compat_sys_##name)
176
+
177
+#define __X32_COMPAT_SYS_NI(name) \
178
+ __SYS_NI(x32, compat_sys_##name)
179
+#else /* CONFIG_X86_X32 */
180
+#define __X32_COMPAT_SYS_STUB0(name)
181
+#define __X32_COMPAT_SYS_STUBx(x, name, ...)
182
+#define __X32_COMPAT_COND_SYSCALL(name)
183
+#define __X32_COMPAT_SYS_NI(name)
184
+#endif /* CONFIG_X86_X32 */
185
+
186
+
187
+#ifdef CONFIG_COMPAT
188
+/*
189
+ * Compat means IA32_EMULATION and/or X86_X32. As they use a different
190
+ * mapping of registers to parameters, we need to generate stubs for each
191
+ * of them.
192
+ */
193
+#define COMPAT_SYSCALL_DEFINE0(name) \
194
+ static long \
195
+ __do_compat_sys_##name(const struct pt_regs *__unused); \
196
+ __IA32_COMPAT_SYS_STUB0(name) \
197
+ __X32_COMPAT_SYS_STUB0(name) \
198
+ static long \
199
+ __do_compat_sys_##name(const struct pt_regs *__unused)
200
+
201
+#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \
202
+ static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
203
+ static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
204
+ __IA32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__) \
205
+ __X32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__) \
206
+ static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
207
+ { \
208
+ return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\
209
+ } \
210
+ static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
211
+
212
+/*
213
+ * As some compat syscalls may not be implemented, we need to expand
214
+ * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
215
+ * kernel/time/posix-stubs.c to cover this case as well.
216
+ */
217
+#define COND_SYSCALL_COMPAT(name) \
218
+ __IA32_COMPAT_COND_SYSCALL(name) \
219
+ __X32_COMPAT_COND_SYSCALL(name)
220
+
221
+#define COMPAT_SYS_NI(name) \
222
+ __IA32_COMPAT_SYS_NI(name) \
223
+ __X32_COMPAT_SYS_NI(name)
224
+
225
+#endif /* CONFIG_COMPAT */
226
+
170227 #define __SYSCALL_DEFINEx(x, name, ...) \
171
- asmlinkage long __x64_sys##name(const struct pt_regs *regs); \
172
- ALLOW_ERROR_INJECTION(__x64_sys##name, ERRNO); \
173228 static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
174229 static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
175
- asmlinkage long __x64_sys##name(const struct pt_regs *regs) \
176
- { \
177
- return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\
178
- } \
230
+ __X64_SYS_STUBx(x, name, __VA_ARGS__) \
179231 __IA32_SYS_STUBx(x, name, __VA_ARGS__) \
180232 static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
181233 { \
....@@ -193,33 +245,28 @@
193245 * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI()
194246 * macros to work correctly.
195247 */
196
-#ifndef SYSCALL_DEFINE0
197
-#define SYSCALL_DEFINE0(sname) \
198
- SYSCALL_METADATA(_##sname, 0); \
199
- asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
200
- ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO); \
201
- asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
202
-#endif
248
+#define SYSCALL_DEFINE0(sname) \
249
+ SYSCALL_METADATA(_##sname, 0); \
250
+ static long __do_sys_##sname(const struct pt_regs *__unused); \
251
+ __X64_SYS_STUB0(sname) \
252
+ __IA32_SYS_STUB0(sname) \
253
+ static long __do_sys_##sname(const struct pt_regs *__unused)
203254
204
-#ifndef COND_SYSCALL
205
-#define COND_SYSCALL(name) \
206
- asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \
207
- { \
208
- return sys_ni_syscall(); \
209
- }
210
-#endif
255
+#define COND_SYSCALL(name) \
256
+ __X64_COND_SYSCALL(name) \
257
+ __IA32_COND_SYSCALL(name)
211258
212
-#ifndef SYS_NI
213
-#define SYS_NI(name) SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers);
214
-#endif
259
+#define SYS_NI(name) \
260
+ __X64_SYS_NI(name) \
261
+ __IA32_SYS_NI(name)
215262
216263
217264 /*
218265 * For VSYSCALLS, we need to declare these three syscalls with the new
219266 * pt_regs-based calling convention for in-kernel use.
220267 */
221
-asmlinkage long __x64_sys_getcpu(const struct pt_regs *regs);
222
-asmlinkage long __x64_sys_gettimeofday(const struct pt_regs *regs);
223
-asmlinkage long __x64_sys_time(const struct pt_regs *regs);
268
+long __x64_sys_getcpu(const struct pt_regs *regs);
269
+long __x64_sys_gettimeofday(const struct pt_regs *regs);
270
+long __x64_sys_time(const struct pt_regs *regs);
224271
225272 #endif /* _ASM_X86_SYSCALL_WRAPPER_H */