xref: /openbmc/linux/arch/s390/include/asm/uaccess.h (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2c6557e7fSMartin Schwidefsky /*
3c6557e7fSMartin Schwidefsky  *  S390 version
4a53c8fabSHeiko Carstens  *    Copyright IBM Corp. 1999, 2000
5c6557e7fSMartin Schwidefsky  *    Author(s): Hartmut Penner (hp@de.ibm.com),
6c6557e7fSMartin Schwidefsky  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
7c6557e7fSMartin Schwidefsky  *
8c6557e7fSMartin Schwidefsky  *  Derived from "include/asm-i386/uaccess.h"
9c6557e7fSMartin Schwidefsky  */
10c6557e7fSMartin Schwidefsky #ifndef __S390_UACCESS_H
11c6557e7fSMartin Schwidefsky #define __S390_UACCESS_H
12c6557e7fSMartin Schwidefsky 
13c6557e7fSMartin Schwidefsky /*
14c6557e7fSMartin Schwidefsky  * User space memory access functions
15c6557e7fSMartin Schwidefsky  */
16d09a307fSHeiko Carstens #include <asm/asm-extable.h>
17b5a882fcSHeiko Carstens #include <asm/processor.h>
18a0616cdeSDavid Howells #include <asm/ctl_reg.h>
19e70f1d59SAl Viro #include <asm/extable.h>
200aaba41bSMartin Schwidefsky #include <asm/facility.h>
2112700c17SArnd Bergmann #include <asm-generic/access_ok.h>
22c6557e7fSMartin Schwidefsky 
2356e62a73SSven Schnelle void debug_user_asce(int exit);
24062e5279SHeiko Carstens 
2537096003SAl Viro unsigned long __must_check
2637096003SAl Viro raw_copy_from_user(void *to, const void __user *from, unsigned long n);
27c6557e7fSMartin Schwidefsky 
2837096003SAl Viro unsigned long __must_check
2937096003SAl Viro raw_copy_to_user(void __user *to, const void *from, unsigned long n);
30c6557e7fSMartin Schwidefsky 
3101eb42afSVasily Gorbik #ifndef CONFIG_KASAN
3237096003SAl Viro #define INLINE_COPY_FROM_USER
3337096003SAl Viro #define INLINE_COPY_TO_USER
3401eb42afSVasily Gorbik #endif
356c1e3e79SGerald Schaefer 
361a82f6abSJanis Schoetterl-Glausch unsigned long __must_check
371a82f6abSJanis Schoetterl-Glausch _copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key);
381a82f6abSJanis Schoetterl-Glausch 
391a82f6abSJanis Schoetterl-Glausch static __always_inline unsigned long __must_check
copy_from_user_key(void * to,const void __user * from,unsigned long n,unsigned long key)401a82f6abSJanis Schoetterl-Glausch copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key)
411a82f6abSJanis Schoetterl-Glausch {
420e3c3b90SAl Viro 	if (check_copy_size(to, n, false))
431a82f6abSJanis Schoetterl-Glausch 		n = _copy_from_user_key(to, from, n, key);
441a82f6abSJanis Schoetterl-Glausch 	return n;
451a82f6abSJanis Schoetterl-Glausch }
461a82f6abSJanis Schoetterl-Glausch 
471a82f6abSJanis Schoetterl-Glausch unsigned long __must_check
481a82f6abSJanis Schoetterl-Glausch _copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key);
491a82f6abSJanis Schoetterl-Glausch 
501a82f6abSJanis Schoetterl-Glausch static __always_inline unsigned long __must_check
copy_to_user_key(void __user * to,const void * from,unsigned long n,unsigned long key)511a82f6abSJanis Schoetterl-Glausch copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key)
521a82f6abSJanis Schoetterl-Glausch {
530e3c3b90SAl Viro 	if (check_copy_size(from, n, true))
541a82f6abSJanis Schoetterl-Glausch 		n = _copy_to_user_key(to, from, n, key);
551a82f6abSJanis Schoetterl-Glausch 	return n;
561a82f6abSJanis Schoetterl-Glausch }
571a82f6abSJanis Schoetterl-Glausch 
58012a224eSNico Boehr union oac {
59012a224eSNico Boehr 	unsigned int val;
60012a224eSNico Boehr 	struct {
61012a224eSNico Boehr 		struct {
62012a224eSNico Boehr 			unsigned short key : 4;
63012a224eSNico Boehr 			unsigned short	   : 4;
64012a224eSNico Boehr 			unsigned short as  : 2;
65012a224eSNico Boehr 			unsigned short	   : 4;
66012a224eSNico Boehr 			unsigned short k   : 1;
67012a224eSNico Boehr 			unsigned short a   : 1;
68012a224eSNico Boehr 		} oac1;
69012a224eSNico Boehr 		struct {
70012a224eSNico Boehr 			unsigned short key : 4;
71012a224eSNico Boehr 			unsigned short	   : 4;
72012a224eSNico Boehr 			unsigned short as  : 2;
73012a224eSNico Boehr 			unsigned short	   : 4;
74012a224eSNico Boehr 			unsigned short k   : 1;
75012a224eSNico Boehr 			unsigned short a   : 1;
76012a224eSNico Boehr 		} oac2;
77012a224eSNico Boehr 	};
78012a224eSNico Boehr };
79012a224eSNico Boehr 
80a0e3a44bSHeiko Carstens int __noreturn __put_user_bad(void);
81a0e3a44bSHeiko Carstens 
82454ede3fSHeiko Carstens #define __put_user_asm(to, from, size)					\
83c9ca7841SHeiko Carstens ({									\
84454ede3fSHeiko Carstens 	union oac __oac_spec = {					\
85454ede3fSHeiko Carstens 		.oac1.as = PSW_BITS_AS_SECONDARY,			\
86454ede3fSHeiko Carstens 		.oac1.a = 1,						\
87454ede3fSHeiko Carstens 	};								\
88c9ca7841SHeiko Carstens 	int __rc;							\
89c9ca7841SHeiko Carstens 									\
90c9ca7841SHeiko Carstens 	asm volatile(							\
91012a224eSNico Boehr 		"	lr	0,%[spec]\n"				\
92dbb8864bSHeiko Carstens 		"0:	mvcos	%[_to],%[_from],%[_size]\n"		\
93dbb8864bSHeiko Carstens 		"1:	xr	%[rc],%[rc]\n"				\
94c9ca7841SHeiko Carstens 		"2:\n"							\
95454ede3fSHeiko Carstens 		EX_TABLE_UA_STORE(0b, 2b, %[rc])			\
96454ede3fSHeiko Carstens 		EX_TABLE_UA_STORE(1b, 2b, %[rc])			\
97dbb8864bSHeiko Carstens 		: [rc] "=&d" (__rc), [_to] "+Q" (*(to))			\
98dbb8864bSHeiko Carstens 		: [_size] "d" (size), [_from] "Q" (*(from)),		\
99454ede3fSHeiko Carstens 		  [spec] "d" (__oac_spec.val)				\
100dbb8864bSHeiko Carstens 		: "cc", "0");						\
101c9ca7841SHeiko Carstens 	__rc;								\
102c9ca7841SHeiko Carstens })
103c9ca7841SHeiko Carstens 
__put_user_fn(void * x,void __user * ptr,unsigned long size)104062795fcSChristian Borntraeger static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
105dc4aace1SHeiko Carstens {
106dc4aace1SHeiko Carstens 	int rc;
107dc4aace1SHeiko Carstens 
108dc4aace1SHeiko Carstens 	switch (size) {
109dc4aace1SHeiko Carstens 	case 1:
110012a224eSNico Boehr 		rc = __put_user_asm((unsigned char __user *)ptr,
111dc4aace1SHeiko Carstens 				    (unsigned char *)x,
112012a224eSNico Boehr 				    size);
113dc4aace1SHeiko Carstens 		break;
114dc4aace1SHeiko Carstens 	case 2:
115012a224eSNico Boehr 		rc = __put_user_asm((unsigned short __user *)ptr,
116dc4aace1SHeiko Carstens 				    (unsigned short *)x,
117012a224eSNico Boehr 				    size);
118dc4aace1SHeiko Carstens 		break;
119dc4aace1SHeiko Carstens 	case 4:
120012a224eSNico Boehr 		rc = __put_user_asm((unsigned int __user *)ptr,
121dc4aace1SHeiko Carstens 				    (unsigned int *)x,
122012a224eSNico Boehr 				    size);
123dc4aace1SHeiko Carstens 		break;
124dc4aace1SHeiko Carstens 	case 8:
125012a224eSNico Boehr 		rc = __put_user_asm((unsigned long __user *)ptr,
126dc4aace1SHeiko Carstens 				    (unsigned long *)x,
127012a224eSNico Boehr 				    size);
128dc4aace1SHeiko Carstens 		break;
129db527397SHeiko Carstens 	default:
130db527397SHeiko Carstens 		__put_user_bad();
131db527397SHeiko Carstens 		break;
1320b925159SHeiko Carstens 	}
133dc4aace1SHeiko Carstens 	return rc;
134dc4aace1SHeiko Carstens }
135dc4aace1SHeiko Carstens 
136a0e3a44bSHeiko Carstens int __noreturn __get_user_bad(void);
137a0e3a44bSHeiko Carstens 
138454ede3fSHeiko Carstens #define __get_user_asm(to, from, size)					\
139454ede3fSHeiko Carstens ({									\
140454ede3fSHeiko Carstens 	union oac __oac_spec = {					\
141454ede3fSHeiko Carstens 		.oac2.as = PSW_BITS_AS_SECONDARY,			\
142454ede3fSHeiko Carstens 		.oac2.a = 1,						\
143454ede3fSHeiko Carstens 	};								\
144454ede3fSHeiko Carstens 	int __rc;							\
145454ede3fSHeiko Carstens 									\
146454ede3fSHeiko Carstens 	asm volatile(							\
147454ede3fSHeiko Carstens 		"	lr	0,%[spec]\n"				\
148454ede3fSHeiko Carstens 		"0:	mvcos	0(%[_to]),%[_from],%[_size]\n"		\
149454ede3fSHeiko Carstens 		"1:	xr	%[rc],%[rc]\n"				\
150454ede3fSHeiko Carstens 		"2:\n"							\
151454ede3fSHeiko Carstens 		EX_TABLE_UA_LOAD_MEM(0b, 2b, %[rc], %[_to], %[_ksize])	\
152454ede3fSHeiko Carstens 		EX_TABLE_UA_LOAD_MEM(1b, 2b, %[rc], %[_to], %[_ksize])	\
153454ede3fSHeiko Carstens 		: [rc] "=&d" (__rc), "=Q" (*(to))			\
154454ede3fSHeiko Carstens 		: [_size] "d" (size), [_from] "Q" (*(from)),		\
155454ede3fSHeiko Carstens 		  [spec] "d" (__oac_spec.val), [_to] "a" (to),		\
156454ede3fSHeiko Carstens 		  [_ksize] "K" (size)					\
157454ede3fSHeiko Carstens 		: "cc", "0");						\
158454ede3fSHeiko Carstens 	__rc;								\
159454ede3fSHeiko Carstens })
160454ede3fSHeiko Carstens 
__get_user_fn(void * x,const void __user * ptr,unsigned long size)161062795fcSChristian Borntraeger static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
162dc4aace1SHeiko Carstens {
163dc4aace1SHeiko Carstens 	int rc;
164dc4aace1SHeiko Carstens 
165dc4aace1SHeiko Carstens 	switch (size) {
166dc4aace1SHeiko Carstens 	case 1:
167012a224eSNico Boehr 		rc = __get_user_asm((unsigned char *)x,
168dc4aace1SHeiko Carstens 				    (unsigned char __user *)ptr,
169012a224eSNico Boehr 				    size);
170dc4aace1SHeiko Carstens 		break;
171dc4aace1SHeiko Carstens 	case 2:
172012a224eSNico Boehr 		rc = __get_user_asm((unsigned short *)x,
173dc4aace1SHeiko Carstens 				    (unsigned short __user *)ptr,
174012a224eSNico Boehr 				    size);
175dc4aace1SHeiko Carstens 		break;
176dc4aace1SHeiko Carstens 	case 4:
177012a224eSNico Boehr 		rc = __get_user_asm((unsigned int *)x,
178dc4aace1SHeiko Carstens 				    (unsigned int __user *)ptr,
179012a224eSNico Boehr 				    size);
180dc4aace1SHeiko Carstens 		break;
181dc4aace1SHeiko Carstens 	case 8:
182012a224eSNico Boehr 		rc = __get_user_asm((unsigned long *)x,
183dc4aace1SHeiko Carstens 				    (unsigned long __user *)ptr,
184012a224eSNico Boehr 				    size);
185dc4aace1SHeiko Carstens 		break;
186db527397SHeiko Carstens 	default:
187db527397SHeiko Carstens 		__get_user_bad();
188db527397SHeiko Carstens 		break;
1890b925159SHeiko Carstens 	}
190dc4aace1SHeiko Carstens 	return rc;
191dc4aace1SHeiko Carstens }
192c9ca7841SHeiko Carstens 
193c6557e7fSMartin Schwidefsky /*
194c6557e7fSMartin Schwidefsky  * These are the main single-value transfer routines.  They automatically
195c6557e7fSMartin Schwidefsky  * use the right size if we just have the right pointer type.
196c6557e7fSMartin Schwidefsky  */
197c6557e7fSMartin Schwidefsky #define __put_user(x, ptr)						\
198c6557e7fSMartin Schwidefsky ({									\
199c6557e7fSMartin Schwidefsky 	__typeof__(*(ptr)) __x = (x);					\
200c6557e7fSMartin Schwidefsky 	int __pu_err = -EFAULT;						\
201d144182eSHeiko Carstens 									\
202c6557e7fSMartin Schwidefsky 	__chk_user_ptr(ptr);						\
203c6557e7fSMartin Schwidefsky 	switch (sizeof(*(ptr))) {					\
204c6557e7fSMartin Schwidefsky 	case 1:								\
205c6557e7fSMartin Schwidefsky 	case 2:								\
206c6557e7fSMartin Schwidefsky 	case 4:								\
207c6557e7fSMartin Schwidefsky 	case 8:								\
208d144182eSHeiko Carstens 		__pu_err = __put_user_fn(&__x, ptr, sizeof(*(ptr)));	\
209c6557e7fSMartin Schwidefsky 		break;							\
210c6557e7fSMartin Schwidefsky 	default:							\
211c6557e7fSMartin Schwidefsky 		__put_user_bad();					\
212c6557e7fSMartin Schwidefsky 		break;							\
213c6557e7fSMartin Schwidefsky 	}								\
214ee64baf4SHeiko Carstens 	__builtin_expect(__pu_err, 0);					\
215c6557e7fSMartin Schwidefsky })
216c6557e7fSMartin Schwidefsky 
217c6557e7fSMartin Schwidefsky #define put_user(x, ptr)						\
218c6557e7fSMartin Schwidefsky ({									\
219dab4079dSHeiko Carstens 	might_fault();							\
220c6557e7fSMartin Schwidefsky 	__put_user(x, ptr);						\
221c6557e7fSMartin Schwidefsky })
222c6557e7fSMartin Schwidefsky 
223c6557e7fSMartin Schwidefsky #define __get_user(x, ptr)						\
224c6557e7fSMartin Schwidefsky ({									\
225c6557e7fSMartin Schwidefsky 	int __gu_err = -EFAULT;						\
226d144182eSHeiko Carstens 									\
227c6557e7fSMartin Schwidefsky 	__chk_user_ptr(ptr);						\
228c6557e7fSMartin Schwidefsky 	switch (sizeof(*(ptr))) {					\
229c6557e7fSMartin Schwidefsky 	case 1: {							\
230454ede3fSHeiko Carstens 		unsigned char __x;					\
231d144182eSHeiko Carstens 									\
232d144182eSHeiko Carstens 		__gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr)));	\
233c6557e7fSMartin Schwidefsky 		(x) = *(__force __typeof__(*(ptr)) *)&__x;		\
234c6557e7fSMartin Schwidefsky 		break;							\
235c6557e7fSMartin Schwidefsky 	};								\
236c6557e7fSMartin Schwidefsky 	case 2: {							\
237454ede3fSHeiko Carstens 		unsigned short __x;					\
238d144182eSHeiko Carstens 									\
239d144182eSHeiko Carstens 		__gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr)));	\
240c6557e7fSMartin Schwidefsky 		(x) = *(__force __typeof__(*(ptr)) *)&__x;		\
241c6557e7fSMartin Schwidefsky 		break;							\
242c6557e7fSMartin Schwidefsky 	};								\
243c6557e7fSMartin Schwidefsky 	case 4: {							\
244454ede3fSHeiko Carstens 		unsigned int __x;					\
245d144182eSHeiko Carstens 									\
246d144182eSHeiko Carstens 		__gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr)));	\
247c6557e7fSMartin Schwidefsky 		(x) = *(__force __typeof__(*(ptr)) *)&__x;		\
248c6557e7fSMartin Schwidefsky 		break;							\
249c6557e7fSMartin Schwidefsky 	};								\
250c6557e7fSMartin Schwidefsky 	case 8: {							\
251454ede3fSHeiko Carstens 		unsigned long __x;					\
252d144182eSHeiko Carstens 									\
253d144182eSHeiko Carstens 		__gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr)));	\
254c6557e7fSMartin Schwidefsky 		(x) = *(__force __typeof__(*(ptr)) *)&__x;		\
255c6557e7fSMartin Schwidefsky 		break;							\
256c6557e7fSMartin Schwidefsky 	};								\
257c6557e7fSMartin Schwidefsky 	default:							\
258c6557e7fSMartin Schwidefsky 		__get_user_bad();					\
259c6557e7fSMartin Schwidefsky 		break;							\
260c6557e7fSMartin Schwidefsky 	}								\
261ee64baf4SHeiko Carstens 	__builtin_expect(__gu_err, 0);					\
262c6557e7fSMartin Schwidefsky })
263c6557e7fSMartin Schwidefsky 
264c6557e7fSMartin Schwidefsky #define get_user(x, ptr)						\
265c6557e7fSMartin Schwidefsky ({									\
266dab4079dSHeiko Carstens 	might_fault();							\
267c6557e7fSMartin Schwidefsky 	__get_user(x, ptr);						\
268c6557e7fSMartin Schwidefsky })
269c6557e7fSMartin Schwidefsky 
270c6557e7fSMartin Schwidefsky /*
271c6557e7fSMartin Schwidefsky  * Copy a null terminated string from userspace.
272c6557e7fSMartin Schwidefsky  */
273e93a1cb8SHeiko Carstens long __must_check strncpy_from_user(char *dst, const char __user *src, long count);
2744f41c2b4SHeiko Carstens 
275e93a1cb8SHeiko Carstens long __must_check strnlen_user(const char __user *src, long count);
276c6557e7fSMartin Schwidefsky 
277c6557e7fSMartin Schwidefsky /*
278c6557e7fSMartin Schwidefsky  * Zero Userspace
279c6557e7fSMartin Schwidefsky  */
280211deca6SHeiko Carstens unsigned long __must_check __clear_user(void __user *to, unsigned long size);
281c6557e7fSMartin Schwidefsky 
clear_user(void __user * to,unsigned long n)282211deca6SHeiko Carstens static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
283c6557e7fSMartin Schwidefsky {
284dab4079dSHeiko Carstens 	might_fault();
2854f41c2b4SHeiko Carstens 	return __clear_user(to, n);
286c6557e7fSMartin Schwidefsky }
287c6557e7fSMartin Schwidefsky 
288cb2cceaeSJosh Poimboeuf void *s390_kernel_write(void *dst, const void *src, size_t size);
289a0616cdeSDavid Howells 
290110a6dbbSHeiko Carstens int __noreturn __put_kernel_bad(void);
291110a6dbbSHeiko Carstens 
292110a6dbbSHeiko Carstens #define __put_kernel_asm(val, to, insn)					\
293110a6dbbSHeiko Carstens ({									\
294110a6dbbSHeiko Carstens 	int __rc;							\
295110a6dbbSHeiko Carstens 									\
296110a6dbbSHeiko Carstens 	asm volatile(							\
29779a74dacSHeiko Carstens 		"0:   " insn "  %[_val],%[_to]\n"			\
29879a74dacSHeiko Carstens 		"1:	xr	%[rc],%[rc]\n"				\
299110a6dbbSHeiko Carstens 		"2:\n"							\
300454ede3fSHeiko Carstens 		EX_TABLE_UA_STORE(0b, 2b, %[rc])			\
301454ede3fSHeiko Carstens 		EX_TABLE_UA_STORE(1b, 2b, %[rc])			\
30279a74dacSHeiko Carstens 		: [rc] "=d" (__rc), [_to] "+Q" (*(to))			\
30379a74dacSHeiko Carstens 		: [_val] "d" (val)					\
304110a6dbbSHeiko Carstens 		: "cc");						\
305110a6dbbSHeiko Carstens 	__rc;								\
306110a6dbbSHeiko Carstens })
307110a6dbbSHeiko Carstens 
308110a6dbbSHeiko Carstens #define __put_kernel_nofault(dst, src, type, err_label)			\
309110a6dbbSHeiko Carstens do {									\
310454ede3fSHeiko Carstens 	unsigned long __x = (unsigned long)(*((type *)(src)));		\
311110a6dbbSHeiko Carstens 	int __pk_err;							\
312110a6dbbSHeiko Carstens 									\
313110a6dbbSHeiko Carstens 	switch (sizeof(type)) {						\
314110a6dbbSHeiko Carstens 	case 1:								\
315110a6dbbSHeiko Carstens 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "stc"); \
316110a6dbbSHeiko Carstens 		break;							\
317110a6dbbSHeiko Carstens 	case 2:								\
318110a6dbbSHeiko Carstens 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "sth"); \
319110a6dbbSHeiko Carstens 		break;							\
320110a6dbbSHeiko Carstens 	case 4:								\
321110a6dbbSHeiko Carstens 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "st");	\
322110a6dbbSHeiko Carstens 		break;							\
323110a6dbbSHeiko Carstens 	case 8:								\
324110a6dbbSHeiko Carstens 		__pk_err = __put_kernel_asm(__x, (type *)(dst), "stg"); \
325110a6dbbSHeiko Carstens 		break;							\
326110a6dbbSHeiko Carstens 	default:							\
327110a6dbbSHeiko Carstens 		__pk_err = __put_kernel_bad();				\
328110a6dbbSHeiko Carstens 		break;							\
329110a6dbbSHeiko Carstens 	}								\
330110a6dbbSHeiko Carstens 	if (unlikely(__pk_err))						\
331110a6dbbSHeiko Carstens 		goto err_label;						\
332110a6dbbSHeiko Carstens } while (0)
333110a6dbbSHeiko Carstens 
334110a6dbbSHeiko Carstens int __noreturn __get_kernel_bad(void);
335110a6dbbSHeiko Carstens 
336110a6dbbSHeiko Carstens #define __get_kernel_asm(val, from, insn)				\
337110a6dbbSHeiko Carstens ({									\
338110a6dbbSHeiko Carstens 	int __rc;							\
339110a6dbbSHeiko Carstens 									\
340110a6dbbSHeiko Carstens 	asm volatile(							\
34179a74dacSHeiko Carstens 		"0:   " insn "  %[_val],%[_from]\n"			\
34279a74dacSHeiko Carstens 		"1:	xr	%[rc],%[rc]\n"				\
343110a6dbbSHeiko Carstens 		"2:\n"							\
344454ede3fSHeiko Carstens 		EX_TABLE_UA_LOAD_REG(0b, 2b, %[rc], %[_val])		\
345454ede3fSHeiko Carstens 		EX_TABLE_UA_LOAD_REG(1b, 2b, %[rc], %[_val])		\
346454ede3fSHeiko Carstens 		: [rc] "=d" (__rc), [_val] "=d" (val)			\
34779a74dacSHeiko Carstens 		: [_from] "Q" (*(from))					\
348110a6dbbSHeiko Carstens 		: "cc");						\
349110a6dbbSHeiko Carstens 	__rc;								\
350110a6dbbSHeiko Carstens })
351110a6dbbSHeiko Carstens 
352110a6dbbSHeiko Carstens #define __get_kernel_nofault(dst, src, type, err_label)			\
353110a6dbbSHeiko Carstens do {									\
354110a6dbbSHeiko Carstens 	int __gk_err;							\
355110a6dbbSHeiko Carstens 									\
356110a6dbbSHeiko Carstens 	switch (sizeof(type)) {						\
357110a6dbbSHeiko Carstens 	case 1: {							\
358454ede3fSHeiko Carstens 		unsigned char __x;					\
359110a6dbbSHeiko Carstens 									\
360110a6dbbSHeiko Carstens 		__gk_err = __get_kernel_asm(__x, (type *)(src), "ic");	\
361110a6dbbSHeiko Carstens 		*((type *)(dst)) = (type)__x;				\
362110a6dbbSHeiko Carstens 		break;							\
363110a6dbbSHeiko Carstens 	};								\
364110a6dbbSHeiko Carstens 	case 2: {							\
365454ede3fSHeiko Carstens 		unsigned short __x;					\
366110a6dbbSHeiko Carstens 									\
367110a6dbbSHeiko Carstens 		__gk_err = __get_kernel_asm(__x, (type *)(src), "lh");	\
368110a6dbbSHeiko Carstens 		*((type *)(dst)) = (type)__x;				\
369110a6dbbSHeiko Carstens 		break;							\
370110a6dbbSHeiko Carstens 	};								\
371110a6dbbSHeiko Carstens 	case 4: {							\
372454ede3fSHeiko Carstens 		unsigned int __x;					\
373110a6dbbSHeiko Carstens 									\
374110a6dbbSHeiko Carstens 		__gk_err = __get_kernel_asm(__x, (type *)(src), "l");	\
375110a6dbbSHeiko Carstens 		*((type *)(dst)) = (type)__x;				\
376110a6dbbSHeiko Carstens 		break;							\
377110a6dbbSHeiko Carstens 	};								\
378110a6dbbSHeiko Carstens 	case 8: {							\
379454ede3fSHeiko Carstens 		unsigned long __x;					\
380110a6dbbSHeiko Carstens 									\
381110a6dbbSHeiko Carstens 		__gk_err = __get_kernel_asm(__x, (type *)(src), "lg");	\
382110a6dbbSHeiko Carstens 		*((type *)(dst)) = (type)__x;				\
383110a6dbbSHeiko Carstens 		break;							\
384110a6dbbSHeiko Carstens 	};								\
385110a6dbbSHeiko Carstens 	default:							\
386110a6dbbSHeiko Carstens 		__gk_err = __get_kernel_bad();				\
387110a6dbbSHeiko Carstens 		break;							\
388110a6dbbSHeiko Carstens 	}								\
389110a6dbbSHeiko Carstens 	if (unlikely(__gk_err))						\
390110a6dbbSHeiko Carstens 		goto err_label;						\
391110a6dbbSHeiko Carstens } while (0)
392110a6dbbSHeiko Carstens 
3934148575aSHeiko Carstens void __cmpxchg_user_key_called_with_bad_pointer(void);
3944148575aSHeiko Carstens 
395739ad2e4SJanis Schoetterl-Glausch #define CMPXCHG_USER_KEY_MAX_LOOPS 128
396739ad2e4SJanis Schoetterl-Glausch 
__cmpxchg_user_key(unsigned long address,void * uval,__uint128_t old,__uint128_t new,unsigned long key,int size)3974148575aSHeiko Carstens static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
3984148575aSHeiko Carstens 					      __uint128_t old, __uint128_t new,
3994148575aSHeiko Carstens 					      unsigned long key, int size)
4004148575aSHeiko Carstens {
4014148575aSHeiko Carstens 	int rc = 0;
4024148575aSHeiko Carstens 
4034148575aSHeiko Carstens 	switch (size) {
4044148575aSHeiko Carstens 	case 1: {
40551098f0eSJanis Schoetterl-Glausch 		unsigned int prev, shift, mask, _old, _new;
406739ad2e4SJanis Schoetterl-Glausch 		unsigned long count;
4074148575aSHeiko Carstens 
4084148575aSHeiko Carstens 		shift = (3 ^ (address & 3)) << 3;
4094148575aSHeiko Carstens 		address ^= address & 3;
410*b33d59fbSHeiko Carstens 		_old = ((unsigned int)old & 0xff) << shift;
411*b33d59fbSHeiko Carstens 		_new = ((unsigned int)new & 0xff) << shift;
41251098f0eSJanis Schoetterl-Glausch 		mask = ~(0xff << shift);
4134148575aSHeiko Carstens 		asm volatile(
4144148575aSHeiko Carstens 			"	spka	0(%[key])\n"
4154148575aSHeiko Carstens 			"	sacf	256\n"
416739ad2e4SJanis Schoetterl-Glausch 			"	llill	%[count],%[max_loops]\n"
4174148575aSHeiko Carstens 			"0:	l	%[prev],%[address]\n"
4184148575aSHeiko Carstens 			"1:	nr	%[prev],%[mask]\n"
41951098f0eSJanis Schoetterl-Glausch 			"	xilf	%[mask],0xffffffff\n"
42051098f0eSJanis Schoetterl-Glausch 			"	or	%[new],%[prev]\n"
42151098f0eSJanis Schoetterl-Glausch 			"	or	%[prev],%[tmp]\n"
42251098f0eSJanis Schoetterl-Glausch 			"2:	lr	%[tmp],%[prev]\n"
42351098f0eSJanis Schoetterl-Glausch 			"3:	cs	%[prev],%[new],%[address]\n"
42451098f0eSJanis Schoetterl-Glausch 			"4:	jnl	5f\n"
4254148575aSHeiko Carstens 			"	xr	%[tmp],%[prev]\n"
42651098f0eSJanis Schoetterl-Glausch 			"	xr	%[new],%[tmp]\n"
4274148575aSHeiko Carstens 			"	nr	%[tmp],%[mask]\n"
428739ad2e4SJanis Schoetterl-Glausch 			"	jnz	5f\n"
429739ad2e4SJanis Schoetterl-Glausch 			"	brct	%[count],2b\n"
43051098f0eSJanis Schoetterl-Glausch 			"5:	sacf	768\n"
4314148575aSHeiko Carstens 			"	spka	%[default_key]\n"
43251098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(0b, 5b, %[rc], %[prev])
43351098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(1b, 5b, %[rc], %[prev])
43451098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(3b, 5b, %[rc], %[prev])
43551098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(4b, 5b, %[rc], %[prev])
4364148575aSHeiko Carstens 			: [rc] "+&d" (rc),
4374148575aSHeiko Carstens 			  [prev] "=&d" (prev),
43851098f0eSJanis Schoetterl-Glausch 			  [address] "+Q" (*(int *)address),
43951098f0eSJanis Schoetterl-Glausch 			  [tmp] "+&d" (_old),
44051098f0eSJanis Schoetterl-Glausch 			  [new] "+&d" (_new),
441739ad2e4SJanis Schoetterl-Glausch 			  [mask] "+&d" (mask),
442739ad2e4SJanis Schoetterl-Glausch 			  [count] "=a" (count)
443739ad2e4SJanis Schoetterl-Glausch 			: [key] "%[count]" (key << 4),
444739ad2e4SJanis Schoetterl-Glausch 			  [default_key] "J" (PAGE_DEFAULT_KEY),
445739ad2e4SJanis Schoetterl-Glausch 			  [max_loops] "J" (CMPXCHG_USER_KEY_MAX_LOOPS)
4464148575aSHeiko Carstens 			: "memory", "cc");
4474148575aSHeiko Carstens 		*(unsigned char *)uval = prev >> shift;
448739ad2e4SJanis Schoetterl-Glausch 		if (!count)
449739ad2e4SJanis Schoetterl-Glausch 			rc = -EAGAIN;
4504148575aSHeiko Carstens 		return rc;
4514148575aSHeiko Carstens 	}
4524148575aSHeiko Carstens 	case 2: {
45351098f0eSJanis Schoetterl-Glausch 		unsigned int prev, shift, mask, _old, _new;
454739ad2e4SJanis Schoetterl-Glausch 		unsigned long count;
4554148575aSHeiko Carstens 
4564148575aSHeiko Carstens 		shift = (2 ^ (address & 2)) << 3;
4574148575aSHeiko Carstens 		address ^= address & 2;
458*b33d59fbSHeiko Carstens 		_old = ((unsigned int)old & 0xffff) << shift;
459*b33d59fbSHeiko Carstens 		_new = ((unsigned int)new & 0xffff) << shift;
46051098f0eSJanis Schoetterl-Glausch 		mask = ~(0xffff << shift);
4614148575aSHeiko Carstens 		asm volatile(
4624148575aSHeiko Carstens 			"	spka	0(%[key])\n"
4634148575aSHeiko Carstens 			"	sacf	256\n"
464739ad2e4SJanis Schoetterl-Glausch 			"	llill	%[count],%[max_loops]\n"
4654148575aSHeiko Carstens 			"0:	l	%[prev],%[address]\n"
4664148575aSHeiko Carstens 			"1:	nr	%[prev],%[mask]\n"
46751098f0eSJanis Schoetterl-Glausch 			"	xilf	%[mask],0xffffffff\n"
46851098f0eSJanis Schoetterl-Glausch 			"	or	%[new],%[prev]\n"
46951098f0eSJanis Schoetterl-Glausch 			"	or	%[prev],%[tmp]\n"
47051098f0eSJanis Schoetterl-Glausch 			"2:	lr	%[tmp],%[prev]\n"
47151098f0eSJanis Schoetterl-Glausch 			"3:	cs	%[prev],%[new],%[address]\n"
47251098f0eSJanis Schoetterl-Glausch 			"4:	jnl	5f\n"
4734148575aSHeiko Carstens 			"	xr	%[tmp],%[prev]\n"
47451098f0eSJanis Schoetterl-Glausch 			"	xr	%[new],%[tmp]\n"
4754148575aSHeiko Carstens 			"	nr	%[tmp],%[mask]\n"
476739ad2e4SJanis Schoetterl-Glausch 			"	jnz	5f\n"
477739ad2e4SJanis Schoetterl-Glausch 			"	brct	%[count],2b\n"
47851098f0eSJanis Schoetterl-Glausch 			"5:	sacf	768\n"
4794148575aSHeiko Carstens 			"	spka	%[default_key]\n"
48051098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(0b, 5b, %[rc], %[prev])
48151098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(1b, 5b, %[rc], %[prev])
48251098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(3b, 5b, %[rc], %[prev])
48351098f0eSJanis Schoetterl-Glausch 			EX_TABLE_UA_LOAD_REG(4b, 5b, %[rc], %[prev])
4844148575aSHeiko Carstens 			: [rc] "+&d" (rc),
4854148575aSHeiko Carstens 			  [prev] "=&d" (prev),
48651098f0eSJanis Schoetterl-Glausch 			  [address] "+Q" (*(int *)address),
48751098f0eSJanis Schoetterl-Glausch 			  [tmp] "+&d" (_old),
48851098f0eSJanis Schoetterl-Glausch 			  [new] "+&d" (_new),
489739ad2e4SJanis Schoetterl-Glausch 			  [mask] "+&d" (mask),
490739ad2e4SJanis Schoetterl-Glausch 			  [count] "=a" (count)
491739ad2e4SJanis Schoetterl-Glausch 			: [key] "%[count]" (key << 4),
492739ad2e4SJanis Schoetterl-Glausch 			  [default_key] "J" (PAGE_DEFAULT_KEY),
493739ad2e4SJanis Schoetterl-Glausch 			  [max_loops] "J" (CMPXCHG_USER_KEY_MAX_LOOPS)
4944148575aSHeiko Carstens 			: "memory", "cc");
4954148575aSHeiko Carstens 		*(unsigned short *)uval = prev >> shift;
496739ad2e4SJanis Schoetterl-Glausch 		if (!count)
497739ad2e4SJanis Schoetterl-Glausch 			rc = -EAGAIN;
4984148575aSHeiko Carstens 		return rc;
4994148575aSHeiko Carstens 	}
5004148575aSHeiko Carstens 	case 4:	{
5014148575aSHeiko Carstens 		unsigned int prev = old;
5024148575aSHeiko Carstens 
5034148575aSHeiko Carstens 		asm volatile(
5044148575aSHeiko Carstens 			"	spka	0(%[key])\n"
5054148575aSHeiko Carstens 			"	sacf	256\n"
5064148575aSHeiko Carstens 			"0:	cs	%[prev],%[new],%[address]\n"
5074148575aSHeiko Carstens 			"1:	sacf	768\n"
5084148575aSHeiko Carstens 			"	spka	%[default_key]\n"
5094148575aSHeiko Carstens 			EX_TABLE_UA_LOAD_REG(0b, 1b, %[rc], %[prev])
5104148575aSHeiko Carstens 			EX_TABLE_UA_LOAD_REG(1b, 1b, %[rc], %[prev])
5114148575aSHeiko Carstens 			: [rc] "+&d" (rc),
5124148575aSHeiko Carstens 			  [prev] "+&d" (prev),
5134148575aSHeiko Carstens 			  [address] "+Q" (*(int *)address)
5144148575aSHeiko Carstens 			: [new] "d" ((unsigned int)new),
5154148575aSHeiko Carstens 			  [key] "a" (key << 4),
5164148575aSHeiko Carstens 			  [default_key] "J" (PAGE_DEFAULT_KEY)
5174148575aSHeiko Carstens 			: "memory", "cc");
5184148575aSHeiko Carstens 		*(unsigned int *)uval = prev;
5194148575aSHeiko Carstens 		return rc;
5204148575aSHeiko Carstens 	}
5214148575aSHeiko Carstens 	case 8: {
5224148575aSHeiko Carstens 		unsigned long prev = old;
5234148575aSHeiko Carstens 
5244148575aSHeiko Carstens 		asm volatile(
5254148575aSHeiko Carstens 			"	spka	0(%[key])\n"
5264148575aSHeiko Carstens 			"	sacf	256\n"
5274148575aSHeiko Carstens 			"0:	csg	%[prev],%[new],%[address]\n"
5284148575aSHeiko Carstens 			"1:	sacf	768\n"
5294148575aSHeiko Carstens 			"	spka	%[default_key]\n"
5304148575aSHeiko Carstens 			EX_TABLE_UA_LOAD_REG(0b, 1b, %[rc], %[prev])
5314148575aSHeiko Carstens 			EX_TABLE_UA_LOAD_REG(1b, 1b, %[rc], %[prev])
5324148575aSHeiko Carstens 			: [rc] "+&d" (rc),
5334148575aSHeiko Carstens 			  [prev] "+&d" (prev),
5344148575aSHeiko Carstens 			  [address] "+QS" (*(long *)address)
5354148575aSHeiko Carstens 			: [new] "d" ((unsigned long)new),
5364148575aSHeiko Carstens 			  [key] "a" (key << 4),
5374148575aSHeiko Carstens 			  [default_key] "J" (PAGE_DEFAULT_KEY)
5384148575aSHeiko Carstens 			: "memory", "cc");
5394148575aSHeiko Carstens 		*(unsigned long *)uval = prev;
5404148575aSHeiko Carstens 		return rc;
5414148575aSHeiko Carstens 	}
5424148575aSHeiko Carstens 	case 16: {
5434148575aSHeiko Carstens 		__uint128_t prev = old;
5444148575aSHeiko Carstens 
5454148575aSHeiko Carstens 		asm volatile(
5464148575aSHeiko Carstens 			"	spka	0(%[key])\n"
5474148575aSHeiko Carstens 			"	sacf	256\n"
5484148575aSHeiko Carstens 			"0:	cdsg	%[prev],%[new],%[address]\n"
5494148575aSHeiko Carstens 			"1:	sacf	768\n"
5504148575aSHeiko Carstens 			"	spka	%[default_key]\n"
5514148575aSHeiko Carstens 			EX_TABLE_UA_LOAD_REGPAIR(0b, 1b, %[rc], %[prev])
5524148575aSHeiko Carstens 			EX_TABLE_UA_LOAD_REGPAIR(1b, 1b, %[rc], %[prev])
5534148575aSHeiko Carstens 			: [rc] "+&d" (rc),
5544148575aSHeiko Carstens 			  [prev] "+&d" (prev),
5554148575aSHeiko Carstens 			  [address] "+QS" (*(__int128_t *)address)
5564148575aSHeiko Carstens 			: [new] "d" (new),
5574148575aSHeiko Carstens 			  [key] "a" (key << 4),
5584148575aSHeiko Carstens 			  [default_key] "J" (PAGE_DEFAULT_KEY)
5594148575aSHeiko Carstens 			: "memory", "cc");
5604148575aSHeiko Carstens 		*(__uint128_t *)uval = prev;
5614148575aSHeiko Carstens 		return rc;
5624148575aSHeiko Carstens 	}
5634148575aSHeiko Carstens 	}
5644148575aSHeiko Carstens 	__cmpxchg_user_key_called_with_bad_pointer();
5654148575aSHeiko Carstens 	return rc;
5664148575aSHeiko Carstens }
5674148575aSHeiko Carstens 
5684148575aSHeiko Carstens /**
5694148575aSHeiko Carstens  * cmpxchg_user_key() - cmpxchg with user space target, honoring storage keys
5704148575aSHeiko Carstens  * @ptr: User space address of value to compare to @old and exchange with
5714148575aSHeiko Carstens  *	 @new. Must be aligned to sizeof(*@ptr).
5724148575aSHeiko Carstens  * @uval: Address where the old value of *@ptr is written to.
5734148575aSHeiko Carstens  * @old: Old value. Compared to the content pointed to by @ptr in order to
5744148575aSHeiko Carstens  *	 determine if the exchange occurs. The old value read from *@ptr is
5754148575aSHeiko Carstens  *	 written to *@uval.
5764148575aSHeiko Carstens  * @new: New value to place at *@ptr.
5774148575aSHeiko Carstens  * @key: Access key to use for checking storage key protection.
5784148575aSHeiko Carstens  *
5794148575aSHeiko Carstens  * Perform a cmpxchg on a user space target, honoring storage key protection.
5804148575aSHeiko Carstens  * @key alone determines how key checking is performed, neither
5814148575aSHeiko Carstens  * storage-protection-override nor fetch-protection-override apply.
5824148575aSHeiko Carstens  * The caller must compare *@uval and @old to determine if values have been
5834148575aSHeiko Carstens  * exchanged. In case of an exception *@uval is set to zero.
5844148575aSHeiko Carstens  *
5854148575aSHeiko Carstens  * Return:     0: cmpxchg executed
5864148575aSHeiko Carstens  *	       -EFAULT: an exception happened when trying to access *@ptr
587739ad2e4SJanis Schoetterl-Glausch  *	       -EAGAIN: maxed out number of retries (byte and short only)
5884148575aSHeiko Carstens  */
5894148575aSHeiko Carstens #define cmpxchg_user_key(ptr, uval, old, new, key)			\
5904148575aSHeiko Carstens ({									\
5914148575aSHeiko Carstens 	__typeof__(ptr) __ptr = (ptr);					\
5924148575aSHeiko Carstens 	__typeof__(uval) __uval = (uval);				\
5934148575aSHeiko Carstens 									\
5944148575aSHeiko Carstens 	BUILD_BUG_ON(sizeof(*(__ptr)) != sizeof(*(__uval)));		\
5954148575aSHeiko Carstens 	might_fault();							\
5964148575aSHeiko Carstens 	__chk_user_ptr(__ptr);						\
5974148575aSHeiko Carstens 	__cmpxchg_user_key((unsigned long)(__ptr), (void *)(__uval),	\
5984148575aSHeiko Carstens 			   (old), (new), (key), sizeof(*(__ptr)));	\
5994148575aSHeiko Carstens })
6004148575aSHeiko Carstens 
601c6557e7fSMartin Schwidefsky #endif /* __S390_UACCESS_H */
602