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