m68knommu: collection of fixes for 5.10
Fixes include: . switch to using asm-generic uaccess code . fix sparse warnings in signal code . fix compilation of ColdFire MMC support . support sysrq in ColdFire serial driver -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEmsfM6tQwfNjBOxr3TiQVqaG9L4AFAl+M4OUACgkQTiQVqaG9 L4Bb0A//fsrbpUL6p0NHiuOoP+327shE+Tw+l78yCQRmnxtSnI2cK/Mq7O4/mLI/ 6w/Fisw/EnBAVeG1v6HZ4BoQopTVzFj7/iE4KgOkum0FDhy55VHKhkAWRAX6ZslW RozzahotW4LbmhD1IUSmlNU5gIyABm3hSlZKjKJEo90FuGTeMpwnClefjhTSzOuY rfKk73PtDHCCRXfF52vweabhR+17Akh2D3gSwje5MSRvIC+7BC3wyE1s4B/pGFX2 Xw9ziGw8dz9J7wqREKT/AUuylqO++HrGfAeXkNJ6xggI8iOJsxVb943BDgu3P1gF MaowvV/sHwwocNBOzqDExobx9OS3/UC124+sSwcPJxBCXDJkMiqvxVGymX+6j/aN WXXv+8DVUDL3hKbRsVVssiBo2oQ/pBtZigyB2HHt9z9zIPtyQ03nm0Nud8o+fYm6 6CT2xdntnBKAjAyP2eu7L3dEBCoK3E6juYMiwdiwys8C2i8SF8hCI+QgXRiSQcml dQeyCxZJLxwH1fG3zJByWDUP9Pm6hC3MV1dKGhzbVJnieX0qKn7sHW1CBcvW/X84 qZp+C7O+DjJs0yfR2QzfJ7gIk1GhJH13HwiXWx4BMEGU4oAUCgajEeEip+XOKol4 as5xSqcyU8eGNDmzjibvi2Lqnn/CPzjx/CATaduYrpAmao55kg4= =QMK9 -----END PGP SIGNATURE----- Merge tag 'm68knommu-for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu Pull m68knommu updates from Greg Ungerer: "A collection of fixes for 5.10: - switch to using asm-generic uaccess code - fix sparse warnings in signal code - fix compilation of ColdFire MMC support - support sysrq in ColdFire serial driver" * tag 'm68knommu-for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu: serial: mcf: add sysrq capability m68knommu: include SDHC support only when hardware has it m68knommu: fix sparse warnings in signal code m68knommu: switch to using asm-generic/uaccess.h
This commit is contained in:
commit
d3876ff744
|
@ -31,6 +31,7 @@ config M68K
|
|||
select NO_DMA if !MMU && !COLDFIRE
|
||||
select OLD_SIGACTION
|
||||
select OLD_SIGSUSPEND3
|
||||
select UACCESS_MEMCPY if !MMU
|
||||
select VIRT_TO_BUS
|
||||
|
||||
config CPU_BIG_ENDIAN
|
||||
|
|
|
@ -554,7 +554,7 @@ static struct platform_device mcf_edma = {
|
|||
};
|
||||
#endif /* IS_ENABLED(CONFIG_MCF_EDMA) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_MMC)
|
||||
#ifdef MCFSDHC_BASE
|
||||
static struct mcf_esdhc_platform_data mcf_esdhc_data = {
|
||||
.max_bus_width = 4,
|
||||
.cd_type = ESDHC_CD_NONE,
|
||||
|
@ -579,7 +579,7 @@ static struct platform_device mcf_esdhc = {
|
|||
.resource = mcf_esdhc_resources,
|
||||
.dev.platform_data = &mcf_esdhc_data,
|
||||
};
|
||||
#endif /* IS_ENABLED(CONFIG_MMC) */
|
||||
#endif /* MCFSDHC_BASE */
|
||||
|
||||
static struct platform_device *mcf_devices[] __initdata = {
|
||||
&mcf_uart,
|
||||
|
@ -613,7 +613,7 @@ static struct platform_device *mcf_devices[] __initdata = {
|
|||
#if IS_ENABLED(CONFIG_MCF_EDMA)
|
||||
&mcf_edma,
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_MMC)
|
||||
#ifdef MCFSDHC_BASE
|
||||
&mcf_esdhc,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -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 */
|
|
@ -920,7 +920,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
|
|||
err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
|
||||
(long __user *)(frame->retcode));
|
||||
#else
|
||||
err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
|
||||
err |= __put_user((long) ret_from_user_signal,
|
||||
(long __user *) &frame->pretcode);
|
||||
#endif
|
||||
|
||||
if (err)
|
||||
|
@ -1004,7 +1005,8 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
|
|||
err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
|
||||
#endif
|
||||
#else
|
||||
err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
|
||||
err |= __put_user((long) ret_from_user_rt_signal,
|
||||
(long __user *) &frame->pretcode);
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
if (err)
|
||||
|
|
Loading…
Reference in a new issue