| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * Macros for issuing an inline system call from the vDSO. | |
| */ | |
| #ifndef X86_ASM_VDSO_SYS_CALL_H | |
| #define X86_ASM_VDSO_SYS_CALL_H | |
| #include <linux/compiler.h> | |
| #include <asm/cpufeatures.h> | |
| #include <asm/alternative.h> | |
| #ifdef CONFIG_X86_64 | |
| # define __sys_instr "syscall" | |
| # define __sys_clobber "rcx", "r11", "memory" | |
| # define __sys_nr(x,y) __NR_ ## x | |
| # define __sys_reg1 "rdi" | |
| # define __sys_reg2 "rsi" | |
| # define __sys_reg3 "rdx" | |
| # define __sys_reg4 "r10" | |
| # define __sys_reg5 "r8" | |
| #else | |
| # define __sys_instr ALTERNATIVE("ds;ds;ds;int $0x80", \ | |
| "call __kernel_vsyscall", \ | |
| X86_FEATURE_SYSFAST32) | |
| # define __sys_clobber "memory" | |
| # define __sys_nr(x,y) __NR_ ## x ## y | |
| # define __sys_reg1 "ebx" | |
| # define __sys_reg2 "ecx" | |
| # define __sys_reg3 "edx" | |
| # define __sys_reg4 "esi" | |
| # define __sys_reg5 "edi" | |
| #endif | |
| /* | |
| * Example usage: | |
| * | |
| * result = VDSO_SYSCALL3(foo,64,x,y,z); | |
| * | |
| * ... calls foo(x,y,z) on 64 bits, and foo64(x,y,z) on 32 bits. | |
| * | |
| * VDSO_SYSCALL6() is currently missing, because it would require | |
| * special handling for %ebp on 32 bits when the vdso is compiled with | |
| * frame pointers enabled (the default on 32 bits.) Add it as a special | |
| * case when and if it becomes necessary. | |
| */ | |
| #define _VDSO_SYSCALL(name,suf32,...) \ | |
| ({ \ | |
| long _sys_num_ret = __sys_nr(name,suf32); \ | |
| asm_inline volatile( \ | |
| __sys_instr \ | |
| : "+a" (_sys_num_ret) \ | |
| : __VA_ARGS__ \ | |
| : __sys_clobber); \ | |
| _sys_num_ret; \ | |
| }) | |
| #define VDSO_SYSCALL0(name,suf32) \ | |
| _VDSO_SYSCALL(name,suf32) | |
| #define VDSO_SYSCALL1(name,suf32,a1) \ | |
| ({ \ | |
| register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ | |
| _VDSO_SYSCALL(name,suf32, \ | |
| "r" (_sys_arg1)); \ | |
| }) | |
| #define VDSO_SYSCALL2(name,suf32,a1,a2) \ | |
| ({ \ | |
| register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ | |
| register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ | |
| _VDSO_SYSCALL(name,suf32, \ | |
| "r" (_sys_arg1), "r" (_sys_arg2)); \ | |
| }) | |
| #define VDSO_SYSCALL3(name,suf32,a1,a2,a3) \ | |
| ({ \ | |
| register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ | |
| register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ | |
| register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \ | |
| _VDSO_SYSCALL(name,suf32, \ | |
| "r" (_sys_arg1), "r" (_sys_arg2), \ | |
| "r" (_sys_arg3)); \ | |
| }) | |
| #define VDSO_SYSCALL4(name,suf32,a1,a2,a3,a4) \ | |
| ({ \ | |
| register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ | |
| register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ | |
| register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \ | |
| register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \ | |
| _VDSO_SYSCALL(name,suf32, \ | |
| "r" (_sys_arg1), "r" (_sys_arg2), \ | |
| "r" (_sys_arg3), "r" (_sys_arg4)); \ | |
| }) | |
| #define VDSO_SYSCALL5(name,suf32,a1,a2,a3,a4,a5) \ | |
| ({ \ | |
| register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ | |
| register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ | |
| register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \ | |
| register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \ | |
| register long _sys_arg5 asm(__sys_reg5) = (long)(a5); \ | |
| _VDSO_SYSCALL(name,suf32, \ | |
| "r" (_sys_arg1), "r" (_sys_arg2), \ | |
| "r" (_sys_arg3), "r" (_sys_arg4), \ | |
| "r" (_sys_arg5)); \ | |
| }) | |
| #endif /* X86_VDSO_SYS_CALL_H */ |