copy_page.o delay.o findbit.o memchr.o memcpy.o    \
                   memmove.o memset.o memzero.o setbit.o              \
                   strncpy_from_user.o strnlen_user.o                 \
-                  strchr.o strrchr.o testchangebit.o                 \
-                  testclearbit.o testsetbit.o uaccess.o              \
+                  strchr.o strrchr.o                                 \
+                  testchangebit.o testclearbit.o testsetbit.o        \
                   getuser.o putuser.o clear_user.o                   \
                   ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
                   ucmpdi2.o lib1funcs.o div64.o sha1.o               \
                   io-readsb.o io-writesb.o io-readsl.o io-writesl.o
 
+# the code in uaccess.S is not preemption safe and
+# probably faster on ARMv3 only
+ifeq ($CONFIG_PREEMPT,y)
+  lib-y        += copy_from_user.o copy_to_user.o
+else
+ifneq ($(CONFIG_CPU_32v3),y)
+  lib-y        += copy_from_user.o copy_to_user.o
+else
+  lib-y        += uaccess.o
+endif
+endif
+
 ifeq ($(CONFIG_CPU_32v3),y)
   lib-y        += io-readsw-armv3.o io-writesw-armv3.o
 else
 
--- /dev/null
+/*
+ *  linux/arch/arm/lib/copy_from_user.S
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   Sep 29, 2005
+ *  Copyright: MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Prototype:
+ *
+ *     size_t __arch_copy_from_user(void *to, const void *from, size_t n)
+ *
+ * Purpose:
+ *
+ *     copy a block to kernel memory from user memory
+ *
+ * Params:
+ *
+ *     to = kernel memory
+ *     from = user memory
+ *     n = number of bytes to copy
+ *
+ * Return value:
+ *
+ *     Number of bytes NOT copied.
+ */
+
+       .macro ldr1w ptr reg abort
+100:   ldrt \reg, [\ptr], #4
+       .section __ex_table, "a"
+       .long 100b, \abort
+       .previous
+       .endm
+
+       .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+       ldr1w \ptr, \reg1, \abort
+       ldr1w \ptr, \reg2, \abort
+       ldr1w \ptr, \reg3, \abort
+       ldr1w \ptr, \reg4, \abort
+       .endm
+
+       .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+       ldr4w \ptr, \reg1, \reg2, \reg3, \reg4, \abort
+       ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort
+       .endm
+
+       .macro ldr1b ptr reg cond=al abort
+100:   ldr\cond\()bt \reg, [\ptr], #1
+       .section __ex_table, "a"
+       .long 100b, \abort
+       .previous
+       .endm
+
+       .macro str1w ptr reg abort
+       str \reg, [\ptr], #4
+       .endm
+
+       .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+       stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+       .endm
+
+       .macro str1b ptr reg cond=al abort
+       str\cond\()b \reg, [\ptr], #1
+       .endm
+
+       .macro enter reg1 reg2
+       mov     r3, #0
+       stmdb   sp!, {r0, r2, r3, \reg1, \reg2}
+       .endm
+
+       .macro exit reg1 reg2
+       add     sp, sp, #8
+       ldmfd   sp!, {r0, \reg1, \reg2}
+       .endm
+
+       .text
+
+ENTRY(__arch_copy_from_user)
+
+#include "copy_template.S"
+
+       .section .fixup,"ax"
+       .align 0
+       copy_abort_preamble
+       ldmfd   sp!, {r1, r2}
+       sub     r3, r0, r1
+       rsb     r1, r3, r2
+       str     r1, [sp]
+       bl      __memzero
+       ldr     r0, [sp], #4
+       copy_abort_end
+       .previous
+
 
--- /dev/null
+/*
+ *  linux/arch/arm/lib/copy_to_user.S
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   Sep 29, 2005
+ *  Copyright: MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Prototype:
+ *
+ *     size_t __arch_copy_to_user(void *to, const void *from, size_t n)
+ *
+ * Purpose:
+ *
+ *     copy a block to user memory from kernel memory
+ *
+ * Params:
+ *
+ *     to = user memory
+ *     from = kernel memory
+ *     n = number of bytes to copy
+ *
+ * Return value:
+ *
+ *     Number of bytes NOT copied.
+ */
+
+       .macro ldr1w ptr reg abort
+       ldr \reg, [\ptr], #4
+       .endm
+
+       .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+       ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
+       .endm
+
+       .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+       ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+       .endm
+
+       .macro ldr1b ptr reg cond=al abort
+       ldr\cond\()b \reg, [\ptr], #1
+       .endm
+
+       .macro str1w ptr reg abort
+100:   strt \reg, [\ptr], #4
+       .section __ex_table, "a"
+       .long 100b, \abort
+       .previous
+       .endm
+
+       .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+       str1w \ptr, \reg1, \abort
+       str1w \ptr, \reg2, \abort
+       str1w \ptr, \reg3, \abort
+       str1w \ptr, \reg4, \abort
+       str1w \ptr, \reg5, \abort
+       str1w \ptr, \reg6, \abort
+       str1w \ptr, \reg7, \abort
+       str1w \ptr, \reg8, \abort
+       .endm
+
+       .macro str1b ptr reg cond=al abort
+100:   str\cond\()bt \reg, [\ptr], #1
+       .section __ex_table, "a"
+       .long 100b, \abort
+       .previous
+       .endm
+
+       .macro enter reg1 reg2
+       mov     r3, #0
+       stmdb   sp!, {r0, r2, r3, \reg1, \reg2}
+       .endm
+
+       .macro exit reg1 reg2
+       add     sp, sp, #8
+       ldmfd   sp!, {r0, \reg1, \reg2}
+       .endm
+
+       .text
+
+ENTRY(__arch_copy_to_user)
+
+#include "copy_template.S"
+
+       .section .fixup,"ax"
+       .align 0
+       copy_abort_preamble
+       ldmfd   sp!, {r1, r2, r3}
+       sub     r0, r0, r1
+       rsb     r0, r0, r2
+       copy_abort_end
+       .previous
+