Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * syscall_wrapper.h - x86 specific wrappers to syscall definitions
0004  */
0005 
0006 #ifndef _ASM_X86_SYSCALL_WRAPPER_H
0007 #define _ASM_X86_SYSCALL_WRAPPER_H
0008 
0009 struct pt_regs;
0010 
0011 extern long __x64_sys_ni_syscall(const struct pt_regs *regs);
0012 extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
0013 
0014 /*
0015  * Instead of the generic __SYSCALL_DEFINEx() definition, the x86 version takes
0016  * struct pt_regs *regs as the only argument of the syscall stub(s) named as:
0017  * __x64_sys_*()         - 64-bit native syscall
0018  * __ia32_sys_*()        - 32-bit native syscall or common compat syscall
0019  * __ia32_compat_sys_*() - 32-bit compat syscall
0020  * __x64_compat_sys_*()  - 64-bit X32 compat syscall
0021  *
0022  * The registers are decoded according to the ABI:
0023  * 64-bit: RDI, RSI, RDX, R10, R8, R9
0024  * 32-bit: EBX, ECX, EDX, ESI, EDI, EBP
0025  *
0026  * The stub then passes the decoded arguments to the __se_sys_*() wrapper to
0027  * perform sign-extension (omitted for zero-argument syscalls).  Finally the
0028  * arguments are passed to the __do_sys_*() function which is the actual
0029  * syscall.  These wrappers are marked as inline so the compiler can optimize
0030  * the functions where appropriate.
0031  *
0032  * Example assembly (slightly re-ordered for better readability):
0033  *
0034  * <__x64_sys_recv>:        <-- syscall with 4 parameters
0035  *  callq   <__fentry__>
0036  *
0037  *  mov 0x70(%rdi),%rdi <-- decode regs->di
0038  *  mov 0x68(%rdi),%rsi <-- decode regs->si
0039  *  mov 0x60(%rdi),%rdx <-- decode regs->dx
0040  *  mov 0x38(%rdi),%rcx <-- decode regs->r10
0041  *
0042  *  xor %r9d,%r9d   <-- clear %r9
0043  *  xor %r8d,%r8d   <-- clear %r8
0044  *
0045  *  callq   __sys_recvfrom  <-- do the actual work in __sys_recvfrom()
0046  *                  which takes 6 arguments
0047  *
0048  *  cltq            <-- extend return value to 64-bit
0049  *  retq            <-- return
0050  *
0051  * This approach avoids leaking random user-provided register content down
0052  * the call chain.
0053  */
0054 
0055 /* Mapping of registers to parameters for syscalls on x86-64 and x32 */
0056 #define SC_X86_64_REGS_TO_ARGS(x, ...)                  \
0057     __MAP(x,__SC_ARGS                       \
0058         ,,regs->di,,regs->si,,regs->dx              \
0059         ,,regs->r10,,regs->r8,,regs->r9)            \
0060 
0061 /* Mapping of registers to parameters for syscalls on i386 */
0062 #define SC_IA32_REGS_TO_ARGS(x, ...)                    \
0063     __MAP(x,__SC_ARGS                       \
0064           ,,(unsigned int)regs->bx,,(unsigned int)regs->cx      \
0065           ,,(unsigned int)regs->dx,,(unsigned int)regs->si      \
0066           ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
0067 
0068 #define __SYS_STUB0(abi, name)                      \
0069     long __##abi##_##name(const struct pt_regs *regs);      \
0070     ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);         \
0071     long __##abi##_##name(const struct pt_regs *regs)       \
0072         __alias(__do_##name);
0073 
0074 #define __SYS_STUBx(abi, name, ...)                 \
0075     long __##abi##_##name(const struct pt_regs *regs);      \
0076     ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);         \
0077     long __##abi##_##name(const struct pt_regs *regs)       \
0078     {                               \
0079         return __se_##name(__VA_ARGS__);            \
0080     }
0081 
0082 #define __COND_SYSCALL(abi, name)                   \
0083     __weak long __##abi##_##name(const struct pt_regs *__unused);   \
0084     __weak long __##abi##_##name(const struct pt_regs *__unused)    \
0085     {                               \
0086         return sys_ni_syscall();                \
0087     }
0088 
0089 #define __SYS_NI(abi, name)                     \
0090     SYSCALL_ALIAS(__##abi##_##name, sys_ni_posix_timers);
0091 
0092 #ifdef CONFIG_X86_64
0093 #define __X64_SYS_STUB0(name)                       \
0094     __SYS_STUB0(x64, sys_##name)
0095 
0096 #define __X64_SYS_STUBx(x, name, ...)                   \
0097     __SYS_STUBx(x64, sys##name,                 \
0098             SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
0099 
0100 #define __X64_COND_SYSCALL(name)                    \
0101     __COND_SYSCALL(x64, sys_##name)
0102 
0103 #define __X64_SYS_NI(name)                      \
0104     __SYS_NI(x64, sys_##name)
0105 #else /* CONFIG_X86_64 */
0106 #define __X64_SYS_STUB0(name)
0107 #define __X64_SYS_STUBx(x, name, ...)
0108 #define __X64_COND_SYSCALL(name)
0109 #define __X64_SYS_NI(name)
0110 #endif /* CONFIG_X86_64 */
0111 
0112 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
0113 #define __IA32_SYS_STUB0(name)                      \
0114     __SYS_STUB0(ia32, sys_##name)
0115 
0116 #define __IA32_SYS_STUBx(x, name, ...)                  \
0117     __SYS_STUBx(ia32, sys##name,                    \
0118             SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
0119 
0120 #define __IA32_COND_SYSCALL(name)                   \
0121     __COND_SYSCALL(ia32, sys_##name)
0122 
0123 #define __IA32_SYS_NI(name)                     \
0124     __SYS_NI(ia32, sys_##name)
0125 #else /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
0126 #define __IA32_SYS_STUB0(name)
0127 #define __IA32_SYS_STUBx(x, name, ...)
0128 #define __IA32_COND_SYSCALL(name)
0129 #define __IA32_SYS_NI(name)
0130 #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
0131 
0132 #ifdef CONFIG_IA32_EMULATION
0133 /*
0134  * For IA32 emulation, we need to handle "compat" syscalls *and* create
0135  * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
0136  * ia32 regs in the proper order for shared or "common" syscalls. As some
0137  * syscalls may not be implemented, we need to expand COND_SYSCALL in
0138  * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
0139  * case as well.
0140  */
0141 #define __IA32_COMPAT_SYS_STUB0(name)                   \
0142     __SYS_STUB0(ia32, compat_sys_##name)
0143 
0144 #define __IA32_COMPAT_SYS_STUBx(x, name, ...)               \
0145     __SYS_STUBx(ia32, compat_sys##name,             \
0146             SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
0147 
0148 #define __IA32_COMPAT_COND_SYSCALL(name)                \
0149     __COND_SYSCALL(ia32, compat_sys_##name)
0150 
0151 #define __IA32_COMPAT_SYS_NI(name)                  \
0152     __SYS_NI(ia32, compat_sys_##name)
0153 
0154 #else /* CONFIG_IA32_EMULATION */
0155 #define __IA32_COMPAT_SYS_STUB0(name)
0156 #define __IA32_COMPAT_SYS_STUBx(x, name, ...)
0157 #define __IA32_COMPAT_COND_SYSCALL(name)
0158 #define __IA32_COMPAT_SYS_NI(name)
0159 #endif /* CONFIG_IA32_EMULATION */
0160 
0161 
0162 #ifdef CONFIG_X86_X32_ABI
0163 /*
0164  * For the x32 ABI, we need to create a stub for compat_sys_*() which is aware
0165  * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
0166  * with x86_64 obviously do not need such care.
0167  */
0168 #define __X32_COMPAT_SYS_STUB0(name)                    \
0169     __SYS_STUB0(x64, compat_sys_##name)
0170 
0171 #define __X32_COMPAT_SYS_STUBx(x, name, ...)                \
0172     __SYS_STUBx(x64, compat_sys##name,              \
0173             SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
0174 
0175 #define __X32_COMPAT_COND_SYSCALL(name)                 \
0176     __COND_SYSCALL(x64, compat_sys_##name)
0177 
0178 #define __X32_COMPAT_SYS_NI(name)                   \
0179     __SYS_NI(x64, compat_sys_##name)
0180 #else /* CONFIG_X86_X32_ABI */
0181 #define __X32_COMPAT_SYS_STUB0(name)
0182 #define __X32_COMPAT_SYS_STUBx(x, name, ...)
0183 #define __X32_COMPAT_COND_SYSCALL(name)
0184 #define __X32_COMPAT_SYS_NI(name)
0185 #endif /* CONFIG_X86_X32_ABI */
0186 
0187 
0188 #ifdef CONFIG_COMPAT
0189 /*
0190  * Compat means IA32_EMULATION and/or X86_X32. As they use a different
0191  * mapping of registers to parameters, we need to generate stubs for each
0192  * of them.
0193  */
0194 #define COMPAT_SYSCALL_DEFINE0(name)                    \
0195     static long                         \
0196     __do_compat_sys_##name(const struct pt_regs *__unused);     \
0197     __IA32_COMPAT_SYS_STUB0(name)                   \
0198     __X32_COMPAT_SYS_STUB0(name)                    \
0199     static long                         \
0200     __do_compat_sys_##name(const struct pt_regs *__unused)
0201 
0202 #define COMPAT_SYSCALL_DEFINEx(x, name, ...)                    \
0203     static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));  \
0204     static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
0205     __IA32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__)               \
0206     __X32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__)                \
0207     static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))   \
0208     {                                   \
0209         return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\
0210     }                                   \
0211     static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
0212 
0213 /*
0214  * As some compat syscalls may not be implemented, we need to expand
0215  * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
0216  * kernel/time/posix-stubs.c to cover this case as well.
0217  */
0218 #define COND_SYSCALL_COMPAT(name)                   \
0219     __IA32_COMPAT_COND_SYSCALL(name)                \
0220     __X32_COMPAT_COND_SYSCALL(name)
0221 
0222 #define COMPAT_SYS_NI(name)                     \
0223     __IA32_COMPAT_SYS_NI(name)                  \
0224     __X32_COMPAT_SYS_NI(name)
0225 
0226 #endif /* CONFIG_COMPAT */
0227 
0228 #define __SYSCALL_DEFINEx(x, name, ...)                 \
0229     static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
0230     static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
0231     __X64_SYS_STUBx(x, name, __VA_ARGS__)               \
0232     __IA32_SYS_STUBx(x, name, __VA_ARGS__)              \
0233     static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))  \
0234     {                               \
0235         long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\
0236         __MAP(x,__SC_TEST,__VA_ARGS__);             \
0237         __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));   \
0238         return ret;                     \
0239     }                               \
0240     static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
0241 
0242 /*
0243  * As the generic SYSCALL_DEFINE0() macro does not decode any parameters for
0244  * obvious reasons, and passing struct pt_regs *regs to it in %rdi does not
0245  * hurt, we only need to re-define it here to keep the naming congruent to
0246  * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI()
0247  * macros to work correctly.
0248  */
0249 #define SYSCALL_DEFINE0(sname)                      \
0250     SYSCALL_METADATA(_##sname, 0);                  \
0251     static long __do_sys_##sname(const struct pt_regs *__unused);   \
0252     __X64_SYS_STUB0(sname)                      \
0253     __IA32_SYS_STUB0(sname)                     \
0254     static long __do_sys_##sname(const struct pt_regs *__unused)
0255 
0256 #define COND_SYSCALL(name)                      \
0257     __X64_COND_SYSCALL(name)                    \
0258     __IA32_COND_SYSCALL(name)
0259 
0260 #define SYS_NI(name)                            \
0261     __X64_SYS_NI(name)                      \
0262     __IA32_SYS_NI(name)
0263 
0264 
0265 /*
0266  * For VSYSCALLS, we need to declare these three syscalls with the new
0267  * pt_regs-based calling convention for in-kernel use.
0268  */
0269 long __x64_sys_getcpu(const struct pt_regs *regs);
0270 long __x64_sys_gettimeofday(const struct pt_regs *regs);
0271 long __x64_sys_time(const struct pt_regs *regs);
0272 
0273 #endif /* _ASM_X86_SYSCALL_WRAPPER_H */