mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
m68knommu: switch to using asm-generic/uaccess.h
Switch to using the asm-generic/uaccess functions for non-MMU builds. Remove all the m68knommu local specific uaccess defines and macros. There is nothing so special about the m68knommu targets that they cannot use all of the asm-generic uaccess support. Using the asm-generic uaccess definitions also resolves some of the existing problems with missing __user annotations in the m68knommu specific functions. The elimination of all of the contents of uaccess_no.h means we can fold the uaccess_mm.h back into uaccess.h - and just have the single file now. The resulting generated code ends up being slightly smaller (by a few hundred bytes) due to the compilers ability to better optimize load and stores without forcing its hand with asm statements. Specifically trivial cases like this contrived example: get_user(x, ptr); x++; put_user(x, ptr); end up now being optimized to a single instruction on m68k. More generally the compiler can avoid using a temporary register in many cases as well. Reported-by: kernel test robot <lkp@intel.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Greg Ungerer <gerg@linux-m68k.org>
This commit is contained in:
parent
549738f15d
commit
a27bc11f4b
@ -24,6 +24,7 @@ config M68K
|
||||
select GENERIC_IOMAP
|
||||
select GENERIC_STRNCPY_FROM_USER if MMU
|
||||
select GENERIC_STRNLEN_USER if MMU
|
||||
select UACCESS_MEMCPY if !MMU
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
|
@ -1,7 +1,397 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifdef __uClinux__
|
||||
#include <asm/uaccess_no.h>
|
||||
#else
|
||||
#include <asm/uaccess_mm.h>
|
||||
#endif
|
||||
#ifndef __M68K_UACCESS_H
|
||||
#define __M68K_UACCESS_H
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
/*
|
||||
* User space memory access functions
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/extable.h>
|
||||
|
||||
/* We let the MMU do all checking */
|
||||
static inline int access_ok(const void __user *addr,
|
||||
unsigned long size)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all varients of the 68k family support the notion of address spaces.
|
||||
* The traditional 680x0 parts do, and they use the sfc/dfc registers and
|
||||
* the "moves" instruction to access user space from kernel space. Other
|
||||
* family members like ColdFire don't support this, and only have a single
|
||||
* address space, and use the usual "move" instruction for user space access.
|
||||
*
|
||||
* Outside of this difference the user space access functions are the same.
|
||||
* So lets keep the code simple and just define in what we need to use.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
|
||||
#define MOVES "moves"
|
||||
#else
|
||||
#define MOVES "move"
|
||||
#endif
|
||||
|
||||
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, r, -EFAULT); \
|
||||
break; \
|
||||
case 4: \
|
||||
__put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
|
||||
break; \
|
||||
case 8: \
|
||||
{ \
|
||||
const void __user *__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.l %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) = (__force typeof(*(ptr)))(__force unsigned 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, r, -EFAULT); \
|
||||
break; \
|
||||
case 4: \
|
||||
__get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
|
||||
break; \
|
||||
case 8: { \
|
||||
const void __user *__gu_ptr = (ptr); \
|
||||
union { \
|
||||
u64 l; \
|
||||
__typeof__(*(ptr)) t; \
|
||||
} __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.l), \
|
||||
"+a" (__gu_ptr) \
|
||||
: "i" (-EFAULT) \
|
||||
: "memory"); \
|
||||
(x) = __gu_val.t; \
|
||||
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);
|
||||
|
||||
#define __suffix0
|
||||
#define __suffix1 b
|
||||
#define __suffix2 w
|
||||
#define __suffix4 l
|
||||
|
||||
#define ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
|
||||
asm volatile ("\n" \
|
||||
"1: "MOVES"."#s1" (%2)+,%3\n" \
|
||||
" move."#s1" %3,(%1)+\n" \
|
||||
" .ifnc \""#s2"\",\"\"\n" \
|
||||
"2: "MOVES"."#s2" (%2)+,%3\n" \
|
||||
" move."#s2" %3,(%1)+\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
"3: "MOVES"."#s3" (%2)+,%3\n" \
|
||||
" move."#s3" %3,(%1)+\n" \
|
||||
" .endif\n" \
|
||||
" .endif\n" \
|
||||
"4:\n" \
|
||||
" .section __ex_table,\"a\"\n" \
|
||||
" .align 4\n" \
|
||||
" .long 1b,10f\n" \
|
||||
" .ifnc \""#s2"\",\"\"\n" \
|
||||
" .long 2b,20f\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
" .long 3b,30f\n" \
|
||||
" .endif\n" \
|
||||
" .endif\n" \
|
||||
" .previous\n" \
|
||||
"\n" \
|
||||
" .section .fixup,\"ax\"\n" \
|
||||
" .even\n" \
|
||||
"10: addq.l #"#n1",%0\n" \
|
||||
" .ifnc \""#s2"\",\"\"\n" \
|
||||
"20: addq.l #"#n2",%0\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
"30: addq.l #"#n3",%0\n" \
|
||||
" .endif\n" \
|
||||
" .endif\n" \
|
||||
" jra 4b\n" \
|
||||
" .previous\n" \
|
||||
: "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
|
||||
: : "memory")
|
||||
|
||||
#define ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
|
||||
____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)
|
||||
#define __constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3) \
|
||||
___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, \
|
||||
__suffix##n1, __suffix##n2, __suffix##n3)
|
||||
|
||||
static __always_inline unsigned long
|
||||
__constant_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
unsigned long res = 0, tmp;
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 1, 0, 0);
|
||||
break;
|
||||
case 2:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 2, 0, 0);
|
||||
break;
|
||||
case 3:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 2, 1, 0);
|
||||
break;
|
||||
case 4:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 0, 0);
|
||||
break;
|
||||
case 5:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 1, 0);
|
||||
break;
|
||||
case 6:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 0);
|
||||
break;
|
||||
case 7:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 1);
|
||||
break;
|
||||
case 8:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 0);
|
||||
break;
|
||||
case 9:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 1);
|
||||
break;
|
||||
case 10:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 2);
|
||||
break;
|
||||
case 12:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 4);
|
||||
break;
|
||||
default:
|
||||
/* we limit the inlined version to 3 moves */
|
||||
return __generic_copy_from_user(to, from, n);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
|
||||
asm volatile ("\n" \
|
||||
" move."#s1" (%2)+,%3\n" \
|
||||
"11: "MOVES"."#s1" %3,(%1)+\n" \
|
||||
"12: move."#s2" (%2)+,%3\n" \
|
||||
"21: "MOVES"."#s2" %3,(%1)+\n" \
|
||||
"22:\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
" move."#s3" (%2)+,%3\n" \
|
||||
"31: "MOVES"."#s3" %3,(%1)+\n" \
|
||||
"32:\n" \
|
||||
" .endif\n" \
|
||||
"4:\n" \
|
||||
"\n" \
|
||||
" .section __ex_table,\"a\"\n" \
|
||||
" .align 4\n" \
|
||||
" .long 11b,5f\n" \
|
||||
" .long 12b,5f\n" \
|
||||
" .long 21b,5f\n" \
|
||||
" .long 22b,5f\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
" .long 31b,5f\n" \
|
||||
" .long 32b,5f\n" \
|
||||
" .endif\n" \
|
||||
" .previous\n" \
|
||||
"\n" \
|
||||
" .section .fixup,\"ax\"\n" \
|
||||
" .even\n" \
|
||||
"5: moveq.l #"#n",%0\n" \
|
||||
" jra 4b\n" \
|
||||
" .previous\n" \
|
||||
: "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
|
||||
: : "memory")
|
||||
|
||||
static __always_inline unsigned long
|
||||
__constant_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
unsigned long res = 0, tmp;
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
__put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
|
||||
break;
|
||||
case 2:
|
||||
__put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
|
||||
break;
|
||||
case 3:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
|
||||
break;
|
||||
case 4:
|
||||
__put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
|
||||
break;
|
||||
case 5:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
|
||||
break;
|
||||
case 6:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
|
||||
break;
|
||||
case 7:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
|
||||
break;
|
||||
case 8:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
|
||||
break;
|
||||
case 9:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
|
||||
break;
|
||||
case 10:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
|
||||
break;
|
||||
case 12:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
|
||||
break;
|
||||
default:
|
||||
/* limit the inlined version to 3 moves */
|
||||
return __generic_copy_to_user(to, from, n);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
if (__builtin_constant_p(n))
|
||||
return __constant_copy_from_user(to, from, n);
|
||||
return __generic_copy_from_user(to, from, n);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
if (__builtin_constant_p(n))
|
||||
return __constant_copy_to_user(to, from, n);
|
||||
return __generic_copy_to_user(to, from, n);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
|
||||
#define user_addr_max() \
|
||||
(uaccess_kernel() ? ~0UL : TASK_SIZE)
|
||||
|
||||
extern long strncpy_from_user(char *dst, const char __user *src, long count);
|
||||
extern __must_check long strnlen_user(const char __user *str, long n);
|
||||
|
||||
unsigned long __clear_user(void __user *to, unsigned long n);
|
||||
|
||||
#define clear_user __clear_user
|
||||
|
||||
#else /* !CONFIG_MMU */
|
||||
#include <asm-generic/uaccess.h>
|
||||
#endif
|
||||
|
||||
#endif /* _M68K_UACCESS_H */
|
||||
|
@ -1,390 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __M68K_UACCESS_H
|
||||
#define __M68K_UACCESS_H
|
||||
|
||||
/*
|
||||
* User space memory access functions
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
/* We let the MMU do all checking */
|
||||
static inline int access_ok(const void __user *addr,
|
||||
unsigned long size)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all varients of the 68k family support the notion of address spaces.
|
||||
* The traditional 680x0 parts do, and they use the sfc/dfc registers and
|
||||
* the "moves" instruction to access user space from kernel space. Other
|
||||
* family members like ColdFire don't support this, and only have a single
|
||||
* address space, and use the usual "move" instruction for user space access.
|
||||
*
|
||||
* Outside of this difference the user space access functions are the same.
|
||||
* So lets keep the code simple and just define in what we need to use.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
|
||||
#define MOVES "moves"
|
||||
#else
|
||||
#define MOVES "move"
|
||||
#endif
|
||||
|
||||
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, r, -EFAULT); \
|
||||
break; \
|
||||
case 4: \
|
||||
__put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
|
||||
break; \
|
||||
case 8: \
|
||||
{ \
|
||||
const void __user *__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.l %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) = (__force typeof(*(ptr)))(__force unsigned 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, r, -EFAULT); \
|
||||
break; \
|
||||
case 4: \
|
||||
__get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
|
||||
break; \
|
||||
case 8: { \
|
||||
const void __user *__gu_ptr = (ptr); \
|
||||
union { \
|
||||
u64 l; \
|
||||
__typeof__(*(ptr)) t; \
|
||||
} __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.l), \
|
||||
"+a" (__gu_ptr) \
|
||||
: "i" (-EFAULT) \
|
||||
: "memory"); \
|
||||
(x) = __gu_val.t; \
|
||||
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);
|
||||
|
||||
#define __suffix0
|
||||
#define __suffix1 b
|
||||
#define __suffix2 w
|
||||
#define __suffix4 l
|
||||
|
||||
#define ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
|
||||
asm volatile ("\n" \
|
||||
"1: "MOVES"."#s1" (%2)+,%3\n" \
|
||||
" move."#s1" %3,(%1)+\n" \
|
||||
" .ifnc \""#s2"\",\"\"\n" \
|
||||
"2: "MOVES"."#s2" (%2)+,%3\n" \
|
||||
" move."#s2" %3,(%1)+\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
"3: "MOVES"."#s3" (%2)+,%3\n" \
|
||||
" move."#s3" %3,(%1)+\n" \
|
||||
" .endif\n" \
|
||||
" .endif\n" \
|
||||
"4:\n" \
|
||||
" .section __ex_table,\"a\"\n" \
|
||||
" .align 4\n" \
|
||||
" .long 1b,10f\n" \
|
||||
" .ifnc \""#s2"\",\"\"\n" \
|
||||
" .long 2b,20f\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
" .long 3b,30f\n" \
|
||||
" .endif\n" \
|
||||
" .endif\n" \
|
||||
" .previous\n" \
|
||||
"\n" \
|
||||
" .section .fixup,\"ax\"\n" \
|
||||
" .even\n" \
|
||||
"10: addq.l #"#n1",%0\n" \
|
||||
" .ifnc \""#s2"\",\"\"\n" \
|
||||
"20: addq.l #"#n2",%0\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
"30: addq.l #"#n3",%0\n" \
|
||||
" .endif\n" \
|
||||
" .endif\n" \
|
||||
" jra 4b\n" \
|
||||
" .previous\n" \
|
||||
: "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
|
||||
: : "memory")
|
||||
|
||||
#define ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
|
||||
____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)
|
||||
#define __constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3) \
|
||||
___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, \
|
||||
__suffix##n1, __suffix##n2, __suffix##n3)
|
||||
|
||||
static __always_inline unsigned long
|
||||
__constant_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
unsigned long res = 0, tmp;
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 1, 0, 0);
|
||||
break;
|
||||
case 2:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 2, 0, 0);
|
||||
break;
|
||||
case 3:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 2, 1, 0);
|
||||
break;
|
||||
case 4:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 0, 0);
|
||||
break;
|
||||
case 5:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 1, 0);
|
||||
break;
|
||||
case 6:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 0);
|
||||
break;
|
||||
case 7:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 1);
|
||||
break;
|
||||
case 8:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 0);
|
||||
break;
|
||||
case 9:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 1);
|
||||
break;
|
||||
case 10:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 2);
|
||||
break;
|
||||
case 12:
|
||||
__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 4);
|
||||
break;
|
||||
default:
|
||||
/* we limit the inlined version to 3 moves */
|
||||
return __generic_copy_from_user(to, from, n);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
|
||||
asm volatile ("\n" \
|
||||
" move."#s1" (%2)+,%3\n" \
|
||||
"11: "MOVES"."#s1" %3,(%1)+\n" \
|
||||
"12: move."#s2" (%2)+,%3\n" \
|
||||
"21: "MOVES"."#s2" %3,(%1)+\n" \
|
||||
"22:\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
" move."#s3" (%2)+,%3\n" \
|
||||
"31: "MOVES"."#s3" %3,(%1)+\n" \
|
||||
"32:\n" \
|
||||
" .endif\n" \
|
||||
"4:\n" \
|
||||
"\n" \
|
||||
" .section __ex_table,\"a\"\n" \
|
||||
" .align 4\n" \
|
||||
" .long 11b,5f\n" \
|
||||
" .long 12b,5f\n" \
|
||||
" .long 21b,5f\n" \
|
||||
" .long 22b,5f\n" \
|
||||
" .ifnc \""#s3"\",\"\"\n" \
|
||||
" .long 31b,5f\n" \
|
||||
" .long 32b,5f\n" \
|
||||
" .endif\n" \
|
||||
" .previous\n" \
|
||||
"\n" \
|
||||
" .section .fixup,\"ax\"\n" \
|
||||
" .even\n" \
|
||||
"5: moveq.l #"#n",%0\n" \
|
||||
" jra 4b\n" \
|
||||
" .previous\n" \
|
||||
: "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
|
||||
: : "memory")
|
||||
|
||||
static __always_inline unsigned long
|
||||
__constant_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
unsigned long res = 0, tmp;
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
__put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
|
||||
break;
|
||||
case 2:
|
||||
__put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
|
||||
break;
|
||||
case 3:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
|
||||
break;
|
||||
case 4:
|
||||
__put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
|
||||
break;
|
||||
case 5:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
|
||||
break;
|
||||
case 6:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
|
||||
break;
|
||||
case 7:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
|
||||
break;
|
||||
case 8:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
|
||||
break;
|
||||
case 9:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
|
||||
break;
|
||||
case 10:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
|
||||
break;
|
||||
case 12:
|
||||
__constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
|
||||
break;
|
||||
default:
|
||||
/* limit the inlined version to 3 moves */
|
||||
return __generic_copy_to_user(to, from, n);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
if (__builtin_constant_p(n))
|
||||
return __constant_copy_from_user(to, from, n);
|
||||
return __generic_copy_from_user(to, from, n);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
if (__builtin_constant_p(n))
|
||||
return __constant_copy_to_user(to, from, n);
|
||||
return __generic_copy_to_user(to, from, n);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
|
||||
#define user_addr_max() \
|
||||
(uaccess_kernel() ? ~0UL : TASK_SIZE)
|
||||
|
||||
extern long strncpy_from_user(char *dst, const char __user *src, long count);
|
||||
extern __must_check long strnlen_user(const char __user *str, long n);
|
||||
|
||||
unsigned long __clear_user(void __user *to, unsigned long n);
|
||||
|
||||
#define clear_user __clear_user
|
||||
|
||||
#endif /* _M68K_UACCESS_H */
|
@ -1,160 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __M68KNOMMU_UACCESS_H
|
||||
#define __M68KNOMMU_UACCESS_H
|
||||
|
||||
/*
|
||||
* User space memory access functions
|
||||
*/
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define access_ok(addr,size) _access_ok((unsigned long)(addr),(size))
|
||||
|
||||
/*
|
||||
* It is not enough to just have access_ok check for a real RAM address.
|
||||
* This would disallow the case of code/ro-data running XIP in flash/rom.
|
||||
* Ideally we would check the possible flash ranges too, but that is
|
||||
* currently not so easy.
|
||||
*/
|
||||
static inline int _access_ok(unsigned long addr, unsigned long size)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) \
|
||||
({ \
|
||||
int __pu_err = 0; \
|
||||
typeof(*(ptr)) __pu_val = (x); \
|
||||
switch (sizeof (*(ptr))) { \
|
||||
case 1: \
|
||||
__put_user_asm(__pu_err, __pu_val, ptr, b); \
|
||||
break; \
|
||||
case 2: \
|
||||
__put_user_asm(__pu_err, __pu_val, ptr, w); \
|
||||
break; \
|
||||
case 4: \
|
||||
__put_user_asm(__pu_err, __pu_val, ptr, l); \
|
||||
break; \
|
||||
case 8: \
|
||||
memcpy((void __force *)ptr, &__pu_val, sizeof(*(ptr))); \
|
||||
break; \
|
||||
default: \
|
||||
__pu_err = __put_user_bad(); \
|
||||
break; \
|
||||
} \
|
||||
__pu_err; \
|
||||
})
|
||||
#define __put_user(x, ptr) put_user(x, ptr)
|
||||
|
||||
extern int __put_user_bad(void);
|
||||
|
||||
/*
|
||||
* Tell gcc we read from memory instead of writing: this is because
|
||||
* we do not write to any memory gcc knows about, so there are no
|
||||
* aliasing issues.
|
||||
*/
|
||||
|
||||
#define __ptr(x) ((unsigned long __user *)(x))
|
||||
|
||||
#define __put_user_asm(err,x,ptr,bwl) \
|
||||
__asm__ ("move" #bwl " %0,%1" \
|
||||
: /* no outputs */ \
|
||||
:"d" (x),"m" (*__ptr(ptr)) : "memory")
|
||||
|
||||
#define get_user(x, ptr) \
|
||||
({ \
|
||||
int __gu_err = 0; \
|
||||
switch (sizeof(*(ptr))) { \
|
||||
case 1: \
|
||||
__get_user_asm(__gu_err, x, ptr, b, "=d"); \
|
||||
break; \
|
||||
case 2: \
|
||||
__get_user_asm(__gu_err, x, ptr, w, "=r"); \
|
||||
break; \
|
||||
case 4: \
|
||||
__get_user_asm(__gu_err, x, ptr, l, "=r"); \
|
||||
break; \
|
||||
case 8: { \
|
||||
union { \
|
||||
u64 l; \
|
||||
__typeof__(*(ptr)) t; \
|
||||
} __gu_val; \
|
||||
memcpy(&__gu_val.l, (const void __force *)ptr, sizeof(__gu_val.l)); \
|
||||
(x) = __gu_val.t; \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
__gu_err = __get_user_bad(); \
|
||||
break; \
|
||||
} \
|
||||
__gu_err; \
|
||||
})
|
||||
#define __get_user(x, ptr) get_user(x, ptr)
|
||||
|
||||
extern int __get_user_bad(void);
|
||||
|
||||
#define __get_user_asm(err,x,ptr,bwl,reg) \
|
||||
__asm__ ("move" #bwl " %1,%0" \
|
||||
: "=d" (x) \
|
||||
: "m" (*__ptr(ptr)))
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
memcpy(to, (__force const void *)from, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
memcpy((__force void *)to, from, n);
|
||||
return 0;
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
|
||||
/*
|
||||
* Copy a null terminated string from userspace.
|
||||
*/
|
||||
|
||||
static inline long
|
||||
strncpy_from_user(char *dst, const char *src, long count)
|
||||
{
|
||||
char *tmp;
|
||||
strncpy(dst, src, count);
|
||||
for (tmp = dst; *tmp && count > 0; tmp++, count--)
|
||||
;
|
||||
return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the size of a string (including the ending 0)
|
||||
*
|
||||
* Return 0 on exception, a value greater than N if too long
|
||||
*/
|
||||
static inline long strnlen_user(const char *src, long n)
|
||||
{
|
||||
return(strlen(src) + 1); /* DAVIDM make safer */
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero Userspace
|
||||
*/
|
||||
|
||||
static inline unsigned long
|
||||
__clear_user(void *to, unsigned long n)
|
||||
{
|
||||
memset(to, 0, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define clear_user(to,n) __clear_user(to,n)
|
||||
|
||||
#endif /* _M68KNOMMU_UACCESS_H */
|
Loading…
Reference in New Issue
Block a user