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