18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  S390 version
48c2ecf20Sopenharmony_ci *    Copyright IBM Corp. 1999, 2000
58c2ecf20Sopenharmony_ci *    Author(s): Hartmut Penner (hp@de.ibm.com),
68c2ecf20Sopenharmony_ci *               Martin Schwidefsky (schwidefsky@de.ibm.com)
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  Derived from "include/asm-i386/uaccess.h"
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#ifndef __S390_UACCESS_H
118c2ecf20Sopenharmony_ci#define __S390_UACCESS_H
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * User space memory access functions
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#include <asm/processor.h>
178c2ecf20Sopenharmony_ci#include <asm/ctl_reg.h>
188c2ecf20Sopenharmony_ci#include <asm/extable.h>
198c2ecf20Sopenharmony_ci#include <asm/facility.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * The fs value determines whether argument validity checking should be
238c2ecf20Sopenharmony_ci * performed or not.  If get_fs() == USER_DS, checking is performed, with
248c2ecf20Sopenharmony_ci * get_fs() == KERNEL_DS, checking is bypassed.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * For historical reasons, these macros are grossly misnamed.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define KERNEL_DS	(0)
308c2ecf20Sopenharmony_ci#define KERNEL_DS_SACF	(1)
318c2ecf20Sopenharmony_ci#define USER_DS		(2)
328c2ecf20Sopenharmony_ci#define USER_DS_SACF	(3)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define get_fs()        (current->thread.mm_segment)
358c2ecf20Sopenharmony_ci#define uaccess_kernel() ((get_fs() & 2) == KERNEL_DS)
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_civoid set_fs(mm_segment_t fs);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic inline int __range_ok(unsigned long addr, unsigned long size)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	return 1;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define __access_ok(addr, size)				\
458c2ecf20Sopenharmony_ci({							\
468c2ecf20Sopenharmony_ci	__chk_user_ptr(addr);				\
478c2ecf20Sopenharmony_ci	__range_ok((unsigned long)(addr), (size));	\
488c2ecf20Sopenharmony_ci})
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define access_ok(addr, size) __access_ok(addr, size)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciunsigned long __must_check
538c2ecf20Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciunsigned long __must_check
568c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#ifndef CONFIG_KASAN
598c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER
608c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER
618c2ecf20Sopenharmony_ci#endif
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciint __put_user_bad(void) __attribute__((noreturn));
648c2ecf20Sopenharmony_ciint __get_user_bad(void) __attribute__((noreturn));
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define __put_get_user_asm(to, from, size, spec)		\
698c2ecf20Sopenharmony_ci({								\
708c2ecf20Sopenharmony_ci	register unsigned long __reg0 asm("0") = spec;		\
718c2ecf20Sopenharmony_ci	int __rc;						\
728c2ecf20Sopenharmony_ci								\
738c2ecf20Sopenharmony_ci	asm volatile(						\
748c2ecf20Sopenharmony_ci		"0:	mvcos	%1,%3,%2\n"			\
758c2ecf20Sopenharmony_ci		"1:	xr	%0,%0\n"			\
768c2ecf20Sopenharmony_ci		"2:\n"						\
778c2ecf20Sopenharmony_ci		".pushsection .fixup, \"ax\"\n"			\
788c2ecf20Sopenharmony_ci		"3:	lhi	%0,%5\n"			\
798c2ecf20Sopenharmony_ci		"	jg	2b\n"				\
808c2ecf20Sopenharmony_ci		".popsection\n"					\
818c2ecf20Sopenharmony_ci		EX_TABLE(0b,3b) EX_TABLE(1b,3b)			\
828c2ecf20Sopenharmony_ci		: "=d" (__rc), "+Q" (*(to))			\
838c2ecf20Sopenharmony_ci		: "d" (size), "Q" (*(from)),			\
848c2ecf20Sopenharmony_ci		  "d" (__reg0), "K" (-EFAULT)			\
858c2ecf20Sopenharmony_ci		: "cc");					\
868c2ecf20Sopenharmony_ci	__rc;							\
878c2ecf20Sopenharmony_ci})
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	unsigned long spec = 0x010000UL;
928c2ecf20Sopenharmony_ci	int rc;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	switch (size) {
958c2ecf20Sopenharmony_ci	case 1:
968c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned char __user *)ptr,
978c2ecf20Sopenharmony_ci					(unsigned char *)x,
988c2ecf20Sopenharmony_ci					size, spec);
998c2ecf20Sopenharmony_ci		break;
1008c2ecf20Sopenharmony_ci	case 2:
1018c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned short __user *)ptr,
1028c2ecf20Sopenharmony_ci					(unsigned short *)x,
1038c2ecf20Sopenharmony_ci					size, spec);
1048c2ecf20Sopenharmony_ci		break;
1058c2ecf20Sopenharmony_ci	case 4:
1068c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned int __user *)ptr,
1078c2ecf20Sopenharmony_ci					(unsigned int *)x,
1088c2ecf20Sopenharmony_ci					size, spec);
1098c2ecf20Sopenharmony_ci		break;
1108c2ecf20Sopenharmony_ci	case 8:
1118c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned long __user *)ptr,
1128c2ecf20Sopenharmony_ci					(unsigned long *)x,
1138c2ecf20Sopenharmony_ci					size, spec);
1148c2ecf20Sopenharmony_ci		break;
1158c2ecf20Sopenharmony_ci	default:
1168c2ecf20Sopenharmony_ci		__put_user_bad();
1178c2ecf20Sopenharmony_ci		break;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci	return rc;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	unsigned long spec = 0x01UL;
1258c2ecf20Sopenharmony_ci	int rc;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	switch (size) {
1288c2ecf20Sopenharmony_ci	case 1:
1298c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned char *)x,
1308c2ecf20Sopenharmony_ci					(unsigned char __user *)ptr,
1318c2ecf20Sopenharmony_ci					size, spec);
1328c2ecf20Sopenharmony_ci		break;
1338c2ecf20Sopenharmony_ci	case 2:
1348c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned short *)x,
1358c2ecf20Sopenharmony_ci					(unsigned short __user *)ptr,
1368c2ecf20Sopenharmony_ci					size, spec);
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	case 4:
1398c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned int *)x,
1408c2ecf20Sopenharmony_ci					(unsigned int __user *)ptr,
1418c2ecf20Sopenharmony_ci					size, spec);
1428c2ecf20Sopenharmony_ci		break;
1438c2ecf20Sopenharmony_ci	case 8:
1448c2ecf20Sopenharmony_ci		rc = __put_get_user_asm((unsigned long *)x,
1458c2ecf20Sopenharmony_ci					(unsigned long __user *)ptr,
1468c2ecf20Sopenharmony_ci					size, spec);
1478c2ecf20Sopenharmony_ci		break;
1488c2ecf20Sopenharmony_ci	default:
1498c2ecf20Sopenharmony_ci		__get_user_bad();
1508c2ecf20Sopenharmony_ci		break;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci	return rc;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#else /* CONFIG_HAVE_MARCH_Z10_FEATURES */
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	size = raw_copy_to_user(ptr, x, size);
1608c2ecf20Sopenharmony_ci	return size ? -EFAULT : 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	size = raw_copy_from_user(x, ptr, size);
1668c2ecf20Sopenharmony_ci	return size ? -EFAULT : 0;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci#endif /* CONFIG_HAVE_MARCH_Z10_FEATURES */
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/*
1728c2ecf20Sopenharmony_ci * These are the main single-value transfer routines.  They automatically
1738c2ecf20Sopenharmony_ci * use the right size if we just have the right pointer type.
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_ci#define __put_user(x, ptr) \
1768c2ecf20Sopenharmony_ci({								\
1778c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __x = (x);				\
1788c2ecf20Sopenharmony_ci	int __pu_err = -EFAULT;					\
1798c2ecf20Sopenharmony_ci        __chk_user_ptr(ptr);                                    \
1808c2ecf20Sopenharmony_ci	switch (sizeof (*(ptr))) {				\
1818c2ecf20Sopenharmony_ci	case 1:							\
1828c2ecf20Sopenharmony_ci	case 2:							\
1838c2ecf20Sopenharmony_ci	case 4:							\
1848c2ecf20Sopenharmony_ci	case 8:							\
1858c2ecf20Sopenharmony_ci		__pu_err = __put_user_fn(&__x, ptr,		\
1868c2ecf20Sopenharmony_ci					 sizeof(*(ptr)));	\
1878c2ecf20Sopenharmony_ci		break;						\
1888c2ecf20Sopenharmony_ci	default:						\
1898c2ecf20Sopenharmony_ci		__put_user_bad();				\
1908c2ecf20Sopenharmony_ci		break;						\
1918c2ecf20Sopenharmony_ci	}							\
1928c2ecf20Sopenharmony_ci	__builtin_expect(__pu_err, 0);				\
1938c2ecf20Sopenharmony_ci})
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci#define put_user(x, ptr)					\
1968c2ecf20Sopenharmony_ci({								\
1978c2ecf20Sopenharmony_ci	might_fault();						\
1988c2ecf20Sopenharmony_ci	__put_user(x, ptr);					\
1998c2ecf20Sopenharmony_ci})
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#define __get_user(x, ptr)					\
2038c2ecf20Sopenharmony_ci({								\
2048c2ecf20Sopenharmony_ci	int __gu_err = -EFAULT;					\
2058c2ecf20Sopenharmony_ci	__chk_user_ptr(ptr);					\
2068c2ecf20Sopenharmony_ci	switch (sizeof(*(ptr))) {				\
2078c2ecf20Sopenharmony_ci	case 1: {						\
2088c2ecf20Sopenharmony_ci		unsigned char __x = 0;				\
2098c2ecf20Sopenharmony_ci		__gu_err = __get_user_fn(&__x, ptr,		\
2108c2ecf20Sopenharmony_ci					 sizeof(*(ptr)));	\
2118c2ecf20Sopenharmony_ci		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
2128c2ecf20Sopenharmony_ci		break;						\
2138c2ecf20Sopenharmony_ci	};							\
2148c2ecf20Sopenharmony_ci	case 2: {						\
2158c2ecf20Sopenharmony_ci		unsigned short __x = 0;				\
2168c2ecf20Sopenharmony_ci		__gu_err = __get_user_fn(&__x, ptr,		\
2178c2ecf20Sopenharmony_ci					 sizeof(*(ptr)));	\
2188c2ecf20Sopenharmony_ci		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
2198c2ecf20Sopenharmony_ci		break;						\
2208c2ecf20Sopenharmony_ci	};							\
2218c2ecf20Sopenharmony_ci	case 4: {						\
2228c2ecf20Sopenharmony_ci		unsigned int __x = 0;				\
2238c2ecf20Sopenharmony_ci		__gu_err = __get_user_fn(&__x, ptr,		\
2248c2ecf20Sopenharmony_ci					 sizeof(*(ptr)));	\
2258c2ecf20Sopenharmony_ci		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
2268c2ecf20Sopenharmony_ci		break;						\
2278c2ecf20Sopenharmony_ci	};							\
2288c2ecf20Sopenharmony_ci	case 8: {						\
2298c2ecf20Sopenharmony_ci		unsigned long long __x = 0;			\
2308c2ecf20Sopenharmony_ci		__gu_err = __get_user_fn(&__x, ptr,		\
2318c2ecf20Sopenharmony_ci					 sizeof(*(ptr)));	\
2328c2ecf20Sopenharmony_ci		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
2338c2ecf20Sopenharmony_ci		break;						\
2348c2ecf20Sopenharmony_ci	};							\
2358c2ecf20Sopenharmony_ci	default:						\
2368c2ecf20Sopenharmony_ci		__get_user_bad();				\
2378c2ecf20Sopenharmony_ci		break;						\
2388c2ecf20Sopenharmony_ci	}							\
2398c2ecf20Sopenharmony_ci	__builtin_expect(__gu_err, 0);				\
2408c2ecf20Sopenharmony_ci})
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci#define get_user(x, ptr)					\
2438c2ecf20Sopenharmony_ci({								\
2448c2ecf20Sopenharmony_ci	might_fault();						\
2458c2ecf20Sopenharmony_ci	__get_user(x, ptr);					\
2468c2ecf20Sopenharmony_ci})
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ciunsigned long __must_check
2498c2ecf20Sopenharmony_ciraw_copy_in_user(void __user *to, const void __user *from, unsigned long n);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/*
2528c2ecf20Sopenharmony_ci * Copy a null terminated string from userspace.
2538c2ecf20Sopenharmony_ci */
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cilong __strncpy_from_user(char *dst, const char __user *src, long count);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic inline long __must_check
2588c2ecf20Sopenharmony_cistrncpy_from_user(char *dst, const char __user *src, long count)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	might_fault();
2618c2ecf20Sopenharmony_ci	return __strncpy_from_user(dst, src, count);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciunsigned long __must_check __strnlen_user(const char __user *src, unsigned long count);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic inline unsigned long strnlen_user(const char __user *src, unsigned long n)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	might_fault();
2698c2ecf20Sopenharmony_ci	return __strnlen_user(src, n);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci/*
2738c2ecf20Sopenharmony_ci * Zero Userspace
2748c2ecf20Sopenharmony_ci */
2758c2ecf20Sopenharmony_ciunsigned long __must_check __clear_user(void __user *to, unsigned long size);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	might_fault();
2808c2ecf20Sopenharmony_ci	return __clear_user(to, n);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ciint copy_to_user_real(void __user *dest, void *src, unsigned long count);
2848c2ecf20Sopenharmony_civoid *s390_kernel_write(void *dst, const void *src, size_t size);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci#define HAVE_GET_KERNEL_NOFAULT
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciint __noreturn __put_kernel_bad(void);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci#define __put_kernel_asm(val, to, insn)					\
2918c2ecf20Sopenharmony_ci({									\
2928c2ecf20Sopenharmony_ci	int __rc;							\
2938c2ecf20Sopenharmony_ci									\
2948c2ecf20Sopenharmony_ci	asm volatile(							\
2958c2ecf20Sopenharmony_ci		"0:   " insn "  %2,%1\n"				\
2968c2ecf20Sopenharmony_ci		"1:	xr	%0,%0\n"				\
2978c2ecf20Sopenharmony_ci		"2:\n"							\
2988c2ecf20Sopenharmony_ci		".pushsection .fixup, \"ax\"\n"				\
2998c2ecf20Sopenharmony_ci		"3:	lhi	%0,%3\n"				\
3008c2ecf20Sopenharmony_ci		"	jg	2b\n"					\
3018c2ecf20Sopenharmony_ci		".popsection\n"						\
3028c2ecf20Sopenharmony_ci		EX_TABLE(0b,3b) EX_TABLE(1b,3b)				\
3038c2ecf20Sopenharmony_ci		: "=d" (__rc), "+Q" (*(to))				\
3048c2ecf20Sopenharmony_ci		: "d" (val), "K" (-EFAULT)				\
3058c2ecf20Sopenharmony_ci		: "cc");						\
3068c2ecf20Sopenharmony_ci	__rc;								\
3078c2ecf20Sopenharmony_ci})
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci#define __put_kernel_nofault(dst, src, type, err_label)			\
3108c2ecf20Sopenharmony_cido {									\
3118c2ecf20Sopenharmony_ci	u64 __x = (u64)(*((type *)(src)));				\
3128c2ecf20Sopenharmony_ci	int __pk_err;							\
3138c2ecf20Sopenharmony_ci									\
3148c2ecf20Sopenharmony_ci	switch (sizeof(type)) {						\
3158c2ecf20Sopenharmony_ci	case 1:								\
3168c2ecf20Sopenharmony_ci		__pk_err = __put_kernel_asm(__x, (type *)(dst), "stc"); \
3178c2ecf20Sopenharmony_ci		break;							\
3188c2ecf20Sopenharmony_ci	case 2:								\
3198c2ecf20Sopenharmony_ci		__pk_err = __put_kernel_asm(__x, (type *)(dst), "sth"); \
3208c2ecf20Sopenharmony_ci		break;							\
3218c2ecf20Sopenharmony_ci	case 4:								\
3228c2ecf20Sopenharmony_ci		__pk_err = __put_kernel_asm(__x, (type *)(dst), "st");	\
3238c2ecf20Sopenharmony_ci		break;							\
3248c2ecf20Sopenharmony_ci	case 8:								\
3258c2ecf20Sopenharmony_ci		__pk_err = __put_kernel_asm(__x, (type *)(dst), "stg"); \
3268c2ecf20Sopenharmony_ci		break;							\
3278c2ecf20Sopenharmony_ci	default:							\
3288c2ecf20Sopenharmony_ci		__pk_err = __put_kernel_bad();				\
3298c2ecf20Sopenharmony_ci		break;							\
3308c2ecf20Sopenharmony_ci	}								\
3318c2ecf20Sopenharmony_ci	if (unlikely(__pk_err))						\
3328c2ecf20Sopenharmony_ci		goto err_label;						\
3338c2ecf20Sopenharmony_ci} while (0)
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ciint __noreturn __get_kernel_bad(void);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci#define __get_kernel_asm(val, from, insn)				\
3388c2ecf20Sopenharmony_ci({									\
3398c2ecf20Sopenharmony_ci	int __rc;							\
3408c2ecf20Sopenharmony_ci									\
3418c2ecf20Sopenharmony_ci	asm volatile(							\
3428c2ecf20Sopenharmony_ci		"0:   " insn "  %1,%2\n"				\
3438c2ecf20Sopenharmony_ci		"1:	xr	%0,%0\n"				\
3448c2ecf20Sopenharmony_ci		"2:\n"							\
3458c2ecf20Sopenharmony_ci		".pushsection .fixup, \"ax\"\n"				\
3468c2ecf20Sopenharmony_ci		"3:	lhi	%0,%3\n"				\
3478c2ecf20Sopenharmony_ci		"	jg	2b\n"					\
3488c2ecf20Sopenharmony_ci		".popsection\n"						\
3498c2ecf20Sopenharmony_ci		EX_TABLE(0b,3b) EX_TABLE(1b,3b)				\
3508c2ecf20Sopenharmony_ci		: "=d" (__rc), "+d" (val)				\
3518c2ecf20Sopenharmony_ci		: "Q" (*(from)), "K" (-EFAULT)				\
3528c2ecf20Sopenharmony_ci		: "cc");						\
3538c2ecf20Sopenharmony_ci	__rc;								\
3548c2ecf20Sopenharmony_ci})
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci#define __get_kernel_nofault(dst, src, type, err_label)			\
3578c2ecf20Sopenharmony_cido {									\
3588c2ecf20Sopenharmony_ci	int __gk_err;							\
3598c2ecf20Sopenharmony_ci									\
3608c2ecf20Sopenharmony_ci	switch (sizeof(type)) {						\
3618c2ecf20Sopenharmony_ci	case 1: {							\
3628c2ecf20Sopenharmony_ci		u8 __x = 0;						\
3638c2ecf20Sopenharmony_ci									\
3648c2ecf20Sopenharmony_ci		__gk_err = __get_kernel_asm(__x, (type *)(src), "ic");	\
3658c2ecf20Sopenharmony_ci		*((type *)(dst)) = (type)__x;				\
3668c2ecf20Sopenharmony_ci		break;							\
3678c2ecf20Sopenharmony_ci	};								\
3688c2ecf20Sopenharmony_ci	case 2: {							\
3698c2ecf20Sopenharmony_ci		u16 __x = 0;						\
3708c2ecf20Sopenharmony_ci									\
3718c2ecf20Sopenharmony_ci		__gk_err = __get_kernel_asm(__x, (type *)(src), "lh");	\
3728c2ecf20Sopenharmony_ci		*((type *)(dst)) = (type)__x;				\
3738c2ecf20Sopenharmony_ci		break;							\
3748c2ecf20Sopenharmony_ci	};								\
3758c2ecf20Sopenharmony_ci	case 4: {							\
3768c2ecf20Sopenharmony_ci		u32 __x = 0;						\
3778c2ecf20Sopenharmony_ci									\
3788c2ecf20Sopenharmony_ci		__gk_err = __get_kernel_asm(__x, (type *)(src), "l");	\
3798c2ecf20Sopenharmony_ci		*((type *)(dst)) = (type)__x;				\
3808c2ecf20Sopenharmony_ci		break;							\
3818c2ecf20Sopenharmony_ci	};								\
3828c2ecf20Sopenharmony_ci	case 8: {							\
3838c2ecf20Sopenharmony_ci		u64 __x = 0;						\
3848c2ecf20Sopenharmony_ci									\
3858c2ecf20Sopenharmony_ci		__gk_err = __get_kernel_asm(__x, (type *)(src), "lg");	\
3868c2ecf20Sopenharmony_ci		*((type *)(dst)) = (type)__x;				\
3878c2ecf20Sopenharmony_ci		break;							\
3888c2ecf20Sopenharmony_ci	};								\
3898c2ecf20Sopenharmony_ci	default:							\
3908c2ecf20Sopenharmony_ci		__gk_err = __get_kernel_bad();				\
3918c2ecf20Sopenharmony_ci		break;							\
3928c2ecf20Sopenharmony_ci	}								\
3938c2ecf20Sopenharmony_ci	if (unlikely(__gk_err))						\
3948c2ecf20Sopenharmony_ci		goto err_label;						\
3958c2ecf20Sopenharmony_ci} while (0)
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci#endif /* __S390_UACCESS_H */
398