18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * uaccess.h: User space memore access functions. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 68c2ecf20Sopenharmony_ci * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef _ASM_UACCESS_H 98c2ecf20Sopenharmony_ci#define _ASM_UACCESS_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/compiler.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/processor.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define ARCH_HAS_SORT_EXTABLE 178c2ecf20Sopenharmony_ci#define ARCH_HAS_SEARCH_EXTABLE 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Sparc is not segmented, however we need to be able to fool access_ok() 208c2ecf20Sopenharmony_ci * when doing system calls from kernel mode legitimately. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * "For historical reasons, these macros are grossly misnamed." -Linus 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define KERNEL_DS ((mm_segment_t) { 0 }) 268c2ecf20Sopenharmony_ci#define USER_DS ((mm_segment_t) { -1 }) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define get_fs() (current->thread.current_ds) 298c2ecf20Sopenharmony_ci#define set_fs(val) ((current->thread.current_ds) = (val)) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* We have there a nice not-mapped page at PAGE_OFFSET - PAGE_SIZE, so that this test 348c2ecf20Sopenharmony_ci * can be fairly lightweight. 358c2ecf20Sopenharmony_ci * No one can read/write anything from userland in the kernel space by setting 368c2ecf20Sopenharmony_ci * large size and address near to PAGE_OFFSET - a fault will break his intentions. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci#define __user_ok(addr, size) ({ (void)(size); (addr) < STACK_TOP; }) 398c2ecf20Sopenharmony_ci#define __kernel_ok (uaccess_kernel()) 408c2ecf20Sopenharmony_ci#define __access_ok(addr, size) (__user_ok((addr) & get_fs().seg, (size))) 418c2ecf20Sopenharmony_ci#define access_ok(addr, size) __access_ok((unsigned long)(addr), size) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * The exception table consists of pairs of addresses: the first is the 458c2ecf20Sopenharmony_ci * address of an instruction that is allowed to fault, and the second is 468c2ecf20Sopenharmony_ci * the address at which the program should continue. No registers are 478c2ecf20Sopenharmony_ci * modified, so it is entirely up to the continuation code to figure out 488c2ecf20Sopenharmony_ci * what to do. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * All the routines below use bits of fixup code that are out of line 518c2ecf20Sopenharmony_ci * with the main instruction path. This means when everything is well, 528c2ecf20Sopenharmony_ci * we don't even have to jump over them. Further, they do not intrude 538c2ecf20Sopenharmony_ci * on our cache or tlb entries. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * There is a special way how to put a range of potentially faulting 568c2ecf20Sopenharmony_ci * insns (like twenty ldd/std's with now intervening other instructions) 578c2ecf20Sopenharmony_ci * You specify address of first in insn and 0 in fixup and in the next 588c2ecf20Sopenharmony_ci * exception_table_entry you specify last potentially faulting insn + 1 598c2ecf20Sopenharmony_ci * and in fixup the routine which should handle the fault. 608c2ecf20Sopenharmony_ci * That fixup code will get 618c2ecf20Sopenharmony_ci * (faulting_insn_address - first_insn_in_the_range_address)/4 628c2ecf20Sopenharmony_ci * in %g2 (ie. index of the faulting instruction in the range). 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct exception_table_entry 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned long insn, fixup; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Returns 0 if exception not found and fixup otherwise. */ 718c2ecf20Sopenharmony_ciunsigned long search_extables_range(unsigned long addr, unsigned long *g2); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Uh, these should become the main single-value transfer routines.. 748c2ecf20Sopenharmony_ci * They automatically use the right size if we just have the right 758c2ecf20Sopenharmony_ci * pointer type.. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * This gets kind of ugly. We want to return _two_ values in "get_user()" 788c2ecf20Sopenharmony_ci * and yet we don't want to do any pointers, because that is too much 798c2ecf20Sopenharmony_ci * of a performance impact. Thus we have a few rather ugly macros here, 808c2ecf20Sopenharmony_ci * and hide all the ugliness from the user. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci#define put_user(x, ptr) ({ \ 838c2ecf20Sopenharmony_ci unsigned long __pu_addr = (unsigned long)(ptr); \ 848c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 858c2ecf20Sopenharmony_ci __put_user_check((__typeof__(*(ptr)))(x), __pu_addr, sizeof(*(ptr))); \ 868c2ecf20Sopenharmony_ci}) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define get_user(x, ptr) ({ \ 898c2ecf20Sopenharmony_ci unsigned long __gu_addr = (unsigned long)(ptr); \ 908c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 918c2ecf20Sopenharmony_ci __get_user_check((x), __gu_addr, sizeof(*(ptr)), __typeof__(*(ptr))); \ 928c2ecf20Sopenharmony_ci}) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * The "__xxx" versions do not do address space checking, useful when 968c2ecf20Sopenharmony_ci * doing multiple accesses to the same area (the user has to do the 978c2ecf20Sopenharmony_ci * checks by hand with "access_ok()") 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci#define __put_user(x, ptr) \ 1008c2ecf20Sopenharmony_ci __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) 1018c2ecf20Sopenharmony_ci#define __get_user(x, ptr) \ 1028c2ecf20Sopenharmony_ci __get_user_nocheck((x), (ptr), sizeof(*(ptr)), __typeof__(*(ptr))) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistruct __large_struct { unsigned long buf[100]; }; 1058c2ecf20Sopenharmony_ci#define __m(x) ((struct __large_struct __user *)(x)) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define __put_user_check(x, addr, size) ({ \ 1088c2ecf20Sopenharmony_ci register int __pu_ret; \ 1098c2ecf20Sopenharmony_ci if (__access_ok(addr, size)) { \ 1108c2ecf20Sopenharmony_ci switch (size) { \ 1118c2ecf20Sopenharmony_ci case 1: \ 1128c2ecf20Sopenharmony_ci __put_user_asm(x, b, addr, __pu_ret); \ 1138c2ecf20Sopenharmony_ci break; \ 1148c2ecf20Sopenharmony_ci case 2: \ 1158c2ecf20Sopenharmony_ci __put_user_asm(x, h, addr, __pu_ret); \ 1168c2ecf20Sopenharmony_ci break; \ 1178c2ecf20Sopenharmony_ci case 4: \ 1188c2ecf20Sopenharmony_ci __put_user_asm(x, , addr, __pu_ret); \ 1198c2ecf20Sopenharmony_ci break; \ 1208c2ecf20Sopenharmony_ci case 8: \ 1218c2ecf20Sopenharmony_ci __put_user_asm(x, d, addr, __pu_ret); \ 1228c2ecf20Sopenharmony_ci break; \ 1238c2ecf20Sopenharmony_ci default: \ 1248c2ecf20Sopenharmony_ci __pu_ret = __put_user_bad(); \ 1258c2ecf20Sopenharmony_ci break; \ 1268c2ecf20Sopenharmony_ci } \ 1278c2ecf20Sopenharmony_ci } else { \ 1288c2ecf20Sopenharmony_ci __pu_ret = -EFAULT; \ 1298c2ecf20Sopenharmony_ci } \ 1308c2ecf20Sopenharmony_ci __pu_ret; \ 1318c2ecf20Sopenharmony_ci}) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define __put_user_nocheck(x, addr, size) ({ \ 1348c2ecf20Sopenharmony_ci register int __pu_ret; \ 1358c2ecf20Sopenharmony_ci switch (size) { \ 1368c2ecf20Sopenharmony_ci case 1: __put_user_asm(x, b, addr, __pu_ret); break; \ 1378c2ecf20Sopenharmony_ci case 2: __put_user_asm(x, h, addr, __pu_ret); break; \ 1388c2ecf20Sopenharmony_ci case 4: __put_user_asm(x, , addr, __pu_ret); break; \ 1398c2ecf20Sopenharmony_ci case 8: __put_user_asm(x, d, addr, __pu_ret); break; \ 1408c2ecf20Sopenharmony_ci default: __pu_ret = __put_user_bad(); break; \ 1418c2ecf20Sopenharmony_ci } \ 1428c2ecf20Sopenharmony_ci __pu_ret; \ 1438c2ecf20Sopenharmony_ci}) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define __put_user_asm(x, size, addr, ret) \ 1468c2ecf20Sopenharmony_ci__asm__ __volatile__( \ 1478c2ecf20Sopenharmony_ci "/* Put user asm, inline. */\n" \ 1488c2ecf20Sopenharmony_ci "1:\t" "st"#size " %1, %2\n\t" \ 1498c2ecf20Sopenharmony_ci "clr %0\n" \ 1508c2ecf20Sopenharmony_ci "2:\n\n\t" \ 1518c2ecf20Sopenharmony_ci ".section .fixup,#alloc,#execinstr\n\t" \ 1528c2ecf20Sopenharmony_ci ".align 4\n" \ 1538c2ecf20Sopenharmony_ci "3:\n\t" \ 1548c2ecf20Sopenharmony_ci "b 2b\n\t" \ 1558c2ecf20Sopenharmony_ci " mov %3, %0\n\t" \ 1568c2ecf20Sopenharmony_ci ".previous\n\n\t" \ 1578c2ecf20Sopenharmony_ci ".section __ex_table,#alloc\n\t" \ 1588c2ecf20Sopenharmony_ci ".align 4\n\t" \ 1598c2ecf20Sopenharmony_ci ".word 1b, 3b\n\t" \ 1608c2ecf20Sopenharmony_ci ".previous\n\n\t" \ 1618c2ecf20Sopenharmony_ci : "=&r" (ret) : "r" (x), "m" (*__m(addr)), \ 1628c2ecf20Sopenharmony_ci "i" (-EFAULT)) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ciint __put_user_bad(void); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define __get_user_check(x, addr, size, type) ({ \ 1678c2ecf20Sopenharmony_ci register int __gu_ret; \ 1688c2ecf20Sopenharmony_ci register unsigned long __gu_val; \ 1698c2ecf20Sopenharmony_ci if (__access_ok(addr, size)) { \ 1708c2ecf20Sopenharmony_ci switch (size) { \ 1718c2ecf20Sopenharmony_ci case 1: \ 1728c2ecf20Sopenharmony_ci __get_user_asm(__gu_val, ub, addr, __gu_ret); \ 1738c2ecf20Sopenharmony_ci break; \ 1748c2ecf20Sopenharmony_ci case 2: \ 1758c2ecf20Sopenharmony_ci __get_user_asm(__gu_val, uh, addr, __gu_ret); \ 1768c2ecf20Sopenharmony_ci break; \ 1778c2ecf20Sopenharmony_ci case 4: \ 1788c2ecf20Sopenharmony_ci __get_user_asm(__gu_val, , addr, __gu_ret); \ 1798c2ecf20Sopenharmony_ci break; \ 1808c2ecf20Sopenharmony_ci case 8: \ 1818c2ecf20Sopenharmony_ci __get_user_asm(__gu_val, d, addr, __gu_ret); \ 1828c2ecf20Sopenharmony_ci break; \ 1838c2ecf20Sopenharmony_ci default: \ 1848c2ecf20Sopenharmony_ci __gu_val = 0; \ 1858c2ecf20Sopenharmony_ci __gu_ret = __get_user_bad(); \ 1868c2ecf20Sopenharmony_ci break; \ 1878c2ecf20Sopenharmony_ci } \ 1888c2ecf20Sopenharmony_ci } else { \ 1898c2ecf20Sopenharmony_ci __gu_val = 0; \ 1908c2ecf20Sopenharmony_ci __gu_ret = -EFAULT; \ 1918c2ecf20Sopenharmony_ci } \ 1928c2ecf20Sopenharmony_ci x = (__force type) __gu_val; \ 1938c2ecf20Sopenharmony_ci __gu_ret; \ 1948c2ecf20Sopenharmony_ci}) 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#define __get_user_nocheck(x, addr, size, type) ({ \ 1978c2ecf20Sopenharmony_ci register int __gu_ret; \ 1988c2ecf20Sopenharmony_ci register unsigned long __gu_val; \ 1998c2ecf20Sopenharmony_ci switch (size) { \ 2008c2ecf20Sopenharmony_ci case 1: __get_user_asm(__gu_val, ub, addr, __gu_ret); break; \ 2018c2ecf20Sopenharmony_ci case 2: __get_user_asm(__gu_val, uh, addr, __gu_ret); break; \ 2028c2ecf20Sopenharmony_ci case 4: __get_user_asm(__gu_val, , addr, __gu_ret); break; \ 2038c2ecf20Sopenharmony_ci case 8: __get_user_asm(__gu_val, d, addr, __gu_ret); break; \ 2048c2ecf20Sopenharmony_ci default: \ 2058c2ecf20Sopenharmony_ci __gu_val = 0; \ 2068c2ecf20Sopenharmony_ci __gu_ret = __get_user_bad(); \ 2078c2ecf20Sopenharmony_ci break; \ 2088c2ecf20Sopenharmony_ci } \ 2098c2ecf20Sopenharmony_ci x = (__force type) __gu_val; \ 2108c2ecf20Sopenharmony_ci __gu_ret; \ 2118c2ecf20Sopenharmony_ci}) 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci#define __get_user_asm(x, size, addr, ret) \ 2148c2ecf20Sopenharmony_ci__asm__ __volatile__( \ 2158c2ecf20Sopenharmony_ci "/* Get user asm, inline. */\n" \ 2168c2ecf20Sopenharmony_ci "1:\t" "ld"#size " %2, %1\n\t" \ 2178c2ecf20Sopenharmony_ci "clr %0\n" \ 2188c2ecf20Sopenharmony_ci "2:\n\n\t" \ 2198c2ecf20Sopenharmony_ci ".section .fixup,#alloc,#execinstr\n\t" \ 2208c2ecf20Sopenharmony_ci ".align 4\n" \ 2218c2ecf20Sopenharmony_ci "3:\n\t" \ 2228c2ecf20Sopenharmony_ci "clr %1\n\t" \ 2238c2ecf20Sopenharmony_ci "b 2b\n\t" \ 2248c2ecf20Sopenharmony_ci " mov %3, %0\n\n\t" \ 2258c2ecf20Sopenharmony_ci ".previous\n\t" \ 2268c2ecf20Sopenharmony_ci ".section __ex_table,#alloc\n\t" \ 2278c2ecf20Sopenharmony_ci ".align 4\n\t" \ 2288c2ecf20Sopenharmony_ci ".word 1b, 3b\n\n\t" \ 2298c2ecf20Sopenharmony_ci ".previous\n\t" \ 2308c2ecf20Sopenharmony_ci : "=&r" (ret), "=&r" (x) : "m" (*__m(addr)), \ 2318c2ecf20Sopenharmony_ci "i" (-EFAULT)) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciint __get_user_bad(void); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ciunsigned long __copy_user(void __user *to, const void __user *from, unsigned long size); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic inline unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci return __copy_user(to, (__force void __user *) from, n); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic inline unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci return __copy_user((__force void __user *) to, from, n); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 2488c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic inline unsigned long __clear_user(void __user *addr, unsigned long size) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci unsigned long ret; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 2558c2ecf20Sopenharmony_ci ".section __ex_table,#alloc\n\t" 2568c2ecf20Sopenharmony_ci ".align 4\n\t" 2578c2ecf20Sopenharmony_ci ".word 1f,3\n\t" 2588c2ecf20Sopenharmony_ci ".previous\n\t" 2598c2ecf20Sopenharmony_ci "mov %2, %%o1\n" 2608c2ecf20Sopenharmony_ci "1:\n\t" 2618c2ecf20Sopenharmony_ci "call __bzero\n\t" 2628c2ecf20Sopenharmony_ci " mov %1, %%o0\n\t" 2638c2ecf20Sopenharmony_ci "mov %%o0, %0\n" 2648c2ecf20Sopenharmony_ci : "=r" (ret) : "r" (addr), "r" (size) : 2658c2ecf20Sopenharmony_ci "o0", "o1", "o2", "o3", "o4", "o5", "o7", 2668c2ecf20Sopenharmony_ci "g1", "g2", "g3", "g4", "g5", "g7", "cc"); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic inline unsigned long clear_user(void __user *addr, unsigned long n) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci if (n && __access_ok((unsigned long) addr, n)) 2748c2ecf20Sopenharmony_ci return __clear_user(addr, n); 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci return n; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci__must_check long strnlen_user(const char __user *str, long n); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#endif /* _ASM_UACCESS_H */ 282