18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci// Copyright (C) 2005-2017 Andes Technology Corporation
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#ifndef _ASMANDES_UACCESS_H
58c2ecf20Sopenharmony_ci#define _ASMANDES_UACCESS_H
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * User space memory access functions
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/sched.h>
118c2ecf20Sopenharmony_ci#include <asm/errno.h>
128c2ecf20Sopenharmony_ci#include <asm/memory.h>
138c2ecf20Sopenharmony_ci#include <asm/types.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * The exception table consists of pairs of addresses: the first is the
198c2ecf20Sopenharmony_ci * address of an instruction that is allowed to fault, and the second is
208c2ecf20Sopenharmony_ci * the address at which the program should continue.  No registers are
218c2ecf20Sopenharmony_ci * modified, so it is entirely up to the continuation code to figure out
228c2ecf20Sopenharmony_ci * what to do.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * All the routines below use bits of fixup code that are out of line
258c2ecf20Sopenharmony_ci * with the main instruction path.  This means when everything is well,
268c2ecf20Sopenharmony_ci * we don't even have to jump over them.  Further, they do not intrude
278c2ecf20Sopenharmony_ci * on our cache or tlb entries.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct exception_table_entry {
318c2ecf20Sopenharmony_ci	unsigned long insn, fixup;
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciextern int fixup_exception(struct pt_regs *regs);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define KERNEL_DS 	((mm_segment_t) { ~0UL })
378c2ecf20Sopenharmony_ci#define USER_DS		((mm_segment_t) {TASK_SIZE - 1})
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define get_fs()	(current_thread_info()->addr_limit)
408c2ecf20Sopenharmony_ci#define user_addr_max	get_fs
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline void set_fs(mm_segment_t fs)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	current_thread_info()->addr_limit = fs;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define uaccess_kernel()	(get_fs() == KERNEL_DS)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define __range_ok(addr, size) (size <= get_fs() && addr <= (get_fs() -size))
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define access_ok(addr, size)	\
528c2ecf20Sopenharmony_ci	__range_ok((unsigned long)addr, (unsigned long)size)
538c2ecf20Sopenharmony_ci/*
548c2ecf20Sopenharmony_ci * Single-value transfer routines.  They automatically use the right
558c2ecf20Sopenharmony_ci * size if we just have the right pointer type.  Note that the functions
568c2ecf20Sopenharmony_ci * which read from user space (*get_*) need to take care not to leak
578c2ecf20Sopenharmony_ci * kernel data even if the calling code is buggy and fails to check
588c2ecf20Sopenharmony_ci * the return value.  This means zeroing out the destination variable
598c2ecf20Sopenharmony_ci * or buffer on error.  Normally this is done out of line by the
608c2ecf20Sopenharmony_ci * fixup code, but there are a few places where it intrudes on the
618c2ecf20Sopenharmony_ci * main code path.  When we only write to user space, there is no
628c2ecf20Sopenharmony_ci * problem.
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * The "__xxx" versions of the user access functions do not verify the
658c2ecf20Sopenharmony_ci * address space - it must have been done previously with a separate
668c2ecf20Sopenharmony_ci * "access_ok()" call.
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * The "xxx_error" versions set the third argument to EFAULT if an
698c2ecf20Sopenharmony_ci * error occurs, and leave it unchanged on success.  Note that these
708c2ecf20Sopenharmony_ci * versions are void (ie, don't return a value as such).
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define get_user(x, ptr)						\
748c2ecf20Sopenharmony_ci({									\
758c2ecf20Sopenharmony_ci	long __gu_err = 0;						\
768c2ecf20Sopenharmony_ci	__get_user_check((x), (ptr), __gu_err);				\
778c2ecf20Sopenharmony_ci	__gu_err;							\
788c2ecf20Sopenharmony_ci})
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#define __get_user_error(x, ptr, err)					\
818c2ecf20Sopenharmony_ci({									\
828c2ecf20Sopenharmony_ci	__get_user_check((x), (ptr), (err));				\
838c2ecf20Sopenharmony_ci	(void)0;							\
848c2ecf20Sopenharmony_ci})
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define __get_user(x, ptr)						\
878c2ecf20Sopenharmony_ci({									\
888c2ecf20Sopenharmony_ci	long __gu_err = 0;						\
898c2ecf20Sopenharmony_ci	const __typeof__(*(ptr)) __user *__p = (ptr);			\
908c2ecf20Sopenharmony_ci	__get_user_err((x), __p, (__gu_err));				\
918c2ecf20Sopenharmony_ci	__gu_err;							\
928c2ecf20Sopenharmony_ci})
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#define __get_user_check(x, ptr, err)					\
958c2ecf20Sopenharmony_ci({									\
968c2ecf20Sopenharmony_ci	const __typeof__(*(ptr)) __user *__p = (ptr);			\
978c2ecf20Sopenharmony_ci	might_fault();							\
988c2ecf20Sopenharmony_ci	if (access_ok(__p, sizeof(*__p))) {		\
998c2ecf20Sopenharmony_ci		__get_user_err((x), __p, (err));			\
1008c2ecf20Sopenharmony_ci	} else {							\
1018c2ecf20Sopenharmony_ci		(x) = 0; (err) = -EFAULT;				\
1028c2ecf20Sopenharmony_ci	}								\
1038c2ecf20Sopenharmony_ci})
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define __get_user_err(x, ptr, err)					\
1068c2ecf20Sopenharmony_cido {									\
1078c2ecf20Sopenharmony_ci	unsigned long __gu_val;						\
1088c2ecf20Sopenharmony_ci	__chk_user_ptr(ptr);						\
1098c2ecf20Sopenharmony_ci	switch (sizeof(*(ptr))) {					\
1108c2ecf20Sopenharmony_ci	case 1:								\
1118c2ecf20Sopenharmony_ci		__get_user_asm("lbi", __gu_val, (ptr), (err));		\
1128c2ecf20Sopenharmony_ci		break;							\
1138c2ecf20Sopenharmony_ci	case 2:								\
1148c2ecf20Sopenharmony_ci		__get_user_asm("lhi", __gu_val, (ptr), (err));		\
1158c2ecf20Sopenharmony_ci		break;							\
1168c2ecf20Sopenharmony_ci	case 4:								\
1178c2ecf20Sopenharmony_ci		__get_user_asm("lwi", __gu_val, (ptr), (err));		\
1188c2ecf20Sopenharmony_ci		break;							\
1198c2ecf20Sopenharmony_ci	case 8:								\
1208c2ecf20Sopenharmony_ci		__get_user_asm_dword(__gu_val, (ptr), (err));		\
1218c2ecf20Sopenharmony_ci		break;							\
1228c2ecf20Sopenharmony_ci	default:							\
1238c2ecf20Sopenharmony_ci		BUILD_BUG(); 						\
1248c2ecf20Sopenharmony_ci		break;							\
1258c2ecf20Sopenharmony_ci	}								\
1268c2ecf20Sopenharmony_ci	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
1278c2ecf20Sopenharmony_ci} while (0)
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#define __get_user_asm(inst, x, addr, err)				\
1308c2ecf20Sopenharmony_ci	__asm__ __volatile__ (						\
1318c2ecf20Sopenharmony_ci		"1:	"inst"	%1,[%2]\n"				\
1328c2ecf20Sopenharmony_ci		"2:\n"							\
1338c2ecf20Sopenharmony_ci		"	.section .fixup,\"ax\"\n"			\
1348c2ecf20Sopenharmony_ci		"	.align	2\n"					\
1358c2ecf20Sopenharmony_ci		"3:	move %0, %3\n"					\
1368c2ecf20Sopenharmony_ci		"	move %1, #0\n"					\
1378c2ecf20Sopenharmony_ci		"	b	2b\n"					\
1388c2ecf20Sopenharmony_ci		"	.previous\n"					\
1398c2ecf20Sopenharmony_ci		"	.section __ex_table,\"a\"\n"			\
1408c2ecf20Sopenharmony_ci		"	.align	3\n"					\
1418c2ecf20Sopenharmony_ci		"	.long	1b, 3b\n"				\
1428c2ecf20Sopenharmony_ci		"	.previous"					\
1438c2ecf20Sopenharmony_ci		: "+r" (err), "=&r" (x)					\
1448c2ecf20Sopenharmony_ci		: "r" (addr), "i" (-EFAULT)				\
1458c2ecf20Sopenharmony_ci		: "cc")
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#ifdef __NDS32_EB__
1488c2ecf20Sopenharmony_ci#define __gu_reg_oper0 "%H1"
1498c2ecf20Sopenharmony_ci#define __gu_reg_oper1 "%L1"
1508c2ecf20Sopenharmony_ci#else
1518c2ecf20Sopenharmony_ci#define __gu_reg_oper0 "%L1"
1528c2ecf20Sopenharmony_ci#define __gu_reg_oper1 "%H1"
1538c2ecf20Sopenharmony_ci#endif
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define __get_user_asm_dword(x, addr, err) 				\
1568c2ecf20Sopenharmony_ci	__asm__ __volatile__ (						\
1578c2ecf20Sopenharmony_ci		"\n1:\tlwi " __gu_reg_oper0 ",[%2]\n"			\
1588c2ecf20Sopenharmony_ci		"\n2:\tlwi " __gu_reg_oper1 ",[%2+4]\n"			\
1598c2ecf20Sopenharmony_ci		"3:\n"							\
1608c2ecf20Sopenharmony_ci		"	.section .fixup,\"ax\"\n"			\
1618c2ecf20Sopenharmony_ci		"	.align	2\n"					\
1628c2ecf20Sopenharmony_ci		"4:	move	%0, %3\n"				\
1638c2ecf20Sopenharmony_ci		"	b	3b\n"					\
1648c2ecf20Sopenharmony_ci		"	.previous\n"					\
1658c2ecf20Sopenharmony_ci		"	.section __ex_table,\"a\"\n"			\
1668c2ecf20Sopenharmony_ci		"	.align	3\n"					\
1678c2ecf20Sopenharmony_ci		"	.long	1b, 4b\n"				\
1688c2ecf20Sopenharmony_ci		"	.long	2b, 4b\n"				\
1698c2ecf20Sopenharmony_ci		"	.previous"					\
1708c2ecf20Sopenharmony_ci		: "+r"(err), "=&r"(x)					\
1718c2ecf20Sopenharmony_ci		: "r"(addr), "i"(-EFAULT)				\
1728c2ecf20Sopenharmony_ci		: "cc")
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#define put_user(x, ptr)						\
1758c2ecf20Sopenharmony_ci({									\
1768c2ecf20Sopenharmony_ci	long __pu_err = 0;						\
1778c2ecf20Sopenharmony_ci	__put_user_check((x), (ptr), __pu_err);				\
1788c2ecf20Sopenharmony_ci	__pu_err;							\
1798c2ecf20Sopenharmony_ci})
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci#define __put_user(x, ptr)						\
1828c2ecf20Sopenharmony_ci({									\
1838c2ecf20Sopenharmony_ci	long __pu_err = 0;						\
1848c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__p = (ptr);				\
1858c2ecf20Sopenharmony_ci	__put_user_err((x), __p, __pu_err);				\
1868c2ecf20Sopenharmony_ci	__pu_err;							\
1878c2ecf20Sopenharmony_ci})
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci#define __put_user_error(x, ptr, err)					\
1908c2ecf20Sopenharmony_ci({									\
1918c2ecf20Sopenharmony_ci	__put_user_err((x), (ptr), (err));				\
1928c2ecf20Sopenharmony_ci	(void)0;							\
1938c2ecf20Sopenharmony_ci})
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci#define __put_user_check(x, ptr, err)					\
1968c2ecf20Sopenharmony_ci({									\
1978c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__p = (ptr);				\
1988c2ecf20Sopenharmony_ci	might_fault();							\
1998c2ecf20Sopenharmony_ci	if (access_ok(__p, sizeof(*__p))) {		\
2008c2ecf20Sopenharmony_ci		__put_user_err((x), __p, (err));			\
2018c2ecf20Sopenharmony_ci	} else	{							\
2028c2ecf20Sopenharmony_ci		(err) = -EFAULT;					\
2038c2ecf20Sopenharmony_ci	}								\
2048c2ecf20Sopenharmony_ci})
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci#define __put_user_err(x, ptr, err)					\
2078c2ecf20Sopenharmony_cido {									\
2088c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __pu_val = (x);				\
2098c2ecf20Sopenharmony_ci	__chk_user_ptr(ptr);						\
2108c2ecf20Sopenharmony_ci	switch (sizeof(*(ptr))) {					\
2118c2ecf20Sopenharmony_ci	case 1:								\
2128c2ecf20Sopenharmony_ci		__put_user_asm("sbi", __pu_val, (ptr), (err));		\
2138c2ecf20Sopenharmony_ci		break;							\
2148c2ecf20Sopenharmony_ci	case 2: 							\
2158c2ecf20Sopenharmony_ci		__put_user_asm("shi", __pu_val, (ptr), (err));		\
2168c2ecf20Sopenharmony_ci		break;							\
2178c2ecf20Sopenharmony_ci	case 4: 							\
2188c2ecf20Sopenharmony_ci		__put_user_asm("swi", __pu_val, (ptr), (err));		\
2198c2ecf20Sopenharmony_ci		break;							\
2208c2ecf20Sopenharmony_ci	case 8:								\
2218c2ecf20Sopenharmony_ci		__put_user_asm_dword(__pu_val, (ptr), (err));		\
2228c2ecf20Sopenharmony_ci		break;							\
2238c2ecf20Sopenharmony_ci	default:							\
2248c2ecf20Sopenharmony_ci		BUILD_BUG(); 						\
2258c2ecf20Sopenharmony_ci		break;							\
2268c2ecf20Sopenharmony_ci	}								\
2278c2ecf20Sopenharmony_ci} while (0)
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci#define __put_user_asm(inst, x, addr, err)				\
2308c2ecf20Sopenharmony_ci	__asm__ __volatile__ (						\
2318c2ecf20Sopenharmony_ci		"1:	"inst"	%1,[%2]\n"				\
2328c2ecf20Sopenharmony_ci		"2:\n"							\
2338c2ecf20Sopenharmony_ci		"	.section .fixup,\"ax\"\n"			\
2348c2ecf20Sopenharmony_ci		"	.align	2\n"					\
2358c2ecf20Sopenharmony_ci		"3:	move	%0, %3\n"				\
2368c2ecf20Sopenharmony_ci		"	b	2b\n"					\
2378c2ecf20Sopenharmony_ci		"	.previous\n"					\
2388c2ecf20Sopenharmony_ci		"	.section __ex_table,\"a\"\n"			\
2398c2ecf20Sopenharmony_ci		"	.align	3\n"					\
2408c2ecf20Sopenharmony_ci		"	.long	1b, 3b\n"				\
2418c2ecf20Sopenharmony_ci		"	.previous"					\
2428c2ecf20Sopenharmony_ci		: "+r" (err)						\
2438c2ecf20Sopenharmony_ci		: "r" (x), "r" (addr), "i" (-EFAULT)			\
2448c2ecf20Sopenharmony_ci		: "cc")
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci#ifdef __NDS32_EB__
2478c2ecf20Sopenharmony_ci#define __pu_reg_oper0 "%H2"
2488c2ecf20Sopenharmony_ci#define __pu_reg_oper1 "%L2"
2498c2ecf20Sopenharmony_ci#else
2508c2ecf20Sopenharmony_ci#define __pu_reg_oper0 "%L2"
2518c2ecf20Sopenharmony_ci#define __pu_reg_oper1 "%H2"
2528c2ecf20Sopenharmony_ci#endif
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci#define __put_user_asm_dword(x, addr, err) 				\
2558c2ecf20Sopenharmony_ci	__asm__ __volatile__ (						\
2568c2ecf20Sopenharmony_ci		"\n1:\tswi " __pu_reg_oper0 ",[%1]\n"			\
2578c2ecf20Sopenharmony_ci		"\n2:\tswi " __pu_reg_oper1 ",[%1+4]\n"			\
2588c2ecf20Sopenharmony_ci		"3:\n"							\
2598c2ecf20Sopenharmony_ci		"	.section .fixup,\"ax\"\n"			\
2608c2ecf20Sopenharmony_ci		"	.align	2\n"					\
2618c2ecf20Sopenharmony_ci		"4:	move	%0, %3\n"				\
2628c2ecf20Sopenharmony_ci		"	b	3b\n"					\
2638c2ecf20Sopenharmony_ci		"	.previous\n"					\
2648c2ecf20Sopenharmony_ci		"	.section __ex_table,\"a\"\n"			\
2658c2ecf20Sopenharmony_ci		"	.align	3\n"					\
2668c2ecf20Sopenharmony_ci		"	.long	1b, 4b\n"				\
2678c2ecf20Sopenharmony_ci		"	.long	2b, 4b\n"				\
2688c2ecf20Sopenharmony_ci		"	.previous"					\
2698c2ecf20Sopenharmony_ci		: "+r"(err)						\
2708c2ecf20Sopenharmony_ci		: "r"(addr), "r"(x), "i"(-EFAULT)			\
2718c2ecf20Sopenharmony_ci		: "cc")
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciextern unsigned long __arch_clear_user(void __user * addr, unsigned long n);
2748c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *dest, const char __user * src, long count);
2758c2ecf20Sopenharmony_ciextern __must_check long strlen_user(const char __user * str);
2768c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user * str, long n);
2778c2ecf20Sopenharmony_ciextern unsigned long __arch_copy_from_user(void *to, const void __user * from,
2788c2ecf20Sopenharmony_ci                                           unsigned long n);
2798c2ecf20Sopenharmony_ciextern unsigned long __arch_copy_to_user(void __user * to, const void *from,
2808c2ecf20Sopenharmony_ci                                         unsigned long n);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci#define raw_copy_from_user __arch_copy_from_user
2838c2ecf20Sopenharmony_ci#define raw_copy_to_user __arch_copy_to_user
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER
2868c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER
2878c2ecf20Sopenharmony_cistatic inline unsigned long clear_user(void __user * to, unsigned long n)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	if (access_ok(to, n))
2908c2ecf20Sopenharmony_ci		n = __arch_clear_user(to, n);
2918c2ecf20Sopenharmony_ci	return n;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic inline unsigned long __clear_user(void __user * to, unsigned long n)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	return __arch_clear_user(to, n);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci#endif /* _ASMNDS32_UACCESS_H */
300