1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Macros for issuing an inline system call from the vDSO. 4 */ 5 6 #ifndef X86_ASM_VDSO_SYS_CALL_H 7 #define X86_ASM_VDSO_SYS_CALL_H 8 9 #include <linux/compiler.h> 10 #include <asm/cpufeatures.h> 11 #include <asm/alternative.h> 12 13 #ifdef CONFIG_X86_64 14 # define __sys_instr "syscall" 15 # define __sys_clobber "rcx", "r11", "memory" 16 # define __sys_nr(x,y) __NR_ ## x 17 # define __sys_reg1 "rdi" 18 # define __sys_reg2 "rsi" 19 # define __sys_reg3 "rdx" 20 # define __sys_reg4 "r10" 21 # define __sys_reg5 "r8" 22 #else 23 # define __sys_instr ALTERNATIVE("ds;ds;ds;int $0x80", \ 24 "call __kernel_vsyscall", \ 25 X86_FEATURE_SYSFAST32) 26 # define __sys_clobber "memory" 27 # define __sys_nr(x,y) __NR_ ## x ## y 28 # define __sys_reg1 "ebx" 29 # define __sys_reg2 "ecx" 30 # define __sys_reg3 "edx" 31 # define __sys_reg4 "esi" 32 # define __sys_reg5 "edi" 33 #endif 34 35 /* 36 * Example usage: 37 * 38 * result = VDSO_SYSCALL3(foo,64,x,y,z); 39 * 40 * ... calls foo(x,y,z) on 64 bits, and foo64(x,y,z) on 32 bits. 41 * 42 * VDSO_SYSCALL6() is currently missing, because it would require 43 * special handling for %ebp on 32 bits when the vdso is compiled with 44 * frame pointers enabled (the default on 32 bits.) Add it as a special 45 * case when and if it becomes necessary. 46 */ 47 #define _VDSO_SYSCALL(name,suf32,...) \ 48 ({ \ 49 long _sys_num_ret = __sys_nr(name,suf32); \ 50 asm_inline volatile( \ 51 __sys_instr \ 52 : "+a" (_sys_num_ret) \ 53 : __VA_ARGS__ \ 54 : __sys_clobber); \ 55 _sys_num_ret; \ 56 }) 57 58 #define VDSO_SYSCALL0(name,suf32) \ 59 _VDSO_SYSCALL(name,suf32) 60 #define VDSO_SYSCALL1(name,suf32,a1) \ 61 ({ \ 62 register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ 63 _VDSO_SYSCALL(name,suf32, \ 64 "r" (_sys_arg1)); \ 65 }) 66 #define VDSO_SYSCALL2(name,suf32,a1,a2) \ 67 ({ \ 68 register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ 69 register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ 70 _VDSO_SYSCALL(name,suf32, \ 71 "r" (_sys_arg1), "r" (_sys_arg2)); \ 72 }) 73 #define VDSO_SYSCALL3(name,suf32,a1,a2,a3) \ 74 ({ \ 75 register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ 76 register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ 77 register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \ 78 _VDSO_SYSCALL(name,suf32, \ 79 "r" (_sys_arg1), "r" (_sys_arg2), \ 80 "r" (_sys_arg3)); \ 81 }) 82 #define VDSO_SYSCALL4(name,suf32,a1,a2,a3,a4) \ 83 ({ \ 84 register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ 85 register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ 86 register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \ 87 register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \ 88 _VDSO_SYSCALL(name,suf32, \ 89 "r" (_sys_arg1), "r" (_sys_arg2), \ 90 "r" (_sys_arg3), "r" (_sys_arg4)); \ 91 }) 92 #define VDSO_SYSCALL5(name,suf32,a1,a2,a3,a4,a5) \ 93 ({ \ 94 register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \ 95 register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \ 96 register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \ 97 register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \ 98 register long _sys_arg5 asm(__sys_reg5) = (long)(a5); \ 99 _VDSO_SYSCALL(name,suf32, \ 100 "r" (_sys_arg1), "r" (_sys_arg2), \ 101 "r" (_sys_arg3), "r" (_sys_arg4), \ 102 "r" (_sys_arg5)); \ 103 }) 104 105 #endif /* X86_VDSO_SYS_CALL_H */ 106