linux-mips
[Top] [All Lists]

[PATCH] Introduce __fill_user() and kill __bzero() [take #3]

To: Ralf Baechle <ralf@linux-mips.org>
Subject: [PATCH] Introduce __fill_user() and kill __bzero() [take #3]
From: Franck Bui-Huu <fbuihuu@gmail.com>
Date: Fri, 16 Nov 2007 13:43:30 +0100
Cc: Thiemo Seufer <ths@networkno.de>, Geert Uytterhoeven <geert@linux-m68k.org>, linux-mips <linux-mips@linux-mips.org>
Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:user-agent:mime-version:to:cc:subject:x-enigmail-version:content-type:content-transfer-encoding; bh=/ChyIysmlntpM+gH5nYHv9L/fI8kdtyNENbO3Sf/Z9I=; b=CnRP5KLyv5wTl7IJ+lUFyhOyhjLgXIlK9/wkkq9+4Rexd/TIqbQn7FT5UVerbusIz5vlvmfUApbh2dvPB3gRUeFFpI8qrMzXRk55hKf3dUXsk57r8jVcgfqLAfdX+LGGvN4VBfKxk8HdJM/MIo2fnrzzUbXhZg0BO9SEtafkH6A=
Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:user-agent:mime-version:to:cc:subject:x-enigmail-version:content-type:content-transfer-encoding; b=Np6i8V/26289kSJb0/ka5gsz2k3Y5ywY1UprCOHignGgBYFdUI1qoPK4RsXpC6pQZSlx0nwg/LBLH2AY/W184lUSU2TUnwVTW3bEHwFKdiZdLDn+1jtobrFiUfc7UofDq+N4An1IUmPdsF8dYoA897NZNqMNHHBqoBFi97xAtrM=
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
User-agent: Thunderbird 2.0.0.5 (X11/20070719)
Currently memset() is used to fill a user space area (clear_user) or
kernel one (memset). These two functions don't have the same
prototype, the former returning the number of bytes not copied and the
latter returning the start address of the area to clear. This forces
memset() to actually returns two values in an unconventional way ie
the number of bytes not copied is given by $a2. Therefore clear_user()
needs to call memset() using inline assembly.

Instead this patch creates __fill_user() which is the same as memset()
except it always returns the number of bytes not copied. This simplify
clear_user() and makes its definition saner. This patch also renames
memset.S into fill_user.S as suggested by Thiemo.

Also an out of line version of memset is given because gcc generates
some calls to it since builtin functions have been disabled. It allows
assembly code to call it too. It has been put into a new file called
string.c.

Eventually __bzero() has been removed because it's not part of the
Linux uaccess API. And the nano-optimization it brings is not
worthing.

Signed-off-by: Franck Bui-Huu <fbuihuu@gmail.com>
---

 Ralf,

 Since you use git, this patch has been generated with rename detection
 enabled. It makes the review a lot easier.

 Please consider,

                Franck

 arch/mips/kernel/mips_ksyms.c           |    2 +-
 arch/mips/lib/Makefile                  |    4 +-
 arch/mips/lib/csum_partial.S            |    2 +-
 arch/mips/lib/{memset.S => fill_user.S} |   34 +++++++++++++++---------------
 arch/mips/lib/memcpy.S                  |    2 +-
 arch/mips/lib/string.c                  |   13 +++++++++++
 include/asm-mips/string.h               |    7 +++++-
 include/asm-mips/uaccess.h              |   17 ++------------
 8 files changed, 44 insertions(+), 37 deletions(-)
 rename arch/mips/lib/{memset.S => fill_user.S} (90%)
 create mode 100644 arch/mips/lib/string.c

diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 225755d..c7613d3 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -38,7 +38,7 @@ EXPORT_SYMBOL(kernel_thread);
  */
 EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(__copy_user_inatomic);
-EXPORT_SYMBOL(__bzero);
+EXPORT_SYMBOL(__fill_user);
 EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm);
 EXPORT_SYMBOL(__strncpy_from_user_asm);
 EXPORT_SYMBOL(__strlen_user_nocheck_asm);
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 8810dfb..1c3fea4 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,8 +2,8 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += csum_partial.o memcpy.o memcpy-inatomic.o memset.o strlen_user.o \
-          strncpy_user.o strnlen_user.o uncached.o
+lib-y  += csum_partial.o fill_user.o memcpy.o memcpy-inatomic.o string.o \
+          strlen_user.o strncpy_user.o strnlen_user.o uncached.o
 
 obj-y                  += iomap.o
 obj-$(CONFIG_PCI)      += iomap-pci.o
diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S
index c0a77fe..8d3fa1e 100644
--- a/arch/mips/lib/csum_partial.S
+++ b/arch/mips/lib/csum_partial.S
@@ -694,7 +694,7 @@ l_exc:
        ADD     dst, t0                 # compute start address in a1
        SUB     dst, src
        /*
-        * Clear len bytes starting at dst.  Can't call __bzero because it
+        * Clear len bytes starting at dst.  Can't call memset because it
         * might modify len.  An inefficient loop for these rare times...
         */
        beqz    len, done
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/fill_user.S
similarity index 90%
rename from arch/mips/lib/memset.S
rename to arch/mips/lib/fill_user.S
index 3f8b8b3..4329811 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/fill_user.S
@@ -46,17 +46,19 @@
        .endm
 
 /*
- * memset(void *s, int c, size_t n)
+ * __kernel_size_t __fill_user(void __user *s, long c, __kernel_size_t n)
  *
  * a0: start of area to clear
  * a1: char to fill with
  * a2: size of area to clear
+ *
+ * Returns the number of bytes NOT set or 0 on success.
  */
        .set    noreorder
        .align  5
-LEAF(memset)
+LEAF(__fill_user)
        beqz            a1, 1f
-        move           v0, a0                  /* result */
+        move           v0, zero                /* result */
 
        andi            a1, 0xff                /* spread fillword */
        LONG_SLL                t1, a1, 8
@@ -68,8 +70,6 @@ LEAF(memset)
 #endif
        or              a1, t1
 1:
-
-FEXPORT(__bzero)
        sltiu           t0, a2, LONGSIZE        /* very small region? */
        bnez            t0, small_memset
         andi           t0, a0, LONGMASK        /* aligned? */
@@ -127,7 +127,7 @@ memset_partial:
        EX(LONG_S_L, a1, -1(a0), last_fixup)
 #endif
 1:     jr              ra
-        move           a2, zero
+        nop
 
 small_memset:
        beqz            a2, 2f
@@ -138,29 +138,29 @@ small_memset:
         sb             a1, -1(a0)
 
 2:     jr              ra                      /* done */
-        move           a2, zero
-       END(memset)
+        nop
+END(__fill_user)
 
 first_fixup:
-       jr      ra
-        nop
+       jr              ra
+        move           v0, a2
 
 fwd_fixup:
        PTR_L           t0, TI_TASK($28)
        LONG_L          t0, THREAD_BUADDR(t0)
-       andi            a2, 0x3f
-       LONG_ADDU       a2, t1
+       andi            v0, a2, 0x3f
+       LONG_ADDU       v0, t1
        jr              ra
-        LONG_SUBU      a2, t0
+        LONG_SUBU      v0, t0
 
 partial_fixup:
        PTR_L           t0, TI_TASK($28)
        LONG_L          t0, THREAD_BUADDR(t0)
-       andi            a2, LONGMASK
-       LONG_ADDU       a2, t1
+       andi            v0, a2, LONGMASK
+       LONG_ADDU       v0, t1
        jr              ra
-        LONG_SUBU      a2, t0
+        LONG_SUBU      v0, t0
 
 last_fixup:
        jr              ra
-        andi           v1, a2, LONGMASK
+        andi           v0, a2, LONGMASK
diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S
index a526c62..425f2c3 100644
--- a/arch/mips/lib/memcpy.S
+++ b/arch/mips/lib/memcpy.S
@@ -443,7 +443,7 @@ l_exc:
        ADD     dst, t0                 # compute start address in a1
        SUB     dst, src
        /*
-        * Clear len bytes starting at dst.  Can't call __bzero because it
+        * Clear len bytes starting at dst.  Can't call memset because it
         * might modify len.  An inefficient loop for these rare times...
         */
        beqz    len, done
diff --git a/arch/mips/lib/string.c b/arch/mips/lib/string.c
new file mode 100644
index 0000000..42fb613
--- /dev/null
+++ b/arch/mips/lib/string.c
@@ -0,0 +1,13 @@
+#include <linux/kernel.h>
+
+#include <asm/uaccess.h>
+
+/*
+ * An outline version of memset, which should be used either by gcc or
+ * by assembly code.
+ */
+void *memset(void *s, int c, __kernel_size_t len)
+{
+       __fill_user(s, c, len);
+       return s;
+}
diff --git a/include/asm-mips/string.h b/include/asm-mips/string.h
index 436e3ad..2bba927 100644
--- a/include/asm-mips/string.h
+++ b/include/asm-mips/string.h
@@ -10,6 +10,7 @@
 #ifndef _ASM_STRING_H
 #define _ASM_STRING_H
 
+#include <asm/uaccess.h>       /* __fill_user() */
 
 /*
  * Most of the inline functions are rather naive implementations so I just
@@ -132,7 +133,11 @@ strncmp(__const__ char *__cs, __const__ char *__ct, size_t 
__count)
 #endif /* CONFIG_32BIT */
 
 #define __HAVE_ARCH_MEMSET
-extern void *memset(void *__s, int __c, size_t __count);
+extern inline void *memset(void *s, int c, size_t count)
+{
+       __fill_user(s, c, count);
+       return s;
+}
 
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h
index c30c718..8c0d226 100644
--- a/include/asm-mips/uaccess.h
+++ b/include/asm-mips/uaccess.h
@@ -11,7 +11,6 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/thread_info.h>
 #include <asm-generic/uaccess.h>
 
 /*
@@ -633,23 +632,13 @@ extern size_t __copy_user_inatomic(void *__to, const void 
*__from, size_t __n);
  * Returns number of bytes that could not be cleared.
  * On success, this will be zero.
  */
+extern __kernel_size_t __fill_user(void __user *s, long c, __kernel_size_t n);
+
 static inline __kernel_size_t
 __clear_user(void __user *addr, __kernel_size_t size)
 {
-       __kernel_size_t res;
-
        might_sleep();
-       __asm__ __volatile__(
-               "move\t$4, %1\n\t"
-               "move\t$5, $0\n\t"
-               "move\t$6, %2\n\t"
-               __MODULE_JAL(__bzero)
-               "move\t%0, $6"
-               : "=r" (res)
-               : "r" (addr), "r" (size)
-               : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
-
-       return res;
+       return __fill_user(addr, 0, size);
 }
 
 #define clear_user(addr,n)                                             \
-- 
1.5.3.5



<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] Introduce __fill_user() and kill __bzero() [take #3], Franck Bui-Huu <=