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