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> |
12700c17 | 21 | #include <asm-generic/access_ok.h> |
5ccc6af5 LFT |
22 | |
23 | # define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" | |
24 | ||
25 | /* | |
26 | * Zero Userspace | |
27 | */ | |
28 | ||
29 | static inline unsigned long __must_check __clear_user(void __user *to, | |
30 | unsigned long n) | |
31 | { | |
32 | __asm__ __volatile__ ( | |
33 | "1: stb zero, 0(%1)\n" | |
34 | " addi %0, %0, -1\n" | |
35 | " addi %1, %1, 1\n" | |
36 | " bne %0, zero, 1b\n" | |
37 | "2:\n" | |
38 | __EX_TABLE_SECTION | |
39 | ".word 1b, 2b\n" | |
40 | ".previous\n" | |
41 | : "=r" (n), "=r" (to) | |
42 | : "0" (n), "1" (to) | |
43 | ); | |
44 | ||
45 | return n; | |
46 | } | |
47 | ||
48 | static inline unsigned long __must_check clear_user(void __user *to, | |
49 | unsigned long n) | |
50 | { | |
96d4f267 | 51 | if (!access_ok(to, n)) |
5ccc6af5 LFT |
52 | return n; |
53 | return __clear_user(to, n); | |
54 | } | |
55 | ||
de51d6cc AV |
56 | extern unsigned long |
57 | raw_copy_from_user(void *to, const void __user *from, unsigned long n); | |
58 | extern unsigned long | |
59 | raw_copy_to_user(void __user *to, const void *from, unsigned long n); | |
60 | #define INLINE_COPY_FROM_USER | |
61 | #define INLINE_COPY_TO_USER | |
5ccc6af5 LFT |
62 | |
63 | extern long strncpy_from_user(char *__to, const char __user *__from, | |
7f1e6141 | 64 | long __len); |
7f1e6141 | 65 | extern __must_check long strnlen_user(const char __user *s, long n); |
5ccc6af5 | 66 | |
5ccc6af5 LFT |
67 | /* Optimized macros */ |
68 | #define __get_user_asm(val, insn, addr, err) \ | |
69 | { \ | |
a97b693c | 70 | unsigned long __gu_val; \ |
5ccc6af5 LFT |
71 | __asm__ __volatile__( \ |
72 | " movi %0, %3\n" \ | |
73 | "1: " insn " %1, 0(%2)\n" \ | |
74 | " movi %0, 0\n" \ | |
75 | "2:\n" \ | |
76 | " .section __ex_table,\"a\"\n" \ | |
77 | " .word 1b, 2b\n" \ | |
78 | " .previous" \ | |
a97b693c | 79 | : "=&r" (err), "=r" (__gu_val) \ |
5ccc6af5 | 80 | : "r" (addr), "i" (-EFAULT)); \ |
a97b693c | 81 | val = (__force __typeof__(*(addr)))__gu_val; \ |
5ccc6af5 LFT |
82 | } |
83 | ||
a97b693c AB |
84 | extern void __get_user_unknown(void); |
85 | ||
86 | #define __get_user_8(val, ptr, err) do { \ | |
87 | u64 __val = 0; \ | |
5ccc6af5 | 88 | err = 0; \ |
a97b693c | 89 | if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ |
5ccc6af5 | 90 | err = -EFAULT; \ |
a97b693c AB |
91 | } else { \ |
92 | val = (typeof(val))(typeof((val) - (val)))__val; \ | |
5ccc6af5 LFT |
93 | } \ |
94 | } while (0) | |
95 | ||
96 | #define __get_user_common(val, size, ptr, err) \ | |
97 | do { \ | |
98 | switch (size) { \ | |
99 | case 1: \ | |
100 | __get_user_asm(val, "ldbu", ptr, err); \ | |
101 | break; \ | |
102 | case 2: \ | |
103 | __get_user_asm(val, "ldhu", ptr, err); \ | |
104 | break; \ | |
105 | case 4: \ | |
106 | __get_user_asm(val, "ldw", ptr, err); \ | |
107 | break; \ | |
a97b693c AB |
108 | case 8: \ |
109 | __get_user_8(val, ptr, err); \ | |
110 | break; \ | |
5ccc6af5 | 111 | default: \ |
a97b693c | 112 | __get_user_unknown(); \ |
5ccc6af5 LFT |
113 | break; \ |
114 | } \ | |
115 | } while (0) | |
116 | ||
117 | #define __get_user(x, ptr) \ | |
118 | ({ \ | |
119 | long __gu_err = -EFAULT; \ | |
120 | const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ | |
a97b693c | 121 | __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ |
5ccc6af5 LFT |
122 | __gu_err; \ |
123 | }) | |
124 | ||
125 | #define get_user(x, ptr) \ | |
126 | ({ \ | |
127 | long __gu_err = -EFAULT; \ | |
128 | const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ | |
96d4f267 | 129 | if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ |
a97b693c | 130 | __get_user_common(x, sizeof(*__gu_ptr), \ |
5ccc6af5 | 131 | __gu_ptr, __gu_err); \ |
5ccc6af5 LFT |
132 | __gu_err; \ |
133 | }) | |
134 | ||
135 | #define __put_user_asm(val, insn, ptr, err) \ | |
136 | { \ | |
137 | __asm__ __volatile__( \ | |
138 | " movi %0, %3\n" \ | |
139 | "1: " insn " %1, 0(%2)\n" \ | |
140 | " movi %0, 0\n" \ | |
141 | "2:\n" \ | |
142 | " .section __ex_table,\"a\"\n" \ | |
143 | " .word 1b, 2b\n" \ | |
144 | " .previous\n" \ | |
145 | : "=&r" (err) \ | |
146 | : "r" (val), "r" (ptr), "i" (-EFAULT)); \ | |
147 | } | |
148 | ||
90997c12 | 149 | #define __put_user_common(__pu_val, __pu_ptr) \ |
5ccc6af5 LFT |
150 | ({ \ |
151 | long __pu_err = -EFAULT; \ | |
90997c12 AB |
152 | switch (sizeof(*__pu_ptr)) { \ |
153 | case 1: \ | |
154 | __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ | |
155 | break; \ | |
156 | case 2: \ | |
157 | __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ | |
158 | break; \ | |
159 | case 4: \ | |
160 | __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ | |
161 | break; \ | |
162 | default: \ | |
163 | /* XXX: This looks wrong... */ \ | |
164 | __pu_err = 0; \ | |
165 | if (__copy_to_user(__pu_ptr, &(__pu_val), \ | |
166 | sizeof(*__pu_ptr))) \ | |
167 | __pu_err = -EFAULT; \ | |
168 | break; \ | |
5ccc6af5 LFT |
169 | } \ |
170 | __pu_err; \ | |
171 | }) | |
172 | ||
90997c12 AB |
173 | #define __put_user(x, ptr) \ |
174 | ({ \ | |
175 | __auto_type __pu_ptr = (ptr); \ | |
176 | typeof(*__pu_ptr) __pu_val = (typeof(*__pu_ptr))(x); \ | |
177 | __put_user_common(__pu_val, __pu_ptr); \ | |
178 | }) | |
179 | ||
180 | #define put_user(x, ptr) \ | |
181 | ({ \ | |
182 | __auto_type __pu_ptr = (ptr); \ | |
183 | typeof(*__pu_ptr) __pu_val = (typeof(*__pu_ptr))(x); \ | |
184 | access_ok(__pu_ptr, sizeof(*__pu_ptr)) ? \ | |
185 | __put_user_common(__pu_val, __pu_ptr) : \ | |
186 | -EFAULT; \ | |
187 | }) | |
5ccc6af5 LFT |
188 | |
189 | #endif /* _ASM_NIOS2_UACCESS_H */ |