uaccess.h (12221B)
1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef __M68K_UACCESS_H 3#define __M68K_UACCESS_H 4 5#ifdef CONFIG_MMU 6 7/* 8 * User space memory access functions 9 */ 10#include <linux/compiler.h> 11#include <linux/types.h> 12#include <asm/extable.h> 13#include <asm-generic/access_ok.h> 14 15/* 16 * Not all varients of the 68k family support the notion of address spaces. 17 * The traditional 680x0 parts do, and they use the sfc/dfc registers and 18 * the "moves" instruction to access user space from kernel space. Other 19 * family members like ColdFire don't support this, and only have a single 20 * address space, and use the usual "move" instruction for user space access. 21 * 22 * Outside of this difference the user space access functions are the same. 23 * So lets keep the code simple and just define in what we need to use. 24 */ 25#ifdef CONFIG_CPU_HAS_ADDRESS_SPACES 26#define MOVES "moves" 27#else 28#define MOVES "move" 29#endif 30 31#define __put_user_asm(inst, res, x, ptr, bwl, reg, err) \ 32asm volatile ("\n" \ 33 "1: "inst"."#bwl" %2,%1\n" \ 34 "2:\n" \ 35 " .section .fixup,\"ax\"\n" \ 36 " .even\n" \ 37 "10: moveq.l %3,%0\n" \ 38 " jra 2b\n" \ 39 " .previous\n" \ 40 "\n" \ 41 " .section __ex_table,\"a\"\n" \ 42 " .align 4\n" \ 43 " .long 1b,10b\n" \ 44 " .long 2b,10b\n" \ 45 " .previous" \ 46 : "+d" (res), "=m" (*(ptr)) \ 47 : #reg (x), "i" (err)) 48 49#define __put_user_asm8(inst, res, x, ptr) \ 50do { \ 51 const void *__pu_ptr = (const void __force *)(ptr); \ 52 \ 53 asm volatile ("\n" \ 54 "1: "inst".l %2,(%1)+\n" \ 55 "2: "inst".l %R2,(%1)\n" \ 56 "3:\n" \ 57 " .section .fixup,\"ax\"\n" \ 58 " .even\n" \ 59 "10: movel %3,%0\n" \ 60 " jra 3b\n" \ 61 " .previous\n" \ 62 "\n" \ 63 " .section __ex_table,\"a\"\n" \ 64 " .align 4\n" \ 65 " .long 1b,10b\n" \ 66 " .long 2b,10b\n" \ 67 " .long 3b,10b\n" \ 68 " .previous" \ 69 : "+d" (res), "+a" (__pu_ptr) \ 70 : "r" (x), "i" (-EFAULT) \ 71 : "memory"); \ 72} while (0) 73 74/* 75 * These are the main single-value transfer routines. They automatically 76 * use the right size if we just have the right pointer type. 77 */ 78 79#define __put_user(x, ptr) \ 80({ \ 81 typeof(*(ptr)) __pu_val = (x); \ 82 int __pu_err = 0; \ 83 __chk_user_ptr(ptr); \ 84 switch (sizeof (*(ptr))) { \ 85 case 1: \ 86 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, b, d, -EFAULT); \ 87 break; \ 88 case 2: \ 89 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, w, r, -EFAULT); \ 90 break; \ 91 case 4: \ 92 __put_user_asm(MOVES, __pu_err, __pu_val, ptr, l, r, -EFAULT); \ 93 break; \ 94 case 8: \ 95 __put_user_asm8(MOVES, __pu_err, __pu_val, ptr); \ 96 break; \ 97 default: \ 98 BUILD_BUG(); \ 99 } \ 100 __pu_err; \ 101}) 102#define put_user(x, ptr) __put_user(x, ptr) 103 104 105#define __get_user_asm(inst, res, x, ptr, type, bwl, reg, err) ({ \ 106 type __gu_val; \ 107 asm volatile ("\n" \ 108 "1: "inst"."#bwl" %2,%1\n" \ 109 "2:\n" \ 110 " .section .fixup,\"ax\"\n" \ 111 " .even\n" \ 112 "10: move.l %3,%0\n" \ 113 " sub.l %1,%1\n" \ 114 " jra 2b\n" \ 115 " .previous\n" \ 116 "\n" \ 117 " .section __ex_table,\"a\"\n" \ 118 " .align 4\n" \ 119 " .long 1b,10b\n" \ 120 " .previous" \ 121 : "+d" (res), "=&" #reg (__gu_val) \ 122 : "m" (*(ptr)), "i" (err)); \ 123 (x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val; \ 124}) 125 126#define __get_user_asm8(inst, res, x, ptr) \ 127do { \ 128 const void *__gu_ptr = (const void __force *)(ptr); \ 129 union { \ 130 u64 l; \ 131 __typeof__(*(ptr)) t; \ 132 } __gu_val; \ 133 \ 134 asm volatile ("\n" \ 135 "1: "inst".l (%2)+,%1\n" \ 136 "2: "inst".l (%2),%R1\n" \ 137 "3:\n" \ 138 " .section .fixup,\"ax\"\n" \ 139 " .even\n" \ 140 "10: move.l %3,%0\n" \ 141 " sub.l %1,%1\n" \ 142 " sub.l %R1,%R1\n" \ 143 " jra 3b\n" \ 144 " .previous\n" \ 145 "\n" \ 146 " .section __ex_table,\"a\"\n" \ 147 " .align 4\n" \ 148 " .long 1b,10b\n" \ 149 " .long 2b,10b\n" \ 150 " .previous" \ 151 : "+d" (res), "=&r" (__gu_val.l), \ 152 "+a" (__gu_ptr) \ 153 : "i" (-EFAULT) \ 154 : "memory"); \ 155 (x) = __gu_val.t; \ 156} while (0) 157 158#define __get_user(x, ptr) \ 159({ \ 160 int __gu_err = 0; \ 161 __chk_user_ptr(ptr); \ 162 switch (sizeof(*(ptr))) { \ 163 case 1: \ 164 __get_user_asm(MOVES, __gu_err, x, ptr, u8, b, d, -EFAULT); \ 165 break; \ 166 case 2: \ 167 __get_user_asm(MOVES, __gu_err, x, ptr, u16, w, r, -EFAULT); \ 168 break; \ 169 case 4: \ 170 __get_user_asm(MOVES, __gu_err, x, ptr, u32, l, r, -EFAULT); \ 171 break; \ 172 case 8: \ 173 __get_user_asm8(MOVES, __gu_err, x, ptr); \ 174 break; \ 175 default: \ 176 BUILD_BUG(); \ 177 } \ 178 __gu_err; \ 179}) 180#define get_user(x, ptr) __get_user(x, ptr) 181 182unsigned 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); 184 185#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)\ 191 asm volatile ("\n" \ 192 "1: "MOVES"."#s1" (%2)+,%3\n" \ 193 " move."#s1" %3,(%1)+\n" \ 194 " .ifnc \""#s2"\",\"\"\n" \ 195 "2: "MOVES"."#s2" (%2)+,%3\n" \ 196 " move."#s2" %3,(%1)+\n" \ 197 " .ifnc \""#s3"\",\"\"\n" \ 198 "3: "MOVES"."#s3" (%2)+,%3\n" \ 199 " move."#s3" %3,(%1)+\n" \ 200 " .endif\n" \ 201 " .endif\n" \ 202 "4:\n" \ 203 " .section __ex_table,\"a\"\n" \ 204 " .align 4\n" \ 205 " .long 1b,10f\n" \ 206 " .ifnc \""#s2"\",\"\"\n" \ 207 " .long 2b,20f\n" \ 208 " .ifnc \""#s3"\",\"\"\n" \ 209 " .long 3b,30f\n" \ 210 " .endif\n" \ 211 " .endif\n" \ 212 " .previous\n" \ 213 "\n" \ 214 " .section .fixup,\"ax\"\n" \ 215 " .even\n" \ 216 "10: addq.l #"#n1",%0\n" \ 217 " .ifnc \""#s2"\",\"\"\n" \ 218 "20: addq.l #"#n2",%0\n" \ 219 " .ifnc \""#s3"\",\"\"\n" \ 220 "30: addq.l #"#n3",%0\n" \ 221 " .endif\n" \ 222 " .endif\n" \ 223 " jra 4b\n" \ 224 " .previous\n" \ 225 : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \ 226 : : "memory") 227 228#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 234static __always_inline unsigned long 235__constant_copy_from_user(void *to, const void __user *from, unsigned long n) 236{ 237 unsigned long res = 0, tmp; 238 239 switch (n) { 240 case 1: 241 __constant_copy_from_user_asm(res, to, from, tmp, 1, 0, 0); 242 break; 243 case 2: 244 __constant_copy_from_user_asm(res, to, from, tmp, 2, 0, 0); 245 break; 246 case 3: 247 __constant_copy_from_user_asm(res, to, from, tmp, 2, 1, 0); 248 break; 249 case 4: 250 __constant_copy_from_user_asm(res, to, from, tmp, 4, 0, 0); 251 break; 252 case 5: 253 __constant_copy_from_user_asm(res, to, from, tmp, 4, 1, 0); 254 break; 255 case 6: 256 __constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 0); 257 break; 258 case 7: 259 __constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 1); 260 break; 261 case 8: 262 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 0); 263 break; 264 case 9: 265 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 1); 266 break; 267 case 10: 268 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 2); 269 break; 270 case 12: 271 __constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 4); 272 break; 273 default: 274 /* we limit the inlined version to 3 moves */ 275 return __generic_copy_from_user(to, from, n); 276 } 277 278 return res; 279} 280 281#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \ 282 asm volatile ("\n" \ 283 " move."#s1" (%2)+,%3\n" \ 284 "11: "MOVES"."#s1" %3,(%1)+\n" \ 285 "12: move."#s2" (%2)+,%3\n" \ 286 "21: "MOVES"."#s2" %3,(%1)+\n" \ 287 "22:\n" \ 288 " .ifnc \""#s3"\",\"\"\n" \ 289 " move."#s3" (%2)+,%3\n" \ 290 "31: "MOVES"."#s3" %3,(%1)+\n" \ 291 "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 315static __always_inline unsigned long 316__constant_copy_to_user(void __user *to, const void *from, unsigned long n) 317{ 318 unsigned long res = 0, tmp; 319 320 switch (n) { 321 case 1: 322 __put_user_asm(MOVES, res, *(u8 *)from, (u8 __user *)to, 323 b, d, 1); 324 break; 325 case 2: 326 __put_user_asm(MOVES, res, *(u16 *)from, (u16 __user *)to, 327 w, r, 2); 328 break; 329 case 3: 330 __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,); 331 break; 332 case 4: 333 __put_user_asm(MOVES, res, *(u32 *)from, (u32 __user *)to, 334 l, r, 4); 335 break; 336 case 5: 337 __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,); 338 break; 339 case 6: 340 __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,); 341 break; 342 case 7: 343 __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b); 344 break; 345 case 8: 346 __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,); 347 break; 348 case 9: 349 __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b); 350 break; 351 case 10: 352 __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w); 353 break; 354 case 12: 355 __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l); 356 break; 357 default: 358 /* limit the inlined version to 3 moves */ 359 return __generic_copy_to_user(to, from, n); 360 } 361 362 return res; 363} 364 365static inline unsigned long 366raw_copy_from_user(void *to, const void __user *from, unsigned long n) 367{ 368 if (__builtin_constant_p(n)) 369 return __constant_copy_from_user(to, from, n); 370 return __generic_copy_from_user(to, from, n); 371} 372 373static inline unsigned long 374raw_copy_to_user(void __user *to, const void *from, unsigned long n) 375{ 376 if (__builtin_constant_p(n)) 377 return __constant_copy_to_user(to, from, n); 378 return __generic_copy_to_user(to, from, n); 379} 380#define INLINE_COPY_FROM_USER 381#define INLINE_COPY_TO_USER 382 383#define __get_kernel_nofault(dst, src, type, err_label) \ 384do { \ 385 type *__gk_dst = (type *)(dst); \ 386 type *__gk_src = (type *)(src); \ 387 int __gk_err = 0; \ 388 \ 389 switch (sizeof(type)) { \ 390 case 1: \ 391 __get_user_asm("move", __gk_err, *__gk_dst, __gk_src, \ 392 u8, b, d, -EFAULT); \ 393 break; \ 394 case 2: \ 395 __get_user_asm("move", __gk_err, *__gk_dst, __gk_src, \ 396 u16, w, r, -EFAULT); \ 397 break; \ 398 case 4: \ 399 __get_user_asm("move", __gk_err, *__gk_dst, __gk_src, \ 400 u32, l, r, -EFAULT); \ 401 break; \ 402 case 8: \ 403 __get_user_asm8("move", __gk_err, *__gk_dst, __gk_src); \ 404 break; \ 405 default: \ 406 BUILD_BUG(); \ 407 } \ 408 if (unlikely(__gk_err)) \ 409 goto err_label; \ 410} while (0) 411 412#define __put_kernel_nofault(dst, src, type, err_label) \ 413do { \ 414 type __pk_src = *(type *)(src); \ 415 type *__pk_dst = (type *)(dst); \ 416 int __pk_err = 0; \ 417 \ 418 switch (sizeof(type)) { \ 419 case 1: \ 420 __put_user_asm("move", __pk_err, __pk_src, __pk_dst, \ 421 b, d, -EFAULT); \ 422 break; \ 423 case 2: \ 424 __put_user_asm("move", __pk_err, __pk_src, __pk_dst, \ 425 w, r, -EFAULT); \ 426 break; \ 427 case 4: \ 428 __put_user_asm("move", __pk_err, __pk_src, __pk_dst, \ 429 l, r, -EFAULT); \ 430 break; \ 431 case 8: \ 432 __put_user_asm8("move", __pk_err, __pk_src, __pk_dst); \ 433 break; \ 434 default: \ 435 BUILD_BUG(); \ 436 } \ 437 if (unlikely(__pk_err)) \ 438 goto err_label; \ 439} while (0) 440 441extern long strncpy_from_user(char *dst, const char __user *src, long count); 442extern __must_check long strnlen_user(const char __user *str, long n); 443 444unsigned long __clear_user(void __user *to, unsigned long n); 445 446#define clear_user __clear_user 447 448#else /* !CONFIG_MMU */ 449#include <asm-generic/uaccess.h> 450#endif 451 452#endif /* _M68K_UACCESS_H */