162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ARCH_POWERPC_UACCESS_H
362306a36Sopenharmony_ci#define _ARCH_POWERPC_UACCESS_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/processor.h>
662306a36Sopenharmony_ci#include <asm/page.h>
762306a36Sopenharmony_ci#include <asm/extable.h>
862306a36Sopenharmony_ci#include <asm/kup.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifdef __powerpc64__
1162306a36Sopenharmony_ci/* We use TASK_SIZE_USER64 as TASK_SIZE is not constant */
1262306a36Sopenharmony_ci#define TASK_SIZE_MAX		TASK_SIZE_USER64
1362306a36Sopenharmony_ci#endif
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm-generic/access_ok.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * These are the main single-value transfer routines.  They automatically
1962306a36Sopenharmony_ci * use the right size if we just have the right pointer type.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * This gets kind of ugly. We want to return _two_ values in "get_user()"
2262306a36Sopenharmony_ci * and yet we don't want to do any pointers, because that is too much
2362306a36Sopenharmony_ci * of a performance impact. Thus we have a few rather ugly macros here,
2462306a36Sopenharmony_ci * and hide all the ugliness from the user.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * The "__xxx" versions of the user access functions are versions that
2762306a36Sopenharmony_ci * do not verify the address space, that must have been done previously
2862306a36Sopenharmony_ci * with a separate "access_ok()" call (this is used when we do multiple
2962306a36Sopenharmony_ci * accesses to the same area of user memory).
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * As we use the same address space for kernel and user data on the
3262306a36Sopenharmony_ci * PowerPC, we can just do these as direct assignments.  (Of course, the
3362306a36Sopenharmony_ci * exception handling means that it's no longer "just"...)
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ci#define __put_user(x, ptr)					\
3762306a36Sopenharmony_ci({								\
3862306a36Sopenharmony_ci	long __pu_err;						\
3962306a36Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
4062306a36Sopenharmony_ci	__typeof__(*(ptr)) __pu_val = (__typeof__(*(ptr)))(x);	\
4162306a36Sopenharmony_ci	__typeof__(sizeof(*(ptr))) __pu_size = sizeof(*(ptr));	\
4262306a36Sopenharmony_ci								\
4362306a36Sopenharmony_ci	might_fault();						\
4462306a36Sopenharmony_ci	do {							\
4562306a36Sopenharmony_ci		__label__ __pu_failed;				\
4662306a36Sopenharmony_ci								\
4762306a36Sopenharmony_ci		allow_write_to_user(__pu_addr, __pu_size);	\
4862306a36Sopenharmony_ci		__put_user_size_goto(__pu_val, __pu_addr, __pu_size, __pu_failed);	\
4962306a36Sopenharmony_ci		prevent_write_to_user(__pu_addr, __pu_size);	\
5062306a36Sopenharmony_ci		__pu_err = 0;					\
5162306a36Sopenharmony_ci		break;						\
5262306a36Sopenharmony_ci								\
5362306a36Sopenharmony_ci__pu_failed:							\
5462306a36Sopenharmony_ci		prevent_write_to_user(__pu_addr, __pu_size);	\
5562306a36Sopenharmony_ci		__pu_err = -EFAULT;				\
5662306a36Sopenharmony_ci	} while (0);						\
5762306a36Sopenharmony_ci								\
5862306a36Sopenharmony_ci	__pu_err;						\
5962306a36Sopenharmony_ci})
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define put_user(x, ptr)						\
6262306a36Sopenharmony_ci({									\
6362306a36Sopenharmony_ci	__typeof__(*(ptr)) __user *_pu_addr = (ptr);			\
6462306a36Sopenharmony_ci									\
6562306a36Sopenharmony_ci	access_ok(_pu_addr, sizeof(*(ptr))) ?				\
6662306a36Sopenharmony_ci		  __put_user(x, _pu_addr) : -EFAULT;			\
6762306a36Sopenharmony_ci})
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * We don't tell gcc that we are accessing memory, but this is OK
7162306a36Sopenharmony_ci * because we do not write to any memory gcc knows about, so there
7262306a36Sopenharmony_ci * are no aliasing issues.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_ci/* -mprefixed can generate offsets beyond range, fall back hack */
7562306a36Sopenharmony_ci#ifdef CONFIG_PPC_KERNEL_PREFIXED
7662306a36Sopenharmony_ci#define __put_user_asm_goto(x, addr, label, op)			\
7762306a36Sopenharmony_ci	asm goto(					\
7862306a36Sopenharmony_ci		"1:	" op " %0,0(%1)	# put_user\n"		\
7962306a36Sopenharmony_ci		EX_TABLE(1b, %l2)				\
8062306a36Sopenharmony_ci		:						\
8162306a36Sopenharmony_ci		: "r" (x), "b" (addr)				\
8262306a36Sopenharmony_ci		:						\
8362306a36Sopenharmony_ci		: label)
8462306a36Sopenharmony_ci#else
8562306a36Sopenharmony_ci#define __put_user_asm_goto(x, addr, label, op)			\
8662306a36Sopenharmony_ci	asm goto(					\
8762306a36Sopenharmony_ci		"1:	" op "%U1%X1 %0,%1	# put_user\n"	\
8862306a36Sopenharmony_ci		EX_TABLE(1b, %l2)				\
8962306a36Sopenharmony_ci		:						\
9062306a36Sopenharmony_ci		: "r" (x), "m<>" (*addr)			\
9162306a36Sopenharmony_ci		:						\
9262306a36Sopenharmony_ci		: label)
9362306a36Sopenharmony_ci#endif
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#ifdef __powerpc64__
9662306a36Sopenharmony_ci#define __put_user_asm2_goto(x, ptr, label)			\
9762306a36Sopenharmony_ci	__put_user_asm_goto(x, ptr, label, "std")
9862306a36Sopenharmony_ci#else /* __powerpc64__ */
9962306a36Sopenharmony_ci#define __put_user_asm2_goto(x, addr, label)			\
10062306a36Sopenharmony_ci	asm goto(					\
10162306a36Sopenharmony_ci		"1:	stw%X1 %0, %1\n"			\
10262306a36Sopenharmony_ci		"2:	stw%X1 %L0, %L1\n"			\
10362306a36Sopenharmony_ci		EX_TABLE(1b, %l2)				\
10462306a36Sopenharmony_ci		EX_TABLE(2b, %l2)				\
10562306a36Sopenharmony_ci		:						\
10662306a36Sopenharmony_ci		: "r" (x), "m" (*addr)				\
10762306a36Sopenharmony_ci		:						\
10862306a36Sopenharmony_ci		: label)
10962306a36Sopenharmony_ci#endif /* __powerpc64__ */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define __put_user_size_goto(x, ptr, size, label)		\
11262306a36Sopenharmony_cido {								\
11362306a36Sopenharmony_ci	__typeof__(*(ptr)) __user *__pus_addr = (ptr);		\
11462306a36Sopenharmony_ci								\
11562306a36Sopenharmony_ci	switch (size) {						\
11662306a36Sopenharmony_ci	case 1: __put_user_asm_goto(x, __pus_addr, label, "stb"); break;	\
11762306a36Sopenharmony_ci	case 2: __put_user_asm_goto(x, __pus_addr, label, "sth"); break;	\
11862306a36Sopenharmony_ci	case 4: __put_user_asm_goto(x, __pus_addr, label, "stw"); break;	\
11962306a36Sopenharmony_ci	case 8: __put_user_asm2_goto(x, __pus_addr, label); break;		\
12062306a36Sopenharmony_ci	default: BUILD_BUG();					\
12162306a36Sopenharmony_ci	}							\
12262306a36Sopenharmony_ci} while (0)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * This does an atomic 128 byte aligned load from userspace.
12662306a36Sopenharmony_ci * Upto caller to do enable_kernel_vmx() before calling!
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_ci#define __get_user_atomic_128_aligned(kaddr, uaddr, err)		\
12962306a36Sopenharmony_ci	__asm__ __volatile__(				\
13062306a36Sopenharmony_ci		".machine push\n"			\
13162306a36Sopenharmony_ci		".machine altivec\n"			\
13262306a36Sopenharmony_ci		"1:	lvx  0,0,%1	# get user\n"	\
13362306a36Sopenharmony_ci		" 	stvx 0,0,%2	# put kernel\n"	\
13462306a36Sopenharmony_ci		".machine pop\n"			\
13562306a36Sopenharmony_ci		"2:\n"					\
13662306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
13762306a36Sopenharmony_ci		"3:	li %0,%3\n"			\
13862306a36Sopenharmony_ci		"	b 2b\n"				\
13962306a36Sopenharmony_ci		".previous\n"				\
14062306a36Sopenharmony_ci		EX_TABLE(1b, 3b)			\
14162306a36Sopenharmony_ci		: "=r" (err)			\
14262306a36Sopenharmony_ci		: "b" (uaddr), "b" (kaddr), "i" (-EFAULT), "0" (err))
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* -mprefixed can generate offsets beyond range, fall back hack */
14762306a36Sopenharmony_ci#ifdef CONFIG_PPC_KERNEL_PREFIXED
14862306a36Sopenharmony_ci#define __get_user_asm_goto(x, addr, label, op)			\
14962306a36Sopenharmony_ci	asm_goto_output(					\
15062306a36Sopenharmony_ci		"1:	"op" %0,0(%1)	# get_user\n"		\
15162306a36Sopenharmony_ci		EX_TABLE(1b, %l2)				\
15262306a36Sopenharmony_ci		: "=r" (x)					\
15362306a36Sopenharmony_ci		: "b" (addr)					\
15462306a36Sopenharmony_ci		:						\
15562306a36Sopenharmony_ci		: label)
15662306a36Sopenharmony_ci#else
15762306a36Sopenharmony_ci#define __get_user_asm_goto(x, addr, label, op)			\
15862306a36Sopenharmony_ci	asm_goto_output(					\
15962306a36Sopenharmony_ci		"1:	"op"%U1%X1 %0, %1	# get_user\n"	\
16062306a36Sopenharmony_ci		EX_TABLE(1b, %l2)				\
16162306a36Sopenharmony_ci		: "=r" (x)					\
16262306a36Sopenharmony_ci		: "m<>" (*addr)					\
16362306a36Sopenharmony_ci		:						\
16462306a36Sopenharmony_ci		: label)
16562306a36Sopenharmony_ci#endif
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#ifdef __powerpc64__
16862306a36Sopenharmony_ci#define __get_user_asm2_goto(x, addr, label)			\
16962306a36Sopenharmony_ci	__get_user_asm_goto(x, addr, label, "ld")
17062306a36Sopenharmony_ci#else /* __powerpc64__ */
17162306a36Sopenharmony_ci#define __get_user_asm2_goto(x, addr, label)			\
17262306a36Sopenharmony_ci	asm_goto_output(					\
17362306a36Sopenharmony_ci		"1:	lwz%X1 %0, %1\n"			\
17462306a36Sopenharmony_ci		"2:	lwz%X1 %L0, %L1\n"			\
17562306a36Sopenharmony_ci		EX_TABLE(1b, %l2)				\
17662306a36Sopenharmony_ci		EX_TABLE(2b, %l2)				\
17762306a36Sopenharmony_ci		: "=&r" (x)					\
17862306a36Sopenharmony_ci		: "m" (*addr)					\
17962306a36Sopenharmony_ci		:						\
18062306a36Sopenharmony_ci		: label)
18162306a36Sopenharmony_ci#endif /* __powerpc64__ */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define __get_user_size_goto(x, ptr, size, label)				\
18462306a36Sopenharmony_cido {										\
18562306a36Sopenharmony_ci	BUILD_BUG_ON(size > sizeof(x));						\
18662306a36Sopenharmony_ci	switch (size) {								\
18762306a36Sopenharmony_ci	case 1: __get_user_asm_goto(x, (u8 __user *)ptr, label, "lbz"); break;	\
18862306a36Sopenharmony_ci	case 2: __get_user_asm_goto(x, (u16 __user *)ptr, label, "lhz"); break;	\
18962306a36Sopenharmony_ci	case 4: __get_user_asm_goto(x, (u32 __user *)ptr, label, "lwz"); break;	\
19062306a36Sopenharmony_ci	case 8: __get_user_asm2_goto(x, (u64 __user *)ptr, label);  break;	\
19162306a36Sopenharmony_ci	default: x = 0; BUILD_BUG();						\
19262306a36Sopenharmony_ci	}									\
19362306a36Sopenharmony_ci} while (0)
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define __get_user_size_allowed(x, ptr, size, retval)			\
19662306a36Sopenharmony_cido {									\
19762306a36Sopenharmony_ci		__label__ __gus_failed;					\
19862306a36Sopenharmony_ci									\
19962306a36Sopenharmony_ci		__get_user_size_goto(x, ptr, size, __gus_failed);	\
20062306a36Sopenharmony_ci		retval = 0;						\
20162306a36Sopenharmony_ci		break;							\
20262306a36Sopenharmony_ci__gus_failed:								\
20362306a36Sopenharmony_ci		x = 0;							\
20462306a36Sopenharmony_ci		retval = -EFAULT;					\
20562306a36Sopenharmony_ci} while (0)
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci#else /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define __get_user_asm(x, addr, err, op)		\
21062306a36Sopenharmony_ci	__asm__ __volatile__(				\
21162306a36Sopenharmony_ci		"1:	"op"%U2%X2 %1, %2	# get_user\n"	\
21262306a36Sopenharmony_ci		"2:\n"					\
21362306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
21462306a36Sopenharmony_ci		"3:	li %0,%3\n"			\
21562306a36Sopenharmony_ci		"	li %1,0\n"			\
21662306a36Sopenharmony_ci		"	b 2b\n"				\
21762306a36Sopenharmony_ci		".previous\n"				\
21862306a36Sopenharmony_ci		EX_TABLE(1b, 3b)			\
21962306a36Sopenharmony_ci		: "=r" (err), "=r" (x)			\
22062306a36Sopenharmony_ci		: "m<>" (*addr), "i" (-EFAULT), "0" (err))
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci#ifdef __powerpc64__
22362306a36Sopenharmony_ci#define __get_user_asm2(x, addr, err)			\
22462306a36Sopenharmony_ci	__get_user_asm(x, addr, err, "ld")
22562306a36Sopenharmony_ci#else /* __powerpc64__ */
22662306a36Sopenharmony_ci#define __get_user_asm2(x, addr, err)			\
22762306a36Sopenharmony_ci	__asm__ __volatile__(				\
22862306a36Sopenharmony_ci		"1:	lwz%X2 %1, %2\n"			\
22962306a36Sopenharmony_ci		"2:	lwz%X2 %L1, %L2\n"		\
23062306a36Sopenharmony_ci		"3:\n"					\
23162306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
23262306a36Sopenharmony_ci		"4:	li %0,%3\n"			\
23362306a36Sopenharmony_ci		"	li %1,0\n"			\
23462306a36Sopenharmony_ci		"	li %1+1,0\n"			\
23562306a36Sopenharmony_ci		"	b 3b\n"				\
23662306a36Sopenharmony_ci		".previous\n"				\
23762306a36Sopenharmony_ci		EX_TABLE(1b, 4b)			\
23862306a36Sopenharmony_ci		EX_TABLE(2b, 4b)			\
23962306a36Sopenharmony_ci		: "=r" (err), "=&r" (x)			\
24062306a36Sopenharmony_ci		: "m" (*addr), "i" (-EFAULT), "0" (err))
24162306a36Sopenharmony_ci#endif /* __powerpc64__ */
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#define __get_user_size_allowed(x, ptr, size, retval)		\
24462306a36Sopenharmony_cido {								\
24562306a36Sopenharmony_ci	retval = 0;						\
24662306a36Sopenharmony_ci	BUILD_BUG_ON(size > sizeof(x));				\
24762306a36Sopenharmony_ci	switch (size) {						\
24862306a36Sopenharmony_ci	case 1: __get_user_asm(x, (u8 __user *)ptr, retval, "lbz"); break;	\
24962306a36Sopenharmony_ci	case 2: __get_user_asm(x, (u16 __user *)ptr, retval, "lhz"); break;	\
25062306a36Sopenharmony_ci	case 4: __get_user_asm(x, (u32 __user *)ptr, retval, "lwz"); break;	\
25162306a36Sopenharmony_ci	case 8: __get_user_asm2(x, (u64 __user *)ptr, retval);  break;	\
25262306a36Sopenharmony_ci	default: x = 0; BUILD_BUG();				\
25362306a36Sopenharmony_ci	}							\
25462306a36Sopenharmony_ci} while (0)
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci#define __get_user_size_goto(x, ptr, size, label)		\
25762306a36Sopenharmony_cido {								\
25862306a36Sopenharmony_ci	long __gus_retval;					\
25962306a36Sopenharmony_ci								\
26062306a36Sopenharmony_ci	__get_user_size_allowed(x, ptr, size, __gus_retval);	\
26162306a36Sopenharmony_ci	if (__gus_retval)					\
26262306a36Sopenharmony_ci		goto label;					\
26362306a36Sopenharmony_ci} while (0)
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * This is a type: either unsigned long, if the argument fits into
26962306a36Sopenharmony_ci * that type, or otherwise unsigned long long.
27062306a36Sopenharmony_ci */
27162306a36Sopenharmony_ci#define __long_type(x) \
27262306a36Sopenharmony_ci	__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#define __get_user(x, ptr)					\
27562306a36Sopenharmony_ci({								\
27662306a36Sopenharmony_ci	long __gu_err;						\
27762306a36Sopenharmony_ci	__long_type(*(ptr)) __gu_val;				\
27862306a36Sopenharmony_ci	__typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
27962306a36Sopenharmony_ci	__typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr));	\
28062306a36Sopenharmony_ci								\
28162306a36Sopenharmony_ci	might_fault();					\
28262306a36Sopenharmony_ci	allow_read_from_user(__gu_addr, __gu_size);		\
28362306a36Sopenharmony_ci	__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err);	\
28462306a36Sopenharmony_ci	prevent_read_from_user(__gu_addr, __gu_size);		\
28562306a36Sopenharmony_ci	(x) = (__typeof__(*(ptr)))__gu_val;			\
28662306a36Sopenharmony_ci								\
28762306a36Sopenharmony_ci	__gu_err;						\
28862306a36Sopenharmony_ci})
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci#define get_user(x, ptr)						\
29162306a36Sopenharmony_ci({									\
29262306a36Sopenharmony_ci	__typeof__(*(ptr)) __user *_gu_addr = (ptr);			\
29362306a36Sopenharmony_ci									\
29462306a36Sopenharmony_ci	access_ok(_gu_addr, sizeof(*(ptr))) ?				\
29562306a36Sopenharmony_ci		  __get_user(x, _gu_addr) :				\
29662306a36Sopenharmony_ci		  ((x) = (__force __typeof__(*(ptr)))0, -EFAULT);	\
29762306a36Sopenharmony_ci})
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/* more complex routines */
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciextern unsigned long __copy_tofrom_user(void __user *to,
30262306a36Sopenharmony_ci		const void __user *from, unsigned long size);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci#ifdef __powerpc64__
30562306a36Sopenharmony_cistatic inline unsigned long
30662306a36Sopenharmony_ciraw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	unsigned long ret;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	allow_read_write_user(to, from, n);
31162306a36Sopenharmony_ci	ret = __copy_tofrom_user(to, from, n);
31262306a36Sopenharmony_ci	prevent_read_write_user(to, from, n);
31362306a36Sopenharmony_ci	return ret;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci#endif /* __powerpc64__ */
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic inline unsigned long raw_copy_from_user(void *to,
31862306a36Sopenharmony_ci		const void __user *from, unsigned long n)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	unsigned long ret;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	allow_read_from_user(from, n);
32362306a36Sopenharmony_ci	ret = __copy_tofrom_user((__force void __user *)to, from, n);
32462306a36Sopenharmony_ci	prevent_read_from_user(from, n);
32562306a36Sopenharmony_ci	return ret;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic inline unsigned long
32962306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	unsigned long ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	allow_write_to_user(to, n);
33462306a36Sopenharmony_ci	ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
33562306a36Sopenharmony_ci	prevent_write_to_user(to, n);
33662306a36Sopenharmony_ci	return ret;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciunsigned long __arch_clear_user(void __user *addr, unsigned long size);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic inline unsigned long __clear_user(void __user *addr, unsigned long size)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	unsigned long ret;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	might_fault();
34662306a36Sopenharmony_ci	allow_write_to_user(addr, size);
34762306a36Sopenharmony_ci	ret = __arch_clear_user(addr, size);
34862306a36Sopenharmony_ci	prevent_write_to_user(addr, size);
34962306a36Sopenharmony_ci	return ret;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic inline unsigned long clear_user(void __user *addr, unsigned long size)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	return likely(access_ok(addr, size)) ? __clear_user(addr, size) : size;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciextern long strncpy_from_user(char *dst, const char __user *src, long count);
35862306a36Sopenharmony_ciextern __must_check long strnlen_user(const char __user *str, long n);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_COPY_MC
36162306a36Sopenharmony_ciunsigned long __must_check
36262306a36Sopenharmony_cicopy_mc_generic(void *to, const void *from, unsigned long size);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic inline unsigned long __must_check
36562306a36Sopenharmony_cicopy_mc_to_kernel(void *to, const void *from, unsigned long size)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	return copy_mc_generic(to, from, size);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci#define copy_mc_to_kernel copy_mc_to_kernel
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic inline unsigned long __must_check
37262306a36Sopenharmony_cicopy_mc_to_user(void __user *to, const void *from, unsigned long n)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	if (check_copy_size(from, n, true)) {
37562306a36Sopenharmony_ci		if (access_ok(to, n)) {
37662306a36Sopenharmony_ci			allow_write_to_user(to, n);
37762306a36Sopenharmony_ci			n = copy_mc_generic((void *)to, from, n);
37862306a36Sopenharmony_ci			prevent_write_to_user(to, n);
37962306a36Sopenharmony_ci		}
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return n;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci#endif
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ciextern long __copy_from_user_flushcache(void *dst, const void __user *src,
38762306a36Sopenharmony_ci		unsigned size);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	if (unlikely(!access_ok(ptr, len)))
39262306a36Sopenharmony_ci		return false;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	might_fault();
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	allow_read_write_user((void __user *)ptr, ptr, len);
39762306a36Sopenharmony_ci	return true;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci#define user_access_begin	user_access_begin
40062306a36Sopenharmony_ci#define user_access_end		prevent_current_access_user
40162306a36Sopenharmony_ci#define user_access_save	prevent_user_access_return
40262306a36Sopenharmony_ci#define user_access_restore	restore_user_access
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic __must_check __always_inline bool
40562306a36Sopenharmony_ciuser_read_access_begin(const void __user *ptr, size_t len)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	if (unlikely(!access_ok(ptr, len)))
40862306a36Sopenharmony_ci		return false;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	might_fault();
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	allow_read_from_user(ptr, len);
41362306a36Sopenharmony_ci	return true;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci#define user_read_access_begin	user_read_access_begin
41662306a36Sopenharmony_ci#define user_read_access_end		prevent_current_read_from_user
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic __must_check __always_inline bool
41962306a36Sopenharmony_ciuser_write_access_begin(const void __user *ptr, size_t len)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	if (unlikely(!access_ok(ptr, len)))
42262306a36Sopenharmony_ci		return false;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	might_fault();
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	allow_write_to_user((void __user *)ptr, len);
42762306a36Sopenharmony_ci	return true;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci#define user_write_access_begin	user_write_access_begin
43062306a36Sopenharmony_ci#define user_write_access_end		prevent_current_write_to_user
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci#define unsafe_get_user(x, p, e) do {					\
43362306a36Sopenharmony_ci	__long_type(*(p)) __gu_val;				\
43462306a36Sopenharmony_ci	__typeof__(*(p)) __user *__gu_addr = (p);		\
43562306a36Sopenharmony_ci								\
43662306a36Sopenharmony_ci	__get_user_size_goto(__gu_val, __gu_addr, sizeof(*(p)), e); \
43762306a36Sopenharmony_ci	(x) = (__typeof__(*(p)))__gu_val;			\
43862306a36Sopenharmony_ci} while (0)
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci#define unsafe_put_user(x, p, e) \
44162306a36Sopenharmony_ci	__put_user_size_goto((__typeof__(*(p)))(x), (p), sizeof(*(p)), e)
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci#define unsafe_copy_from_user(d, s, l, e) \
44462306a36Sopenharmony_cido {											\
44562306a36Sopenharmony_ci	u8 *_dst = (u8 *)(d);								\
44662306a36Sopenharmony_ci	const u8 __user *_src = (const u8 __user *)(s);					\
44762306a36Sopenharmony_ci	size_t _len = (l);								\
44862306a36Sopenharmony_ci	int _i;										\
44962306a36Sopenharmony_ci											\
45062306a36Sopenharmony_ci	for (_i = 0; _i < (_len & ~(sizeof(u64) - 1)); _i += sizeof(u64))		\
45162306a36Sopenharmony_ci		unsafe_get_user(*(u64 *)(_dst + _i), (u64 __user *)(_src + _i), e);	\
45262306a36Sopenharmony_ci	if (_len & 4) {									\
45362306a36Sopenharmony_ci		unsafe_get_user(*(u32 *)(_dst + _i), (u32 __user *)(_src + _i), e);	\
45462306a36Sopenharmony_ci		_i += 4;								\
45562306a36Sopenharmony_ci	}										\
45662306a36Sopenharmony_ci	if (_len & 2) {									\
45762306a36Sopenharmony_ci		unsafe_get_user(*(u16 *)(_dst + _i), (u16 __user *)(_src + _i), e);	\
45862306a36Sopenharmony_ci		_i += 2;								\
45962306a36Sopenharmony_ci	}										\
46062306a36Sopenharmony_ci	if (_len & 1)									\
46162306a36Sopenharmony_ci		unsafe_get_user(*(u8 *)(_dst + _i), (u8 __user *)(_src + _i), e);	\
46262306a36Sopenharmony_ci} while (0)
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#define unsafe_copy_to_user(d, s, l, e) \
46562306a36Sopenharmony_cido {									\
46662306a36Sopenharmony_ci	u8 __user *_dst = (u8 __user *)(d);				\
46762306a36Sopenharmony_ci	const u8 *_src = (const u8 *)(s);				\
46862306a36Sopenharmony_ci	size_t _len = (l);						\
46962306a36Sopenharmony_ci	int _i;								\
47062306a36Sopenharmony_ci									\
47162306a36Sopenharmony_ci	for (_i = 0; _i < (_len & ~(sizeof(u64) - 1)); _i += sizeof(u64))	\
47262306a36Sopenharmony_ci		unsafe_put_user(*(u64 *)(_src + _i), (u64 __user *)(_dst + _i), e); \
47362306a36Sopenharmony_ci	if (_len & 4) {							\
47462306a36Sopenharmony_ci		unsafe_put_user(*(u32*)(_src + _i), (u32 __user *)(_dst + _i), e); \
47562306a36Sopenharmony_ci		_i += 4;						\
47662306a36Sopenharmony_ci	}								\
47762306a36Sopenharmony_ci	if (_len & 2) {							\
47862306a36Sopenharmony_ci		unsafe_put_user(*(u16*)(_src + _i), (u16 __user *)(_dst + _i), e); \
47962306a36Sopenharmony_ci		_i += 2;						\
48062306a36Sopenharmony_ci	}								\
48162306a36Sopenharmony_ci	if (_len & 1) \
48262306a36Sopenharmony_ci		unsafe_put_user(*(u8*)(_src + _i), (u8 __user *)(_dst + _i), e); \
48362306a36Sopenharmony_ci} while (0)
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci#define __get_kernel_nofault(dst, src, type, err_label)			\
48662306a36Sopenharmony_ci	__get_user_size_goto(*((type *)(dst)),				\
48762306a36Sopenharmony_ci		(__force type __user *)(src), sizeof(type), err_label)
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci#define __put_kernel_nofault(dst, src, type, err_label)			\
49062306a36Sopenharmony_ci	__put_user_size_goto(*((type *)(src)),				\
49162306a36Sopenharmony_ci		(__force type __user *)(dst), sizeof(type), err_label)
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci#endif	/* _ARCH_POWERPC_UACCESS_H */
494