18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef __PARISC_UACCESS_H 38c2ecf20Sopenharmony_ci#define __PARISC_UACCESS_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * User space memory access functions 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <asm/page.h> 98c2ecf20Sopenharmony_ci#include <asm/cache.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bug.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define KERNEL_DS ((mm_segment_t){0}) 158c2ecf20Sopenharmony_ci#define USER_DS ((mm_segment_t){1}) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define get_fs() (current_thread_info()->addr_limit) 208c2ecf20Sopenharmony_ci#define set_fs(x) (current_thread_info()->addr_limit = (x)) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Note that since kernel addresses are in a separate address space on 248c2ecf20Sopenharmony_ci * parisc, we don't need to do anything for access_ok(). 258c2ecf20Sopenharmony_ci * We just let the page fault handler do the right thing. This also means 268c2ecf20Sopenharmony_ci * that put_user is the same as __put_user, etc. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define access_ok(uaddr, size) \ 308c2ecf20Sopenharmony_ci ( (uaddr) == (uaddr) ) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define put_user __put_user 338c2ecf20Sopenharmony_ci#define get_user __get_user 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#if !defined(CONFIG_64BIT) 368c2ecf20Sopenharmony_ci#define LDD_USER(val, ptr) __get_user_asm64(val, ptr) 378c2ecf20Sopenharmony_ci#define STD_USER(x, ptr) __put_user_asm64(x, ptr) 388c2ecf20Sopenharmony_ci#else 398c2ecf20Sopenharmony_ci#define LDD_USER(val, ptr) __get_user_asm(val, "ldd", ptr) 408c2ecf20Sopenharmony_ci#define STD_USER(x, ptr) __put_user_asm("std", x, ptr) 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * The exception table contains two values: the first is the relative offset to 458c2ecf20Sopenharmony_ci * the address of the instruction that is allowed to fault, and the second is 468c2ecf20Sopenharmony_ci * the relative offset to the address of the fixup routine. Since relative 478c2ecf20Sopenharmony_ci * addresses are used, 32bit values are sufficient even on 64bit kernel. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define ARCH_HAS_RELATIVE_EXTABLE 518c2ecf20Sopenharmony_cistruct exception_table_entry { 528c2ecf20Sopenharmony_ci int insn; /* relative address of insn that is allowed to fault. */ 538c2ecf20Sopenharmony_ci int fixup; /* relative address of fixup routine */ 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ 578c2ecf20Sopenharmony_ci ".section __ex_table,\"aw\"\n" \ 588c2ecf20Sopenharmony_ci ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ 598c2ecf20Sopenharmony_ci ".previous\n" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry 638c2ecf20Sopenharmony_ci * (with lowest bit set) for which the fault handler in fixup_exception() will 648c2ecf20Sopenharmony_ci * load -EFAULT into %r8 for a read or write fault, and zeroes the target 658c2ecf20Sopenharmony_ci * register in case of a read fault in get_user(). 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\ 688c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * load_sr2() preloads the space register %%sr2 - based on the value of 728c2ecf20Sopenharmony_ci * get_fs() - with either a value of 0 to access kernel space (KERNEL_DS which 738c2ecf20Sopenharmony_ci * is 0), or with the current value of %%sr3 to access user space (USER_DS) 748c2ecf20Sopenharmony_ci * memory. The following __get_user_asm() and __put_user_asm() functions have 758c2ecf20Sopenharmony_ci * %%sr2 hard-coded to access the requested memory. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci#define load_sr2() \ 788c2ecf20Sopenharmony_ci __asm__(" or,= %0,%%r0,%%r0\n\t" \ 798c2ecf20Sopenharmony_ci " mfsp %%sr3,%0\n\t" \ 808c2ecf20Sopenharmony_ci " mtsp %0,%%sr2\n\t" \ 818c2ecf20Sopenharmony_ci : : "r"(get_fs()) : ) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define __get_user_internal(val, ptr) \ 848c2ecf20Sopenharmony_ci({ \ 858c2ecf20Sopenharmony_ci register long __gu_err __asm__ ("r8") = 0; \ 868c2ecf20Sopenharmony_ci \ 878c2ecf20Sopenharmony_ci switch (sizeof(*(ptr))) { \ 888c2ecf20Sopenharmony_ci case 1: __get_user_asm(val, "ldb", ptr); break; \ 898c2ecf20Sopenharmony_ci case 2: __get_user_asm(val, "ldh", ptr); break; \ 908c2ecf20Sopenharmony_ci case 4: __get_user_asm(val, "ldw", ptr); break; \ 918c2ecf20Sopenharmony_ci case 8: LDD_USER(val, ptr); break; \ 928c2ecf20Sopenharmony_ci default: BUILD_BUG(); \ 938c2ecf20Sopenharmony_ci } \ 948c2ecf20Sopenharmony_ci \ 958c2ecf20Sopenharmony_ci __gu_err; \ 968c2ecf20Sopenharmony_ci}) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define __get_user(val, ptr) \ 998c2ecf20Sopenharmony_ci({ \ 1008c2ecf20Sopenharmony_ci load_sr2(); \ 1018c2ecf20Sopenharmony_ci __get_user_internal(val, ptr); \ 1028c2ecf20Sopenharmony_ci}) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define __get_user_asm(val, ldx, ptr) \ 1058c2ecf20Sopenharmony_ci{ \ 1068c2ecf20Sopenharmony_ci register long __gu_val; \ 1078c2ecf20Sopenharmony_ci \ 1088c2ecf20Sopenharmony_ci __asm__("1: " ldx " 0(%%sr2,%2),%0\n" \ 1098c2ecf20Sopenharmony_ci "9:\n" \ 1108c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ 1118c2ecf20Sopenharmony_ci : "=r"(__gu_val), "=r"(__gu_err) \ 1128c2ecf20Sopenharmony_ci : "r"(ptr), "1"(__gu_err)); \ 1138c2ecf20Sopenharmony_ci \ 1148c2ecf20Sopenharmony_ci (val) = (__force __typeof__(*(ptr))) __gu_val; \ 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#if !defined(CONFIG_64BIT) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define __get_user_asm64(val, ptr) \ 1208c2ecf20Sopenharmony_ci{ \ 1218c2ecf20Sopenharmony_ci union { \ 1228c2ecf20Sopenharmony_ci unsigned long long l; \ 1238c2ecf20Sopenharmony_ci __typeof__(*(ptr)) t; \ 1248c2ecf20Sopenharmony_ci } __gu_tmp; \ 1258c2ecf20Sopenharmony_ci \ 1268c2ecf20Sopenharmony_ci __asm__(" copy %%r0,%R0\n" \ 1278c2ecf20Sopenharmony_ci "1: ldw 0(%%sr2,%2),%0\n" \ 1288c2ecf20Sopenharmony_ci "2: ldw 4(%%sr2,%2),%R0\n" \ 1298c2ecf20Sopenharmony_ci "9:\n" \ 1308c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ 1318c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ 1328c2ecf20Sopenharmony_ci : "=&r"(__gu_tmp.l), "=r"(__gu_err) \ 1338c2ecf20Sopenharmony_ci : "r"(ptr), "1"(__gu_err)); \ 1348c2ecf20Sopenharmony_ci \ 1358c2ecf20Sopenharmony_ci (val) = __gu_tmp.t; \ 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#endif /* !defined(CONFIG_64BIT) */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define __put_user_internal(x, ptr) \ 1428c2ecf20Sopenharmony_ci({ \ 1438c2ecf20Sopenharmony_ci register long __pu_err __asm__ ("r8") = 0; \ 1448c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x); \ 1458c2ecf20Sopenharmony_ci \ 1468c2ecf20Sopenharmony_ci switch (sizeof(*(ptr))) { \ 1478c2ecf20Sopenharmony_ci case 1: __put_user_asm("stb", __x, ptr); break; \ 1488c2ecf20Sopenharmony_ci case 2: __put_user_asm("sth", __x, ptr); break; \ 1498c2ecf20Sopenharmony_ci case 4: __put_user_asm("stw", __x, ptr); break; \ 1508c2ecf20Sopenharmony_ci case 8: STD_USER(__x, ptr); break; \ 1518c2ecf20Sopenharmony_ci default: BUILD_BUG(); \ 1528c2ecf20Sopenharmony_ci } \ 1538c2ecf20Sopenharmony_ci \ 1548c2ecf20Sopenharmony_ci __pu_err; \ 1558c2ecf20Sopenharmony_ci}) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define __put_user(x, ptr) \ 1588c2ecf20Sopenharmony_ci({ \ 1598c2ecf20Sopenharmony_ci load_sr2(); \ 1608c2ecf20Sopenharmony_ci __put_user_internal(x, ptr); \ 1618c2ecf20Sopenharmony_ci}) 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * The "__put_user/kernel_asm()" macros tell gcc they read from memory 1668c2ecf20Sopenharmony_ci * instead of writing. This is because they do not write to any memory 1678c2ecf20Sopenharmony_ci * gcc knows about, so there are no aliasing issues. These macros must 1688c2ecf20Sopenharmony_ci * also be aware that fixups are executed in the context of the fault, 1698c2ecf20Sopenharmony_ci * and any registers used there must be listed as clobbers. 1708c2ecf20Sopenharmony_ci * r8 is already listed as err. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define __put_user_asm(stx, x, ptr) \ 1748c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 1758c2ecf20Sopenharmony_ci "1: " stx " %2,0(%%sr2,%1)\n" \ 1768c2ecf20Sopenharmony_ci "9:\n" \ 1778c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ 1788c2ecf20Sopenharmony_ci : "=r"(__pu_err) \ 1798c2ecf20Sopenharmony_ci : "r"(ptr), "r"(x), "0"(__pu_err)) 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#if !defined(CONFIG_64BIT) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define __put_user_asm64(__val, ptr) do { \ 1858c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 1868c2ecf20Sopenharmony_ci "1: stw %2,0(%%sr2,%1)\n" \ 1878c2ecf20Sopenharmony_ci "2: stw %R2,4(%%sr2,%1)\n" \ 1888c2ecf20Sopenharmony_ci "9:\n" \ 1898c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ 1908c2ecf20Sopenharmony_ci ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ 1918c2ecf20Sopenharmony_ci : "=r"(__pu_err) \ 1928c2ecf20Sopenharmony_ci : "r"(ptr), "r"(__val), "0"(__pu_err)); \ 1938c2ecf20Sopenharmony_ci} while (0) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#endif /* !defined(CONFIG_64BIT) */ 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * Complex access routines -- external declarations 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *, const char __user *, long); 2038c2ecf20Sopenharmony_ciextern unsigned lclear_user(void __user *, unsigned long); 2048c2ecf20Sopenharmony_ciextern long lstrnlen_user(const char __user *, long); 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * Complex access routines -- macros 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci#define user_addr_max() (~0UL) 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#define strnlen_user lstrnlen_user 2118c2ecf20Sopenharmony_ci#define clear_user lclear_user 2128c2ecf20Sopenharmony_ci#define __clear_user lclear_user 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciunsigned long __must_check raw_copy_to_user(void __user *dst, const void *src, 2158c2ecf20Sopenharmony_ci unsigned long len); 2168c2ecf20Sopenharmony_ciunsigned long __must_check raw_copy_from_user(void *dst, const void __user *src, 2178c2ecf20Sopenharmony_ci unsigned long len); 2188c2ecf20Sopenharmony_ciunsigned long __must_check raw_copy_in_user(void __user *dst, const void __user *src, 2198c2ecf20Sopenharmony_ci unsigned long len); 2208c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 2218c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistruct pt_regs; 2248c2ecf20Sopenharmony_ciint fixup_exception(struct pt_regs *regs); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#endif /* __PARISC_UACCESS_H */ 227