xref: /openbmc/linux/arch/s390/include/asm/uaccess.h (revision 56edb6c2)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  *  S390 version
4  *    Copyright IBM Corp. 1999, 2000
5  *    Author(s): Hartmut Penner (hp@de.ibm.com),
6  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
7  *
8  *  Derived from "include/asm-i386/uaccess.h"
9  */
10 #ifndef __S390_UACCESS_H
11 #define __S390_UACCESS_H
12 
13 /*
14  * User space memory access functions
15  */
16 #include <asm/processor.h>
17 #include <asm/ctl_reg.h>
18 #include <asm/extable.h>
19 #include <asm/facility.h>
20 
21 void debug_user_asce(int exit);
22 
23 static inline int __range_ok(unsigned long addr, unsigned long size)
24 {
25 	return 1;
26 }
27 
28 #define __access_ok(addr, size)				\
29 ({							\
30 	__chk_user_ptr(addr);				\
31 	__range_ok((unsigned long)(addr), (size));	\
32 })
33 
34 #define access_ok(addr, size) __access_ok(addr, size)
35 
36 unsigned long __must_check
37 raw_copy_from_user(void *to, const void __user *from, unsigned long n);
38 
39 unsigned long __must_check
40 raw_copy_to_user(void __user *to, const void *from, unsigned long n);
41 
42 #ifndef CONFIG_KASAN
43 #define INLINE_COPY_FROM_USER
44 #define INLINE_COPY_TO_USER
45 #endif
46 
47 int __put_user_bad(void) __attribute__((noreturn));
48 int __get_user_bad(void) __attribute__((noreturn));
49 
50 union oac {
51 	unsigned int val;
52 	struct {
53 		struct {
54 			unsigned short key : 4;
55 			unsigned short	   : 4;
56 			unsigned short as  : 2;
57 			unsigned short	   : 4;
58 			unsigned short k   : 1;
59 			unsigned short a   : 1;
60 		} oac1;
61 		struct {
62 			unsigned short key : 4;
63 			unsigned short	   : 4;
64 			unsigned short as  : 2;
65 			unsigned short	   : 4;
66 			unsigned short k   : 1;
67 			unsigned short a   : 1;
68 		} oac2;
69 	};
70 };
71 
72 #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
73 
74 #define __put_get_user_asm(to, from, size, oac_spec)			\
75 ({									\
76 	int __rc;							\
77 									\
78 	asm volatile(							\
79 		"	lr	0,%[spec]\n"				\
80 		"0:	mvcos	%[_to],%[_from],%[_size]\n"		\
81 		"1:	xr	%[rc],%[rc]\n"				\
82 		"2:\n"							\
83 		".pushsection .fixup, \"ax\"\n"				\
84 		"3:	lhi	%[rc],%[retval]\n"			\
85 		"	jg	2b\n"					\
86 		".popsection\n"						\
87 		EX_TABLE(0b,3b) EX_TABLE(1b,3b)				\
88 		: [rc] "=&d" (__rc), [_to] "+Q" (*(to))			\
89 		: [_size] "d" (size), [_from] "Q" (*(from)),		\
90 		  [retval] "K" (-EFAULT), [spec] "d" (oac_spec.val)	\
91 		: "cc", "0");						\
92 	__rc;								\
93 })
94 
95 #define __put_user_asm(to, from, size)				\
96 	__put_get_user_asm(to, from, size, ((union oac) {	\
97 		.oac1.as = PSW_BITS_AS_SECONDARY,		\
98 		.oac1.a = 1					\
99 	}))
100 
101 #define __get_user_asm(to, from, size)				\
102 	__put_get_user_asm(to, from, size, ((union oac) {	\
103 		.oac2.as = PSW_BITS_AS_SECONDARY,		\
104 		.oac2.a = 1					\
105 	}))							\
106 
107 static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
108 {
109 	int rc;
110 
111 	switch (size) {
112 	case 1:
113 		rc = __put_user_asm((unsigned char __user *)ptr,
114 				    (unsigned char *)x,
115 				    size);
116 		break;
117 	case 2:
118 		rc = __put_user_asm((unsigned short __user *)ptr,
119 				    (unsigned short *)x,
120 				    size);
121 		break;
122 	case 4:
123 		rc = __put_user_asm((unsigned int __user *)ptr,
124 				    (unsigned int *)x,
125 				    size);
126 		break;
127 	case 8:
128 		rc = __put_user_asm((unsigned long __user *)ptr,
129 				    (unsigned long *)x,
130 				    size);
131 		break;
132 	default:
133 		__put_user_bad();
134 		break;
135 	}
136 	return rc;
137 }
138 
139 static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
140 {
141 	int rc;
142 
143 	switch (size) {
144 	case 1:
145 		rc = __get_user_asm((unsigned char *)x,
146 				    (unsigned char __user *)ptr,
147 				    size);
148 		break;
149 	case 2:
150 		rc = __get_user_asm((unsigned short *)x,
151 				    (unsigned short __user *)ptr,
152 				    size);
153 		break;
154 	case 4:
155 		rc = __get_user_asm((unsigned int *)x,
156 				    (unsigned int __user *)ptr,
157 				    size);
158 		break;
159 	case 8:
160 		rc = __get_user_asm((unsigned long *)x,
161 				    (unsigned long __user *)ptr,
162 				    size);
163 		break;
164 	default:
165 		__get_user_bad();
166 		break;
167 	}
168 	return rc;
169 }
170 
171 #else /* CONFIG_HAVE_MARCH_Z10_FEATURES */
172 
173 static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
174 {
175 	size = raw_copy_to_user(ptr, x, size);
176 	return size ? -EFAULT : 0;
177 }
178 
179 static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
180 {
181 	size = raw_copy_from_user(x, ptr, size);
182 	return size ? -EFAULT : 0;
183 }
184 
185 #endif /* CONFIG_HAVE_MARCH_Z10_FEATURES */
186 
187 /*
188  * These are the main single-value transfer routines.  They automatically
189  * use the right size if we just have the right pointer type.
190  */
191 #define __put_user(x, ptr) \
192 ({								\
193 	__typeof__(*(ptr)) __x = (x);				\
194 	int __pu_err = -EFAULT;					\
195         __chk_user_ptr(ptr);                                    \
196 	switch (sizeof (*(ptr))) {				\
197 	case 1:							\
198 	case 2:							\
199 	case 4:							\
200 	case 8:							\
201 		__pu_err = __put_user_fn(&__x, ptr,		\
202 					 sizeof(*(ptr)));	\
203 		break;						\
204 	default:						\
205 		__put_user_bad();				\
206 		break;						\
207 	}							\
208 	__builtin_expect(__pu_err, 0);				\
209 })
210 
211 #define put_user(x, ptr)					\
212 ({								\
213 	might_fault();						\
214 	__put_user(x, ptr);					\
215 })
216 
217 
218 #define __get_user(x, ptr)					\
219 ({								\
220 	int __gu_err = -EFAULT;					\
221 	__chk_user_ptr(ptr);					\
222 	switch (sizeof(*(ptr))) {				\
223 	case 1: {						\
224 		unsigned char __x = 0;				\
225 		__gu_err = __get_user_fn(&__x, ptr,		\
226 					 sizeof(*(ptr)));	\
227 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
228 		break;						\
229 	};							\
230 	case 2: {						\
231 		unsigned short __x = 0;				\
232 		__gu_err = __get_user_fn(&__x, ptr,		\
233 					 sizeof(*(ptr)));	\
234 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
235 		break;						\
236 	};							\
237 	case 4: {						\
238 		unsigned int __x = 0;				\
239 		__gu_err = __get_user_fn(&__x, ptr,		\
240 					 sizeof(*(ptr)));	\
241 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
242 		break;						\
243 	};							\
244 	case 8: {						\
245 		unsigned long long __x = 0;			\
246 		__gu_err = __get_user_fn(&__x, ptr,		\
247 					 sizeof(*(ptr)));	\
248 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
249 		break;						\
250 	};							\
251 	default:						\
252 		__get_user_bad();				\
253 		break;						\
254 	}							\
255 	__builtin_expect(__gu_err, 0);				\
256 })
257 
258 #define get_user(x, ptr)					\
259 ({								\
260 	might_fault();						\
261 	__get_user(x, ptr);					\
262 })
263 
264 /*
265  * Copy a null terminated string from userspace.
266  */
267 long __must_check strncpy_from_user(char *dst, const char __user *src, long count);
268 
269 long __must_check strnlen_user(const char __user *src, long count);
270 
271 /*
272  * Zero Userspace
273  */
274 unsigned long __must_check __clear_user(void __user *to, unsigned long size);
275 
276 static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
277 {
278 	might_fault();
279 	return __clear_user(to, n);
280 }
281 
282 int copy_to_user_real(void __user *dest, void *src, unsigned long count);
283 void *s390_kernel_write(void *dst, const void *src, size_t size);
284 
285 #define HAVE_GET_KERNEL_NOFAULT
286 
287 int __noreturn __put_kernel_bad(void);
288 
289 #define __put_kernel_asm(val, to, insn)					\
290 ({									\
291 	int __rc;							\
292 									\
293 	asm volatile(							\
294 		"0:   " insn "  %2,%1\n"				\
295 		"1:	xr	%0,%0\n"				\
296 		"2:\n"							\
297 		".pushsection .fixup, \"ax\"\n"				\
298 		"3:	lhi	%0,%3\n"				\
299 		"	jg	2b\n"					\
300 		".popsection\n"						\
301 		EX_TABLE(0b,3b) EX_TABLE(1b,3b)				\
302 		: "=d" (__rc), "+Q" (*(to))				\
303 		: "d" (val), "K" (-EFAULT)				\
304 		: "cc");						\
305 	__rc;								\
306 })
307 
308 #define __put_kernel_nofault(dst, src, type, err_label)			\
309 do {									\
310 	u64 __x = (u64)(*((type *)(src)));				\
311 	int __pk_err;							\
312 									\
313 	switch (sizeof(type)) {						\
314 	case 1:								\
315 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "stc"); \
316 		break;							\
317 	case 2:								\
318 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "sth"); \
319 		break;							\
320 	case 4:								\
321 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "st");	\
322 		break;							\
323 	case 8:								\
324 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "stg"); \
325 		break;							\
326 	default:							\
327 		__pk_err = __put_kernel_bad();				\
328 		break;							\
329 	}								\
330 	if (unlikely(__pk_err))						\
331 		goto err_label;						\
332 } while (0)
333 
334 int __noreturn __get_kernel_bad(void);
335 
336 #define __get_kernel_asm(val, from, insn)				\
337 ({									\
338 	int __rc;							\
339 									\
340 	asm volatile(							\
341 		"0:   " insn "  %1,%2\n"				\
342 		"1:	xr	%0,%0\n"				\
343 		"2:\n"							\
344 		".pushsection .fixup, \"ax\"\n"				\
345 		"3:	lhi	%0,%3\n"				\
346 		"	jg	2b\n"					\
347 		".popsection\n"						\
348 		EX_TABLE(0b,3b) EX_TABLE(1b,3b)				\
349 		: "=d" (__rc), "+d" (val)				\
350 		: "Q" (*(from)), "K" (-EFAULT)				\
351 		: "cc");						\
352 	__rc;								\
353 })
354 
355 #define __get_kernel_nofault(dst, src, type, err_label)			\
356 do {									\
357 	int __gk_err;							\
358 									\
359 	switch (sizeof(type)) {						\
360 	case 1: {							\
361 		u8 __x = 0;						\
362 									\
363 		__gk_err = __get_kernel_asm(__x, (type *)(src), "ic");	\
364 		*((type *)(dst)) = (type)__x;				\
365 		break;							\
366 	};								\
367 	case 2: {							\
368 		u16 __x = 0;						\
369 									\
370 		__gk_err = __get_kernel_asm(__x, (type *)(src), "lh");	\
371 		*((type *)(dst)) = (type)__x;				\
372 		break;							\
373 	};								\
374 	case 4: {							\
375 		u32 __x = 0;						\
376 									\
377 		__gk_err = __get_kernel_asm(__x, (type *)(src), "l");	\
378 		*((type *)(dst)) = (type)__x;				\
379 		break;							\
380 	};								\
381 	case 8: {							\
382 		u64 __x = 0;						\
383 									\
384 		__gk_err = __get_kernel_asm(__x, (type *)(src), "lg");	\
385 		*((type *)(dst)) = (type)__x;				\
386 		break;							\
387 	};								\
388 	default:							\
389 		__gk_err = __get_kernel_bad();				\
390 		break;							\
391 	}								\
392 	if (unlikely(__gk_err))						\
393 		goto err_label;						\
394 } while (0)
395 
396 #endif /* __S390_UACCESS_H */
397