sh: switch to generic strncpy_from_user().
This kills off the special sh32/64 versions and adopts the generic version. It should be possible to optimize this for SH-4A unaligned loads, but this is a corner case that can be supported incrementally. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
@@ -32,6 +32,7 @@ config SUPERH
|
|||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
|
select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
|
||||||
|
select GENERIC_STRNCPY_FROM_USER
|
||||||
help
|
help
|
||||||
The SuperH is a RISC processor targeted for use in embedded systems
|
The SuperH is a RISC processor targeted for use in embedded systems
|
||||||
and consumer electronics; it was also used in the Sega Dreamcast
|
and consumer electronics; it was also used in the Sega Dreamcast
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
(__chk_user_ptr(addr), \
|
(__chk_user_ptr(addr), \
|
||||||
__access_ok((unsigned long __force)(addr), (size)))
|
__access_ok((unsigned long __force)(addr), (size)))
|
||||||
|
|
||||||
|
#define user_addr_max() (current_thread_info()->addr_limit.seg)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Uh, these should become the main single-value transfer routines ...
|
* Uh, these should become the main single-value transfer routines ...
|
||||||
* They automatically use the right size if we just have the right
|
* They automatically use the right size if we just have the right
|
||||||
@@ -100,6 +102,8 @@ struct __large_struct { unsigned long buf[100]; };
|
|||||||
# include "uaccess_64.h"
|
# include "uaccess_64.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern long strncpy_from_user(char *dest, const char __user *src, long count);
|
||||||
|
|
||||||
/* Generic arbitrary sized copy. */
|
/* Generic arbitrary sized copy. */
|
||||||
/* Return the number of bytes NOT copied */
|
/* Return the number of bytes NOT copied */
|
||||||
__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
|
__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
|
||||||
@@ -137,37 +141,6 @@ __kernel_size_t __clear_user(void *addr, __kernel_size_t size);
|
|||||||
__cl_size; \
|
__cl_size; \
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* strncpy_from_user: - Copy a NUL terminated string from userspace.
|
|
||||||
* @dst: Destination address, in kernel space. This buffer must be at
|
|
||||||
* least @count bytes long.
|
|
||||||
* @src: Source address, in user space.
|
|
||||||
* @count: Maximum number of bytes to copy, including the trailing NUL.
|
|
||||||
*
|
|
||||||
* Copies a NUL-terminated string from userspace to kernel space.
|
|
||||||
*
|
|
||||||
* On success, returns the length of the string (not including the trailing
|
|
||||||
* NUL).
|
|
||||||
*
|
|
||||||
* If access to userspace fails, returns -EFAULT (some data may have been
|
|
||||||
* copied).
|
|
||||||
*
|
|
||||||
* If @count is smaller than the length of the string, copies @count bytes
|
|
||||||
* and returns @count.
|
|
||||||
*/
|
|
||||||
#define strncpy_from_user(dest,src,count) \
|
|
||||||
({ \
|
|
||||||
unsigned long __sfu_src = (unsigned long)(src); \
|
|
||||||
int __sfu_count = (int)(count); \
|
|
||||||
long __sfu_res = -EFAULT; \
|
|
||||||
\
|
|
||||||
if (__access_ok(__sfu_src, __sfu_count)) \
|
|
||||||
__sfu_res = __strncpy_from_user((unsigned long)(dest), \
|
|
||||||
__sfu_src, __sfu_count); \
|
|
||||||
\
|
|
||||||
__sfu_res; \
|
|
||||||
})
|
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
copy_from_user(void *to, const void __user *from, unsigned long n)
|
copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||||
{
|
{
|
||||||
|
@@ -170,45 +170,6 @@ __asm__ __volatile__( \
|
|||||||
|
|
||||||
extern void __put_user_unknown(void);
|
extern void __put_user_unknown(void);
|
||||||
|
|
||||||
static inline int
|
|
||||||
__strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __count)
|
|
||||||
{
|
|
||||||
__kernel_size_t res;
|
|
||||||
unsigned long __dummy, _d, _s, _c;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"9:\n"
|
|
||||||
"mov.b @%2+, %1\n\t"
|
|
||||||
"cmp/eq #0, %1\n\t"
|
|
||||||
"bt/s 2f\n"
|
|
||||||
"1:\n"
|
|
||||||
"mov.b %1, @%3\n\t"
|
|
||||||
"dt %4\n\t"
|
|
||||||
"bf/s 9b\n\t"
|
|
||||||
" add #1, %3\n\t"
|
|
||||||
"2:\n\t"
|
|
||||||
"sub %4, %0\n"
|
|
||||||
"3:\n"
|
|
||||||
".section .fixup,\"ax\"\n"
|
|
||||||
"4:\n\t"
|
|
||||||
"mov.l 5f, %1\n\t"
|
|
||||||
"jmp @%1\n\t"
|
|
||||||
" mov %9, %0\n\t"
|
|
||||||
".balign 4\n"
|
|
||||||
"5: .long 3b\n"
|
|
||||||
".previous\n"
|
|
||||||
".section __ex_table,\"a\"\n"
|
|
||||||
" .balign 4\n"
|
|
||||||
" .long 9b,4b\n"
|
|
||||||
".previous"
|
|
||||||
: "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d), "=r"(_c)
|
|
||||||
: "0" (__count), "2" (__src), "3" (__dest), "4" (__count),
|
|
||||||
"i" (-EFAULT)
|
|
||||||
: "memory", "t");
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the size of a string (including the ending 0 even when we have
|
* Return the size of a string (including the ending 0 even when we have
|
||||||
* exceeded the maximum string length).
|
* exceeded the maximum string length).
|
||||||
|
@@ -85,7 +85,5 @@ extern long __put_user_asm_q(void *, long);
|
|||||||
extern void __put_user_unknown(void);
|
extern void __put_user_unknown(void);
|
||||||
|
|
||||||
extern long __strnlen_user(const char *__s, long __n);
|
extern long __strnlen_user(const char *__s, long __n);
|
||||||
extern int __strncpy_from_user(unsigned long __dest,
|
|
||||||
unsigned long __user __src, int __count);
|
|
||||||
|
|
||||||
#endif /* __ASM_SH_UACCESS_64_H */
|
#endif /* __ASM_SH_UACCESS_64_H */
|
||||||
|
@@ -1568,46 +1568,6 @@ ___clear_user_exit:
|
|||||||
|
|
||||||
#endif /* CONFIG_MMU */
|
#endif /* CONFIG_MMU */
|
||||||
|
|
||||||
/*
|
|
||||||
* int __strncpy_from_user(unsigned long __dest, unsigned long __src,
|
|
||||||
* int __count)
|
|
||||||
*
|
|
||||||
* Inputs:
|
|
||||||
* (r2) target address
|
|
||||||
* (r3) source address
|
|
||||||
* (r4) maximum size in bytes
|
|
||||||
*
|
|
||||||
* Ouputs:
|
|
||||||
* (*r2) copied data
|
|
||||||
* (r2) -EFAULT (in case of faulting)
|
|
||||||
* copied data (otherwise)
|
|
||||||
*/
|
|
||||||
.global __strncpy_from_user
|
|
||||||
__strncpy_from_user:
|
|
||||||
pta ___strncpy_from_user1, tr0
|
|
||||||
pta ___strncpy_from_user_done, tr1
|
|
||||||
or r4, ZERO, r5 /* r5 = original count */
|
|
||||||
beq/u r4, r63, tr1 /* early exit if r4==0 */
|
|
||||||
movi -(EFAULT), r6 /* r6 = reply, no real fixup */
|
|
||||||
or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */
|
|
||||||
|
|
||||||
___strncpy_from_user1:
|
|
||||||
ld.b r3, 0, r7 /* Fault address: only in reading */
|
|
||||||
st.b r2, 0, r7
|
|
||||||
addi r2, 1, r2
|
|
||||||
addi r3, 1, r3
|
|
||||||
beq/u ZERO, r7, tr1
|
|
||||||
addi r4, -1, r4 /* return real number of copied bytes */
|
|
||||||
bne/l ZERO, r4, tr0
|
|
||||||
|
|
||||||
___strncpy_from_user_done:
|
|
||||||
sub r5, r4, r6 /* If done, return copied */
|
|
||||||
|
|
||||||
___strncpy_from_user_exit:
|
|
||||||
or r6, ZERO, r2
|
|
||||||
ptabs LINK, tr0
|
|
||||||
blink tr0, ZERO
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extern long __strnlen_user(const char *__s, long __n)
|
* extern long __strnlen_user(const char *__s, long __n)
|
||||||
*
|
*
|
||||||
@@ -1982,7 +1942,6 @@ asm_uaccess_start:
|
|||||||
.long ___copy_user2, ___copy_user_exit
|
.long ___copy_user2, ___copy_user_exit
|
||||||
.long ___clear_user1, ___clear_user_exit
|
.long ___clear_user1, ___clear_user_exit
|
||||||
#endif
|
#endif
|
||||||
.long ___strncpy_from_user1, ___strncpy_from_user_exit
|
|
||||||
.long ___strnlen_user1, ___strnlen_user_exit
|
.long ___strnlen_user1, ___strnlen_user_exit
|
||||||
.long ___get_user_asm_b1, ___get_user_asm_b_exit
|
.long ___get_user_asm_b1, ___get_user_asm_b_exit
|
||||||
.long ___get_user_asm_w1, ___get_user_asm_w_exit
|
.long ___get_user_asm_w1, ___get_user_asm_w_exit
|
||||||
|
@@ -33,7 +33,6 @@ EXPORT_SYMBOL(__get_user_asm_w);
|
|||||||
EXPORT_SYMBOL(__get_user_asm_l);
|
EXPORT_SYMBOL(__get_user_asm_l);
|
||||||
EXPORT_SYMBOL(__get_user_asm_q);
|
EXPORT_SYMBOL(__get_user_asm_q);
|
||||||
EXPORT_SYMBOL(__strnlen_user);
|
EXPORT_SYMBOL(__strnlen_user);
|
||||||
EXPORT_SYMBOL(__strncpy_from_user);
|
|
||||||
EXPORT_SYMBOL(__clear_user);
|
EXPORT_SYMBOL(__clear_user);
|
||||||
EXPORT_SYMBOL(copy_page);
|
EXPORT_SYMBOL(copy_page);
|
||||||
EXPORT_SYMBOL(__copy_user);
|
EXPORT_SYMBOL(__copy_user);
|
||||||
|
Reference in New Issue
Block a user