18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * User space memory access functions for Nios II
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch>
58c2ecf20Sopenharmony_ci * Copyright (C) 2009, Wind River Systems Inc
68c2ecf20Sopenharmony_ci *   Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
98c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
108c2ecf20Sopenharmony_ci * for more details.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifndef _ASM_NIOS2_UACCESS_H
148c2ecf20Sopenharmony_ci#define _ASM_NIOS2_UACCESS_H
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/page.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/extable.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * Segment stuff
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci#define MAKE_MM_SEG(s)		((mm_segment_t) { (s) })
268c2ecf20Sopenharmony_ci#define USER_DS			MAKE_MM_SEG(0x80000000UL)
278c2ecf20Sopenharmony_ci#define KERNEL_DS		MAKE_MM_SEG(0)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define get_fs()		(current_thread_info()->addr_limit)
318c2ecf20Sopenharmony_ci#define set_fs(seg)		(current_thread_info()->addr_limit = (seg))
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define __access_ok(addr, len)			\
368c2ecf20Sopenharmony_ci	(((signed long)(((long)get_fs().seg) &	\
378c2ecf20Sopenharmony_ci		((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define access_ok(addr, len)		\
408c2ecf20Sopenharmony_ci	likely(__access_ok((unsigned long)(addr), (unsigned long)(len)))
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci# define __EX_TABLE_SECTION	".section __ex_table,\"a\"\n"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE)
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/*
478c2ecf20Sopenharmony_ci * Zero Userspace
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline unsigned long __must_check __clear_user(void __user *to,
518c2ecf20Sopenharmony_ci						      unsigned long n)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
548c2ecf20Sopenharmony_ci		"1:     stb     zero, 0(%1)\n"
558c2ecf20Sopenharmony_ci		"       addi    %0, %0, -1\n"
568c2ecf20Sopenharmony_ci		"       addi    %1, %1, 1\n"
578c2ecf20Sopenharmony_ci		"       bne     %0, zero, 1b\n"
588c2ecf20Sopenharmony_ci		"2:\n"
598c2ecf20Sopenharmony_ci		__EX_TABLE_SECTION
608c2ecf20Sopenharmony_ci		".word  1b, 2b\n"
618c2ecf20Sopenharmony_ci		".previous\n"
628c2ecf20Sopenharmony_ci		: "=r" (n), "=r" (to)
638c2ecf20Sopenharmony_ci		: "0" (n), "1" (to)
648c2ecf20Sopenharmony_ci	);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return n;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to,
708c2ecf20Sopenharmony_ci						    unsigned long n)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	if (!access_ok(to, n))
738c2ecf20Sopenharmony_ci		return n;
748c2ecf20Sopenharmony_ci	return __clear_user(to, n);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciextern unsigned long
788c2ecf20Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n);
798c2ecf20Sopenharmony_ciextern unsigned long
808c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n);
818c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER
828c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *__to, const char __user *__from,
858c2ecf20Sopenharmony_ci			      long __len);
868c2ecf20Sopenharmony_ciextern __must_check long strlen_user(const char __user *str);
878c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user *s, long n);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* Optimized macros */
908c2ecf20Sopenharmony_ci#define __get_user_asm(val, insn, addr, err)				\
918c2ecf20Sopenharmony_ci{									\
928c2ecf20Sopenharmony_ci	unsigned long __gu_val;						\
938c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
948c2ecf20Sopenharmony_ci	"       movi    %0, %3\n"					\
958c2ecf20Sopenharmony_ci	"1:   " insn " %1, 0(%2)\n"					\
968c2ecf20Sopenharmony_ci	"       movi     %0, 0\n"					\
978c2ecf20Sopenharmony_ci	"2:\n"								\
988c2ecf20Sopenharmony_ci	"       .section __ex_table,\"a\"\n"				\
998c2ecf20Sopenharmony_ci	"       .word 1b, 2b\n"						\
1008c2ecf20Sopenharmony_ci	"       .previous"						\
1018c2ecf20Sopenharmony_ci	: "=&r" (err), "=r" (__gu_val)					\
1028c2ecf20Sopenharmony_ci	: "r" (addr), "i" (-EFAULT));					\
1038c2ecf20Sopenharmony_ci	val = (__force __typeof__(*(addr)))__gu_val;			\
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciextern void __get_user_unknown(void);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci#define __get_user_8(val, ptr, err) do {				\
1098c2ecf20Sopenharmony_ci	u64 __val = 0;							\
1108c2ecf20Sopenharmony_ci	err = 0;							\
1118c2ecf20Sopenharmony_ci	if (raw_copy_from_user(&(__val), ptr, sizeof(val))) {		\
1128c2ecf20Sopenharmony_ci		err = -EFAULT;						\
1138c2ecf20Sopenharmony_ci	} else {							\
1148c2ecf20Sopenharmony_ci		val = (typeof(val))(typeof((val) - (val)))__val;	\
1158c2ecf20Sopenharmony_ci	}								\
1168c2ecf20Sopenharmony_ci	} while (0)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define __get_user_common(val, size, ptr, err)				\
1198c2ecf20Sopenharmony_cido {									\
1208c2ecf20Sopenharmony_ci	switch (size) {							\
1218c2ecf20Sopenharmony_ci	case 1:								\
1228c2ecf20Sopenharmony_ci		__get_user_asm(val, "ldbu", ptr, err);			\
1238c2ecf20Sopenharmony_ci		break;							\
1248c2ecf20Sopenharmony_ci	case 2:								\
1258c2ecf20Sopenharmony_ci		__get_user_asm(val, "ldhu", ptr, err);			\
1268c2ecf20Sopenharmony_ci		break;							\
1278c2ecf20Sopenharmony_ci	case 4:								\
1288c2ecf20Sopenharmony_ci		__get_user_asm(val, "ldw", ptr, err);			\
1298c2ecf20Sopenharmony_ci		break;							\
1308c2ecf20Sopenharmony_ci	case 8:								\
1318c2ecf20Sopenharmony_ci		__get_user_8(val, ptr, err);				\
1328c2ecf20Sopenharmony_ci		break;							\
1338c2ecf20Sopenharmony_ci	default:							\
1348c2ecf20Sopenharmony_ci		__get_user_unknown();					\
1358c2ecf20Sopenharmony_ci		break;							\
1368c2ecf20Sopenharmony_ci	}								\
1378c2ecf20Sopenharmony_ci} while (0)
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define __get_user(x, ptr)						\
1408c2ecf20Sopenharmony_ci	({								\
1418c2ecf20Sopenharmony_ci	long __gu_err = -EFAULT;					\
1428c2ecf20Sopenharmony_ci	const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);		\
1438c2ecf20Sopenharmony_ci	__get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err);	\
1448c2ecf20Sopenharmony_ci	__gu_err;							\
1458c2ecf20Sopenharmony_ci	})
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#define get_user(x, ptr)						\
1488c2ecf20Sopenharmony_ci({									\
1498c2ecf20Sopenharmony_ci	long __gu_err = -EFAULT;					\
1508c2ecf20Sopenharmony_ci	const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);		\
1518c2ecf20Sopenharmony_ci	if (access_ok( __gu_ptr, sizeof(*__gu_ptr)))	\
1528c2ecf20Sopenharmony_ci		__get_user_common(x, sizeof(*__gu_ptr),			\
1538c2ecf20Sopenharmony_ci			__gu_ptr, __gu_err);				\
1548c2ecf20Sopenharmony_ci	__gu_err;							\
1558c2ecf20Sopenharmony_ci})
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci#define __put_user_asm(val, insn, ptr, err)				\
1588c2ecf20Sopenharmony_ci{									\
1598c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
1608c2ecf20Sopenharmony_ci	"       movi    %0, %3\n"					\
1618c2ecf20Sopenharmony_ci	"1:   " insn " %1, 0(%2)\n"					\
1628c2ecf20Sopenharmony_ci	"       movi     %0, 0\n"					\
1638c2ecf20Sopenharmony_ci	"2:\n"								\
1648c2ecf20Sopenharmony_ci	"       .section __ex_table,\"a\"\n"				\
1658c2ecf20Sopenharmony_ci	"       .word 1b, 2b\n"						\
1668c2ecf20Sopenharmony_ci	"       .previous\n"						\
1678c2ecf20Sopenharmony_ci	: "=&r" (err)							\
1688c2ecf20Sopenharmony_ci	: "r" (val), "r" (ptr), "i" (-EFAULT));				\
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci#define put_user(x, ptr)						\
1728c2ecf20Sopenharmony_ci({									\
1738c2ecf20Sopenharmony_ci	long __pu_err = -EFAULT;					\
1748c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_ptr = (ptr);			\
1758c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x);		\
1768c2ecf20Sopenharmony_ci	if (access_ok(__pu_ptr, sizeof(*__pu_ptr))) {	\
1778c2ecf20Sopenharmony_ci		switch (sizeof(*__pu_ptr)) {				\
1788c2ecf20Sopenharmony_ci		case 1:							\
1798c2ecf20Sopenharmony_ci			__put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \
1808c2ecf20Sopenharmony_ci			break;						\
1818c2ecf20Sopenharmony_ci		case 2:							\
1828c2ecf20Sopenharmony_ci			__put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \
1838c2ecf20Sopenharmony_ci			break;						\
1848c2ecf20Sopenharmony_ci		case 4:							\
1858c2ecf20Sopenharmony_ci			__put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \
1868c2ecf20Sopenharmony_ci			break;						\
1878c2ecf20Sopenharmony_ci		default:						\
1888c2ecf20Sopenharmony_ci			/* XXX: This looks wrong... */			\
1898c2ecf20Sopenharmony_ci			__pu_err = 0;					\
1908c2ecf20Sopenharmony_ci			if (copy_to_user(__pu_ptr, &(__pu_val),		\
1918c2ecf20Sopenharmony_ci				sizeof(*__pu_ptr)))			\
1928c2ecf20Sopenharmony_ci				__pu_err = -EFAULT;			\
1938c2ecf20Sopenharmony_ci			break;						\
1948c2ecf20Sopenharmony_ci		}							\
1958c2ecf20Sopenharmony_ci	}								\
1968c2ecf20Sopenharmony_ci	__pu_err;							\
1978c2ecf20Sopenharmony_ci})
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci#define __put_user(x, ptr) put_user(x, ptr)
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci#endif /* _ASM_NIOS2_UACCESS_H */
202