Commit 5db6db0d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull uaccess unification updates from Al Viro:
 "This is the uaccess unification pile. It's _not_ the end of uaccess
  work, but the next batch of that will go into the next cycle. This one
  mostly takes copy_from_user() and friends out of arch/* and gets the
  zero-padding behaviour in sync for all architectures.

  Dealing with the nocache/writethrough mess is for the next cycle;
  fortunately, that's x86-only. Same for cleanups in iov_iter.c (I am
  sold on access_ok() in there, BTW; just not in this pile), same for
  reducing __copy_... callsites, strn*... stuff, etc. - there will be a
  pile about as large as this one in the next merge window.

  This one sat in -next for weeks. -3KLoC"

* 'work.uaccess' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (96 commits)
  HAVE_ARCH_HARDENED_USERCOPY is unconditional now
  CONFIG_ARCH_HAS_RAW_COPY_USER is unconditional now
  m32r: switch to RAW_COPY_USER
  hexagon: switch to RAW_COPY_USER
  microblaze: switch to RAW_COPY_USER
  get rid of padding, switch to RAW_COPY_USER
  ia64: get rid of copy_in_user()
  ia64: sanitize __access_ok()
  ia64: get rid of 'segment' argument of __do_{get,put}_user()
  ia64: get rid of 'segment' argument of __{get,put}_user_check()
  ia64: add extable.h
  powerpc: get rid of zeroing, switch to RAW_COPY_USER
  esas2r: don't open-code memdup_user()
  alpha: fix stack smashing in old_adjtimex(2)
  don't open-code kernel_setsockopt()
  mips: switch to RAW_COPY_USER
  mips: get rid of tail-zeroing in primitives
  mips: make copy_from_user() zero tail explicitly
  mips: clean and reorder the forest of macros...
  mips: consolidate __invoke_... wrappers
  ...
parents 5fab1004 2fefc97b
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
#ifndef _ASM_EXTABLE_H
#define _ASM_EXTABLE_H

/*
 * About the exception table:
 *
 * - insn is a 32-bit pc-relative offset from the faulting insn.
 * - nextinsn is a 16-bit offset off of the faulting instruction
 *   (not off of the *next* instruction as branches are).
 * - errreg is the register in which to place -EFAULT.
 * - valreg is the final target register for the load sequence
 *   and will be zeroed.
 *
 * Either errreg or valreg may be $31, in which case nothing happens.
 *
 * The exception fixup information "just so happens" to be arranged
 * as in a MEM format instruction.  This lets us emit our three
 * values like so:
 *
 *      lda valreg, nextinsn(errreg)
 *
 */

struct exception_table_entry
{
	signed int insn;
	union exception_fixup {
		unsigned unit;
		struct {
			signed int nextinsn : 16;
			unsigned int errreg : 5;
			unsigned int valreg : 5;
		} bits;
	} fixup;
};

/* Returns the new pc */
#define fixup_exception(map_reg, _fixup, pc)			\
({								\
	if ((_fixup)->fixup.bits.valreg != 31)			\
		map_reg((_fixup)->fixup.bits.valreg) = 0;	\
	if ((_fixup)->fixup.bits.errreg != 31)			\
		map_reg((_fixup)->fixup.bits.errreg) = -EFAULT;	\
	(pc) + (_fixup)->fixup.bits.nextinsn;			\
})

#define ARCH_HAS_RELATIVE_EXTABLE

#define swap_ex_entry_fixup(a, b, tmp, delta)			\
	do {							\
		(a)->fixup.unit = (b)->fixup.unit;		\
		(b)->fixup.unit = (tmp).fixup.unit;		\
	} while (0)

#endif
+4 −12
Original line number Diff line number Diff line
@@ -19,12 +19,8 @@
	"3:	.subsection 2\n"				\
	"4:	br	1b\n"					\
	"	.previous\n"					\
	"	.section __ex_table,\"a\"\n"			\
	"	.long	1b-.\n"					\
	"	lda	$31,3b-1b(%1)\n"			\
	"	.long	2b-.\n"					\
	"	lda	$31,3b-2b(%1)\n"			\
	"	.previous\n"					\
	EXC(1b,3b,%1,$31)					\
	EXC(2b,3b,%1,$31)					\
	:	"=&r" (oldval), "=&r"(ret)			\
	:	"r" (uaddr), "r"(oparg)				\
	:	"memory")
@@ -101,12 +97,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
	"3:	.subsection 2\n"
	"4:	br	1b\n"
	"	.previous\n"
	"	.section __ex_table,\"a\"\n"
	"	.long	1b-.\n"
	"	lda	$31,3b-1b(%0)\n"
	"	.long	2b-.\n"
	"	lda	$31,3b-2b(%0)\n"
	"	.previous\n"
	EXC(1b,3b,%0,$31)
	EXC(2b,3b,%0,$31)
	:	"+r"(ret), "=&r"(prev), "=&r"(cmp)
	:	"r"(uaddr), "r"((long)(int)oldval), "r"(newval)
	:	"memory");
+73 −232
Original line number Diff line number Diff line
#ifndef __ALPHA_UACCESS_H
#define __ALPHA_UACCESS_H

#include <linux/errno.h>
#include <linux/sched.h>


/*
 * The fs value determines whether argument validity checking should be
 * performed or not.  If get_fs() == USER_DS, checking is performed, with
@@ -20,9 +16,6 @@
#define KERNEL_DS	((mm_segment_t) { 0UL })
#define USER_DS		((mm_segment_t) { -0x40000000000UL })

#define VERIFY_READ	0
#define VERIFY_WRITE	1

#define get_fs()  (current_thread_info()->addr_limit)
#define get_ds()  (KERNEL_DS)
#define set_fs(x) (current_thread_info()->addr_limit = (x))
@@ -39,13 +32,13 @@
 *  - AND "addr+size" doesn't have any high-bits set
 *  - OR we are in kernel mode.
 */
#define __access_ok(addr, size, segment) \
	(((segment).seg & (addr | size | (addr+size))) == 0)
#define __access_ok(addr, size) \
	((get_fs().seg & (addr | size | (addr+size))) == 0)

#define access_ok(type, addr, size)			\
({							\
	__chk_user_ptr(addr);				\
	__access_ok(((unsigned long)(addr)), (size), get_fs());	\
	__access_ok(((unsigned long)(addr)), (size));	\
})

/*
@@ -61,9 +54,9 @@
 * (b) require any knowledge of processes at this stage
 */
#define put_user(x, ptr) \
  __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), get_fs())
  __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
#define get_user(x, ptr) \
  __get_user_check((x), (ptr), sizeof(*(ptr)), get_fs())
  __get_user_check((x), (ptr), sizeof(*(ptr)))

/*
 * The "__xxx" versions do not do address space checking, useful when
@@ -81,6 +74,11 @@
 * more extensive comments with fixup_inline_exception below for
 * more information.
 */
#define EXC(label,cont,res,err)				\
	".section __ex_table,\"a\"\n"			\
	"	.long "#label"-.\n"			\
	"	lda "#res","#cont"-"#label"("#err")\n"	\
	".previous\n"

extern void __get_user_unknown(void);

@@ -100,12 +98,12 @@ extern void __get_user_unknown(void);
	__gu_err;						\
})

#define __get_user_check(x, ptr, size, segment)				\
#define __get_user_check(x, ptr, size)				\
({								\
	long __gu_err = -EFAULT;				\
	unsigned long __gu_val = 0;				\
	const __typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
	if (__access_ok((unsigned long)__gu_addr, size, segment)) {	\
	if (__access_ok((unsigned long)__gu_addr, size)) {	\
		__gu_err = 0;					\
		switch (size) {					\
		  case 1: __get_user_8(__gu_addr); break;	\
@@ -125,20 +123,14 @@ struct __large_struct { unsigned long buf[100]; };
#define __get_user_64(addr)				\
	__asm__("1: ldq %0,%2\n"			\
	"2:\n"						\
	".section __ex_table,\"a\"\n"			\
	"	.long 1b - .\n"				\
	"	lda %0, 2b-1b(%1)\n"			\
	".previous"					\
	EXC(1b,2b,%0,%1)				\
		: "=r"(__gu_val), "=r"(__gu_err)	\
		: "m"(__m(addr)), "1"(__gu_err))

#define __get_user_32(addr)				\
	__asm__("1: ldl %0,%2\n"			\
	"2:\n"						\
	".section __ex_table,\"a\"\n"			\
	"	.long 1b - .\n"				\
	"	lda %0, 2b-1b(%1)\n"			\
	".previous"					\
	EXC(1b,2b,%0,%1)				\
		: "=r"(__gu_val), "=r"(__gu_err)	\
		: "m"(__m(addr)), "1"(__gu_err))

@@ -148,20 +140,14 @@ struct __large_struct { unsigned long buf[100]; };
#define __get_user_16(addr)				\
	__asm__("1: ldwu %0,%2\n"			\
	"2:\n"						\
	".section __ex_table,\"a\"\n"			\
	"	.long 1b - .\n"				\
	"	lda %0, 2b-1b(%1)\n"			\
	".previous"					\
	EXC(1b,2b,%0,%1)				\
		: "=r"(__gu_val), "=r"(__gu_err)	\
		: "m"(__m(addr)), "1"(__gu_err))

#define __get_user_8(addr)				\
	__asm__("1: ldbu %0,%2\n"			\
	"2:\n"						\
	".section __ex_table,\"a\"\n"			\
	"	.long 1b - .\n"				\
	"	lda %0, 2b-1b(%1)\n"			\
	".previous"					\
	EXC(1b,2b,%0,%1)				\
		: "=r"(__gu_val), "=r"(__gu_err)	\
		: "m"(__m(addr)), "1"(__gu_err))
#else
@@ -177,12 +163,8 @@ struct __large_struct { unsigned long buf[100]; };
	"	extwh %1,%3,%1\n"					\
	"	or %0,%1,%0\n"						\
	"3:\n"								\
	".section __ex_table,\"a\"\n"					\
	"	.long 1b - .\n"						\
	"	lda %0, 3b-1b(%2)\n"					\
	"	.long 2b - .\n"						\
	"	lda %0, 3b-2b(%2)\n"					\
	".previous"							\
	EXC(1b,3b,%0,%2)						\
	EXC(2b,3b,%0,%2)						\
		: "=&r"(__gu_val), "=&r"(__gu_tmp), "=r"(__gu_err)	\
		: "r"(addr), "2"(__gu_err));				\
}
@@ -191,10 +173,7 @@ struct __large_struct { unsigned long buf[100]; };
	__asm__("1: ldq_u %0,0(%2)\n"					\
	"	extbl %0,%2,%0\n"					\
	"2:\n"								\
	".section __ex_table,\"a\"\n"					\
	"	.long 1b - .\n"						\
	"	lda %0, 2b-1b(%1)\n"					\
	".previous"							\
	EXC(1b,2b,%0,%1)						\
		: "=&r"(__gu_val), "=r"(__gu_err)			\
		: "r"(addr), "1"(__gu_err))
#endif
@@ -215,11 +194,11 @@ extern void __put_user_unknown(void);
	__pu_err;						\
})

#define __put_user_check(x, ptr, size, segment)				\
#define __put_user_check(x, ptr, size)				\
({								\
	long __pu_err = -EFAULT;				\
	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
	if (__access_ok((unsigned long)__pu_addr, size, segment)) {	\
	if (__access_ok((unsigned long)__pu_addr, size)) {	\
		__pu_err = 0;					\
		switch (size) {					\
		  case 1: __put_user_8(x, __pu_addr); break;	\
@@ -240,20 +219,14 @@ extern void __put_user_unknown(void);
#define __put_user_64(x, addr)					\
__asm__ __volatile__("1: stq %r2,%1\n"				\
	"2:\n"							\
	".section __ex_table,\"a\"\n"				\
	"	.long 1b - .\n"					\
	"	lda $31,2b-1b(%0)\n"				\
	".previous"						\
	EXC(1b,2b,$31,%0)					\
		: "=r"(__pu_err)				\
		: "m" (__m(addr)), "rJ" (x), "0"(__pu_err))

#define __put_user_32(x, addr)					\
__asm__ __volatile__("1: stl %r2,%1\n"				\
	"2:\n"							\
	".section __ex_table,\"a\"\n"				\
	"	.long 1b - .\n"					\
	"	lda $31,2b-1b(%0)\n"				\
	".previous"						\
	EXC(1b,2b,$31,%0)					\
		: "=r"(__pu_err)				\
		: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))

@@ -263,20 +236,14 @@ __asm__ __volatile__("1: stl %r2,%1\n" \
#define __put_user_16(x, addr)					\
__asm__ __volatile__("1: stw %r2,%1\n"				\
	"2:\n"							\
	".section __ex_table,\"a\"\n"				\
	"	.long 1b - .\n"					\
	"	lda $31,2b-1b(%0)\n"				\
	".previous"						\
	EXC(1b,2b,$31,%0)					\
		: "=r"(__pu_err)				\
		: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))

#define __put_user_8(x, addr)					\
__asm__ __volatile__("1: stb %r2,%1\n"				\
	"2:\n"							\
	".section __ex_table,\"a\"\n"				\
	"	.long 1b - .\n"					\
	"	lda $31,2b-1b(%0)\n"				\
	".previous"						\
	EXC(1b,2b,$31,%0)					\
		: "=r"(__pu_err)				\
		: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
#else
@@ -298,16 +265,10 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
	"3:	stq_u %2,1(%5)\n"				\
	"4:	stq_u %1,0(%5)\n"				\
	"5:\n"							\
	".section __ex_table,\"a\"\n"				\
	"	.long 1b - .\n"					\
	"	lda $31, 5b-1b(%0)\n"				\
	"	.long 2b - .\n"					\
	"	lda $31, 5b-2b(%0)\n"				\
	"	.long 3b - .\n"					\
	"	lda $31, 5b-3b(%0)\n"				\
	"	.long 4b - .\n"					\
	"	lda $31, 5b-4b(%0)\n"				\
	".previous"						\
	EXC(1b,5b,$31,%0)					\
	EXC(2b,5b,$31,%0)					\
	EXC(3b,5b,$31,%0)					\
	EXC(4b,5b,$31,%0)					\
		: "=r"(__pu_err), "=&r"(__pu_tmp1), 		\
		  "=&r"(__pu_tmp2), "=&r"(__pu_tmp3), 		\
		  "=&r"(__pu_tmp4)				\
@@ -324,12 +285,8 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
	"	or %1,%2,%1\n"					\
	"2:	stq_u %1,0(%4)\n"				\
	"3:\n"							\
	".section __ex_table,\"a\"\n"				\
	"	.long 1b - .\n"					\
	"	lda $31, 3b-1b(%0)\n"				\
	"	.long 2b - .\n"					\
	"	lda $31, 3b-2b(%0)\n"				\
	".previous"						\
	EXC(1b,3b,$31,%0)					\
	EXC(2b,3b,$31,%0)					\
		: "=r"(__pu_err), 				\
	  	  "=&r"(__pu_tmp1), "=&r"(__pu_tmp2)		\
		: "r"((unsigned long)(x)), "r"(addr), "0"(__pu_err)); \
@@ -341,153 +298,37 @@ __asm__ __volatile__("1: stb %r2,%1\n" \
 * Complex access routines
 */

/* This little bit of silliness is to get the GP loaded for a function
   that ordinarily wouldn't.  Otherwise we could have it done by the macro
   directly, which can be optimized the linker.  */
#ifdef MODULE
#define __module_address(sym)		"r"(sym),
#define __module_call(ra, arg, sym)	"jsr $" #ra ",(%" #arg ")," #sym
#else
#define __module_address(sym)
#define __module_call(ra, arg, sym)	"bsr $" #ra "," #sym " !samegp"
#endif

extern void __copy_user(void);

extern inline long
__copy_tofrom_user_nocheck(void *to, const void *from, long len)
{
	register void * __cu_to __asm__("$6") = to;
	register const void * __cu_from __asm__("$7") = from;
	register long __cu_len __asm__("$0") = len;

	__asm__ __volatile__(
		__module_call(28, 3, __copy_user)
		: "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
		: __module_address(__copy_user)
		  "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
		: "$1", "$2", "$3", "$4", "$5", "$28", "memory");

	return __cu_len;
}

#define __copy_to_user(to, from, n)					\
({									\
	__chk_user_ptr(to);						\
	__copy_tofrom_user_nocheck((__force void *)(to), (from), (n));	\
})
#define __copy_from_user(to, from, n)					\
({									\
	__chk_user_ptr(from);						\
	__copy_tofrom_user_nocheck((to), (__force void *)(from), (n));	\
})

#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user
extern long __copy_user(void *to, const void *from, long len);

extern inline long
copy_to_user(void __user *to, const void *from, long n)
static inline unsigned long
raw_copy_from_user(void *to, const void __user *from, unsigned long len)
{
	if (likely(__access_ok((unsigned long)to, n, get_fs())))
		n = __copy_tofrom_user_nocheck((__force void *)to, from, n);
	return n;
	return __copy_user(to, (__force const void *)from, len);
}

extern inline long
copy_from_user(void *to, const void __user *from, long n)
static inline unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long len)
{
	long res = n;
	if (likely(__access_ok((unsigned long)from, n, get_fs())))
		res = __copy_from_user_inatomic(to, from, n);
	if (unlikely(res))
		memset(to + (n - res), 0, res);
	return res;
	return __copy_user((__force void *)to, from, len);
}

extern void __do_clear_user(void);

extern inline long
__clear_user(void __user *to, long len)
{
	register void __user * __cl_to __asm__("$6") = to;
	register long __cl_len __asm__("$0") = len;
	__asm__ __volatile__(
		__module_call(28, 2, __do_clear_user)
		: "=r"(__cl_len), "=r"(__cl_to)
		: __module_address(__do_clear_user)
		  "0"(__cl_len), "1"(__cl_to)
		: "$1", "$2", "$3", "$4", "$5", "$28", "memory");
	return __cl_len;
}
extern long __clear_user(void __user *to, long len);

extern inline long
clear_user(void __user *to, long len)
{
	if (__access_ok((unsigned long)to, len, get_fs()))
	if (__access_ok((unsigned long)to, len))
		len = __clear_user(to, len);
	return len;
}

#undef __module_address
#undef __module_call

#define user_addr_max() \
        (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
        (uaccess_kernel() ? ~0UL : TASK_SIZE)

extern long strncpy_from_user(char *dest, const char __user *src, long count);
extern __must_check long strlen_user(const char __user *str);
extern __must_check long strnlen_user(const char __user *str, long n);

/*
 * About the exception table:
 *
 * - insn is a 32-bit pc-relative offset from the faulting insn.
 * - nextinsn is a 16-bit offset off of the faulting instruction
 *   (not off of the *next* instruction as branches are).
 * - errreg is the register in which to place -EFAULT.
 * - valreg is the final target register for the load sequence
 *   and will be zeroed.
 *
 * Either errreg or valreg may be $31, in which case nothing happens.
 *
 * The exception fixup information "just so happens" to be arranged
 * as in a MEM format instruction.  This lets us emit our three
 * values like so:
 *
 *      lda valreg, nextinsn(errreg)
 *
 */

struct exception_table_entry
{
	signed int insn;
	union exception_fixup {
		unsigned unit;
		struct {
			signed int nextinsn : 16;
			unsigned int errreg : 5;
			unsigned int valreg : 5;
		} bits;
	} fixup;
};

/* Returns the new pc */
#define fixup_exception(map_reg, _fixup, pc)			\
({								\
	if ((_fixup)->fixup.bits.valreg != 31)			\
		map_reg((_fixup)->fixup.bits.valreg) = 0;	\
	if ((_fixup)->fixup.bits.errreg != 31)			\
		map_reg((_fixup)->fixup.bits.errreg) = -EFAULT;	\
	(pc) + (_fixup)->fixup.bits.nextinsn;			\
})

#define ARCH_HAS_RELATIVE_EXTABLE

#define swap_ex_entry_fixup(a, b, tmp, delta)			\
	do {							\
		(a)->fixup.unit = (b)->fixup.unit;		\
		(b)->fixup.unit = (tmp).fixup.unit;		\
	} while (0)

#include <asm/extable.h>

#endif /* __ALPHA_UACCESS_H */
+42 −110
Original line number Diff line number Diff line
@@ -482,12 +482,8 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
		"	extwl %1,%3,%1\n"
		"	extwh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -502,12 +498,8 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
		"	extll %1,%3,%1\n"
		"	extlh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -522,12 +514,8 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
		"	extql %1,%3,%1\n"
		"	extqh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -551,16 +539,10 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
		"3:	stq_u %2,1(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %2,5b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %1,5b-2b(%0)\n"
		"	.long 3b - .\n"
		"	lda $31,5b-3b(%0)\n"
		"	.long 4b - .\n"
		"	lda $31,5b-4b(%0)\n"
		".previous"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -581,16 +563,10 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
		"3:	stq_u %2,3(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %2,5b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %1,5b-2b(%0)\n"
		"	.long 3b - .\n"
		"	lda $31,5b-3b(%0)\n"
		"	.long 4b - .\n"
		"	lda $31,5b-4b(%0)\n"
		".previous"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -611,16 +587,10 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg,
		"3:	stq_u %2,7(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		".section __ex_table,\"a\"\n\t"
		"	.long 1b - .\n"
		"	lda %2,5b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %1,5b-2b(%0)\n"
		"	.long 3b - .\n"
		"	lda $31,5b-3b(%0)\n"
		"	.long 4b - .\n"
		"	lda $31,5b-4b(%0)\n"
		".previous"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -802,7 +772,7 @@ do_entUnaUser(void __user * va, unsigned long opcode,
	/* Don't bother reading ds in the access check since we already
	   know that this came from the user.  Also rely on the fact that
	   the page at TASK_SIZE is unmapped and so can't be touched anyway. */
	if (!__access_ok((unsigned long)va, 0, USER_DS))
	if ((unsigned long)va >= TASK_SIZE)
		goto give_sigsegv;

	++unaligned[1].count;
@@ -835,12 +805,8 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"	extwl %1,%3,%1\n"
		"	extwh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -855,12 +821,8 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"	extll %1,%3,%1\n"
		"	extlh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -875,12 +837,8 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"	extql %1,%3,%1\n"
		"	extqh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -895,12 +853,8 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"	extll %1,%3,%1\n"
		"	extlh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -915,12 +869,8 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"	extql %1,%3,%1\n"
		"	extqh %2,%3,%2\n"
		"3:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %1,3b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %2,3b-2b(%0)\n"
		".previous"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
@@ -944,16 +894,10 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"3:	stq_u %2,1(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %2,5b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %1,5b-2b(%0)\n"
		"	.long 3b - .\n"
		"	lda $31,5b-3b(%0)\n"
		"	.long 4b - .\n"
		"	lda $31,5b-4b(%0)\n"
		".previous"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(*reg_addr), "0"(0));
@@ -978,16 +922,10 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"3:	stq_u %2,3(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		".section __ex_table,\"a\"\n"
		"	.long 1b - .\n"
		"	lda %2,5b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %1,5b-2b(%0)\n"
		"	.long 3b - .\n"
		"	lda $31,5b-3b(%0)\n"
		"	.long 4b - .\n"
		"	lda $31,5b-4b(%0)\n"
		".previous"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(*reg_addr), "0"(0));
@@ -1012,16 +950,10 @@ do_entUnaUser(void __user * va, unsigned long opcode,
		"3:	stq_u %2,7(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		".section __ex_table,\"a\"\n\t"
		"	.long 1b - .\n"
		"	lda %2,5b-1b(%0)\n"
		"	.long 2b - .\n"
		"	lda %1,5b-2b(%0)\n"
		"	.long 3b - .\n"
		"	lda $31,5b-3b(%0)\n"
		"	.long 4b - .\n"
		"	lda $31,5b-4b(%0)\n"
		".previous"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(*reg_addr), "0"(0));
@@ -1047,7 +979,7 @@ give_sigsegv:
	/* We need to replicate some of the logic in mm/fault.c,
	   since we don't have access to the fault code in the
	   exception handling return path.  */
	if (!__access_ok((unsigned long)va, 0, USER_DS))
	if ((unsigned long)va >= TASK_SIZE)
		info.si_code = SEGV_ACCERR;
	else {
		struct mm_struct *mm = current->mm;
+26 −40
Original line number Diff line number Diff line
@@ -8,21 +8,6 @@
 * right "bytes left to zero" value (and that it is updated only _after_
 * a successful copy).  There is also some rather minor exception setup
 * stuff.
 *
 * NOTE! This is not directly C-callable, because the calling semantics
 * are different:
 *
 * Inputs:
 *	length in $0
 *	destination address in $6
 *	exception pointer in $7
 *	return address in $28 (exceptions expect it there)
 *
 * Outputs:
 *	bytes left to copy in $0
 *
 * Clobbers:
 *	$1,$2,$3,$4,$5,$6
 */
#include <asm/export.h>

@@ -38,62 +23,63 @@
	.set noreorder
	.align 4

	.globl __do_clear_user
	.ent __do_clear_user
	.frame	$30, 0, $28
	.globl __clear_user
	.ent __clear_user
	.frame	$30, 0, $26
	.prologue 0

$loop:
	and	$1, 3, $4	# e0    :
	beq	$4, 1f		# .. e1 :

0:	EX( stq_u $31, 0($6) )	# e0    : zero one word
0:	EX( stq_u $31, 0($16) )	# e0    : zero one word
	subq	$0, 8, $0	# .. e1 :
	subq	$4, 1, $4	# e0    :
	addq	$6, 8, $6	# .. e1 :
	addq	$16, 8, $16	# .. e1 :
	bne	$4, 0b		# e1    :
	unop			#       :

1:	bic	$1, 3, $1	# e0    :
	beq	$1, $tail	# .. e1 :

2:	EX( stq_u $31, 0($6) )	# e0    : zero four words
2:	EX( stq_u $31, 0($16) )	# e0    : zero four words
	subq	$0, 8, $0	# .. e1 :
	EX( stq_u $31, 8($6) )	# e0    :
	EX( stq_u $31, 8($16) )	# e0    :
	subq	$0, 8, $0	# .. e1 :
	EX( stq_u $31, 16($6) )	# e0    :
	EX( stq_u $31, 16($16) )	# e0    :
	subq	$0, 8, $0	# .. e1 :
	EX( stq_u $31, 24($6) )	# e0    :
	EX( stq_u $31, 24($16) )	# e0    :
	subq	$0, 8, $0	# .. e1 :
	subq	$1, 4, $1	# e0    :
	addq	$6, 32, $6	# .. e1 :
	addq	$16, 32, $16	# .. e1 :
	bne	$1, 2b		# e1    :

$tail:
	bne	$2, 1f		# e1    : is there a tail to do?
	ret	$31, ($28), 1	# .. e1 :
	ret	$31, ($26), 1	# .. e1 :

1:	EX( ldq_u $5, 0($6) )	# e0    :
1:	EX( ldq_u $5, 0($16) )	# e0    :
	clr	$0		# .. e1 :
	nop			# e1    :
	mskqh	$5, $0, $5	# e0    :
	EX( stq_u $5, 0($6) )	# e0    :
	ret	$31, ($28), 1	# .. e1 :
	EX( stq_u $5, 0($16) )	# e0    :
	ret	$31, ($26), 1	# .. e1 :

__do_clear_user:
	and	$6, 7, $4	# e0    : find dest misalignment
__clear_user:
	and	$17, $17, $0
	and	$16, 7, $4	# e0    : find dest misalignment
	beq	$0, $zerolength # .. e1 :
	addq	$0, $4, $1	# e0    : bias counter
	and	$1, 7, $2	# e1    : number of bytes in tail
	srl	$1, 3, $1	# e0    :
	beq	$4, $loop	# .. e1 :

	EX( ldq_u $5, 0($6) )	# e0    : load dst word to mask back in
	EX( ldq_u $5, 0($16) )	# e0    : load dst word to mask back in
	beq	$1, $oneword	# .. e1 : sub-word store?

	mskql	$5, $6, $5	# e0    : take care of misaligned head
	addq	$6, 8, $6	# .. e1 :
	EX( stq_u $5, -8($6) )	# e0    :
	mskql	$5, $16, $5	# e0    : take care of misaligned head
	addq	$16, 8, $16	# .. e1 :
	EX( stq_u $5, -8($16) )	# e0    :
	addq	$0, $4, $0	# .. e1 : bytes left -= 8 - misalignment
	subq	$1, 1, $1	# e0    :
	subq	$0, 8, $0	# .. e1 :
@@ -101,15 +87,15 @@ __do_clear_user:
	unop			#       :

$oneword:
	mskql	$5, $6, $4	# e0    :
	mskql	$5, $16, $4	# e0    :
	mskqh	$5, $2, $5	# e0    :
	or	$5, $4, $5	# e1    :
	EX( stq_u $5, 0($6) )	# e0    :
	EX( stq_u $5, 0($16) )	# e0    :
	clr	$0		# .. e1 :

$zerolength:
$exception:
	ret	$31, ($28), 1	# .. e1 :
	ret	$31, ($26), 1	# .. e1 :

	.end __do_clear_user
	EXPORT_SYMBOL(__do_clear_user)
	.end __clear_user
	EXPORT_SYMBOL(__clear_user)
Loading