xref: /linux/arch/x86/include/asm/vdso/sys_call.h (revision a0636d4c3ad0da0cd6069eb6fef5d2b7d3449378)
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	"call __kernel_vsyscall"
24 # define __sys_clobber	"memory"
25 # define __sys_nr(x,y)	__NR_ ## x ## y
26 # define __sys_reg1	"ebx"
27 # define __sys_reg2	"ecx"
28 # define __sys_reg3	"edx"
29 # define __sys_reg4	"esi"
30 # define __sys_reg5	"edi"
31 #endif
32 
33 /*
34  * Example usage:
35  *
36  * result = VDSO_SYSCALL3(foo,64,x,y,z);
37  *
38  * ... calls foo(x,y,z) on 64 bits, and foo64(x,y,z) on 32 bits.
39  *
40  * VDSO_SYSCALL6() is currently missing, because it would require
41  * special handling for %ebp on 32 bits when the vdso is compiled with
42  * frame pointers enabled (the default on 32 bits.) Add it as a special
43  * case when and if it becomes necessary.
44  */
45 #define _VDSO_SYSCALL(name,suf32,...)					\
46 	({								\
47 		long _sys_num_ret = __sys_nr(name,suf32);		\
48 		asm_inline volatile(					\
49 			__sys_instr					\
50 			: "+a" (_sys_num_ret)				\
51 			: __VA_ARGS__					\
52 			: __sys_clobber);				\
53 		_sys_num_ret;						\
54 	})
55 
56 #define VDSO_SYSCALL0(name,suf32)					\
57 	_VDSO_SYSCALL(name,suf32)
58 #define VDSO_SYSCALL1(name,suf32,a1)					\
59 	({								\
60 		register long _sys_arg1 asm(__sys_reg1) = (long)(a1);	\
61 		_VDSO_SYSCALL(name,suf32,				\
62 			      "r" (_sys_arg1));				\
63 	})
64 #define VDSO_SYSCALL2(name,suf32,a1,a2)				\
65 	({								\
66 		register long _sys_arg1 asm(__sys_reg1) = (long)(a1);	\
67 		register long _sys_arg2 asm(__sys_reg2) = (long)(a2);	\
68 		_VDSO_SYSCALL(name,suf32,				\
69 			      "r" (_sys_arg1), "r" (_sys_arg2));	\
70 	})
71 #define VDSO_SYSCALL3(name,suf32,a1,a2,a3)				\
72 	({								\
73 		register long _sys_arg1 asm(__sys_reg1) = (long)(a1);	\
74 		register long _sys_arg2 asm(__sys_reg2) = (long)(a2);	\
75 		register long _sys_arg3 asm(__sys_reg3) = (long)(a3);	\
76 		_VDSO_SYSCALL(name,suf32,				\
77 			      "r" (_sys_arg1), "r" (_sys_arg2),		\
78 			      "r" (_sys_arg3));				\
79 	})
80 #define VDSO_SYSCALL4(name,suf32,a1,a2,a3,a4)				\
81 	({								\
82 		register long _sys_arg1 asm(__sys_reg1) = (long)(a1);	\
83 		register long _sys_arg2 asm(__sys_reg2) = (long)(a2);	\
84 		register long _sys_arg3 asm(__sys_reg3) = (long)(a3);	\
85 		register long _sys_arg4 asm(__sys_reg4) = (long)(a4);	\
86 		_VDSO_SYSCALL(name,suf32,				\
87 			      "r" (_sys_arg1), "r" (_sys_arg2),		\
88 			      "r" (_sys_arg3), "r" (_sys_arg4));	\
89 	})
90 #define VDSO_SYSCALL5(name,suf32,a1,a2,a3,a4,a5)			\
91 	({								\
92 		register long _sys_arg1 asm(__sys_reg1) = (long)(a1);	\
93 		register long _sys_arg2 asm(__sys_reg2) = (long)(a2);	\
94 		register long _sys_arg3 asm(__sys_reg3) = (long)(a3);	\
95 		register long _sys_arg4 asm(__sys_reg4) = (long)(a4);	\
96 		register long _sys_arg5 asm(__sys_reg5) = (long)(a5);	\
97 		_VDSO_SYSCALL(name,suf32,				\
98 			      "r" (_sys_arg1), "r" (_sys_arg2),		\
99 			      "r" (_sys_arg3), "r" (_sys_arg4),		\
100 			      "r" (_sys_arg5));				\
101 	})
102 
103 #endif /* X86_VDSO_SYS_CALL_H */
104