summaryrefslogtreecommitdiffstats
path: root/arch/i386/lib
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/i386/lib
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/i386/lib')
-rw-r--r--arch/i386/lib/.cvsignore1
-rw-r--r--arch/i386/lib/Makefile2
-rw-r--r--arch/i386/lib/checksum.c2
-rw-r--r--arch/i386/lib/delay.c8
-rw-r--r--arch/i386/lib/getuser.S73
-rw-r--r--arch/i386/lib/putuser.S71
-rw-r--r--arch/i386/lib/usercopy.c136
7 files changed, 284 insertions, 9 deletions
diff --git a/arch/i386/lib/.cvsignore b/arch/i386/lib/.cvsignore
index 4671378ae..857dd22e9 100644
--- a/arch/i386/lib/.cvsignore
+++ b/arch/i386/lib/.cvsignore
@@ -1 +1,2 @@
.depend
+.*.flags
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
index 6b76e32d6..a4e4b1486 100644
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -11,6 +11,6 @@ else
endif
L_TARGET = lib.a
-L_OBJS = checksum.o semaphore.o locks.o delay.o
+L_OBJS = checksum.o semaphore.o locks.o delay.o usercopy.o getuser.o putuser.o
include $(TOPDIR)/Rules.make
diff --git a/arch/i386/lib/checksum.c b/arch/i386/lib/checksum.c
index 2293a6c5e..88f250d62 100644
--- a/arch/i386/lib/checksum.c
+++ b/arch/i386/lib/checksum.c
@@ -208,7 +208,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
# Exception handler:
################################################
#
-.section .fixup, \"a\" #
+.section .fixup, \"ax\" #
#
6000: #
#
diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c
index 4afc206e5..12b6b4683 100644
--- a/arch/i386/lib/delay.c
+++ b/arch/i386/lib/delay.c
@@ -15,12 +15,6 @@
#include <asm/smp.h>
#endif
-#ifdef __SMP__
-#define __udelay_val cpu_data[smp_processor_id()].udelay_val
-#else
-#define __udelay_val loops_per_sec
-#endif
-
void __delay(unsigned long loops)
{
__asm__ __volatile__(
@@ -34,7 +28,7 @@ inline void __const_udelay(unsigned long xloops)
{
__asm__("mull %0"
:"=d" (xloops)
- :"a" (xloops),"0" (__udelay_val)
+ :"a" (xloops),"0" (current_cpu_data.loops_per_sec)
:"ax");
__delay(xloops);
}
diff --git a/arch/i386/lib/getuser.S b/arch/i386/lib/getuser.S
new file mode 100644
index 000000000..c244721e7
--- /dev/null
+++ b/arch/i386/lib/getuser.S
@@ -0,0 +1,73 @@
+/*
+ * __get_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
+ */
+
+/*
+ * __get_user_X
+ *
+ * Inputs: %eax contains the address
+ *
+ * Outputs: %eax is error code (0 or -EFAULT)
+ * %edx contains zero-extended value
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+addr_limit = 12
+
+.text
+.align 4
+.globl __get_user_1
+__get_user_1:
+ movl %esp,%edx
+ andl $0xffffe000,%edx
+ cmpl addr_limit(%edx),%eax
+ jae bad_get_user
+1: movzbl (%eax),%edx
+ xorl %eax,%eax
+ ret
+
+.align 4
+.globl __get_user_2
+__get_user_2:
+ addl $1,%eax
+ movl %esp,%edx
+ jc bad_get_user
+ andl $0xffffe000,%edx
+ cmpl addr_limit(%edx),%eax
+ jae bad_get_user
+2: movzwl -1(%eax),%edx
+ xorl %eax,%eax
+ ret
+
+.align 4
+.globl __get_user_4
+__get_user_4:
+ addl $3,%eax
+ movl %esp,%edx
+ jc bad_get_user
+ andl $0xffffe000,%edx
+ cmpl addr_limit(%edx),%eax
+ jae bad_get_user
+3: movl -3(%eax),%edx
+ xorl %eax,%eax
+ ret
+
+bad_get_user:
+ xorl %edx,%edx
+ movl $-14,%eax
+ ret
+
+.section __ex_table,"a"
+ .long 1b,bad_get_user
+ .long 2b,bad_get_user
+ .long 3b,bad_get_user
+.previous
diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser.S
new file mode 100644
index 000000000..ee56d83f7
--- /dev/null
+++ b/arch/i386/lib/putuser.S
@@ -0,0 +1,71 @@
+/*
+ * __put_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient.
+ */
+
+/*
+ * __put_user_X
+ *
+ * Inputs: %eax contains the address
+ * %edx contains the value
+ *
+ * Outputs: %eax is error code (0 or -EFAULT)
+ * %ecx is corrupted (will contain "current_task").
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+addr_limit = 12
+
+.text
+.align 4
+.globl __put_user_1
+__put_user_1:
+ movl %esp,%ecx
+ andl $0xffffe000,%ecx
+ cmpl addr_limit(%ecx),%eax
+ jae bad_put_user
+1: movb %dl,(%eax)
+ xorl %eax,%eax
+ ret
+
+.align 4
+.globl __put_user_2
+__put_user_2:
+ addl $1,%eax
+ movl %esp,%ecx
+ jc bad_put_user
+ andl $0xffffe000,%ecx
+ cmpl addr_limit(%ecx),%eax
+ jae bad_put_user
+2: movw %dx,-1(%eax)
+ xorl %eax,%eax
+ ret
+
+.align 4
+.globl __put_user_4
+__put_user_4:
+ addl $3,%eax
+ movl %esp,%ecx
+ jc bad_put_user
+ andl $0xffffe000,%ecx
+ cmpl addr_limit(%ecx),%eax
+ jae bad_put_user
+3: movl %edx,-3(%eax)
+ xorl %eax,%eax
+ ret
+
+bad_put_user:
+ movl $-14,%eax
+ ret
+
+.section __ex_table,"a"
+ .long 1b,bad_put_user
+ .long 2b,bad_put_user
+ .long 3b,bad_put_user
+.previous
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
new file mode 100644
index 000000000..6b313d99c
--- /dev/null
+++ b/arch/i386/lib/usercopy.c
@@ -0,0 +1,136 @@
+/*
+ * User address space access functions.
+ * The non inlined parts of asm-i386/uaccess.h are here.
+ *
+ * Copyright 1997 Andi Kleen <ak@muc.de>
+ * Copyright 1997 Linus Torvalds
+ */
+#include <asm/uaccess.h>
+
+inline unsigned long
+__generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ __copy_user(to,from,n);
+ return n;
+}
+
+inline unsigned long
+__generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ __copy_user(to,from,n);
+ return n;
+}
+
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+#define __do_strncpy_from_user(dst,src,count,res) \
+ __asm__ __volatile__( \
+ " testl %1,%1\n" \
+ " jz 2f\n" \
+ "0: lodsb\n" \
+ " stosb\n" \
+ " testb %%al,%%al\n" \
+ " jz 1f\n" \
+ " decl %1\n" \
+ " jnz 0b\n" \
+ "1: subl %1,%0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: movl %2,%0\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,3b\n" \
+ ".previous" \
+ : "=d"(res), "=c"(count) \
+ : "i"(-EFAULT), "0"(count), "1"(count), "S"(src), "D"(dst) \
+ : "si", "di", "ax", "memory")
+
+long
+__strncpy_from_user(char *dst, const char *src, long count)
+{
+ long res;
+ __do_strncpy_from_user(dst, src, count, res);
+ return res;
+}
+
+long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+ long res = -EFAULT;
+ if (access_ok(VERIFY_READ, src, 1))
+ __do_strncpy_from_user(dst, src, count, res);
+ return res;
+}
+
+
+/*
+ * Zero Userspace
+ */
+
+#define __do_clear_user(addr,size) \
+ __asm__ __volatile__( \
+ "0: rep; stosl\n" \
+ " movl %1,%0\n" \
+ "1: rep; stosb\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: lea 0(%1,%0,4),%0\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,3b\n" \
+ " .long 1b,2b\n" \
+ ".previous" \
+ : "=&c"(size) \
+ : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \
+ : "di")
+
+unsigned long
+clear_user(void *to, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ __do_clear_user(to, n);
+ return n;
+}
+
+unsigned long
+__clear_user(void *to, unsigned long n)
+{
+ __do_clear_user(to, n);
+ return n;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+
+long strlen_user(const char *s)
+{
+ unsigned long res;
+
+ __asm__ __volatile__(
+ "0: repne; scasb\n"
+ " notl %0\n"
+ "1:\n"
+ ".section .fixup,\"ax\"\n"
+ "2: xorl %0,%0\n"
+ " jmp 1b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,2b\n"
+ ".previous"
+ :"=c" (res), "=D" (s)
+ :"1" (s), "a" (0), "0" (-__addr_ok(s)));
+ return res & -__addr_ok(s);
+}