#ifndef __M68K_UACCESS_H #define __M68K_UACCESS_H /* * User space memory access functions */ #include #include #include #include #define VERIFY_READ 0 #define VERIFY_WRITE 1 /* We let the MMU do all checking */ #define access_ok(type,addr,size) 1 /* * The exception table consists of pairs of addresses: the first is the * address of an instruction that is allowed to fault, and the second is * the address at which the program should continue. No registers are * modified, so it is entirely up to the continuation code to figure out * what to do. * * All the routines below use bits of fixup code that are out of line * with the main instruction path. This means when everything is well, * we don't even have to jump over them. Further, they do not intrude * on our cache or tlb entries. */ struct exception_table_entry { unsigned long insn, fixup; }; extern int __put_user_bad(void); extern int __get_user_bad(void); #define __put_user_asm(res, x, ptr, bwl, reg, err) \ asm volatile ("\n" \ "1: moves."#bwl" %2,%1\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .even\n" \ "10: moveq.l %3,%0\n" \ " jra 2b\n" \ " .previous\n" \ "\n" \ " .section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 1b,10b\n" \ " .long 2b,10b\n" \ " .previous" \ : "+d" (res), "=m" (*(ptr)) \ : #reg (x), "i" (err)) /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. */ #define __put_user(x, ptr) \ ({ \ typeof(*(ptr)) __pu_val = (x); \ int __pu_err = 0; \ __chk_user_ptr(ptr); \ switch (sizeof (*(ptr))) { \ case 1: \ __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \ break; \ case 2: \ __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \ break; \ case 4: \ __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \ break; \ case 8: \ { \ const void *__pu_ptr = (ptr); \ asm volatile ("\n" \ "1: moves.l %2,(%1)+\n" \ "2: moves.l %R2,(%1)\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .even\n" \ "10: movel %3,%0\n" \ " jra 3b\n" \ " .previous\n" \ "\n" \ " .section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 1b,10b\n" \ " .long 2b,10b\n" \ " .long 3b,10b\n" \ " .previous" \ : "+d" (__pu_err), "+a" (__pu_ptr) \ : "r" (__pu_val), "i" (-EFAULT) \ : "memory"); \ break; \ } \ default: \ __pu_err = __put_user_bad(); \ break; \ } \ __pu_err; \ }) #define put_user(x, ptr) __put_user(x, ptr) #define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \ type __gu_val; \ asm volatile ("\n" \ "1: moves."#bwl" %2,%1\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .even\n" \ "10: move.l %3,%0\n" \ " sub."#bwl" %1,%1\n" \ " jra 2b\n" \ " .previous\n" \ "\n" \ " .section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 1b,10b\n" \ " .previous" \ : "+d" (res), "=&" #reg (__gu_val) \ : "m" (*(ptr)), "i" (err)); \ (x) = (typeof(*(ptr)))(long)__gu_val; \ }) #define __get_user(x, ptr) \ ({ \ int __gu_err = 0; \ __chk_user_ptr(ptr); \ switch (sizeof(*(ptr))) { \ case 1: \ __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \ break; \ case 2: \ __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \ break; \ case 4: \ __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \ break; \ /* case 8: disabled because gcc-4.1 has a broken typeof \ { \ const void *__gu_ptr = (ptr); \ u64 __gu_val; \ asm volatile ("\n" \ "1: moves.l (%2)+,%1\n" \ "2: moves.l (%2),%R1\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .even\n" \ "10: move.l %3,%0\n" \ " sub.l %1,%1\n" \ " sub.l %R1,%R1\n" \ " jra 3b\n" \ " .previous\n" \ "\n" \ " .section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 1b,10b\n" \ " .long 2b,10b\n" \ " .previous" \ : "+d" (__gu_err), "=&r" (__gu_val), \ "+a" (__gu_ptr) \ : "i" (-EFAULT) \ : "memory"); \ (x) = (typeof(*(ptr)))__gu_val; \ break; \ } */ \ default: \ __gu_err = __get_user_bad(); \ break; \ } \ __gu_err; \ }) #define get_user(x, ptr) __get_user(x, ptr) unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n); unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n); static __always_inline unsigned long __constant_copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long res = 0, tmp; /* limit the inlined version to 3 moves */ if (n == 11 || n > 12) return __generic_copy_from_user(to, from, n); switch (n) { case 1: __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1); return res; case 2: __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2); return res; case 4: __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4); return res; } asm volatile ("\n" " .ifndef .Lfrom_user\n" " .set .Lfrom_user,1\n" " .macro copy_from_user to,from,tmp\n" " .if .Lcnt >= 4\n" "1: moves.l (\\from)+,\\tmp\n" " move.l \\tmp,(\\to)+\n" " .set .Lcnt,.Lcnt-4\n" " .elseif .Lcnt & 2\n" "1: moves.w (\\from)+,\\tmp\n" " move.w \\tmp,(\\to)+\n" " .set .Lcnt,.Lcnt-2\n" " .elseif .Lcnt & 1\n" "1: moves.b (\\from)+,\\tmp\n" " move.b \\tmp,(\\to)+\n" " .set .Lcnt,.Lcnt-1\n" " .else\n" " .exitm\n" " .endif\n" "\n" " .section __ex_table,\"a\"\n" " .align 4\n" " .long 1b,3f\n" " .previous\n" " .endm\n" " .endif\n" "\n" " .set .Lcnt,%c4\n" " copy_from_user %1,%2,%3\n" " copy_from_user %1,%2,%3\n" " copy_from_user %1,%2,%3\n" "2:\n" " .section .fixup,\"ax\"\n" " .even\n" "3: moveq.l %4,%0\n" " move.l %5,%1\n" " .rept %c4 / 4\n" " clr.l (%1)+\n" " .endr\n" " .if %c4 & 2\n" " clr.w (%1)+\n" " .endif\n" " .if %c4 & 1\n" " clr.b (%1)+\n" " .endif\n" " jra 2b\n" " .previous\n" : "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp) : "i" (n), "g" (to) : "memory"); return res; } static __always_inline unsigned long __constant_copy_to_user(void __user *to, const void *from, unsigned long n) { unsigned long res = 0, tmp; /* limit the inlined version to 3 moves */ if (n == 11 || n > 12) return __generic_copy_to_user(to, from, n); switch (n) { case 1: __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1); return res; case 2: __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2); return res; case 4: __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4); return res; } asm volatile ("\n" " .ifndef .Lto_user\n" " .set .Lto_user,1\n" " .macro copy_to_user to,from,tmp\n" " .if .Lcnt >= 4\n" " move.l (\\from)+,\\tmp\n" "11: moves.l \\tmp,(\\to)+\n" "12: .set .Lcnt,.Lcnt-4\n" " .elseif .Lcnt & 2\n" " move.w (\\from)+,\\tmp\n" "11: moves.w \\tmp,(\\to)+\n" "12: .set .Lcnt,.Lcnt-2\n" " .elseif .Lcnt & 1\n" " move.b (\\from)+,\\tmp\n" "11: moves.b \\tmp,(\\to)+\n" "12: .set .Lcnt,.Lcnt-1\n" " .else\n" " .exitm\n" " .endif\n" "\n" " .section __ex_table,\"a\"\n" " .align 4\n" " .long 11b,3f\n" " .long 12b,3f\n" " .previous\n" " .endm\n" " .endif\n" "\n" " .set .Lcnt,%c4\n" " copy_to_user %1,%2,%3\n" " copy_to_user %1,%2,%3\n" " copy_to_user %1,%2,%3\n" "2:\n" " .section .fixup,\"ax\"\n" " .even\n" "3: moveq.l %4,%0\n" " jra 2b\n" " .previous\n" : "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp) : "i" (n) : "memory"); return res; } #define __copy_from_user(to, from, n) \ (__builtin_constant_p(n) ? \ __constant_copy_from_user(to, from, n) : \ __generic_copy_from_user(to, from, n)) #define __copy_to_user(to, from, n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user(to, from, n) : \ __generic_copy_to_user(to, from, n)) #define __copy_to_user_inatomic __copy_to_user #define __copy_from_user_inatomic __copy_from_user #define copy_from_user(to, from, n) __copy_from_user(to, from, n) #define copy_to_user(to, from, n) __copy_to_user(to, from, n) long strncpy_from_user(char *dst, const char __user *src, long count); long strnlen_user(const char __user *src, long n); unsigned long clear_user(void __user *to, unsigned long n); #define strlen_user(str) strnlen_user(str, 32767) #endif /* _M68K_UACCESS_H */