blob: c4cb889660aa0c3582d59f0f40428fec718d92a3 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#ifndef __M68K_UACCESS_H
3#define __M68K_UACCESS_H
4
5/*
6 * User space memory access functions
7 */
Roman Zippeld94af932006-06-23 02:05:00 -07008#include <linux/compiler.h>
Roman Zippeld94af932006-06-23 02:05:00 -07009#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <asm/segment.h>
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012/* We let the MMU do all checking */
Geert Uytterhoeven70f9cac2008-05-18 20:47:07 +020013static inline int access_ok(int type, const void __user *addr,
14 unsigned long size)
15{
16 return 1;
17}
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/*
Greg Ungerere08d7032011-10-14 14:43:30 +100020 * Not all varients of the 68k family support the notion of address spaces.
21 * The traditional 680x0 parts do, and they use the sfc/dfc registers and
22 * the "moves" instruction to access user space from kernel space. Other
23 * family members like ColdFire don't support this, and only have a single
24 * address space, and use the usual "move" instruction for user space access.
25 *
26 * Outside of this difference the user space access functions are the same.
27 * So lets keep the code simple and just define in what we need to use.
28 */
29#ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
30#define MOVES "moves"
31#else
32#define MOVES "move"
33#endif
34
Roman Zippeld94af932006-06-23 02:05:00 -070035extern int __put_user_bad(void);
36extern int __get_user_bad(void);
37
38#define __put_user_asm(res, x, ptr, bwl, reg, err) \
39asm volatile ("\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +100040 "1: "MOVES"."#bwl" %2,%1\n" \
Roman Zippeld94af932006-06-23 02:05:00 -070041 "2:\n" \
42 " .section .fixup,\"ax\"\n" \
43 " .even\n" \
44 "10: moveq.l %3,%0\n" \
45 " jra 2b\n" \
46 " .previous\n" \
47 "\n" \
48 " .section __ex_table,\"a\"\n" \
49 " .align 4\n" \
50 " .long 1b,10b\n" \
51 " .long 2b,10b\n" \
52 " .previous" \
53 : "+d" (res), "=m" (*(ptr)) \
54 : #reg (x), "i" (err))
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56/*
57 * These are the main single-value transfer routines. They automatically
58 * use the right size if we just have the right pointer type.
59 */
60
Roman Zippeld94af932006-06-23 02:05:00 -070061#define __put_user(x, ptr) \
62({ \
63 typeof(*(ptr)) __pu_val = (x); \
64 int __pu_err = 0; \
65 __chk_user_ptr(ptr); \
66 switch (sizeof (*(ptr))) { \
67 case 1: \
68 __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
69 break; \
70 case 2: \
Geert Uytterhoeven631d8b62013-06-09 20:12:42 +020071 __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \
Roman Zippeld94af932006-06-23 02:05:00 -070072 break; \
73 case 4: \
74 __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
75 break; \
76 case 8: \
77 { \
Al Virob9710182006-10-11 17:27:57 +010078 const void __user *__pu_ptr = (ptr); \
Roman Zippeld94af932006-06-23 02:05:00 -070079 asm volatile ("\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +100080 "1: "MOVES".l %2,(%1)+\n" \
81 "2: "MOVES".l %R2,(%1)\n" \
Roman Zippeld94af932006-06-23 02:05:00 -070082 "3:\n" \
83 " .section .fixup,\"ax\"\n" \
84 " .even\n" \
85 "10: movel %3,%0\n" \
86 " jra 3b\n" \
87 " .previous\n" \
88 "\n" \
89 " .section __ex_table,\"a\"\n" \
90 " .align 4\n" \
91 " .long 1b,10b\n" \
92 " .long 2b,10b\n" \
93 " .long 3b,10b\n" \
94 " .previous" \
95 : "+d" (__pu_err), "+a" (__pu_ptr) \
96 : "r" (__pu_val), "i" (-EFAULT) \
97 : "memory"); \
98 break; \
99 } \
100 default: \
101 __pu_err = __put_user_bad(); \
102 break; \
103 } \
104 __pu_err; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105})
Roman Zippeld94af932006-06-23 02:05:00 -0700106#define put_user(x, ptr) __put_user(x, ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Michael S. Tsirkin09a2f7c2014-12-12 01:56:04 +0200109#define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \
110 type __gu_val; \
111 asm volatile ("\n" \
112 "1: "MOVES"."#bwl" %2,%1\n" \
113 "2:\n" \
114 " .section .fixup,\"ax\"\n" \
115 " .even\n" \
116 "10: move.l %3,%0\n" \
117 " sub.l %1,%1\n" \
118 " jra 2b\n" \
119 " .previous\n" \
120 "\n" \
121 " .section __ex_table,\"a\"\n" \
122 " .align 4\n" \
123 " .long 1b,10b\n" \
124 " .previous" \
125 : "+d" (res), "=&" #reg (__gu_val) \
126 : "m" (*(ptr)), "i" (err)); \
127 (x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128})
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Roman Zippeld94af932006-06-23 02:05:00 -0700130#define __get_user(x, ptr) \
131({ \
132 int __gu_err = 0; \
133 __chk_user_ptr(ptr); \
134 switch (sizeof(*(ptr))) { \
135 case 1: \
136 __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \
137 break; \
138 case 2: \
Geert Uytterhoeven631d8b62013-06-09 20:12:42 +0200139 __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT); \
Roman Zippeld94af932006-06-23 02:05:00 -0700140 break; \
141 case 4: \
142 __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
143 break; \
Geert Uytterhoeven71243302018-05-14 15:33:14 +0200144 case 8: { \
145 const void *__gu_ptr = (ptr); \
146 union { \
147 u64 l; \
148 __typeof__(*(ptr)) t; \
149 } __gu_val; \
Roman Zippeld94af932006-06-23 02:05:00 -0700150 asm volatile ("\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000151 "1: "MOVES".l (%2)+,%1\n" \
152 "2: "MOVES".l (%2),%R1\n" \
Roman Zippeld94af932006-06-23 02:05:00 -0700153 "3:\n" \
154 " .section .fixup,\"ax\"\n" \
155 " .even\n" \
156 "10: move.l %3,%0\n" \
157 " sub.l %1,%1\n" \
158 " sub.l %R1,%R1\n" \
159 " jra 3b\n" \
160 " .previous\n" \
161 "\n" \
162 " .section __ex_table,\"a\"\n" \
163 " .align 4\n" \
164 " .long 1b,10b\n" \
165 " .long 2b,10b\n" \
166 " .previous" \
Geert Uytterhoeven71243302018-05-14 15:33:14 +0200167 : "+d" (__gu_err), "=&r" (__gu_val.l), \
Roman Zippeld94af932006-06-23 02:05:00 -0700168 "+a" (__gu_ptr) \
169 : "i" (-EFAULT) \
170 : "memory"); \
Geert Uytterhoeven71243302018-05-14 15:33:14 +0200171 (x) = __gu_val.t; \
Roman Zippeld94af932006-06-23 02:05:00 -0700172 break; \
Geert Uytterhoeven71243302018-05-14 15:33:14 +0200173 } \
Roman Zippeld94af932006-06-23 02:05:00 -0700174 default: \
175 __gu_err = __get_user_bad(); \
176 break; \
177 } \
178 __gu_err; \
179})
180#define get_user(x, ptr) __get_user(x, ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Roman Zippeld94af932006-06-23 02:05:00 -0700182unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
183unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Al Viro7cefa5a2017-03-20 00:55:24 -0400185#define __suffix0
186#define __suffix1 b
187#define __suffix2 w
188#define __suffix4 l
189
190#define ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
Roman Zippel53617822006-06-25 05:46:53 -0700191 asm volatile ("\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000192 "1: "MOVES"."#s1" (%2)+,%3\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700193 " move."#s1" %3,(%1)+\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400194 " .ifnc \""#s2"\",\"\"\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000195 "2: "MOVES"."#s2" (%2)+,%3\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700196 " move."#s2" %3,(%1)+\n" \
197 " .ifnc \""#s3"\",\"\"\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000198 "3: "MOVES"."#s3" (%2)+,%3\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700199 " move."#s3" %3,(%1)+\n" \
200 " .endif\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400201 " .endif\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700202 "4:\n" \
203 " .section __ex_table,\"a\"\n" \
204 " .align 4\n" \
205 " .long 1b,10f\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400206 " .ifnc \""#s2"\",\"\"\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700207 " .long 2b,20f\n" \
208 " .ifnc \""#s3"\",\"\"\n" \
209 " .long 3b,30f\n" \
210 " .endif\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400211 " .endif\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700212 " .previous\n" \
213 "\n" \
214 " .section .fixup,\"ax\"\n" \
215 " .even\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400216 "10: addq.l #"#n1",%0\n" \
217 " .ifnc \""#s2"\",\"\"\n" \
218 "20: addq.l #"#n2",%0\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700219 " .ifnc \""#s3"\",\"\"\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400220 "30: addq.l #"#n3",%0\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700221 " .endif\n" \
Al Viro7cefa5a2017-03-20 00:55:24 -0400222 " .endif\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700223 " jra 4b\n" \
224 " .previous\n" \
225 : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
226 : : "memory")
227
Al Viro7cefa5a2017-03-20 00:55:24 -0400228#define ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
229 ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)
230#define __constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3) \
231 ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, \
232 __suffix##n1, __suffix##n2, __suffix##n3)
233
Roman Zippeld94af932006-06-23 02:05:00 -0700234static __always_inline unsigned long
Al Viro11c40f82006-01-12 01:06:24 -0800235__constant_copy_from_user(void *to, const void __user *from, unsigned long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Roman Zippeld94af932006-06-23 02:05:00 -0700237 unsigned long res = 0, tmp;
238
Roman Zippeld94af932006-06-23 02:05:00 -0700239 switch (n) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 case 1:
Al Viro7cefa5a2017-03-20 00:55:24 -0400241 __constant_copy_from_user_asm(res, to, from, tmp, 1, 0, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700242 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 case 2:
Al Viro7cefa5a2017-03-20 00:55:24 -0400244 __constant_copy_from_user_asm(res, to, from, tmp, 2, 0, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700245 break;
246 case 3:
Al Viro7cefa5a2017-03-20 00:55:24 -0400247 __constant_copy_from_user_asm(res, to, from, tmp, 2, 1, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700248 break;
Roman Zippeld94af932006-06-23 02:05:00 -0700249 case 4:
Al Viro7cefa5a2017-03-20 00:55:24 -0400250 __constant_copy_from_user_asm(res, to, from, tmp, 4, 0, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700251 break;
252 case 5:
Al Viro7cefa5a2017-03-20 00:55:24 -0400253 __constant_copy_from_user_asm(res, to, from, tmp, 4, 1, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700254 break;
255 case 6:
Al Viro7cefa5a2017-03-20 00:55:24 -0400256 __constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700257 break;
258 case 7:
Al Viro7cefa5a2017-03-20 00:55:24 -0400259 __constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 1);
Roman Zippel53617822006-06-25 05:46:53 -0700260 break;
261 case 8:
Al Viro7cefa5a2017-03-20 00:55:24 -0400262 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 0);
Roman Zippel53617822006-06-25 05:46:53 -0700263 break;
264 case 9:
Al Viro7cefa5a2017-03-20 00:55:24 -0400265 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 1);
Roman Zippel53617822006-06-25 05:46:53 -0700266 break;
267 case 10:
Al Viro7cefa5a2017-03-20 00:55:24 -0400268 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 2);
Roman Zippel53617822006-06-25 05:46:53 -0700269 break;
270 case 12:
Al Viro7cefa5a2017-03-20 00:55:24 -0400271 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 4);
Roman Zippel53617822006-06-25 05:46:53 -0700272 break;
273 default:
274 /* we limit the inlined version to 3 moves */
275 return __generic_copy_from_user(to, from, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 }
Roman Zippeld94af932006-06-23 02:05:00 -0700277
Roman Zippeld94af932006-06-23 02:05:00 -0700278 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
Roman Zippel53617822006-06-25 05:46:53 -0700281#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
282 asm volatile ("\n" \
283 " move."#s1" (%2)+,%3\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000284 "11: "MOVES"."#s1" %3,(%1)+\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700285 "12: move."#s2" (%2)+,%3\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000286 "21: "MOVES"."#s2" %3,(%1)+\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700287 "22:\n" \
288 " .ifnc \""#s3"\",\"\"\n" \
289 " move."#s3" (%2)+,%3\n" \
Greg Ungerere08d7032011-10-14 14:43:30 +1000290 "31: "MOVES"."#s3" %3,(%1)+\n" \
Roman Zippel53617822006-06-25 05:46:53 -0700291 "32:\n" \
292 " .endif\n" \
293 "4:\n" \
294 "\n" \
295 " .section __ex_table,\"a\"\n" \
296 " .align 4\n" \
297 " .long 11b,5f\n" \
298 " .long 12b,5f\n" \
299 " .long 21b,5f\n" \
300 " .long 22b,5f\n" \
301 " .ifnc \""#s3"\",\"\"\n" \
302 " .long 31b,5f\n" \
303 " .long 32b,5f\n" \
304 " .endif\n" \
305 " .previous\n" \
306 "\n" \
307 " .section .fixup,\"ax\"\n" \
308 " .even\n" \
309 "5: moveq.l #"#n",%0\n" \
310 " jra 4b\n" \
311 " .previous\n" \
312 : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
313 : : "memory")
314
Roman Zippeld94af932006-06-23 02:05:00 -0700315static __always_inline unsigned long
Al Viro11c40f82006-01-12 01:06:24 -0800316__constant_copy_to_user(void __user *to, const void *from, unsigned long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Roman Zippeld94af932006-06-23 02:05:00 -0700318 unsigned long res = 0, tmp;
319
Roman Zippeld94af932006-06-23 02:05:00 -0700320 switch (n) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 case 1:
Al Virob9710182006-10-11 17:27:57 +0100322 __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
Roman Zippel53617822006-06-25 05:46:53 -0700323 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 case 2:
Geert Uytterhoeven631d8b62013-06-09 20:12:42 +0200325 __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
Roman Zippel53617822006-06-25 05:46:53 -0700326 break;
327 case 3:
328 __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
329 break;
Roman Zippeld94af932006-06-23 02:05:00 -0700330 case 4:
Al Virob9710182006-10-11 17:27:57 +0100331 __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
Roman Zippel53617822006-06-25 05:46:53 -0700332 break;
333 case 5:
334 __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
335 break;
336 case 6:
337 __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
338 break;
339 case 7:
340 __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
341 break;
342 case 8:
343 __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
344 break;
345 case 9:
346 __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
347 break;
348 case 10:
349 __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
350 break;
351 case 12:
352 __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
353 break;
354 default:
355 /* limit the inlined version to 3 moves */
356 return __generic_copy_to_user(to, from, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
Roman Zippeld94af932006-06-23 02:05:00 -0700358
Roman Zippeld94af932006-06-23 02:05:00 -0700359 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
Al Viro29be02e2017-03-21 08:50:56 -0400362static inline unsigned long
363raw_copy_from_user(void *to, const void __user *from, unsigned long n)
364{
365 if (__builtin_constant_p(n))
366 return __constant_copy_from_user(to, from, n);
367 return __generic_copy_from_user(to, from, n);
368}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Al Viro7cefa5a2017-03-20 00:55:24 -0400370static inline unsigned long
Al Viro29be02e2017-03-21 08:50:56 -0400371raw_copy_to_user(void __user *to, const void *from, unsigned long n)
Al Viro7cefa5a2017-03-20 00:55:24 -0400372{
Al Viro29be02e2017-03-21 08:50:56 -0400373 if (__builtin_constant_p(n))
374 return __constant_copy_to_user(to, from, n);
375 return __generic_copy_to_user(to, from, n);
Al Viro7cefa5a2017-03-20 00:55:24 -0400376}
Al Viro29be02e2017-03-21 08:50:56 -0400377#define INLINE_COPY_FROM_USER
378#define INLINE_COPY_TO_USER
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Geert Uytterhoevend8ce7262012-05-29 23:30:08 +0200380#define user_addr_max() \
Al Virodb68ce12017-03-20 21:08:07 -0400381 (uaccess_kernel() ? ~0UL : TASK_SIZE)
Geert Uytterhoevend8ce7262012-05-29 23:30:08 +0200382
383extern long strncpy_from_user(char *dst, const char __user *src, long count);
Geert Uytterhoevend8ce7262012-05-29 23:30:08 +0200384extern __must_check long strnlen_user(const char __user *str, long n);
385
Geert Uytterhoeven3c46bdc2007-05-15 01:41:29 -0700386unsigned long __clear_user(void __user *to, unsigned long n);
387
388#define clear_user __clear_user
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390#endif /* _M68K_UACCESS_H */