18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_UACCESS_H 38c2ecf20Sopenharmony_ci#define _ASM_UACCESS_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * User space memory access functions 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/compiler.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <asm/asi.h> 128c2ecf20Sopenharmony_ci#include <asm/spitfire.h> 138c2ecf20Sopenharmony_ci#include <asm/extable_64.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/processor.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * Sparc64 is segmented, though more like the M68K than the I386. 198c2ecf20Sopenharmony_ci * We use the secondary ASI to address user memory, which references a 208c2ecf20Sopenharmony_ci * completely different VM map, thus there is zero chance of the user 218c2ecf20Sopenharmony_ci * doing something queer and tricking us into poking kernel memory. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * What is left here is basically what is needed for the other parts of 248c2ecf20Sopenharmony_ci * the kernel that expect to be able to manipulate, erum, "segments". 258c2ecf20Sopenharmony_ci * Or perhaps more properly, permissions. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * "For historical reasons, these macros are grossly misnamed." -Linus 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define KERNEL_DS ((mm_segment_t) { ASI_P }) 318c2ecf20Sopenharmony_ci#define USER_DS ((mm_segment_t) { ASI_AIUS }) /* har har har */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define get_fs() ((mm_segment_t){(current_thread_info()->current_ds)}) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define set_fs(val) \ 388c2ecf20Sopenharmony_cido { \ 398c2ecf20Sopenharmony_ci current_thread_info()->current_ds = (val).seg; \ 408c2ecf20Sopenharmony_ci __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg)); \ 418c2ecf20Sopenharmony_ci} while(0) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * Test whether a block of memory is a valid user space address. 458c2ecf20Sopenharmony_ci * Returns 0 if the range is valid, nonzero otherwise. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, unsigned long limit) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (__builtin_constant_p(size)) 508c2ecf20Sopenharmony_ci return addr > limit - size; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci addr += size; 538c2ecf20Sopenharmony_ci if (addr < size) 548c2ecf20Sopenharmony_ci return true; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return addr > limit; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define __range_not_ok(addr, size, limit) \ 608c2ecf20Sopenharmony_ci({ \ 618c2ecf20Sopenharmony_ci __chk_user_ptr(addr); \ 628c2ecf20Sopenharmony_ci __chk_range_not_ok((unsigned long __force)(addr), size, limit); \ 638c2ecf20Sopenharmony_ci}) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline int __access_ok(const void __user * addr, unsigned long size) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci return 1; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic inline int access_ok(const void __user * addr, unsigned long size) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci return 1; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid __retl_efault(void); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Uh, these should become the main single-value transfer routines.. 788c2ecf20Sopenharmony_ci * They automatically use the right size if we just have the right 798c2ecf20Sopenharmony_ci * pointer type.. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * This gets kind of ugly. We want to return _two_ values in "get_user()" 828c2ecf20Sopenharmony_ci * and yet we don't want to do any pointers, because that is too much 838c2ecf20Sopenharmony_ci * of a performance impact. Thus we have a few rather ugly macros here, 848c2ecf20Sopenharmony_ci * and hide all the ugliness from the user. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define put_user(x, ptr) ({ \ 878c2ecf20Sopenharmony_ci unsigned long __pu_addr = (unsigned long)(ptr); \ 888c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 898c2ecf20Sopenharmony_ci __put_user_nocheck((__typeof__(*(ptr)))(x), __pu_addr, sizeof(*(ptr)));\ 908c2ecf20Sopenharmony_ci}) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define get_user(x, ptr) ({ \ 938c2ecf20Sopenharmony_ci unsigned long __gu_addr = (unsigned long)(ptr); \ 948c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 958c2ecf20Sopenharmony_ci __get_user_nocheck((x), __gu_addr, sizeof(*(ptr)), __typeof__(*(ptr)));\ 968c2ecf20Sopenharmony_ci}) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define __put_user(x, ptr) put_user(x, ptr) 998c2ecf20Sopenharmony_ci#define __get_user(x, ptr) get_user(x, ptr) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct __large_struct { unsigned long buf[100]; }; 1028c2ecf20Sopenharmony_ci#define __m(x) ((struct __large_struct *)(x)) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define __put_user_nocheck(data, addr, size) ({ \ 1058c2ecf20Sopenharmony_ci register int __pu_ret; \ 1068c2ecf20Sopenharmony_ci switch (size) { \ 1078c2ecf20Sopenharmony_ci case 1: __put_user_asm(data, b, addr, __pu_ret); break; \ 1088c2ecf20Sopenharmony_ci case 2: __put_user_asm(data, h, addr, __pu_ret); break; \ 1098c2ecf20Sopenharmony_ci case 4: __put_user_asm(data, w, addr, __pu_ret); break; \ 1108c2ecf20Sopenharmony_ci case 8: __put_user_asm(data, x, addr, __pu_ret); break; \ 1118c2ecf20Sopenharmony_ci default: __pu_ret = __put_user_bad(); break; \ 1128c2ecf20Sopenharmony_ci } \ 1138c2ecf20Sopenharmony_ci __pu_ret; \ 1148c2ecf20Sopenharmony_ci}) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define __put_user_asm(x, size, addr, ret) \ 1178c2ecf20Sopenharmony_ci__asm__ __volatile__( \ 1188c2ecf20Sopenharmony_ci "/* Put user asm, inline. */\n" \ 1198c2ecf20Sopenharmony_ci "1:\t" "st"#size "a %1, [%2] %%asi\n\t" \ 1208c2ecf20Sopenharmony_ci "clr %0\n" \ 1218c2ecf20Sopenharmony_ci "2:\n\n\t" \ 1228c2ecf20Sopenharmony_ci ".section .fixup,#alloc,#execinstr\n\t" \ 1238c2ecf20Sopenharmony_ci ".align 4\n" \ 1248c2ecf20Sopenharmony_ci "3:\n\t" \ 1258c2ecf20Sopenharmony_ci "sethi %%hi(2b), %0\n\t" \ 1268c2ecf20Sopenharmony_ci "jmpl %0 + %%lo(2b), %%g0\n\t" \ 1278c2ecf20Sopenharmony_ci " mov %3, %0\n\n\t" \ 1288c2ecf20Sopenharmony_ci ".previous\n\t" \ 1298c2ecf20Sopenharmony_ci ".section __ex_table,\"a\"\n\t" \ 1308c2ecf20Sopenharmony_ci ".align 4\n\t" \ 1318c2ecf20Sopenharmony_ci ".word 1b, 3b\n\t" \ 1328c2ecf20Sopenharmony_ci ".previous\n\n\t" \ 1338c2ecf20Sopenharmony_ci : "=r" (ret) : "r" (x), "r" (__m(addr)), \ 1348c2ecf20Sopenharmony_ci "i" (-EFAULT)) 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint __put_user_bad(void); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#define __get_user_nocheck(data, addr, size, type) ({ \ 1398c2ecf20Sopenharmony_ci register int __gu_ret; \ 1408c2ecf20Sopenharmony_ci register unsigned long __gu_val; \ 1418c2ecf20Sopenharmony_ci switch (size) { \ 1428c2ecf20Sopenharmony_ci case 1: __get_user_asm(__gu_val, ub, addr, __gu_ret); break; \ 1438c2ecf20Sopenharmony_ci case 2: __get_user_asm(__gu_val, uh, addr, __gu_ret); break; \ 1448c2ecf20Sopenharmony_ci case 4: __get_user_asm(__gu_val, uw, addr, __gu_ret); break; \ 1458c2ecf20Sopenharmony_ci case 8: __get_user_asm(__gu_val, x, addr, __gu_ret); break; \ 1468c2ecf20Sopenharmony_ci default: \ 1478c2ecf20Sopenharmony_ci __gu_val = 0; \ 1488c2ecf20Sopenharmony_ci __gu_ret = __get_user_bad(); \ 1498c2ecf20Sopenharmony_ci break; \ 1508c2ecf20Sopenharmony_ci } \ 1518c2ecf20Sopenharmony_ci data = (__force type) __gu_val; \ 1528c2ecf20Sopenharmony_ci __gu_ret; \ 1538c2ecf20Sopenharmony_ci}) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define __get_user_asm(x, size, addr, ret) \ 1568c2ecf20Sopenharmony_ci__asm__ __volatile__( \ 1578c2ecf20Sopenharmony_ci "/* Get user asm, inline. */\n" \ 1588c2ecf20Sopenharmony_ci "1:\t" "ld"#size "a [%2] %%asi, %1\n\t" \ 1598c2ecf20Sopenharmony_ci "clr %0\n" \ 1608c2ecf20Sopenharmony_ci "2:\n\n\t" \ 1618c2ecf20Sopenharmony_ci ".section .fixup,#alloc,#execinstr\n\t" \ 1628c2ecf20Sopenharmony_ci ".align 4\n" \ 1638c2ecf20Sopenharmony_ci "3:\n\t" \ 1648c2ecf20Sopenharmony_ci "sethi %%hi(2b), %0\n\t" \ 1658c2ecf20Sopenharmony_ci "clr %1\n\t" \ 1668c2ecf20Sopenharmony_ci "jmpl %0 + %%lo(2b), %%g0\n\t" \ 1678c2ecf20Sopenharmony_ci " mov %3, %0\n\n\t" \ 1688c2ecf20Sopenharmony_ci ".previous\n\t" \ 1698c2ecf20Sopenharmony_ci ".section __ex_table,\"a\"\n\t" \ 1708c2ecf20Sopenharmony_ci ".align 4\n\t" \ 1718c2ecf20Sopenharmony_ci ".word 1b, 3b\n\n\t" \ 1728c2ecf20Sopenharmony_ci ".previous\n\t" \ 1738c2ecf20Sopenharmony_ci : "=r" (ret), "=r" (x) : "r" (__m(addr)), \ 1748c2ecf20Sopenharmony_ci "i" (-EFAULT)) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciint __get_user_bad(void); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciunsigned long __must_check raw_copy_from_user(void *to, 1798c2ecf20Sopenharmony_ci const void __user *from, 1808c2ecf20Sopenharmony_ci unsigned long size); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciunsigned long __must_check raw_copy_to_user(void __user *to, 1838c2ecf20Sopenharmony_ci const void *from, 1848c2ecf20Sopenharmony_ci unsigned long size); 1858c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 1868c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciunsigned long __must_check raw_copy_in_user(void __user *to, 1898c2ecf20Sopenharmony_ci const void __user *from, 1908c2ecf20Sopenharmony_ci unsigned long size); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciunsigned long __must_check __clear_user(void __user *, unsigned long); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define clear_user __clear_user 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci__must_check long strnlen_user(const char __user *str, long n); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistruct pt_regs; 1998c2ecf20Sopenharmony_ciunsigned long compute_effective_address(struct pt_regs *, 2008c2ecf20Sopenharmony_ci unsigned int insn, 2018c2ecf20Sopenharmony_ci unsigned int rd); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#endif /* _ASM_UACCESS_H */ 204