18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci// Copyright (C) 2005-2017 Andes Technology Corporation 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#ifndef _ASMANDES_UACCESS_H 58c2ecf20Sopenharmony_ci#define _ASMANDES_UACCESS_H 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * User space memory access functions 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/sched.h> 118c2ecf20Sopenharmony_ci#include <asm/errno.h> 128c2ecf20Sopenharmony_ci#include <asm/memory.h> 138c2ecf20Sopenharmony_ci#include <asm/types.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * The exception table consists of pairs of addresses: the first is the 198c2ecf20Sopenharmony_ci * address of an instruction that is allowed to fault, and the second is 208c2ecf20Sopenharmony_ci * the address at which the program should continue. No registers are 218c2ecf20Sopenharmony_ci * modified, so it is entirely up to the continuation code to figure out 228c2ecf20Sopenharmony_ci * what to do. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * All the routines below use bits of fixup code that are out of line 258c2ecf20Sopenharmony_ci * with the main instruction path. This means when everything is well, 268c2ecf20Sopenharmony_ci * we don't even have to jump over them. Further, they do not intrude 278c2ecf20Sopenharmony_ci * on our cache or tlb entries. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct exception_table_entry { 318c2ecf20Sopenharmony_ci unsigned long insn, fixup; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciextern int fixup_exception(struct pt_regs *regs); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define KERNEL_DS ((mm_segment_t) { ~0UL }) 378c2ecf20Sopenharmony_ci#define USER_DS ((mm_segment_t) {TASK_SIZE - 1}) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define get_fs() (current_thread_info()->addr_limit) 408c2ecf20Sopenharmony_ci#define user_addr_max get_fs 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline void set_fs(mm_segment_t fs) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci current_thread_info()->addr_limit = fs; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs() == KERNEL_DS) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define __range_ok(addr, size) (size <= get_fs() && addr <= (get_fs() -size)) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define access_ok(addr, size) \ 528c2ecf20Sopenharmony_ci __range_ok((unsigned long)addr, (unsigned long)size) 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Single-value transfer routines. They automatically use the right 558c2ecf20Sopenharmony_ci * size if we just have the right pointer type. Note that the functions 568c2ecf20Sopenharmony_ci * which read from user space (*get_*) need to take care not to leak 578c2ecf20Sopenharmony_ci * kernel data even if the calling code is buggy and fails to check 588c2ecf20Sopenharmony_ci * the return value. This means zeroing out the destination variable 598c2ecf20Sopenharmony_ci * or buffer on error. Normally this is done out of line by the 608c2ecf20Sopenharmony_ci * fixup code, but there are a few places where it intrudes on the 618c2ecf20Sopenharmony_ci * main code path. When we only write to user space, there is no 628c2ecf20Sopenharmony_ci * problem. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * The "__xxx" versions of the user access functions do not verify the 658c2ecf20Sopenharmony_ci * address space - it must have been done previously with a separate 668c2ecf20Sopenharmony_ci * "access_ok()" call. 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * The "xxx_error" versions set the third argument to EFAULT if an 698c2ecf20Sopenharmony_ci * error occurs, and leave it unchanged on success. Note that these 708c2ecf20Sopenharmony_ci * versions are void (ie, don't return a value as such). 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define get_user(x, ptr) \ 748c2ecf20Sopenharmony_ci({ \ 758c2ecf20Sopenharmony_ci long __gu_err = 0; \ 768c2ecf20Sopenharmony_ci __get_user_check((x), (ptr), __gu_err); \ 778c2ecf20Sopenharmony_ci __gu_err; \ 788c2ecf20Sopenharmony_ci}) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define __get_user_error(x, ptr, err) \ 818c2ecf20Sopenharmony_ci({ \ 828c2ecf20Sopenharmony_ci __get_user_check((x), (ptr), (err)); \ 838c2ecf20Sopenharmony_ci (void)0; \ 848c2ecf20Sopenharmony_ci}) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define __get_user(x, ptr) \ 878c2ecf20Sopenharmony_ci({ \ 888c2ecf20Sopenharmony_ci long __gu_err = 0; \ 898c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) __user *__p = (ptr); \ 908c2ecf20Sopenharmony_ci __get_user_err((x), __p, (__gu_err)); \ 918c2ecf20Sopenharmony_ci __gu_err; \ 928c2ecf20Sopenharmony_ci}) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define __get_user_check(x, ptr, err) \ 958c2ecf20Sopenharmony_ci({ \ 968c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) __user *__p = (ptr); \ 978c2ecf20Sopenharmony_ci might_fault(); \ 988c2ecf20Sopenharmony_ci if (access_ok(__p, sizeof(*__p))) { \ 998c2ecf20Sopenharmony_ci __get_user_err((x), __p, (err)); \ 1008c2ecf20Sopenharmony_ci } else { \ 1018c2ecf20Sopenharmony_ci (x) = 0; (err) = -EFAULT; \ 1028c2ecf20Sopenharmony_ci } \ 1038c2ecf20Sopenharmony_ci}) 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define __get_user_err(x, ptr, err) \ 1068c2ecf20Sopenharmony_cido { \ 1078c2ecf20Sopenharmony_ci unsigned long __gu_val; \ 1088c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 1098c2ecf20Sopenharmony_ci switch (sizeof(*(ptr))) { \ 1108c2ecf20Sopenharmony_ci case 1: \ 1118c2ecf20Sopenharmony_ci __get_user_asm("lbi", __gu_val, (ptr), (err)); \ 1128c2ecf20Sopenharmony_ci break; \ 1138c2ecf20Sopenharmony_ci case 2: \ 1148c2ecf20Sopenharmony_ci __get_user_asm("lhi", __gu_val, (ptr), (err)); \ 1158c2ecf20Sopenharmony_ci break; \ 1168c2ecf20Sopenharmony_ci case 4: \ 1178c2ecf20Sopenharmony_ci __get_user_asm("lwi", __gu_val, (ptr), (err)); \ 1188c2ecf20Sopenharmony_ci break; \ 1198c2ecf20Sopenharmony_ci case 8: \ 1208c2ecf20Sopenharmony_ci __get_user_asm_dword(__gu_val, (ptr), (err)); \ 1218c2ecf20Sopenharmony_ci break; \ 1228c2ecf20Sopenharmony_ci default: \ 1238c2ecf20Sopenharmony_ci BUILD_BUG(); \ 1248c2ecf20Sopenharmony_ci break; \ 1258c2ecf20Sopenharmony_ci } \ 1268c2ecf20Sopenharmony_ci (x) = (__force __typeof__(*(ptr)))__gu_val; \ 1278c2ecf20Sopenharmony_ci} while (0) 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define __get_user_asm(inst, x, addr, err) \ 1308c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 1318c2ecf20Sopenharmony_ci "1: "inst" %1,[%2]\n" \ 1328c2ecf20Sopenharmony_ci "2:\n" \ 1338c2ecf20Sopenharmony_ci " .section .fixup,\"ax\"\n" \ 1348c2ecf20Sopenharmony_ci " .align 2\n" \ 1358c2ecf20Sopenharmony_ci "3: move %0, %3\n" \ 1368c2ecf20Sopenharmony_ci " move %1, #0\n" \ 1378c2ecf20Sopenharmony_ci " b 2b\n" \ 1388c2ecf20Sopenharmony_ci " .previous\n" \ 1398c2ecf20Sopenharmony_ci " .section __ex_table,\"a\"\n" \ 1408c2ecf20Sopenharmony_ci " .align 3\n" \ 1418c2ecf20Sopenharmony_ci " .long 1b, 3b\n" \ 1428c2ecf20Sopenharmony_ci " .previous" \ 1438c2ecf20Sopenharmony_ci : "+r" (err), "=&r" (x) \ 1448c2ecf20Sopenharmony_ci : "r" (addr), "i" (-EFAULT) \ 1458c2ecf20Sopenharmony_ci : "cc") 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#ifdef __NDS32_EB__ 1488c2ecf20Sopenharmony_ci#define __gu_reg_oper0 "%H1" 1498c2ecf20Sopenharmony_ci#define __gu_reg_oper1 "%L1" 1508c2ecf20Sopenharmony_ci#else 1518c2ecf20Sopenharmony_ci#define __gu_reg_oper0 "%L1" 1528c2ecf20Sopenharmony_ci#define __gu_reg_oper1 "%H1" 1538c2ecf20Sopenharmony_ci#endif 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define __get_user_asm_dword(x, addr, err) \ 1568c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 1578c2ecf20Sopenharmony_ci "\n1:\tlwi " __gu_reg_oper0 ",[%2]\n" \ 1588c2ecf20Sopenharmony_ci "\n2:\tlwi " __gu_reg_oper1 ",[%2+4]\n" \ 1598c2ecf20Sopenharmony_ci "3:\n" \ 1608c2ecf20Sopenharmony_ci " .section .fixup,\"ax\"\n" \ 1618c2ecf20Sopenharmony_ci " .align 2\n" \ 1628c2ecf20Sopenharmony_ci "4: move %0, %3\n" \ 1638c2ecf20Sopenharmony_ci " b 3b\n" \ 1648c2ecf20Sopenharmony_ci " .previous\n" \ 1658c2ecf20Sopenharmony_ci " .section __ex_table,\"a\"\n" \ 1668c2ecf20Sopenharmony_ci " .align 3\n" \ 1678c2ecf20Sopenharmony_ci " .long 1b, 4b\n" \ 1688c2ecf20Sopenharmony_ci " .long 2b, 4b\n" \ 1698c2ecf20Sopenharmony_ci " .previous" \ 1708c2ecf20Sopenharmony_ci : "+r"(err), "=&r"(x) \ 1718c2ecf20Sopenharmony_ci : "r"(addr), "i"(-EFAULT) \ 1728c2ecf20Sopenharmony_ci : "cc") 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define put_user(x, ptr) \ 1758c2ecf20Sopenharmony_ci({ \ 1768c2ecf20Sopenharmony_ci long __pu_err = 0; \ 1778c2ecf20Sopenharmony_ci __put_user_check((x), (ptr), __pu_err); \ 1788c2ecf20Sopenharmony_ci __pu_err; \ 1798c2ecf20Sopenharmony_ci}) 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define __put_user(x, ptr) \ 1828c2ecf20Sopenharmony_ci({ \ 1838c2ecf20Sopenharmony_ci long __pu_err = 0; \ 1848c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __user *__p = (ptr); \ 1858c2ecf20Sopenharmony_ci __put_user_err((x), __p, __pu_err); \ 1868c2ecf20Sopenharmony_ci __pu_err; \ 1878c2ecf20Sopenharmony_ci}) 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#define __put_user_error(x, ptr, err) \ 1908c2ecf20Sopenharmony_ci({ \ 1918c2ecf20Sopenharmony_ci __put_user_err((x), (ptr), (err)); \ 1928c2ecf20Sopenharmony_ci (void)0; \ 1938c2ecf20Sopenharmony_ci}) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define __put_user_check(x, ptr, err) \ 1968c2ecf20Sopenharmony_ci({ \ 1978c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __user *__p = (ptr); \ 1988c2ecf20Sopenharmony_ci might_fault(); \ 1998c2ecf20Sopenharmony_ci if (access_ok(__p, sizeof(*__p))) { \ 2008c2ecf20Sopenharmony_ci __put_user_err((x), __p, (err)); \ 2018c2ecf20Sopenharmony_ci } else { \ 2028c2ecf20Sopenharmony_ci (err) = -EFAULT; \ 2038c2ecf20Sopenharmony_ci } \ 2048c2ecf20Sopenharmony_ci}) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define __put_user_err(x, ptr, err) \ 2078c2ecf20Sopenharmony_cido { \ 2088c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __pu_val = (x); \ 2098c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 2108c2ecf20Sopenharmony_ci switch (sizeof(*(ptr))) { \ 2118c2ecf20Sopenharmony_ci case 1: \ 2128c2ecf20Sopenharmony_ci __put_user_asm("sbi", __pu_val, (ptr), (err)); \ 2138c2ecf20Sopenharmony_ci break; \ 2148c2ecf20Sopenharmony_ci case 2: \ 2158c2ecf20Sopenharmony_ci __put_user_asm("shi", __pu_val, (ptr), (err)); \ 2168c2ecf20Sopenharmony_ci break; \ 2178c2ecf20Sopenharmony_ci case 4: \ 2188c2ecf20Sopenharmony_ci __put_user_asm("swi", __pu_val, (ptr), (err)); \ 2198c2ecf20Sopenharmony_ci break; \ 2208c2ecf20Sopenharmony_ci case 8: \ 2218c2ecf20Sopenharmony_ci __put_user_asm_dword(__pu_val, (ptr), (err)); \ 2228c2ecf20Sopenharmony_ci break; \ 2238c2ecf20Sopenharmony_ci default: \ 2248c2ecf20Sopenharmony_ci BUILD_BUG(); \ 2258c2ecf20Sopenharmony_ci break; \ 2268c2ecf20Sopenharmony_ci } \ 2278c2ecf20Sopenharmony_ci} while (0) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define __put_user_asm(inst, x, addr, err) \ 2308c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 2318c2ecf20Sopenharmony_ci "1: "inst" %1,[%2]\n" \ 2328c2ecf20Sopenharmony_ci "2:\n" \ 2338c2ecf20Sopenharmony_ci " .section .fixup,\"ax\"\n" \ 2348c2ecf20Sopenharmony_ci " .align 2\n" \ 2358c2ecf20Sopenharmony_ci "3: move %0, %3\n" \ 2368c2ecf20Sopenharmony_ci " b 2b\n" \ 2378c2ecf20Sopenharmony_ci " .previous\n" \ 2388c2ecf20Sopenharmony_ci " .section __ex_table,\"a\"\n" \ 2398c2ecf20Sopenharmony_ci " .align 3\n" \ 2408c2ecf20Sopenharmony_ci " .long 1b, 3b\n" \ 2418c2ecf20Sopenharmony_ci " .previous" \ 2428c2ecf20Sopenharmony_ci : "+r" (err) \ 2438c2ecf20Sopenharmony_ci : "r" (x), "r" (addr), "i" (-EFAULT) \ 2448c2ecf20Sopenharmony_ci : "cc") 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci#ifdef __NDS32_EB__ 2478c2ecf20Sopenharmony_ci#define __pu_reg_oper0 "%H2" 2488c2ecf20Sopenharmony_ci#define __pu_reg_oper1 "%L2" 2498c2ecf20Sopenharmony_ci#else 2508c2ecf20Sopenharmony_ci#define __pu_reg_oper0 "%L2" 2518c2ecf20Sopenharmony_ci#define __pu_reg_oper1 "%H2" 2528c2ecf20Sopenharmony_ci#endif 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define __put_user_asm_dword(x, addr, err) \ 2558c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 2568c2ecf20Sopenharmony_ci "\n1:\tswi " __pu_reg_oper0 ",[%1]\n" \ 2578c2ecf20Sopenharmony_ci "\n2:\tswi " __pu_reg_oper1 ",[%1+4]\n" \ 2588c2ecf20Sopenharmony_ci "3:\n" \ 2598c2ecf20Sopenharmony_ci " .section .fixup,\"ax\"\n" \ 2608c2ecf20Sopenharmony_ci " .align 2\n" \ 2618c2ecf20Sopenharmony_ci "4: move %0, %3\n" \ 2628c2ecf20Sopenharmony_ci " b 3b\n" \ 2638c2ecf20Sopenharmony_ci " .previous\n" \ 2648c2ecf20Sopenharmony_ci " .section __ex_table,\"a\"\n" \ 2658c2ecf20Sopenharmony_ci " .align 3\n" \ 2668c2ecf20Sopenharmony_ci " .long 1b, 4b\n" \ 2678c2ecf20Sopenharmony_ci " .long 2b, 4b\n" \ 2688c2ecf20Sopenharmony_ci " .previous" \ 2698c2ecf20Sopenharmony_ci : "+r"(err) \ 2708c2ecf20Sopenharmony_ci : "r"(addr), "r"(x), "i"(-EFAULT) \ 2718c2ecf20Sopenharmony_ci : "cc") 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciextern unsigned long __arch_clear_user(void __user * addr, unsigned long n); 2748c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *dest, const char __user * src, long count); 2758c2ecf20Sopenharmony_ciextern __must_check long strlen_user(const char __user * str); 2768c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user * str, long n); 2778c2ecf20Sopenharmony_ciextern unsigned long __arch_copy_from_user(void *to, const void __user * from, 2788c2ecf20Sopenharmony_ci unsigned long n); 2798c2ecf20Sopenharmony_ciextern unsigned long __arch_copy_to_user(void __user * to, const void *from, 2808c2ecf20Sopenharmony_ci unsigned long n); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci#define raw_copy_from_user __arch_copy_from_user 2838c2ecf20Sopenharmony_ci#define raw_copy_to_user __arch_copy_to_user 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 2868c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 2878c2ecf20Sopenharmony_cistatic inline unsigned long clear_user(void __user * to, unsigned long n) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci if (access_ok(to, n)) 2908c2ecf20Sopenharmony_ci n = __arch_clear_user(to, n); 2918c2ecf20Sopenharmony_ci return n; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic inline unsigned long __clear_user(void __user * to, unsigned long n) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci return __arch_clear_user(to, n); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci#endif /* _ASMNDS32_UACCESS_H */ 300