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