1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * User space memory access functions for Nios II
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch>
5*4882a593Smuzhiyun * Copyright (C) 2009, Wind River Systems Inc
6*4882a593Smuzhiyun * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
9*4882a593Smuzhiyun * License. See the file "COPYING" in the main directory of this archive
10*4882a593Smuzhiyun * for more details.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #ifndef _ASM_NIOS2_UACCESS_H
14*4882a593Smuzhiyun #define _ASM_NIOS2_UACCESS_H
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/string.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <asm/page.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <asm/extable.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * Segment stuff
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
26*4882a593Smuzhiyun #define USER_DS MAKE_MM_SEG(0x80000000UL)
27*4882a593Smuzhiyun #define KERNEL_DS MAKE_MM_SEG(0)
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define get_fs() (current_thread_info()->addr_limit)
31*4882a593Smuzhiyun #define set_fs(seg) (current_thread_info()->addr_limit = (seg))
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define __access_ok(addr, len) \
36*4882a593Smuzhiyun (((signed long)(((long)get_fs().seg) & \
37*4882a593Smuzhiyun ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define access_ok(addr, len) \
40*4882a593Smuzhiyun likely(__access_ok((unsigned long)(addr), (unsigned long)(len)))
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun # define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /*
47*4882a593Smuzhiyun * Zero Userspace
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun
__clear_user(void __user * to,unsigned long n)50*4882a593Smuzhiyun static inline unsigned long __must_check __clear_user(void __user *to,
51*4882a593Smuzhiyun unsigned long n)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun __asm__ __volatile__ (
54*4882a593Smuzhiyun "1: stb zero, 0(%1)\n"
55*4882a593Smuzhiyun " addi %0, %0, -1\n"
56*4882a593Smuzhiyun " addi %1, %1, 1\n"
57*4882a593Smuzhiyun " bne %0, zero, 1b\n"
58*4882a593Smuzhiyun "2:\n"
59*4882a593Smuzhiyun __EX_TABLE_SECTION
60*4882a593Smuzhiyun ".word 1b, 2b\n"
61*4882a593Smuzhiyun ".previous\n"
62*4882a593Smuzhiyun : "=r" (n), "=r" (to)
63*4882a593Smuzhiyun : "0" (n), "1" (to)
64*4882a593Smuzhiyun );
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return n;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
clear_user(void __user * to,unsigned long n)69*4882a593Smuzhiyun static inline unsigned long __must_check clear_user(void __user *to,
70*4882a593Smuzhiyun unsigned long n)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun if (!access_ok(to, n))
73*4882a593Smuzhiyun return n;
74*4882a593Smuzhiyun return __clear_user(to, n);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun extern unsigned long
78*4882a593Smuzhiyun raw_copy_from_user(void *to, const void __user *from, unsigned long n);
79*4882a593Smuzhiyun extern unsigned long
80*4882a593Smuzhiyun raw_copy_to_user(void __user *to, const void *from, unsigned long n);
81*4882a593Smuzhiyun #define INLINE_COPY_FROM_USER
82*4882a593Smuzhiyun #define INLINE_COPY_TO_USER
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun extern long strncpy_from_user(char *__to, const char __user *__from,
85*4882a593Smuzhiyun long __len);
86*4882a593Smuzhiyun extern __must_check long strlen_user(const char __user *str);
87*4882a593Smuzhiyun extern __must_check long strnlen_user(const char __user *s, long n);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* Optimized macros */
90*4882a593Smuzhiyun #define __get_user_asm(val, insn, addr, err) \
91*4882a593Smuzhiyun { \
92*4882a593Smuzhiyun unsigned long __gu_val; \
93*4882a593Smuzhiyun __asm__ __volatile__( \
94*4882a593Smuzhiyun " movi %0, %3\n" \
95*4882a593Smuzhiyun "1: " insn " %1, 0(%2)\n" \
96*4882a593Smuzhiyun " movi %0, 0\n" \
97*4882a593Smuzhiyun "2:\n" \
98*4882a593Smuzhiyun " .section __ex_table,\"a\"\n" \
99*4882a593Smuzhiyun " .word 1b, 2b\n" \
100*4882a593Smuzhiyun " .previous" \
101*4882a593Smuzhiyun : "=&r" (err), "=r" (__gu_val) \
102*4882a593Smuzhiyun : "r" (addr), "i" (-EFAULT)); \
103*4882a593Smuzhiyun val = (__force __typeof__(*(addr)))__gu_val; \
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun extern void __get_user_unknown(void);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun #define __get_user_8(val, ptr, err) do { \
109*4882a593Smuzhiyun u64 __val = 0; \
110*4882a593Smuzhiyun err = 0; \
111*4882a593Smuzhiyun if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \
112*4882a593Smuzhiyun err = -EFAULT; \
113*4882a593Smuzhiyun } else { \
114*4882a593Smuzhiyun val = (typeof(val))(typeof((val) - (val)))__val; \
115*4882a593Smuzhiyun } \
116*4882a593Smuzhiyun } while (0)
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #define __get_user_common(val, size, ptr, err) \
119*4882a593Smuzhiyun do { \
120*4882a593Smuzhiyun switch (size) { \
121*4882a593Smuzhiyun case 1: \
122*4882a593Smuzhiyun __get_user_asm(val, "ldbu", ptr, err); \
123*4882a593Smuzhiyun break; \
124*4882a593Smuzhiyun case 2: \
125*4882a593Smuzhiyun __get_user_asm(val, "ldhu", ptr, err); \
126*4882a593Smuzhiyun break; \
127*4882a593Smuzhiyun case 4: \
128*4882a593Smuzhiyun __get_user_asm(val, "ldw", ptr, err); \
129*4882a593Smuzhiyun break; \
130*4882a593Smuzhiyun case 8: \
131*4882a593Smuzhiyun __get_user_8(val, ptr, err); \
132*4882a593Smuzhiyun break; \
133*4882a593Smuzhiyun default: \
134*4882a593Smuzhiyun __get_user_unknown(); \
135*4882a593Smuzhiyun break; \
136*4882a593Smuzhiyun } \
137*4882a593Smuzhiyun } while (0)
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define __get_user(x, ptr) \
140*4882a593Smuzhiyun ({ \
141*4882a593Smuzhiyun long __gu_err = -EFAULT; \
142*4882a593Smuzhiyun const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
143*4882a593Smuzhiyun __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \
144*4882a593Smuzhiyun __gu_err; \
145*4882a593Smuzhiyun })
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun #define get_user(x, ptr) \
148*4882a593Smuzhiyun ({ \
149*4882a593Smuzhiyun long __gu_err = -EFAULT; \
150*4882a593Smuzhiyun const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
151*4882a593Smuzhiyun if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \
152*4882a593Smuzhiyun __get_user_common(x, sizeof(*__gu_ptr), \
153*4882a593Smuzhiyun __gu_ptr, __gu_err); \
154*4882a593Smuzhiyun __gu_err; \
155*4882a593Smuzhiyun })
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun #define __put_user_asm(val, insn, ptr, err) \
158*4882a593Smuzhiyun { \
159*4882a593Smuzhiyun __asm__ __volatile__( \
160*4882a593Smuzhiyun " movi %0, %3\n" \
161*4882a593Smuzhiyun "1: " insn " %1, 0(%2)\n" \
162*4882a593Smuzhiyun " movi %0, 0\n" \
163*4882a593Smuzhiyun "2:\n" \
164*4882a593Smuzhiyun " .section __ex_table,\"a\"\n" \
165*4882a593Smuzhiyun " .word 1b, 2b\n" \
166*4882a593Smuzhiyun " .previous\n" \
167*4882a593Smuzhiyun : "=&r" (err) \
168*4882a593Smuzhiyun : "r" (val), "r" (ptr), "i" (-EFAULT)); \
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun #define put_user(x, ptr) \
172*4882a593Smuzhiyun ({ \
173*4882a593Smuzhiyun long __pu_err = -EFAULT; \
174*4882a593Smuzhiyun __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \
175*4882a593Smuzhiyun __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x); \
176*4882a593Smuzhiyun if (access_ok(__pu_ptr, sizeof(*__pu_ptr))) { \
177*4882a593Smuzhiyun switch (sizeof(*__pu_ptr)) { \
178*4882a593Smuzhiyun case 1: \
179*4882a593Smuzhiyun __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \
180*4882a593Smuzhiyun break; \
181*4882a593Smuzhiyun case 2: \
182*4882a593Smuzhiyun __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \
183*4882a593Smuzhiyun break; \
184*4882a593Smuzhiyun case 4: \
185*4882a593Smuzhiyun __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \
186*4882a593Smuzhiyun break; \
187*4882a593Smuzhiyun default: \
188*4882a593Smuzhiyun /* XXX: This looks wrong... */ \
189*4882a593Smuzhiyun __pu_err = 0; \
190*4882a593Smuzhiyun if (copy_to_user(__pu_ptr, &(__pu_val), \
191*4882a593Smuzhiyun sizeof(*__pu_ptr))) \
192*4882a593Smuzhiyun __pu_err = -EFAULT; \
193*4882a593Smuzhiyun break; \
194*4882a593Smuzhiyun } \
195*4882a593Smuzhiyun } \
196*4882a593Smuzhiyun __pu_err; \
197*4882a593Smuzhiyun })
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun #define __put_user(x, ptr) put_user(x, ptr)
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun #endif /* _ASM_NIOS2_UACCESS_H */
202