uaccess: fix type mismatch warnings from access_ok()
[linux-2.6-block.git] / arch / microblaze / include / asm / uaccess.h
CommitLineData
4726dd60 1/* SPDX-License-Identifier: GPL-2.0 */
2660663f 2/*
0d6de953
MS
3 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
4 * Copyright (C) 2008-2009 PetaLogix
2660663f 5 * Copyright (C) 2006 Atmark Techno, Inc.
2660663f
MS
6 */
7
8#ifndef _ASM_MICROBLAZE_UACCESS_H
9#define _ASM_MICROBLAZE_UACCESS_H
10
2660663f 11#include <linux/kernel.h>
2660663f
MS
12
13#include <asm/mmu.h>
14#include <asm/page.h>
ca5999fd 15#include <linux/pgtable.h>
730132e7 16#include <asm/extable.h>
2660663f
MS
17#include <linux/string.h>
18
40db0834
MS
19/*
20 * On Microblaze the fs value is actually the top of the corresponding
21 * address space.
22 *
23 * The fs value determines whether argument validity checking should be
24 * performed or not. If get_fs() == USER_DS, checking is performed, with
25 * get_fs() == KERNEL_DS, checking is bypassed.
26 *
27 * For historical reasons, these macros are grossly misnamed.
28 *
29 * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal.
30 */
31# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
32
40db0834
MS
33# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
34# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1)
40db0834 35
40db0834
MS
36# define get_fs() (current_thread_info()->addr_limit)
37# define set_fs(val) (current_thread_info()->addr_limit = (val))
b26b1816 38# define user_addr_max() get_fs().seg
40db0834 39
428e2976 40# define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
40db0834 41
222ca305 42static inline int __access_ok(unsigned long addr, unsigned long size)
f663b60f 43{
222ca305 44 unsigned long limit = user_addr_max();
f663b60f 45
222ca305 46 return (size <= limit) && (addr <= (limit - size));
f663b60f 47}
222ca305 48#define access_ok(addr, size) __access_ok((unsigned long)addr, size)
40b1156d 49
40b1156d
MS
50# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
51# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
40b1156d 52
94804a9b
MS
53extern unsigned long __copy_tofrom_user(void __user *to,
54 const void __user *from, unsigned long size);
55
527bdb52
MS
56/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
57static inline unsigned long __must_check __clear_user(void __user *to,
58 unsigned long n)
59{
60 /* normal memset with two words to __ex_table */
61 __asm__ __volatile__ ( \
6f3946b4 62 "1: sb r0, %1, r0;" \
527bdb52
MS
63 " addik %0, %0, -1;" \
64 " bneid %0, 1b;" \
6f3946b4 65 " addik %1, %1, 1;" \
527bdb52
MS
66 "2: " \
67 __EX_TABLE_SECTION \
68 ".word 1b,2b;" \
69 ".previous;" \
6f3946b4
SM
70 : "=r"(n), "=r"(to) \
71 : "0"(n), "1"(to)
527bdb52
MS
72 );
73 return n;
74}
75
76static inline unsigned long __must_check clear_user(void __user *to,
77 unsigned long n)
78{
ac093f8d 79 might_fault();
96d4f267 80 if (unlikely(!access_ok(to, n)))
527bdb52
MS
81 return n;
82
83 return __clear_user(to, n);
84}
85
cca79120 86/* put_user and get_user macros */
3a6d7724
MS
87extern long __user_bad(void);
88
89#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \
90({ \
91 __asm__ __volatile__ ( \
92 "1:" insn " %1, %2, r0;" \
93 " addk %0, r0, r0;" \
94 "2: " \
95 __FIXUP_SECTION \
96 "3: brid 2b;" \
97 " addik %0, r0, %3;" \
98 ".previous;" \
99 __EX_TABLE_SECTION \
100 ".word 1b,3b;" \
101 ".previous;" \
102 : "=&r"(__gu_err), "=r"(__gu_val) \
103 : "r"(__gu_ptr), "i"(-EFAULT) \
104 ); \
105})
106
107/**
108 * get_user: - Get a simple variable from user space.
109 * @x: Variable to store result.
110 * @ptr: Source address, in user space.
111 *
b3c395ef
DH
112 * Context: User context only. This function may sleep if pagefaults are
113 * enabled.
3a6d7724
MS
114 *
115 * This macro copies a single simple variable from user space to kernel
116 * space. It supports simple types like char and int, but not larger
117 * data types like structures or arrays.
118 *
119 * @ptr must have pointer-to-simple-variable type, and the result of
120 * dereferencing @ptr must be assignable to @x without a cast.
121 *
122 * Returns zero on success, or -EFAULT on error.
123 * On error, the variable @x is set to zero.
124 */
6a090e97
RD
125#define get_user(x, ptr) ({ \
126 const typeof(*(ptr)) __user *__gu_ptr = (ptr); \
127 access_ok(__gu_ptr, sizeof(*__gu_ptr)) ? \
128 __get_user(x, __gu_ptr) : -EFAULT; \
538722ca 129})
838d2406 130
3a6d7724
MS
131#define __get_user(x, ptr) \
132({ \
3a6d7724
MS
133 long __gu_err; \
134 switch (sizeof(*(ptr))) { \
135 case 1: \
a97b693c 136 __get_user_asm("lbu", (ptr), x, __gu_err); \
3a6d7724
MS
137 break; \
138 case 2: \
a97b693c 139 __get_user_asm("lhu", (ptr), x, __gu_err); \
3a6d7724
MS
140 break; \
141 case 4: \
a97b693c 142 __get_user_asm("lw", (ptr), x, __gu_err); \
3a6d7724 143 break; \
a97b693c
AB
144 case 8: { \
145 __u64 __x = 0; \
146 __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \
147 -EFAULT : 0; \
148 (x) = (typeof(x))(typeof((x) - (x)))__x; \
6a090e97 149 break; \
a97b693c 150 } \
3a6d7724
MS
151 default: \
152 /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
153 } \
3a6d7724 154 __gu_err; \
0d6de953 155})
2660663f 156
3a6d7724 157
ef4e277b
MS
158#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \
159({ \
160 __asm__ __volatile__ ( \
161 "1:" insn " %1, %2, r0;" \
162 " addk %0, r0, r0;" \
163 "2: " \
164 __FIXUP_SECTION \
165 "3: brid 2b;" \
166 " addik %0, r0, %3;" \
167 ".previous;" \
168 __EX_TABLE_SECTION \
169 ".word 1b,3b;" \
170 ".previous;" \
171 : "=&r"(__gu_err) \
172 : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \
173 ); \
174})
2660663f 175
ef4e277b 176#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \
0d6de953 177({ \
ef4e277b
MS
178 __asm__ __volatile__ (" lwi %0, %1, 0;" \
179 "1: swi %0, %2, 0;" \
180 " lwi %0, %1, 4;" \
181 "2: swi %0, %2, 4;" \
182 " addk %0, r0, r0;" \
183 "3: " \
184 __FIXUP_SECTION \
185 "4: brid 3b;" \
186 " addik %0, r0, %3;" \
187 ".previous;" \
188 __EX_TABLE_SECTION \
189 ".word 1b,4b,2b,4b;" \
190 ".previous;" \
191 : "=&r"(__gu_err) \
192 : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \
193 ); \
0d6de953 194})
2660663f 195
cca79120
MS
196/**
197 * put_user: - Write a simple value into user space.
198 * @x: Value to copy to user space.
199 * @ptr: Destination address, in user space.
200 *
b3c395ef
DH
201 * Context: User context only. This function may sleep if pagefaults are
202 * enabled.
cca79120
MS
203 *
204 * This macro copies a single simple value from kernel space to user
205 * space. It supports simple types like char and int, but not larger
206 * data types like structures or arrays.
207 *
208 * @ptr must have pointer-to-simple-variable type, and @x must be assignable
209 * to the result of dereferencing @ptr.
210 *
211 * Returns zero on success, or -EFAULT on error.
212 */
538722ca
SM
213#define put_user(x, ptr) \
214 __put_user_check((x), (ptr), sizeof(*(ptr)))
215
216#define __put_user_check(x, ptr, size) \
217({ \
132d5dfc 218 typeof(*(ptr)) volatile __pu_val = x; \
538722ca
SM
219 typeof(*(ptr)) __user *__pu_addr = (ptr); \
220 int __pu_err = 0; \
221 \
96d4f267 222 if (access_ok(__pu_addr, size)) { \
538722ca
SM
223 switch (size) { \
224 case 1: \
225 __put_user_asm("sb", __pu_addr, __pu_val, \
226 __pu_err); \
227 break; \
228 case 2: \
229 __put_user_asm("sh", __pu_addr, __pu_val, \
230 __pu_err); \
231 break; \
232 case 4: \
233 __put_user_asm("sw", __pu_addr, __pu_val, \
234 __pu_err); \
235 break; \
236 case 8: \
237 __put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
238 break; \
239 default: \
240 __pu_err = __user_bad(); \
241 break; \
242 } \
243 } else { \
244 __pu_err = -EFAULT; \
245 } \
246 __pu_err; \
247})
cca79120 248
ef4e277b
MS
249#define __put_user(x, ptr) \
250({ \
251 __typeof__(*(ptr)) volatile __gu_val = (x); \
252 long __gu_err = 0; \
253 switch (sizeof(__gu_val)) { \
254 case 1: \
255 __put_user_asm("sb", (ptr), __gu_val, __gu_err); \
256 break; \
257 case 2: \
258 __put_user_asm("sh", (ptr), __gu_val, __gu_err); \
259 break; \
260 case 4: \
261 __put_user_asm("sw", (ptr), __gu_val, __gu_err); \
262 break; \
263 case 8: \
264 __put_user_asm_8((ptr), __gu_val, __gu_err); \
265 break; \
266 default: \
267 /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \
268 } \
269 __gu_err; \
270})
2660663f 271
d491afb8
AV
272static inline unsigned long
273raw_copy_from_user(void *to, const void __user *from, unsigned long n)
4270690b 274{
d491afb8 275 return __copy_tofrom_user((__force void __user *)to, from, n);
4270690b
MS
276}
277
d491afb8
AV
278static inline unsigned long
279raw_copy_to_user(void __user *to, const void *from, unsigned long n)
cc5a428b 280{
d491afb8 281 return __copy_tofrom_user(to, (__force const void __user *)from, n);
89ae9753 282}
d491afb8
AV
283#define INLINE_COPY_FROM_USER
284#define INLINE_COPY_TO_USER
89ae9753
MS
285
286/*
287 * Copy a null terminated string from userspace.
288 */
b26b1816
AB
289__must_check long strncpy_from_user(char *dst, const char __user *src,
290 long count);
89ae9753
MS
291
292/*
293 * Return the size of a string (including the ending 0)
294 *
295 * Return 0 on exception, a value greater than N if too long
296 */
b26b1816 297__must_check long strnlen_user(const char __user *sstr, long len);
cc5a428b 298
2660663f 299#endif /* _ASM_MICROBLAZE_UACCESS_H */