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