]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
373cd784 JH |
2 | #ifndef __METAG_UACCESS_H |
3 | #define __METAG_UACCESS_H | |
4 | ||
5 | /* | |
6 | * User space memory access functions | |
7 | */ | |
373cd784 | 8 | |
373cd784 JH |
9 | /* |
10 | * The fs value determines whether argument validity checking should be | |
11 | * performed or not. If get_fs() == USER_DS, checking is performed, with | |
12 | * get_fs() == KERNEL_DS, checking is bypassed. | |
13 | * | |
14 | * For historical reasons, these macros are grossly misnamed. | |
15 | */ | |
16 | ||
17 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) | |
18 | ||
19 | #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) | |
20 | #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) | |
21 | ||
22 | #define get_ds() (KERNEL_DS) | |
23 | #define get_fs() (current_thread_info()->addr_limit) | |
24 | #define set_fs(x) (current_thread_info()->addr_limit = (x)) | |
25 | ||
26 | #define segment_eq(a, b) ((a).seg == (b).seg) | |
27 | ||
373cd784 JH |
28 | static inline int __access_ok(unsigned long addr, unsigned long size) |
29 | { | |
8a8b5663 JH |
30 | /* |
31 | * Allow access to the user mapped memory area, but not the system area | |
32 | * before it. The check extends to the top of the address space when | |
33 | * kernel access is allowed (there's no real reason to user copy to the | |
34 | * system area in any case). | |
35 | */ | |
36 | if (likely(addr >= META_MEMORY_BASE && addr < get_fs().seg && | |
37 | size <= get_fs().seg - addr)) | |
38 | return true; | |
39 | /* | |
40 | * Explicitly allow NULL pointers here. Parts of the kernel such | |
41 | * as readv/writev use access_ok to validate pointers, but want | |
42 | * to allow NULL pointers for various reasons. NULL pointers are | |
43 | * safe to allow through because the first page is not mappable on | |
44 | * Meta. | |
45 | */ | |
46 | if (!addr) | |
47 | return true; | |
48 | /* Allow access to core code memory area... */ | |
49 | if (addr >= LINCORE_CODE_BASE && addr <= LINCORE_CODE_LIMIT && | |
50 | size <= LINCORE_CODE_LIMIT + 1 - addr) | |
51 | return true; | |
52 | /* ... but no other areas. */ | |
53 | return false; | |
373cd784 JH |
54 | } |
55 | ||
56 | #define access_ok(type, addr, size) __access_ok((unsigned long)(addr), \ | |
57 | (unsigned long)(size)) | |
58 | ||
8b9a7e56 | 59 | #include <asm/extable.h> |
373cd784 JH |
60 | |
61 | /* | |
62 | * These are the main single-value transfer routines. They automatically | |
63 | * use the right size if we just have the right pointer type. | |
64 | */ | |
65 | ||
66 | #define put_user(x, ptr) \ | |
67 | __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) | |
68 | #define __put_user(x, ptr) \ | |
69 | __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) | |
70 | ||
71 | extern void __put_user_bad(void); | |
72 | ||
73 | #define __put_user_nocheck(x, ptr, size) \ | |
74 | ({ \ | |
75 | long __pu_err; \ | |
76 | __put_user_size((x), (ptr), (size), __pu_err); \ | |
77 | __pu_err; \ | |
78 | }) | |
79 | ||
80 | #define __put_user_check(x, ptr, size) \ | |
81 | ({ \ | |
82 | long __pu_err = -EFAULT; \ | |
83 | __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ | |
84 | if (access_ok(VERIFY_WRITE, __pu_addr, size)) \ | |
85 | __put_user_size((x), __pu_addr, (size), __pu_err); \ | |
86 | __pu_err; \ | |
87 | }) | |
88 | ||
89 | extern long __put_user_asm_b(unsigned int x, void __user *addr); | |
90 | extern long __put_user_asm_w(unsigned int x, void __user *addr); | |
91 | extern long __put_user_asm_d(unsigned int x, void __user *addr); | |
92 | extern long __put_user_asm_l(unsigned long long x, void __user *addr); | |
93 | ||
9ef8dc16 MT |
94 | #define __put_user_size(x, ptr, size, retval) \ |
95 | do { \ | |
96 | retval = 0; \ | |
97 | switch (size) { \ | |
373cd784 | 98 | case 1: \ |
9ef8dc16 MT |
99 | retval = __put_user_asm_b((__force unsigned int)x, ptr);\ |
100 | break; \ | |
373cd784 | 101 | case 2: \ |
9ef8dc16 MT |
102 | retval = __put_user_asm_w((__force unsigned int)x, ptr);\ |
103 | break; \ | |
373cd784 | 104 | case 4: \ |
9ef8dc16 MT |
105 | retval = __put_user_asm_d((__force unsigned int)x, ptr);\ |
106 | break; \ | |
373cd784 | 107 | case 8: \ |
9ef8dc16 MT |
108 | retval = __put_user_asm_l((__force unsigned long long)x,\ |
109 | ptr); \ | |
110 | break; \ | |
373cd784 JH |
111 | default: \ |
112 | __put_user_bad(); \ | |
113 | } \ | |
114 | } while (0) | |
115 | ||
116 | #define get_user(x, ptr) \ | |
117 | __get_user_check((x), (ptr), sizeof(*(ptr))) | |
118 | #define __get_user(x, ptr) \ | |
119 | __get_user_nocheck((x), (ptr), sizeof(*(ptr))) | |
120 | ||
121 | extern long __get_user_bad(void); | |
122 | ||
123 | #define __get_user_nocheck(x, ptr, size) \ | |
124 | ({ \ | |
d3ba2e92 JH |
125 | long __gu_err; \ |
126 | long long __gu_val; \ | |
373cd784 | 127 | __get_user_size(__gu_val, (ptr), (size), __gu_err); \ |
8f4e4c1a | 128 | (x) = (__force __typeof__(*(ptr)))__gu_val; \ |
373cd784 JH |
129 | __gu_err; \ |
130 | }) | |
131 | ||
132 | #define __get_user_check(x, ptr, size) \ | |
133 | ({ \ | |
d3ba2e92 JH |
134 | long __gu_err = -EFAULT; \ |
135 | long long __gu_val = 0; \ | |
373cd784 JH |
136 | const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ |
137 | if (access_ok(VERIFY_READ, __gu_addr, size)) \ | |
138 | __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ | |
8f4e4c1a | 139 | (x) = (__force __typeof__(*(ptr)))__gu_val; \ |
373cd784 JH |
140 | __gu_err; \ |
141 | }) | |
142 | ||
143 | extern unsigned char __get_user_asm_b(const void __user *addr, long *err); | |
144 | extern unsigned short __get_user_asm_w(const void __user *addr, long *err); | |
145 | extern unsigned int __get_user_asm_d(const void __user *addr, long *err); | |
d3ba2e92 | 146 | extern unsigned long long __get_user_asm_l(const void __user *addr, long *err); |
373cd784 JH |
147 | |
148 | #define __get_user_size(x, ptr, size, retval) \ | |
149 | do { \ | |
150 | retval = 0; \ | |
151 | switch (size) { \ | |
152 | case 1: \ | |
153 | x = __get_user_asm_b(ptr, &retval); break; \ | |
154 | case 2: \ | |
155 | x = __get_user_asm_w(ptr, &retval); break; \ | |
156 | case 4: \ | |
157 | x = __get_user_asm_d(ptr, &retval); break; \ | |
d3ba2e92 JH |
158 | case 8: \ |
159 | x = __get_user_asm_l(ptr, &retval); break; \ | |
373cd784 JH |
160 | default: \ |
161 | (x) = __get_user_bad(); \ | |
162 | } \ | |
163 | } while (0) | |
164 | ||
165 | /* | |
166 | * Copy a null terminated string from userspace. | |
167 | * | |
168 | * Must return: | |
169 | * -EFAULT for an exception | |
170 | * count if we hit the buffer limit | |
171 | * bytes copied if we hit a null byte | |
172 | * (without the null byte) | |
173 | */ | |
174 | ||
175 | extern long __must_check __strncpy_from_user(char *dst, const char __user *src, | |
176 | long count); | |
177 | ||
3a158a62 JH |
178 | static inline long |
179 | strncpy_from_user(char *dst, const char __user *src, long count) | |
180 | { | |
181 | if (!access_ok(VERIFY_READ, src, 1)) | |
182 | return -EFAULT; | |
183 | return __strncpy_from_user(dst, src, count); | |
184 | } | |
373cd784 JH |
185 | /* |
186 | * Return the size of a string (including the ending 0) | |
187 | * | |
188 | * Return 0 on exception, a value greater than N if too long | |
189 | */ | |
190 | extern long __must_check strnlen_user(const char __user *src, long count); | |
191 | ||
563ddc10 JH |
192 | extern unsigned long raw_copy_from_user(void *to, const void __user *from, |
193 | unsigned long n); | |
840db3f9 JH |
194 | extern unsigned long raw_copy_to_user(void __user *to, const void *from, |
195 | unsigned long n); | |
373cd784 JH |
196 | |
197 | /* | |
198 | * Zero Userspace | |
199 | */ | |
200 | ||
201 | extern unsigned long __must_check __do_clear_user(void __user *to, | |
202 | unsigned long n); | |
203 | ||
204 | static inline unsigned long clear_user(void __user *to, unsigned long n) | |
205 | { | |
206 | if (access_ok(VERIFY_WRITE, to, n)) | |
207 | return __do_clear_user(to, n); | |
208 | return n; | |
209 | } | |
210 | ||
211 | #define __clear_user(to, n) __do_clear_user(to, n) | |
212 | ||
213 | #endif /* _METAG_UACCESS_H */ |