18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ARCH_POWERPC_UACCESS_H
38c2ecf20Sopenharmony_ci#define _ARCH_POWERPC_UACCESS_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <asm/ppc_asm.h>
68c2ecf20Sopenharmony_ci#include <asm/processor.h>
78c2ecf20Sopenharmony_ci#include <asm/page.h>
88c2ecf20Sopenharmony_ci#include <asm/extable.h>
98c2ecf20Sopenharmony_ci#include <asm/kup.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifdef __powerpc64__
128c2ecf20Sopenharmony_ci/* We use TASK_SIZE_USER64 as TASK_SIZE is not constant */
138c2ecf20Sopenharmony_ci#define TASK_SIZE_MAX		TASK_SIZE_USER64
148c2ecf20Sopenharmony_ci#else
158c2ecf20Sopenharmony_ci#define TASK_SIZE_MAX		TASK_SIZE
168c2ecf20Sopenharmony_ci#endif
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic inline bool __access_ok(unsigned long addr, unsigned long size)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	return addr < TASK_SIZE_MAX && size <= TASK_SIZE_MAX - addr;
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define access_ok(addr, size)		\
248c2ecf20Sopenharmony_ci	(__chk_user_ptr(addr),		\
258c2ecf20Sopenharmony_ci	 __access_ok((unsigned long)(addr), (size)))
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * These are the main single-value transfer routines.  They automatically
298c2ecf20Sopenharmony_ci * use the right size if we just have the right pointer type.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * This gets kind of ugly. We want to return _two_ values in "get_user()"
328c2ecf20Sopenharmony_ci * and yet we don't want to do any pointers, because that is too much
338c2ecf20Sopenharmony_ci * of a performance impact. Thus we have a few rather ugly macros here,
348c2ecf20Sopenharmony_ci * and hide all the ugliness from the user.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * The "__xxx" versions of the user access functions are versions that
378c2ecf20Sopenharmony_ci * do not verify the address space, that must have been done previously
388c2ecf20Sopenharmony_ci * with a separate "access_ok()" call (this is used when we do multiple
398c2ecf20Sopenharmony_ci * accesses to the same area of user memory).
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * As we use the same address space for kernel and user data on the
428c2ecf20Sopenharmony_ci * PowerPC, we can just do these as direct assignments.  (Of course, the
438c2ecf20Sopenharmony_ci * exception handling means that it's no longer "just"...)
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_ci#define get_user(x, ptr) \
478c2ecf20Sopenharmony_ci	__get_user_check((x), (ptr), sizeof(*(ptr)))
488c2ecf20Sopenharmony_ci#define put_user(x, ptr) \
498c2ecf20Sopenharmony_ci	__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define __get_user(x, ptr) \
528c2ecf20Sopenharmony_ci	__get_user_nocheck((x), (ptr), sizeof(*(ptr)), true)
538c2ecf20Sopenharmony_ci#define __put_user(x, ptr) \
548c2ecf20Sopenharmony_ci	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
558c2ecf20Sopenharmony_ci#define __put_user_goto(x, ptr, label) \
568c2ecf20Sopenharmony_ci	__put_user_nocheck_goto((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label)
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define __get_user_allowed(x, ptr) \
598c2ecf20Sopenharmony_ci	__get_user_nocheck((x), (ptr), sizeof(*(ptr)), false)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define __get_user_inatomic(x, ptr) \
628c2ecf20Sopenharmony_ci	__get_user_nosleep((x), (ptr), sizeof(*(ptr)))
638c2ecf20Sopenharmony_ci#define __put_user_inatomic(x, ptr) \
648c2ecf20Sopenharmony_ci	__put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define ___get_user_instr(gu_op, dest, ptr)				\
698c2ecf20Sopenharmony_ci({									\
708c2ecf20Sopenharmony_ci	long __gui_ret = 0;						\
718c2ecf20Sopenharmony_ci	unsigned long __gui_ptr = (unsigned long)ptr;			\
728c2ecf20Sopenharmony_ci	struct ppc_inst __gui_inst;					\
738c2ecf20Sopenharmony_ci	unsigned int __prefix, __suffix;				\
748c2ecf20Sopenharmony_ci	__gui_ret = gu_op(__prefix, (unsigned int __user *)__gui_ptr);	\
758c2ecf20Sopenharmony_ci	if (__gui_ret == 0) {						\
768c2ecf20Sopenharmony_ci		if ((__prefix >> 26) == OP_PREFIX) {			\
778c2ecf20Sopenharmony_ci			__gui_ret = gu_op(__suffix,			\
788c2ecf20Sopenharmony_ci				(unsigned int __user *)__gui_ptr + 1);	\
798c2ecf20Sopenharmony_ci			__gui_inst = ppc_inst_prefix(__prefix,		\
808c2ecf20Sopenharmony_ci						     __suffix);		\
818c2ecf20Sopenharmony_ci		} else {						\
828c2ecf20Sopenharmony_ci			__gui_inst = ppc_inst(__prefix);		\
838c2ecf20Sopenharmony_ci		}							\
848c2ecf20Sopenharmony_ci		if (__gui_ret == 0)					\
858c2ecf20Sopenharmony_ci			(dest) = __gui_inst;				\
868c2ecf20Sopenharmony_ci	}								\
878c2ecf20Sopenharmony_ci	__gui_ret;							\
888c2ecf20Sopenharmony_ci})
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define get_user_instr(x, ptr) \
918c2ecf20Sopenharmony_ci	___get_user_instr(get_user, x, ptr)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define __get_user_instr(x, ptr) \
948c2ecf20Sopenharmony_ci	___get_user_instr(__get_user, x, ptr)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define __get_user_instr_inatomic(x, ptr) \
978c2ecf20Sopenharmony_ci	___get_user_instr(__get_user_inatomic, x, ptr)
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#else /* !CONFIG_PPC64 */
1008c2ecf20Sopenharmony_ci#define get_user_instr(x, ptr) \
1018c2ecf20Sopenharmony_ci	get_user((x).val, (u32 __user *)(ptr))
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define __get_user_instr(x, ptr) \
1048c2ecf20Sopenharmony_ci	__get_user_nocheck((x).val, (u32 __user *)(ptr), sizeof(u32), true)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define __get_user_instr_inatomic(x, ptr) \
1078c2ecf20Sopenharmony_ci	__get_user_nosleep((x).val, (u32 __user *)(ptr), sizeof(u32))
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ciextern long __put_user_bad(void);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#define __put_user_size_allowed(x, ptr, size, retval)		\
1148c2ecf20Sopenharmony_cido {								\
1158c2ecf20Sopenharmony_ci	__label__ __pu_failed;					\
1168c2ecf20Sopenharmony_ci								\
1178c2ecf20Sopenharmony_ci	retval = 0;						\
1188c2ecf20Sopenharmony_ci	__put_user_size_goto(x, ptr, size, __pu_failed);	\
1198c2ecf20Sopenharmony_ci	break;							\
1208c2ecf20Sopenharmony_ci								\
1218c2ecf20Sopenharmony_ci__pu_failed:							\
1228c2ecf20Sopenharmony_ci	retval = -EFAULT;					\
1238c2ecf20Sopenharmony_ci} while (0)
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define __put_user_size(x, ptr, size, retval)			\
1268c2ecf20Sopenharmony_cido {								\
1278c2ecf20Sopenharmony_ci	allow_write_to_user(ptr, size);				\
1288c2ecf20Sopenharmony_ci	__put_user_size_allowed(x, ptr, size, retval);		\
1298c2ecf20Sopenharmony_ci	prevent_write_to_user(ptr, size);			\
1308c2ecf20Sopenharmony_ci} while (0)
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define __put_user_nocheck(x, ptr, size)			\
1338c2ecf20Sopenharmony_ci({								\
1348c2ecf20Sopenharmony_ci	long __pu_err;						\
1358c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
1368c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __pu_val = (x);			\
1378c2ecf20Sopenharmony_ci	__typeof__(size) __pu_size = (size);			\
1388c2ecf20Sopenharmony_ci								\
1398c2ecf20Sopenharmony_ci	if (!is_kernel_addr((unsigned long)__pu_addr))		\
1408c2ecf20Sopenharmony_ci		might_fault();					\
1418c2ecf20Sopenharmony_ci	__chk_user_ptr(__pu_addr);				\
1428c2ecf20Sopenharmony_ci	__put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err);	\
1438c2ecf20Sopenharmony_ci								\
1448c2ecf20Sopenharmony_ci	__pu_err;						\
1458c2ecf20Sopenharmony_ci})
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#define __put_user_check(x, ptr, size)					\
1488c2ecf20Sopenharmony_ci({									\
1498c2ecf20Sopenharmony_ci	long __pu_err = -EFAULT;					\
1508c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
1518c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __pu_val = (x);				\
1528c2ecf20Sopenharmony_ci	__typeof__(size) __pu_size = (size);				\
1538c2ecf20Sopenharmony_ci									\
1548c2ecf20Sopenharmony_ci	might_fault();							\
1558c2ecf20Sopenharmony_ci	if (access_ok(__pu_addr, __pu_size))				\
1568c2ecf20Sopenharmony_ci		__put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \
1578c2ecf20Sopenharmony_ci									\
1588c2ecf20Sopenharmony_ci	__pu_err;							\
1598c2ecf20Sopenharmony_ci})
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#define __put_user_nosleep(x, ptr, size)			\
1628c2ecf20Sopenharmony_ci({								\
1638c2ecf20Sopenharmony_ci	long __pu_err;						\
1648c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
1658c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __pu_val = (x);			\
1668c2ecf20Sopenharmony_ci	__typeof__(size) __pu_size = (size);			\
1678c2ecf20Sopenharmony_ci								\
1688c2ecf20Sopenharmony_ci	__chk_user_ptr(__pu_addr);				\
1698c2ecf20Sopenharmony_ci	__put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \
1708c2ecf20Sopenharmony_ci								\
1718c2ecf20Sopenharmony_ci	__pu_err;						\
1728c2ecf20Sopenharmony_ci})
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/*
1768c2ecf20Sopenharmony_ci * We don't tell gcc that we are accessing memory, but this is OK
1778c2ecf20Sopenharmony_ci * because we do not write to any memory gcc knows about, so there
1788c2ecf20Sopenharmony_ci * are no aliasing issues.
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_ci#define __put_user_asm_goto(x, addr, label, op)			\
1818c2ecf20Sopenharmony_ci	asm_volatile_goto(					\
1828c2ecf20Sopenharmony_ci		"1:	" op "%U1%X1 %0,%1	# put_user\n"	\
1838c2ecf20Sopenharmony_ci		EX_TABLE(1b, %l2)				\
1848c2ecf20Sopenharmony_ci		:						\
1858c2ecf20Sopenharmony_ci		: "r" (x), "m"UPD_CONSTR (*addr)		\
1868c2ecf20Sopenharmony_ci		:						\
1878c2ecf20Sopenharmony_ci		: label)
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci#ifdef __powerpc64__
1908c2ecf20Sopenharmony_ci#define __put_user_asm2_goto(x, ptr, label)			\
1918c2ecf20Sopenharmony_ci	__put_user_asm_goto(x, ptr, label, "std")
1928c2ecf20Sopenharmony_ci#else /* __powerpc64__ */
1938c2ecf20Sopenharmony_ci#define __put_user_asm2_goto(x, addr, label)			\
1948c2ecf20Sopenharmony_ci	asm_volatile_goto(					\
1958c2ecf20Sopenharmony_ci		"1:	stw%X1 %0, %1\n"			\
1968c2ecf20Sopenharmony_ci		"2:	stw%X1 %L0, %L1\n"			\
1978c2ecf20Sopenharmony_ci		EX_TABLE(1b, %l2)				\
1988c2ecf20Sopenharmony_ci		EX_TABLE(2b, %l2)				\
1998c2ecf20Sopenharmony_ci		:						\
2008c2ecf20Sopenharmony_ci		: "r" (x), "m" (*addr)				\
2018c2ecf20Sopenharmony_ci		:						\
2028c2ecf20Sopenharmony_ci		: label)
2038c2ecf20Sopenharmony_ci#endif /* __powerpc64__ */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#define __put_user_size_goto(x, ptr, size, label)		\
2068c2ecf20Sopenharmony_cido {								\
2078c2ecf20Sopenharmony_ci	switch (size) {						\
2088c2ecf20Sopenharmony_ci	case 1: __put_user_asm_goto(x, ptr, label, "stb"); break;	\
2098c2ecf20Sopenharmony_ci	case 2: __put_user_asm_goto(x, ptr, label, "sth"); break;	\
2108c2ecf20Sopenharmony_ci	case 4: __put_user_asm_goto(x, ptr, label, "stw"); break;	\
2118c2ecf20Sopenharmony_ci	case 8: __put_user_asm2_goto(x, ptr, label); break;	\
2128c2ecf20Sopenharmony_ci	default: __put_user_bad();				\
2138c2ecf20Sopenharmony_ci	}							\
2148c2ecf20Sopenharmony_ci} while (0)
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci#define __put_user_nocheck_goto(x, ptr, size, label)		\
2178c2ecf20Sopenharmony_cido {								\
2188c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
2198c2ecf20Sopenharmony_ci	__chk_user_ptr(ptr);					\
2208c2ecf20Sopenharmony_ci	__put_user_size_goto((x), __pu_addr, (size), label);	\
2218c2ecf20Sopenharmony_ci} while (0)
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ciextern long __get_user_bad(void);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci/*
2278c2ecf20Sopenharmony_ci * This does an atomic 128 byte aligned load from userspace.
2288c2ecf20Sopenharmony_ci * Upto caller to do enable_kernel_vmx() before calling!
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_ci#define __get_user_atomic_128_aligned(kaddr, uaddr, err)		\
2318c2ecf20Sopenharmony_ci	__asm__ __volatile__(				\
2328c2ecf20Sopenharmony_ci		".machine push\n"			\
2338c2ecf20Sopenharmony_ci		".machine altivec\n"			\
2348c2ecf20Sopenharmony_ci		"1:	lvx  0,0,%1	# get user\n"	\
2358c2ecf20Sopenharmony_ci		" 	stvx 0,0,%2	# put kernel\n"	\
2368c2ecf20Sopenharmony_ci		".machine pop\n"			\
2378c2ecf20Sopenharmony_ci		"2:\n"					\
2388c2ecf20Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
2398c2ecf20Sopenharmony_ci		"3:	li %0,%3\n"			\
2408c2ecf20Sopenharmony_ci		"	b 2b\n"				\
2418c2ecf20Sopenharmony_ci		".previous\n"				\
2428c2ecf20Sopenharmony_ci		EX_TABLE(1b, 3b)			\
2438c2ecf20Sopenharmony_ci		: "=r" (err)			\
2448c2ecf20Sopenharmony_ci		: "b" (uaddr), "b" (kaddr), "i" (-EFAULT), "0" (err))
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci#define __get_user_asm(x, addr, err, op)		\
2478c2ecf20Sopenharmony_ci	__asm__ __volatile__(				\
2488c2ecf20Sopenharmony_ci		"1:	"op"%U2%X2 %1, %2	# get_user\n"	\
2498c2ecf20Sopenharmony_ci		"2:\n"					\
2508c2ecf20Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
2518c2ecf20Sopenharmony_ci		"3:	li %0,%3\n"			\
2528c2ecf20Sopenharmony_ci		"	li %1,0\n"			\
2538c2ecf20Sopenharmony_ci		"	b 2b\n"				\
2548c2ecf20Sopenharmony_ci		".previous\n"				\
2558c2ecf20Sopenharmony_ci		EX_TABLE(1b, 3b)			\
2568c2ecf20Sopenharmony_ci		: "=r" (err), "=r" (x)			\
2578c2ecf20Sopenharmony_ci		: "m"UPD_CONSTR (*addr), "i" (-EFAULT), "0" (err))
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci#ifdef __powerpc64__
2608c2ecf20Sopenharmony_ci#define __get_user_asm2(x, addr, err)			\
2618c2ecf20Sopenharmony_ci	__get_user_asm(x, addr, err, "ld")
2628c2ecf20Sopenharmony_ci#else /* __powerpc64__ */
2638c2ecf20Sopenharmony_ci#define __get_user_asm2(x, addr, err)			\
2648c2ecf20Sopenharmony_ci	__asm__ __volatile__(				\
2658c2ecf20Sopenharmony_ci		"1:	lwz%X2 %1, %2\n"			\
2668c2ecf20Sopenharmony_ci		"2:	lwz%X2 %L1, %L2\n"		\
2678c2ecf20Sopenharmony_ci		"3:\n"					\
2688c2ecf20Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
2698c2ecf20Sopenharmony_ci		"4:	li %0,%3\n"			\
2708c2ecf20Sopenharmony_ci		"	li %1,0\n"			\
2718c2ecf20Sopenharmony_ci		"	li %1+1,0\n"			\
2728c2ecf20Sopenharmony_ci		"	b 3b\n"				\
2738c2ecf20Sopenharmony_ci		".previous\n"				\
2748c2ecf20Sopenharmony_ci		EX_TABLE(1b, 4b)			\
2758c2ecf20Sopenharmony_ci		EX_TABLE(2b, 4b)			\
2768c2ecf20Sopenharmony_ci		: "=r" (err), "=&r" (x)			\
2778c2ecf20Sopenharmony_ci		: "m" (*addr), "i" (-EFAULT), "0" (err))
2788c2ecf20Sopenharmony_ci#endif /* __powerpc64__ */
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci#define __get_user_size_allowed(x, ptr, size, retval)		\
2818c2ecf20Sopenharmony_cido {								\
2828c2ecf20Sopenharmony_ci	retval = 0;						\
2838c2ecf20Sopenharmony_ci	__chk_user_ptr(ptr);					\
2848c2ecf20Sopenharmony_ci	if (size > sizeof(x))					\
2858c2ecf20Sopenharmony_ci		(x) = __get_user_bad();				\
2868c2ecf20Sopenharmony_ci	switch (size) {						\
2878c2ecf20Sopenharmony_ci	case 1: __get_user_asm(x, (u8 __user *)ptr, retval, "lbz"); break;	\
2888c2ecf20Sopenharmony_ci	case 2: __get_user_asm(x, (u16 __user *)ptr, retval, "lhz"); break;	\
2898c2ecf20Sopenharmony_ci	case 4: __get_user_asm(x, (u32 __user *)ptr, retval, "lwz"); break;	\
2908c2ecf20Sopenharmony_ci	case 8: __get_user_asm2(x, (u64 __user *)ptr, retval);  break;	\
2918c2ecf20Sopenharmony_ci	default: (x) = __get_user_bad();			\
2928c2ecf20Sopenharmony_ci	}							\
2938c2ecf20Sopenharmony_ci} while (0)
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci#define __get_user_size(x, ptr, size, retval)			\
2968c2ecf20Sopenharmony_cido {								\
2978c2ecf20Sopenharmony_ci	allow_read_from_user(ptr, size);			\
2988c2ecf20Sopenharmony_ci	__get_user_size_allowed(x, ptr, size, retval);		\
2998c2ecf20Sopenharmony_ci	prevent_read_from_user(ptr, size);			\
3008c2ecf20Sopenharmony_ci} while (0)
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci/*
3038c2ecf20Sopenharmony_ci * This is a type: either unsigned long, if the argument fits into
3048c2ecf20Sopenharmony_ci * that type, or otherwise unsigned long long.
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_ci#define __long_type(x) \
3078c2ecf20Sopenharmony_ci	__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci#define __get_user_nocheck(x, ptr, size, do_allow)			\
3108c2ecf20Sopenharmony_ci({								\
3118c2ecf20Sopenharmony_ci	long __gu_err;						\
3128c2ecf20Sopenharmony_ci	__long_type(*(ptr)) __gu_val;				\
3138c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
3148c2ecf20Sopenharmony_ci	__typeof__(size) __gu_size = (size);			\
3158c2ecf20Sopenharmony_ci								\
3168c2ecf20Sopenharmony_ci	__chk_user_ptr(__gu_addr);				\
3178c2ecf20Sopenharmony_ci	if (do_allow && !is_kernel_addr((unsigned long)__gu_addr)) \
3188c2ecf20Sopenharmony_ci		might_fault();					\
3198c2ecf20Sopenharmony_ci	barrier_nospec();					\
3208c2ecf20Sopenharmony_ci	if (do_allow)								\
3218c2ecf20Sopenharmony_ci		__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err);	\
3228c2ecf20Sopenharmony_ci	else									\
3238c2ecf20Sopenharmony_ci		__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \
3248c2ecf20Sopenharmony_ci	(x) = (__typeof__(*(ptr)))__gu_val;			\
3258c2ecf20Sopenharmony_ci								\
3268c2ecf20Sopenharmony_ci	__gu_err;						\
3278c2ecf20Sopenharmony_ci})
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci#define __get_user_check(x, ptr, size)					\
3308c2ecf20Sopenharmony_ci({									\
3318c2ecf20Sopenharmony_ci	long __gu_err = -EFAULT;					\
3328c2ecf20Sopenharmony_ci	__long_type(*(ptr)) __gu_val = 0;				\
3338c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__gu_addr = (ptr);		\
3348c2ecf20Sopenharmony_ci	__typeof__(size) __gu_size = (size);				\
3358c2ecf20Sopenharmony_ci									\
3368c2ecf20Sopenharmony_ci	might_fault();							\
3378c2ecf20Sopenharmony_ci	if (access_ok(__gu_addr, __gu_size)) {				\
3388c2ecf20Sopenharmony_ci		barrier_nospec();					\
3398c2ecf20Sopenharmony_ci		__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \
3408c2ecf20Sopenharmony_ci	}								\
3418c2ecf20Sopenharmony_ci	(x) = (__force __typeof__(*(ptr)))__gu_val;				\
3428c2ecf20Sopenharmony_ci									\
3438c2ecf20Sopenharmony_ci	__gu_err;							\
3448c2ecf20Sopenharmony_ci})
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci#define __get_user_nosleep(x, ptr, size)			\
3478c2ecf20Sopenharmony_ci({								\
3488c2ecf20Sopenharmony_ci	long __gu_err;						\
3498c2ecf20Sopenharmony_ci	__long_type(*(ptr)) __gu_val;				\
3508c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
3518c2ecf20Sopenharmony_ci	__typeof__(size) __gu_size = (size);			\
3528c2ecf20Sopenharmony_ci								\
3538c2ecf20Sopenharmony_ci	__chk_user_ptr(__gu_addr);				\
3548c2ecf20Sopenharmony_ci	barrier_nospec();					\
3558c2ecf20Sopenharmony_ci	__get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \
3568c2ecf20Sopenharmony_ci	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
3578c2ecf20Sopenharmony_ci								\
3588c2ecf20Sopenharmony_ci	__gu_err;						\
3598c2ecf20Sopenharmony_ci})
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci/* more complex routines */
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ciextern unsigned long __copy_tofrom_user(void __user *to,
3658c2ecf20Sopenharmony_ci		const void __user *from, unsigned long size);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_COPY_MC
3688c2ecf20Sopenharmony_ciunsigned long __must_check
3698c2ecf20Sopenharmony_cicopy_mc_generic(void *to, const void *from, unsigned long size);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic inline unsigned long __must_check
3728c2ecf20Sopenharmony_cicopy_mc_to_kernel(void *to, const void *from, unsigned long size)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	return copy_mc_generic(to, from, size);
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci#define copy_mc_to_kernel copy_mc_to_kernel
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic inline unsigned long __must_check
3798c2ecf20Sopenharmony_cicopy_mc_to_user(void __user *to, const void *from, unsigned long n)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	if (likely(check_copy_size(from, n, true))) {
3828c2ecf20Sopenharmony_ci		if (access_ok(to, n)) {
3838c2ecf20Sopenharmony_ci			allow_write_to_user(to, n);
3848c2ecf20Sopenharmony_ci			n = copy_mc_generic((void *)to, from, n);
3858c2ecf20Sopenharmony_ci			prevent_write_to_user(to, n);
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	return n;
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci#endif
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci#ifdef __powerpc64__
3948c2ecf20Sopenharmony_cistatic inline unsigned long
3958c2ecf20Sopenharmony_ciraw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	unsigned long ret;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	barrier_nospec();
4008c2ecf20Sopenharmony_ci	allow_read_write_user(to, from, n);
4018c2ecf20Sopenharmony_ci	ret = __copy_tofrom_user(to, from, n);
4028c2ecf20Sopenharmony_ci	prevent_read_write_user(to, from, n);
4038c2ecf20Sopenharmony_ci	return ret;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci#endif /* __powerpc64__ */
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic inline unsigned long raw_copy_from_user(void *to,
4088c2ecf20Sopenharmony_ci		const void __user *from, unsigned long n)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	unsigned long ret;
4118c2ecf20Sopenharmony_ci	if (__builtin_constant_p(n) && (n <= 8)) {
4128c2ecf20Sopenharmony_ci		ret = 1;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		switch (n) {
4158c2ecf20Sopenharmony_ci		case 1:
4168c2ecf20Sopenharmony_ci			barrier_nospec();
4178c2ecf20Sopenharmony_ci			__get_user_size(*(u8 *)to, from, 1, ret);
4188c2ecf20Sopenharmony_ci			break;
4198c2ecf20Sopenharmony_ci		case 2:
4208c2ecf20Sopenharmony_ci			barrier_nospec();
4218c2ecf20Sopenharmony_ci			__get_user_size(*(u16 *)to, from, 2, ret);
4228c2ecf20Sopenharmony_ci			break;
4238c2ecf20Sopenharmony_ci		case 4:
4248c2ecf20Sopenharmony_ci			barrier_nospec();
4258c2ecf20Sopenharmony_ci			__get_user_size(*(u32 *)to, from, 4, ret);
4268c2ecf20Sopenharmony_ci			break;
4278c2ecf20Sopenharmony_ci		case 8:
4288c2ecf20Sopenharmony_ci			barrier_nospec();
4298c2ecf20Sopenharmony_ci			__get_user_size(*(u64 *)to, from, 8, ret);
4308c2ecf20Sopenharmony_ci			break;
4318c2ecf20Sopenharmony_ci		}
4328c2ecf20Sopenharmony_ci		if (ret == 0)
4338c2ecf20Sopenharmony_ci			return 0;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	barrier_nospec();
4378c2ecf20Sopenharmony_ci	allow_read_from_user(from, n);
4388c2ecf20Sopenharmony_ci	ret = __copy_tofrom_user((__force void __user *)to, from, n);
4398c2ecf20Sopenharmony_ci	prevent_read_from_user(from, n);
4408c2ecf20Sopenharmony_ci	return ret;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic inline unsigned long
4448c2ecf20Sopenharmony_ciraw_copy_to_user_allowed(void __user *to, const void *from, unsigned long n)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	if (__builtin_constant_p(n) && (n <= 8)) {
4478c2ecf20Sopenharmony_ci		unsigned long ret = 1;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		switch (n) {
4508c2ecf20Sopenharmony_ci		case 1:
4518c2ecf20Sopenharmony_ci			__put_user_size_allowed(*(u8 *)from, (u8 __user *)to, 1, ret);
4528c2ecf20Sopenharmony_ci			break;
4538c2ecf20Sopenharmony_ci		case 2:
4548c2ecf20Sopenharmony_ci			__put_user_size_allowed(*(u16 *)from, (u16 __user *)to, 2, ret);
4558c2ecf20Sopenharmony_ci			break;
4568c2ecf20Sopenharmony_ci		case 4:
4578c2ecf20Sopenharmony_ci			__put_user_size_allowed(*(u32 *)from, (u32 __user *)to, 4, ret);
4588c2ecf20Sopenharmony_ci			break;
4598c2ecf20Sopenharmony_ci		case 8:
4608c2ecf20Sopenharmony_ci			__put_user_size_allowed(*(u64 *)from, (u64 __user *)to, 8, ret);
4618c2ecf20Sopenharmony_ci			break;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci		if (ret == 0)
4648c2ecf20Sopenharmony_ci			return 0;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return __copy_tofrom_user(to, (__force const void __user *)from, n);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic inline unsigned long
4718c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	unsigned long ret;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	allow_write_to_user(to, n);
4768c2ecf20Sopenharmony_ci	ret = raw_copy_to_user_allowed(to, from, n);
4778c2ecf20Sopenharmony_ci	prevent_write_to_user(to, n);
4788c2ecf20Sopenharmony_ci	return ret;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ciunsigned long __arch_clear_user(void __user *addr, unsigned long size);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic inline unsigned long clear_user(void __user *addr, unsigned long size)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	unsigned long ret = size;
4868c2ecf20Sopenharmony_ci	might_fault();
4878c2ecf20Sopenharmony_ci	if (likely(access_ok(addr, size))) {
4888c2ecf20Sopenharmony_ci		allow_write_to_user(addr, size);
4898c2ecf20Sopenharmony_ci		ret = __arch_clear_user(addr, size);
4908c2ecf20Sopenharmony_ci		prevent_write_to_user(addr, size);
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci	return ret;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic inline unsigned long __clear_user(void __user *addr, unsigned long size)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	return clear_user(addr, size);
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *dst, const char __user *src, long count);
5018c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user *str, long n);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ciextern long __copy_from_user_flushcache(void *dst, const void __user *src,
5048c2ecf20Sopenharmony_ci		unsigned size);
5058c2ecf20Sopenharmony_ciextern void memcpy_page_flushcache(char *to, struct page *page, size_t offset,
5068c2ecf20Sopenharmony_ci			   size_t len);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic __must_check inline bool user_access_begin(const void __user *ptr, size_t len)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	if (unlikely(!access_ok(ptr, len)))
5118c2ecf20Sopenharmony_ci		return false;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	might_fault();
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	allow_read_write_user((void __user *)ptr, ptr, len);
5168c2ecf20Sopenharmony_ci	return true;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci#define user_access_begin	user_access_begin
5198c2ecf20Sopenharmony_ci#define user_access_end		prevent_current_access_user
5208c2ecf20Sopenharmony_ci#define user_access_save	prevent_user_access_return
5218c2ecf20Sopenharmony_ci#define user_access_restore	restore_user_access
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic __must_check inline bool
5248c2ecf20Sopenharmony_ciuser_read_access_begin(const void __user *ptr, size_t len)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	if (unlikely(!access_ok(ptr, len)))
5278c2ecf20Sopenharmony_ci		return false;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	might_fault();
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	allow_read_from_user(ptr, len);
5328c2ecf20Sopenharmony_ci	return true;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci#define user_read_access_begin	user_read_access_begin
5358c2ecf20Sopenharmony_ci#define user_read_access_end		prevent_current_read_from_user
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic __must_check inline bool
5388c2ecf20Sopenharmony_ciuser_write_access_begin(const void __user *ptr, size_t len)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	if (unlikely(!access_ok(ptr, len)))
5418c2ecf20Sopenharmony_ci		return false;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	might_fault();
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	allow_write_to_user((void __user *)ptr, len);
5468c2ecf20Sopenharmony_ci	return true;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci#define user_write_access_begin	user_write_access_begin
5498c2ecf20Sopenharmony_ci#define user_write_access_end		prevent_current_write_to_user
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci#define unsafe_op_wrap(op, err) do { if (unlikely(op)) goto err; } while (0)
5528c2ecf20Sopenharmony_ci#define unsafe_get_user(x, p, e) unsafe_op_wrap(__get_user_allowed(x, p), e)
5538c2ecf20Sopenharmony_ci#define unsafe_put_user(x, p, e) __put_user_goto(x, p, e)
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci#define unsafe_copy_to_user(d, s, l, e) \
5568c2ecf20Sopenharmony_cido {									\
5578c2ecf20Sopenharmony_ci	u8 __user *_dst = (u8 __user *)(d);				\
5588c2ecf20Sopenharmony_ci	const u8 *_src = (const u8 *)(s);				\
5598c2ecf20Sopenharmony_ci	size_t _len = (l);						\
5608c2ecf20Sopenharmony_ci	int _i;								\
5618c2ecf20Sopenharmony_ci									\
5628c2ecf20Sopenharmony_ci	for (_i = 0; _i < (_len & ~(sizeof(long) - 1)); _i += sizeof(long))		\
5638c2ecf20Sopenharmony_ci		__put_user_goto(*(long*)(_src + _i), (long __user *)(_dst + _i), e);\
5648c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_PPC64) && (_len & 4)) {			\
5658c2ecf20Sopenharmony_ci		__put_user_goto(*(u32*)(_src + _i), (u32 __user *)(_dst + _i), e);	\
5668c2ecf20Sopenharmony_ci		_i += 4;						\
5678c2ecf20Sopenharmony_ci	}								\
5688c2ecf20Sopenharmony_ci	if (_len & 2) {							\
5698c2ecf20Sopenharmony_ci		__put_user_goto(*(u16*)(_src + _i), (u16 __user *)(_dst + _i), e);	\
5708c2ecf20Sopenharmony_ci		_i += 2;						\
5718c2ecf20Sopenharmony_ci	}								\
5728c2ecf20Sopenharmony_ci	if (_len & 1) \
5738c2ecf20Sopenharmony_ci		__put_user_goto(*(u8*)(_src + _i), (u8 __user *)(_dst + _i), e);\
5748c2ecf20Sopenharmony_ci} while (0)
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci#define HAVE_GET_KERNEL_NOFAULT
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci#define __get_kernel_nofault(dst, src, type, err_label)			\
5798c2ecf20Sopenharmony_cido {									\
5808c2ecf20Sopenharmony_ci	int __kr_err;							\
5818c2ecf20Sopenharmony_ci									\
5828c2ecf20Sopenharmony_ci	__get_user_size_allowed(*((type *)(dst)), (__force type __user *)(src),\
5838c2ecf20Sopenharmony_ci			sizeof(type), __kr_err);			\
5848c2ecf20Sopenharmony_ci	if (unlikely(__kr_err))						\
5858c2ecf20Sopenharmony_ci		goto err_label;						\
5868c2ecf20Sopenharmony_ci} while (0)
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci#define __put_kernel_nofault(dst, src, type, err_label)			\
5898c2ecf20Sopenharmony_ci	__put_user_size_goto(*((type *)(src)),				\
5908c2ecf20Sopenharmony_ci		(__force type __user *)(dst), sizeof(type), err_label)
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci#endif	/* _ARCH_POWERPC_UACCESS_H */
593