1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * syscall_wrapper.h - s390 specific wrappers to syscall definitions
4  *
5  */
6 
7 #ifndef _ASM_S390_SYSCALL_WRAPPER_H
8 #define _ASM_S390_SYSCALL_WRAPPER_H
9 
10 #define __SC_TYPE(t, a) t
11 
12 #define SYSCALL_PT_ARG6(regs, m, t1, t2, t3, t4, t5, t6)\
13 	SYSCALL_PT_ARG5(regs, m, t1, t2, t3, t4, t5),	\
14 		m(t6, (regs->gprs[7]))
15 
16 #define SYSCALL_PT_ARG5(regs, m, t1, t2, t3, t4, t5)	\
17 	SYSCALL_PT_ARG4(regs, m, t1, t2, t3, t4),	\
18 		m(t5, (regs->gprs[6]))
19 
20 #define SYSCALL_PT_ARG4(regs, m, t1, t2, t3, t4)	\
21 	SYSCALL_PT_ARG3(regs, m, t1, t2, t3),		\
22 		m(t4, (regs->gprs[5]))
23 
24 #define SYSCALL_PT_ARG3(regs, m, t1, t2, t3)		\
25 	SYSCALL_PT_ARG2(regs, m, t1, t2),		\
26 		m(t3, (regs->gprs[4]))
27 
28 #define SYSCALL_PT_ARG2(regs, m, t1, t2)		\
29 	SYSCALL_PT_ARG1(regs, m, t1),			\
30 		m(t2, (regs->gprs[3]))
31 
32 #define SYSCALL_PT_ARG1(regs, m, t1)			\
33 		m(t1, (regs->orig_gpr2))
34 
35 #define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__)
36 
37 #ifdef CONFIG_COMPAT
38 #define __SC_COMPAT_TYPE(t, a) \
39 	__typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a
40 
41 #define __SC_COMPAT_CAST(t, a)						\
42 ({									\
43 	long __ReS = a;							\
44 									\
45 	BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) &&		\
46 		     !__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t) &&		\
47 		     !__TYPE_IS_LL(t));					\
48 	if (__TYPE_IS_L(t))						\
49 		__ReS = (s32)a;						\
50 	if (__TYPE_IS_UL(t))						\
51 		__ReS = (u32)a;						\
52 	if (__TYPE_IS_PTR(t))						\
53 		__ReS = a & 0x7fffffff;					\
54 	if (__TYPE_IS_LL(t))						\
55 		return -ENOSYS;						\
56 	(t)__ReS;							\
57 })
58 
59 #define __S390_SYS_STUBx(x, name, ...)						\
60 	long __s390_sys##name(struct pt_regs *regs);				\
61 	ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO);				\
62 	long __s390_sys##name(struct pt_regs *regs)				\
63 	{									\
64 		long ret = __do_sys##name(SYSCALL_PT_ARGS(x, regs,		\
65 			__SC_COMPAT_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__)));	\
66 		__MAP(x,__SC_TEST,__VA_ARGS__);					\
67 		return ret;							\
68 	}
69 
70 /*
71  * To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias
72  * named __s390x_sys_*()
73  */
74 #define COMPAT_SYSCALL_DEFINE0(sname)					\
75 	SYSCALL_METADATA(_##sname, 0);					\
76 	long __s390_compat_sys_##sname(void);				\
77 	ALLOW_ERROR_INJECTION(__s390_compat_sys_##sname, ERRNO);	\
78 	long __s390_compat_sys_##sname(void)
79 
80 #define SYSCALL_DEFINE0(sname)						\
81 	SYSCALL_METADATA(_##sname, 0);					\
82 	long __s390x_sys_##sname(void);					\
83 	ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO);		\
84 	long __s390_sys_##sname(void)					\
85 		__attribute__((alias(__stringify(__s390x_sys_##sname)))); \
86 	long __s390x_sys_##sname(void)
87 
88 #define COND_SYSCALL(name)						\
89 	cond_syscall(__s390x_sys_##name);				\
90 	cond_syscall(__s390_sys_##name)
91 
92 #define SYS_NI(name)							\
93 	SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers);		\
94 	SYSCALL_ALIAS(__s390_sys_##name, sys_ni_posix_timers)
95 
96 #define COMPAT_SYSCALL_DEFINEx(x, name, ...)						\
97 	__diag_push();									\
98 	__diag_ignore(GCC, 8, "-Wattribute-alias",					\
99 		      "Type aliasing is used to sanitize syscall arguments");		\
100 	long __s390_compat_sys##name(struct pt_regs *regs);				\
101 	long __s390_compat_sys##name(struct pt_regs *regs)				\
102 		__attribute__((alias(__stringify(__se_compat_sys##name))));		\
103 	ALLOW_ERROR_INJECTION(__s390_compat_sys##name, ERRNO);				\
104 	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));	\
105 	long __se_compat_sys##name(struct pt_regs *regs);				\
106 	long __se_compat_sys##name(struct pt_regs *regs)				\
107 	{										\
108 		long ret = __do_compat_sys##name(SYSCALL_PT_ARGS(x, regs, __SC_DELOUSE,	\
109 						 __MAP(x, __SC_TYPE, __VA_ARGS__)));	\
110 		__MAP(x,__SC_TEST,__VA_ARGS__);						\
111 		return ret;								\
112 	}										\
113 	__diag_pop();									\
114 	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
115 
116 /*
117  * As some compat syscalls may not be implemented, we need to expand
118  * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
119  * kernel/time/posix-stubs.c to cover this case as well.
120  */
121 #define COND_SYSCALL_COMPAT(name)					\
122 	cond_syscall(__s390_compat_sys_##name)
123 
124 #define COMPAT_SYS_NI(name)						\
125 	SYSCALL_ALIAS(__s390_compat_sys_##name, sys_ni_posix_timers)
126 
127 #else /* CONFIG_COMPAT */
128 
129 #define __S390_SYS_STUBx(x, fullname, name, ...)
130 
131 #define SYSCALL_DEFINE0(sname)						\
132 	SYSCALL_METADATA(_##sname, 0);					\
133 	long __s390x_sys_##sname(void);					\
134 	ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO);		\
135 	long __s390x_sys_##sname(void)
136 
137 #define COND_SYSCALL(name)						\
138 	cond_syscall(__s390x_sys_##name)
139 
140 #define SYS_NI(name)							\
141 	SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers);
142 
143 #endif /* CONFIG_COMPAT */
144 
145 #define __SYSCALL_DEFINEx(x, name, ...)							\
146 	__diag_push();									\
147 	__diag_ignore(GCC, 8, "-Wattribute-alias",					\
148 		      "Type aliasing is used to sanitize syscall arguments");		\
149 	long __s390x_sys##name(struct pt_regs *regs)					\
150 		__attribute__((alias(__stringify(__se_sys##name))));			\
151 	ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO);				\
152 	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));		\
153 	long __se_sys##name(struct pt_regs *regs);					\
154 	__S390_SYS_STUBx(x, name, __VA_ARGS__)						\
155 	long __se_sys##name(struct pt_regs *regs)					\
156 	{										\
157 		long ret = __do_sys##name(SYSCALL_PT_ARGS(x, regs,			\
158 				    __SC_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__)));	\
159 		__MAP(x,__SC_TEST,__VA_ARGS__);						\
160 		return ret;								\
161 	}										\
162 	__diag_pop();									\
163 	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
164 
165 #endif /* _ASM_S390_SYSCALL_WRAPPER_H */
166