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