xref: /linux/arch/x86/include/asm/vdso/sys_call.h (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
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