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