]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #ifndef __PARISC_UACCESS_H |
2 | #define __PARISC_UACCESS_H | |
3 | ||
4 | /* | |
5 | * User space memory access functions | |
6 | */ | |
1da177e4 | 7 | #include <asm/page.h> |
1da177e4 | 8 | #include <asm/cache.h> |
888c31fc | 9 | #include <asm/errno.h> |
5b17e1cd | 10 | #include <asm-generic/uaccess-unaligned.h> |
1da177e4 | 11 | |
8dd95c68 | 12 | #include <linux/bug.h> |
aace880f | 13 | #include <linux/string.h> |
9e91db6b | 14 | #include <linux/thread_info.h> |
8dd95c68 | 15 | |
1da177e4 LT |
16 | #define VERIFY_READ 0 |
17 | #define VERIFY_WRITE 1 | |
18 | ||
19 | #define KERNEL_DS ((mm_segment_t){0}) | |
20 | #define USER_DS ((mm_segment_t){1}) | |
21 | ||
b9762e7b | 22 | #define segment_eq(a, b) ((a).seg == (b).seg) |
1da177e4 LT |
23 | |
24 | #define get_ds() (KERNEL_DS) | |
25 | #define get_fs() (current_thread_info()->addr_limit) | |
26 | #define set_fs(x) (current_thread_info()->addr_limit = (x)) | |
27 | ||
28 | /* | |
29 | * Note that since kernel addresses are in a separate address space on | |
e49332bd | 30 | * parisc, we don't need to do anything for access_ok(). |
1da177e4 LT |
31 | * We just let the page fault handler do the right thing. This also means |
32 | * that put_user is the same as __put_user, etc. | |
33 | */ | |
34 | ||
09b871ff | 35 | #define access_ok(type, uaddr, size) (1) |
1da177e4 | 36 | |
1da177e4 LT |
37 | #define put_user __put_user |
38 | #define get_user __get_user | |
39 | ||
ca72a223 | 40 | #if !defined(CONFIG_64BIT) |
d2ad824f | 41 | #define LDD_USER(ptr) __get_user_asm64(ptr) |
b9762e7b | 42 | #define STD_USER(x, ptr) __put_user_asm64(x, ptr) |
1da177e4 | 43 | #else |
b9762e7b | 44 | #define LDD_USER(ptr) __get_user_asm("ldd", ptr) |
b9762e7b | 45 | #define STD_USER(x, ptr) __put_user_asm("std", x, ptr) |
1da177e4 LT |
46 | #endif |
47 | ||
48 | /* | |
cb910c17 HD |
49 | * The exception table contains two values: the first is the relative offset to |
50 | * the address of the instruction that is allowed to fault, and the second is | |
51 | * the relative offset to the address of the fixup routine. Since relative | |
52 | * addresses are used, 32bit values are sufficient even on 64bit kernel. | |
1da177e4 LT |
53 | */ |
54 | ||
0de79858 | 55 | #define ARCH_HAS_RELATIVE_EXTABLE |
1da177e4 | 56 | struct exception_table_entry { |
0de79858 HD |
57 | int insn; /* relative address of insn that is allowed to fault. */ |
58 | int fixup; /* relative address of fixup routine */ | |
1da177e4 LT |
59 | }; |
60 | ||
0b3d643f HD |
61 | #define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ |
62 | ".section __ex_table,\"aw\"\n" \ | |
0de79858 | 63 | ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ |
0b3d643f HD |
64 | ".previous\n" |
65 | ||
1da177e4 LT |
66 | /* |
67 | * The page fault handler stores, in a per-cpu area, the following information | |
68 | * if a fixup routine is available. | |
69 | */ | |
70 | struct exception_data { | |
71 | unsigned long fault_ip; | |
2ef4dfd9 | 72 | unsigned long fault_gp; |
1da177e4 LT |
73 | unsigned long fault_space; |
74 | unsigned long fault_addr; | |
75 | }; | |
76 | ||
06bff6b9 HD |
77 | /* |
78 | * load_sr2() preloads the space register %%sr2 - based on the value of | |
79 | * get_fs() - with either a value of 0 to access kernel space (KERNEL_DS which | |
80 | * is 0), or with the current value of %%sr3 to access user space (USER_DS) | |
81 | * memory. The following __get_user_asm() and __put_user_asm() functions have | |
82 | * %%sr2 hard-coded to access the requested memory. | |
83 | */ | |
84 | #define load_sr2() \ | |
85 | __asm__(" or,= %0,%%r0,%%r0\n\t" \ | |
86 | " mfsp %%sr3,%0\n\t" \ | |
87 | " mtsp %0,%%sr2\n\t" \ | |
88 | : : "r"(get_fs()) : ) | |
89 | ||
b9762e7b MT |
90 | #define __get_user(x, ptr) \ |
91 | ({ \ | |
92 | register long __gu_err __asm__ ("r8") = 0; \ | |
93 | register long __gu_val __asm__ ("r9") = 0; \ | |
94 | \ | |
06bff6b9 HD |
95 | load_sr2(); \ |
96 | switch (sizeof(*(ptr))) { \ | |
b9762e7b MT |
97 | case 1: __get_user_asm("ldb", ptr); break; \ |
98 | case 2: __get_user_asm("ldh", ptr); break; \ | |
99 | case 4: __get_user_asm("ldw", ptr); break; \ | |
100 | case 8: LDD_USER(ptr); break; \ | |
101 | default: BUILD_BUG(); break; \ | |
b9762e7b MT |
102 | } \ |
103 | \ | |
104 | (x) = (__force __typeof__(*(ptr))) __gu_val; \ | |
105 | __gu_err; \ | |
1da177e4 LT |
106 | }) |
107 | ||
b9762e7b | 108 | #define __get_user_asm(ldx, ptr) \ |
06bff6b9 | 109 | __asm__("\n1:\t" ldx "\t0(%%sr2,%2),%0\n\t" \ |
b9762e7b | 110 | ASM_EXCEPTIONTABLE_ENTRY(1b, fixup_get_user_skip_1)\ |
1da177e4 LT |
111 | : "=r"(__gu_val), "=r"(__gu_err) \ |
112 | : "r"(ptr), "1"(__gu_err) \ | |
113 | : "r1"); | |
1da177e4 | 114 | |
d2ad824f HD |
115 | #if !defined(CONFIG_64BIT) |
116 | ||
117 | #define __get_user_asm64(ptr) \ | |
118 | __asm__("\n1:\tldw 0(%%sr2,%2),%0" \ | |
119 | "\n2:\tldw 4(%%sr2,%2),%R0\n\t" \ | |
120 | ASM_EXCEPTIONTABLE_ENTRY(1b, fixup_get_user_skip_2)\ | |
121 | ASM_EXCEPTIONTABLE_ENTRY(2b, fixup_get_user_skip_1)\ | |
122 | : "=r"(__gu_val), "=r"(__gu_err) \ | |
123 | : "r"(ptr), "1"(__gu_err) \ | |
124 | : "r1"); | |
125 | ||
126 | #endif /* !defined(CONFIG_64BIT) */ | |
127 | ||
128 | ||
b9762e7b | 129 | #define __put_user(x, ptr) \ |
1da177e4 LT |
130 | ({ \ |
131 | register long __pu_err __asm__ ("r8") = 0; \ | |
132 | __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x); \ | |
133 | \ | |
06bff6b9 HD |
134 | load_sr2(); \ |
135 | switch (sizeof(*(ptr))) { \ | |
b9762e7b MT |
136 | case 1: __put_user_asm("stb", __x, ptr); break; \ |
137 | case 2: __put_user_asm("sth", __x, ptr); break; \ | |
138 | case 4: __put_user_asm("stw", __x, ptr); break; \ | |
139 | case 8: STD_USER(__x, ptr); break; \ | |
8dd95c68 | 140 | default: BUILD_BUG(); break; \ |
1da177e4 LT |
141 | } \ |
142 | \ | |
143 | __pu_err; \ | |
144 | }) | |
145 | ||
146 | /* | |
147 | * The "__put_user/kernel_asm()" macros tell gcc they read from memory | |
148 | * instead of writing. This is because they do not write to any memory | |
3fd3a74f CD |
149 | * gcc knows about, so there are no aliasing issues. These macros must |
150 | * also be aware that "fixup_put_user_skip_[12]" are executed in the | |
151 | * context of the fault, and any registers used there must be listed | |
152 | * as clobbers. In this case only "r1" is used by the current routines. | |
153 | * r8/r9 are already listed as err/val. | |
1da177e4 LT |
154 | */ |
155 | ||
b9762e7b | 156 | #define __put_user_asm(stx, x, ptr) \ |
1da177e4 | 157 | __asm__ __volatile__ ( \ |
06bff6b9 | 158 | "\n1:\t" stx "\t%2,0(%%sr2,%1)\n\t" \ |
b9762e7b | 159 | ASM_EXCEPTIONTABLE_ENTRY(1b, fixup_put_user_skip_1)\ |
1da177e4 LT |
160 | : "=r"(__pu_err) \ |
161 | : "r"(ptr), "r"(x), "0"(__pu_err) \ | |
162 | : "r1") | |
163 | ||
1da177e4 | 164 | |
ca72a223 | 165 | #if !defined(CONFIG_64BIT) |
94a1981d | 166 | |
b9762e7b | 167 | #define __put_user_asm64(__val, ptr) do { \ |
1da177e4 | 168 | __asm__ __volatile__ ( \ |
06bff6b9 HD |
169 | "\n1:\tstw %2,0(%%sr2,%1)" \ |
170 | "\n2:\tstw %R2,4(%%sr2,%1)\n\t" \ | |
b9762e7b MT |
171 | ASM_EXCEPTIONTABLE_ENTRY(1b, fixup_put_user_skip_2)\ |
172 | ASM_EXCEPTIONTABLE_ENTRY(2b, fixup_put_user_skip_1)\ | |
1da177e4 | 173 | : "=r"(__pu_err) \ |
0f28b628 | 174 | : "r"(ptr), "r"(__val), "0"(__pu_err) \ |
1da177e4 LT |
175 | : "r1"); \ |
176 | } while (0) | |
177 | ||
ca72a223 | 178 | #endif /* !defined(CONFIG_64BIT) */ |
1da177e4 LT |
179 | |
180 | ||
181 | /* | |
182 | * Complex access routines -- external declarations | |
183 | */ | |
184 | ||
185 | extern unsigned long lcopy_to_user(void __user *, const void *, unsigned long); | |
186 | extern unsigned long lcopy_from_user(void *, const void __user *, unsigned long); | |
187 | extern unsigned long lcopy_in_user(void __user *, const void __user *, unsigned long); | |
b1195c0e | 188 | extern long strncpy_from_user(char *, const char __user *, long); |
b9762e7b MT |
189 | extern unsigned lclear_user(void __user *, unsigned long); |
190 | extern long lstrnlen_user(const char __user *, long); | |
1da177e4 LT |
191 | /* |
192 | * Complex access routines -- macros | |
193 | */ | |
a0ffa8f0 | 194 | #define user_addr_max() (~0UL) |
1da177e4 | 195 | |
1da177e4 LT |
196 | #define strnlen_user lstrnlen_user |
197 | #define strlen_user(str) lstrnlen_user(str, 0x7fffffffL) | |
198 | #define clear_user lclear_user | |
199 | #define __clear_user lclear_user | |
200 | ||
9e91db6b HD |
201 | unsigned long __must_check __copy_to_user(void __user *dst, const void *src, |
202 | unsigned long len); | |
203 | unsigned long __must_check __copy_from_user(void *dst, const void __user *src, | |
204 | unsigned long len); | |
205 | unsigned long copy_in_user(void __user *dst, const void __user *src, | |
206 | unsigned long len); | |
1da177e4 LT |
207 | #define __copy_in_user copy_in_user |
208 | #define __copy_to_user_inatomic __copy_to_user | |
209 | #define __copy_from_user_inatomic __copy_from_user | |
210 | ||
0d025d27 JP |
211 | extern void __compiletime_error("usercopy buffer size is too small") |
212 | __bad_copy_user(void); | |
213 | ||
214 | static inline void copy_user_overflow(int size, unsigned long count) | |
215 | { | |
216 | WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); | |
217 | } | |
888c31fc | 218 | |
9e91db6b HD |
219 | static __always_inline unsigned long __must_check |
220 | copy_from_user(void *to, const void __user *from, unsigned long n) | |
888c31fc | 221 | { |
9e91db6b HD |
222 | int sz = __compiletime_object_size(to); |
223 | unsigned long ret = n; | |
888c31fc | 224 | |
9e91db6b HD |
225 | if (likely(sz < 0 || sz >= n)) { |
226 | check_object_size(to, n, false); | |
227 | ret = __copy_from_user(to, from, n); | |
228 | } else if (!__builtin_constant_p(n)) | |
0d025d27 JP |
229 | copy_user_overflow(sz, n); |
230 | else | |
9e91db6b | 231 | __bad_copy_user(); |
888c31fc | 232 | |
aace880f AV |
233 | if (unlikely(ret)) |
234 | memset(to + (n - ret), 0, ret); | |
9e91db6b HD |
235 | |
236 | return ret; | |
237 | } | |
238 | ||
239 | static __always_inline unsigned long __must_check | |
240 | copy_to_user(void __user *to, const void *from, unsigned long n) | |
241 | { | |
242 | int sz = __compiletime_object_size(from); | |
243 | ||
244 | if (likely(sz < 0 || sz >= n)) { | |
245 | check_object_size(from, n, true); | |
246 | n = __copy_to_user(to, from, n); | |
247 | } else if (!__builtin_constant_p(n)) | |
248 | copy_user_overflow(sz, n); | |
249 | else | |
250 | __bad_copy_user(); | |
251 | ||
252 | return n; | |
888c31fc HD |
253 | } |
254 | ||
e448372c | 255 | struct pt_regs; |
c61c25eb KM |
256 | int fixup_exception(struct pt_regs *regs); |
257 | ||
1da177e4 | 258 | #endif /* __PARISC_UACCESS_H */ |