summaryrefslogtreecommitdiffstats
path: root/arch/um/sys-i386
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/sys-i386
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/um/sys-i386')
-rw-r--r--arch/um/sys-i386/Makefile29
-rw-r--r--arch/um/sys-i386/bugs.c222
-rw-r--r--arch/um/sys-i386/checksum.S460
-rw-r--r--arch/um/sys-i386/delay.c14
-rw-r--r--arch/um/sys-i386/fault.c42
-rw-r--r--arch/um/sys-i386/ksyms.c17
-rw-r--r--arch/um/sys-i386/ldt.c98
-rw-r--r--arch/um/sys-i386/ptrace.c369
-rw-r--r--arch/um/sys-i386/ptrace_user.c131
-rw-r--r--arch/um/sys-i386/sigcontext.c71
-rw-r--r--arch/um/sys-i386/signal.c382
-rw-r--r--arch/um/sys-i386/syscalls.c210
-rw-r--r--arch/um/sys-i386/sysrq.c35
-rw-r--r--arch/um/sys-i386/util/Makefile8
-rw-r--r--arch/um/sys-i386/util/mk_sc.c52
-rw-r--r--arch/um/sys-i386/util/mk_thread_kern.c22
-rw-r--r--arch/um/sys-i386/util/mk_thread_user.c30
17 files changed, 2192 insertions, 0 deletions
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
new file mode 100644
index 00000000000..71b47e61860
--- /dev/null
+++ b/arch/um/sys-i386/Makefile
@@ -0,0 +1,29 @@
+obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+ ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o
+
+obj-$(CONFIG_HIGHMEM) += highmem.o
+obj-$(CONFIG_MODULES) += module.o
+
+USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
+
+include arch/um/scripts/Makefile.rules
+
+SYMLINKS = bitops.c semaphore.c highmem.c module.c
+
+# this needs to be before the foreach, because clean-files does not accept
+# complete paths like $(src)/$f.
+clean-files := $(SYMLINKS)
+
+targets += $(SYMLINKS)
+
+SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f)
+
+bitops.c-dir = lib
+semaphore.c-dir = kernel
+highmem.c-dir = mm
+module.c-dir = kernel
+
+$(SYMLINKS): FORCE
+ $(call if_changed,make_link)
+
+subdir- := util
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
new file mode 100644
index 00000000000..41b0ab2fe83
--- /dev/null
+++ b/arch/um/sys-i386/bugs.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <asm/ldt.h>
+#include "kern_util.h"
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "task.h"
+#include "os.h"
+
+#define MAXTOKEN 64
+
+/* Set during early boot */
+int host_has_cmov = 1;
+int host_has_xmm = 0;
+
+static char token(int fd, char *buf, int len, char stop)
+{
+ int n;
+ char *ptr, *end, c;
+
+ ptr = buf;
+ end = &buf[len];
+ do {
+ n = os_read_file(fd, ptr, sizeof(*ptr));
+ c = *ptr++;
+ if(n != sizeof(*ptr)){
+ if(n == 0) return(0);
+ printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
+ if(n < 0)
+ return(n);
+ else
+ return(-EIO);
+ }
+ } while((c != '\n') && (c != stop) && (ptr < end));
+
+ if(ptr == end){
+ printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
+ return(-1);
+ }
+ *(ptr - 1) = '\0';
+ return(c);
+}
+
+static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
+{
+ int n;
+ char c;
+
+ scratch[len - 1] = '\0';
+ while(1){
+ c = token(fd, scratch, len - 1, ':');
+ if(c <= 0)
+ return(0);
+ else if(c != ':'){
+ printk("Failed to find ':' in /proc/cpuinfo\n");
+ return(0);
+ }
+
+ if(!strncmp(scratch, key, strlen(key)))
+ return(1);
+
+ do {
+ n = os_read_file(fd, &c, sizeof(c));
+ if(n != sizeof(c)){
+ printk("Failed to find newline in "
+ "/proc/cpuinfo, err = %d\n", -n);
+ return(0);
+ }
+ } while(c != '\n');
+ }
+ return(0);
+}
+
+int cpu_feature(char *what, char *buf, int len)
+{
+ int fd, ret = 0;
+
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+ return(0);
+ }
+
+ if(!find_cpuinfo_line(fd, what, buf, len)){
+ printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
+ goto out_close;
+ }
+
+ token(fd, buf, len, '\n');
+ ret = 1;
+
+ out_close:
+ os_close_file(fd);
+ return(ret);
+}
+
+static int check_cpu_flag(char *feature, int *have_it)
+{
+ char buf[MAXTOKEN], c;
+ int fd, len = sizeof(buf)/sizeof(buf[0]);
+
+ printk("Checking for host processor %s support...", feature);
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+ return(0);
+ }
+
+ *have_it = 0;
+ if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
+ goto out;
+
+ c = token(fd, buf, len - 1, ' ');
+ if(c < 0) goto out;
+ else if(c != ' '){
+ printk("Failed to find ' ' in /proc/cpuinfo\n");
+ goto out;
+ }
+
+ while(1){
+ c = token(fd, buf, len - 1, ' ');
+ if(c < 0) goto out;
+ else if(c == '\n') break;
+
+ if(!strcmp(buf, feature)){
+ *have_it = 1;
+ goto out;
+ }
+ }
+ out:
+ if(*have_it == 0) printk("No\n");
+ else if(*have_it == 1) printk("Yes\n");
+ os_close_file(fd);
+ return(1);
+}
+
+#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
+ * for some people.
+ */
+static void disable_lcall(void)
+{
+ struct modify_ldt_ldt_s ldt;
+ int err;
+
+ bzero(&ldt, sizeof(ldt));
+ ldt.entry_number = 7;
+ ldt.base_addr = 0;
+ ldt.limit = 0;
+ err = modify_ldt(1, &ldt, sizeof(ldt));
+ if(err)
+ printk("Failed to disable lcall7 - errno = %d\n", errno);
+}
+#endif
+
+void arch_init_thread(void)
+{
+#if 0
+ disable_lcall();
+#endif
+}
+
+void arch_check_bugs(void)
+{
+ int have_it;
+
+ if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
+ printk("/proc/cpuinfo not available - skipping CPU capability "
+ "checks\n");
+ return;
+ }
+ if(check_cpu_flag("cmov", &have_it))
+ host_has_cmov = have_it;
+ if(check_cpu_flag("xmm", &have_it))
+ host_has_xmm = have_it;
+}
+
+int arch_handle_signal(int sig, union uml_pt_regs *regs)
+{
+ unsigned char tmp[2];
+
+ /* This is testing for a cmov (0x0f 0x4x) instruction causing a
+ * SIGILL in init.
+ */
+ if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
+
+ if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
+ panic("SIGILL in init, could not read instructions!\n");
+ if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
+ return(0);
+
+ if(host_has_cmov == 0)
+ panic("SIGILL caused by cmov, which this processor doesn't "
+ "implement, boot a filesystem compiled for older "
+ "processors");
+ else if(host_has_cmov == 1)
+ panic("SIGILL caused by cmov, which this processor claims to "
+ "implement");
+ else if(host_has_cmov == -1)
+ panic("SIGILL caused by cmov, couldn't tell if this processor "
+ "implements it, boot a filesystem compiled for older "
+ "processors");
+ else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
+ return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S
new file mode 100644
index 00000000000..a11171fb622
--- /dev/null
+++ b/arch/um/sys-i386/checksum.S
@@ -0,0 +1,460 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ * handling.
+ * Andi Kleen, add zeroing on error
+ * converted to pure assembler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/errno.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+.text
+.align 4
+.globl arch_csum_partial
+
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
+
+ /*
+ * Experiments with Ethernet and SLIP connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+arch_csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: unsigned char *buff
+ testl $2, %esi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%esi), %bx
+ addl $2, %esi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, %edx
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+1: movl (%esi), %ebx
+ adcl %ebx, %eax
+ movl 4(%esi), %ebx
+ adcl %ebx, %eax
+ movl 8(%esi), %ebx
+ adcl %ebx, %eax
+ movl 12(%esi), %ebx
+ adcl %ebx, %eax
+ movl 16(%esi), %ebx
+ adcl %ebx, %eax
+ movl 20(%esi), %ebx
+ adcl %ebx, %eax
+ movl 24(%esi), %ebx
+ adcl %ebx, %eax
+ movl 28(%esi), %ebx
+ adcl %ebx, %eax
+ lea 32(%esi), %esi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+3: adcl (%esi), %eax
+ lea 4(%esi), %esi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+ movw (%esi),%cx
+ leal 2(%esi),%esi
+ je 6f
+ shll $16,%ecx
+5: movb (%esi),%cl
+6: addl %ecx,%eax
+ adcl $0, %eax
+7:
+ popl %ebx
+ popl %esi
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+arch_csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: const unsigned char *buf
+
+ testl $2, %esi
+ jnz 30f
+10:
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ andl $0x7c, %ebx
+ shrl $7, %ecx
+ addl %ebx,%esi
+ shrl $2, %ebx
+ negl %ebx
+ lea 45f(%ebx,%ebx,2), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+
+ # Handle 2-byte-aligned regions
+20: addw (%esi), %ax
+ lea 2(%esi), %esi
+ adcl $0, %eax
+ jmp 10b
+
+30: subl $2, %ecx
+ ja 20b
+ je 32f
+ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
+ addl %ebx, %eax
+ adcl $0, %eax
+ jmp 80f
+32:
+ addw (%esi), %ax # csumming 2 bytes, 2-aligned
+ adcl $0, %eax
+ jmp 80f
+
+40:
+ addl -128(%esi), %eax
+ adcl -124(%esi), %eax
+ adcl -120(%esi), %eax
+ adcl -116(%esi), %eax
+ adcl -112(%esi), %eax
+ adcl -108(%esi), %eax
+ adcl -104(%esi), %eax
+ adcl -100(%esi), %eax
+ adcl -96(%esi), %eax
+ adcl -92(%esi), %eax
+ adcl -88(%esi), %eax
+ adcl -84(%esi), %eax
+ adcl -80(%esi), %eax
+ adcl -76(%esi), %eax
+ adcl -72(%esi), %eax
+ adcl -68(%esi), %eax
+ adcl -64(%esi), %eax
+ adcl -60(%esi), %eax
+ adcl -56(%esi), %eax
+ adcl -52(%esi), %eax
+ adcl -48(%esi), %eax
+ adcl -44(%esi), %eax
+ adcl -40(%esi), %eax
+ adcl -36(%esi), %eax
+ adcl -32(%esi), %eax
+ adcl -28(%esi), %eax
+ adcl -24(%esi), %eax
+ adcl -20(%esi), %eax
+ adcl -16(%esi), %eax
+ adcl -12(%esi), %eax
+ adcl -8(%esi), %eax
+ adcl -4(%esi), %eax
+45:
+ lea 128(%esi), %esi
+ adcl $0, %eax
+ dec %ecx
+ jge 40b
+ movl %edx, %ecx
+50: andl $3, %ecx
+ jz 80f
+
+ # Handle the last 1-3 bytes without jumping
+ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
+ movl $0xffffff,%ebx # by the shll and shrl instructions
+ shll $3,%ecx
+ shrl %cl,%ebx
+ andl -128(%esi),%ebx # esi is 4-aligned so should be ok
+ addl %ebx,%eax
+ adcl $0,%eax
+80:
+ popl %ebx
+ popl %esi
+ ret
+
+#endif
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+ int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+ */
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ * DST definitions? It's damn hard to trigger all cases. I hope I got
+ * them all but there's no guarantee.
+ */
+
+#define SRC(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6001f ; \
+ .previous
+
+#define DST(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6002f ; \
+ .previous
+
+.align 4
+.globl csum_partial_copy_generic_i386
+
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
+
+#define ARGBASE 16
+#define FP 12
+
+csum_partial_copy_generic_i386:
+ subl $4,%esp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ movl ARGBASE+16(%esp),%eax # sum
+ movl ARGBASE+12(%esp),%ecx # len
+ movl ARGBASE+4(%esp),%esi # src
+ movl ARGBASE+8(%esp),%edi # dst
+
+ testl $2, %edi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+SRC(1: movw (%esi), %bx )
+ addl $2, %esi
+DST( movw %bx, (%edi) )
+ addl $2, %edi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, FP(%esp)
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+SRC(1: movl (%esi), %ebx )
+SRC( movl 4(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 4(%edi) )
+
+SRC( movl 8(%esi), %ebx )
+SRC( movl 12(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 8(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 12(%edi) )
+
+SRC( movl 16(%esi), %ebx )
+SRC( movl 20(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 16(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 20(%edi) )
+
+SRC( movl 24(%esi), %ebx )
+SRC( movl 28(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 24(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 28(%edi) )
+
+ lea 32(%esi), %esi
+ lea 32(%edi), %edi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl FP(%esp), %edx
+ movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+SRC(3: movl (%esi), %ebx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ lea 4(%esi), %esi
+ lea 4(%edi), %edi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+SRC( movw (%esi), %cx )
+ leal 2(%esi), %esi
+DST( movw %cx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%ecx
+SRC(5: movb (%esi), %cl )
+DST( movb %cl, (%edi) )
+6: addl %ecx, %eax
+ adcl $0, %eax
+7:
+5000:
+
+# Exception handler:
+.section .fixup, "ax"
+
+6001:
+ movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+
+ # zero the complete destination - computing the rest
+ # is too much work
+ movl ARGBASE+8(%esp), %edi # dst
+ movl ARGBASE+12(%esp), %ecx # len
+ xorl %eax,%eax
+ rep ; stosb
+
+ jmp 5000b
+
+6002:
+ movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT,(%ebx)
+ jmp 5000b
+
+.previous
+
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ecx # equivalent to addl $4,%esp
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+#define ROUND1(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ addl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ROUND(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ adcl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ARGBASE 12
+
+csum_partial_copy_generic_i386:
+ pushl %ebx
+ pushl %edi
+ pushl %esi
+ movl ARGBASE+4(%esp),%esi #src
+ movl ARGBASE+8(%esp),%edi #dst
+ movl ARGBASE+12(%esp),%ecx #len
+ movl ARGBASE+16(%esp),%eax #sum
+# movl %ecx, %edx
+ movl %ecx, %ebx
+ movl %esi, %edx
+ shrl $6, %ecx
+ andl $0x3c, %ebx
+ negl %ebx
+ subl %ebx, %esi
+ subl %ebx, %edi
+ lea -1(%esi),%edx
+ andl $-32,%edx
+ lea 3f(%ebx,%ebx), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+1: addl $64,%esi
+ addl $64,%edi
+ SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
+ ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
+3: adcl $0,%eax
+ addl $64, %edx
+ dec %ecx
+ jge 1b
+4: movl ARGBASE+12(%esp),%edx #len
+ andl $3, %edx
+ jz 7f
+ cmpl $2, %edx
+ jb 5f
+SRC( movw (%esi), %dx )
+ leal 2(%esi), %esi
+DST( movw %dx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%edx
+5:
+SRC( movb (%esi), %dl )
+DST( movb %dl, (%edi) )
+6: addl %edx, %eax
+ adcl $0, %eax
+7:
+.section .fixup, "ax"
+6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+ # zero the complete destination (computing the rest is too much work)
+ movl ARGBASE+8(%esp),%edi # dst
+ movl ARGBASE+12(%esp),%ecx # len
+ xorl %eax,%eax
+ rep; stosb
+ jmp 7b
+6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT, (%ebx)
+ jmp 7b
+.previous
+
+ popl %esi
+ popl %edi
+ popl %ebx
+ ret
+
+#undef ROUND
+#undef ROUND1
+
+#endif
diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c
new file mode 100644
index 00000000000..20d37dbbaf0
--- /dev/null
+++ b/arch/um/sys-i386/delay.c
@@ -0,0 +1,14 @@
+void __delay(unsigned long time)
+{
+ /* Stolen from the i386 __loop_delay */
+ int d0;
+ __asm__ __volatile__(
+ "\tjmp 1f\n"
+ ".align 16\n"
+ "1:\tjmp 2f\n"
+ ".align 16\n"
+ "2:\tdecl %0\n\tjns 2b"
+ :"=&a" (d0)
+ :"0" (time));
+}
+
diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
new file mode 100644
index 00000000000..d0bbcdfdb53
--- /dev/null
+++ b/arch/um/sys-i386/fault.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+
+/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
+struct exception_table_entry
+{
+ unsigned long insn;
+ unsigned long fixup;
+};
+
+const struct exception_table_entry *search_exception_tables(unsigned long add);
+
+/* Compare this to arch/i386/mm/extable.c:fixup_exception() */
+int arch_fixup(unsigned long address, void *sc_ptr)
+{
+ struct sigcontext *sc = sc_ptr;
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(address);
+ if(fixup != 0){
+ sc->eip = fixup->fixup;
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c
new file mode 100644
index 00000000000..74f70a12045
--- /dev/null
+++ b/arch/um/sys-i386/ksyms.c
@@ -0,0 +1,17 @@
+#include "linux/module.h"
+#include "linux/in6.h"
+#include "linux/rwsem.h"
+#include "asm/byteorder.h"
+#include "asm/semaphore.h"
+#include "asm/uaccess.h"
+#include "asm/checksum.h"
+#include "asm/errno.h"
+
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__down_failed_trylock);
+EXPORT_SYMBOL(__up_wakeup);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_from);
+EXPORT_SYMBOL(csum_partial_copy_to);
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
new file mode 100644
index 00000000000..31bcb2f997d
--- /dev/null
+++ b/arch/um/sys-i386/ldt.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/slab.h"
+#include "asm/uaccess.h"
+#include "asm/ptrace.h"
+#include "choose-mode.h"
+#include "kern.h"
+
+#ifdef CONFIG_MODE_TT
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
+
+/* XXX this needs copy_to_user and copy_from_user */
+
+int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
+{
+ if (!access_ok(VERIFY_READ, ptr, bytecount))
+ return -EFAULT;
+
+ return modify_ldt(func, ptr, bytecount);
+}
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+extern int userspace_pid;
+
+#include "skas_ptrace.h"
+
+int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount)
+{
+ struct ptrace_ldt ldt;
+ void *buf;
+ int res, n;
+
+ buf = kmalloc(bytecount, GFP_KERNEL);
+ if(buf == NULL)
+ return(-ENOMEM);
+
+ res = 0;
+
+ switch(func){
+ case 1:
+ case 0x11:
+ res = copy_from_user(buf, ptr, bytecount);
+ break;
+ }
+
+ if(res != 0){
+ res = -EFAULT;
+ goto out;
+ }
+
+ ldt = ((struct ptrace_ldt) { .func = func,
+ .ptr = buf,
+ .bytecount = bytecount });
+ res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
+ if(res < 0)
+ goto out;
+
+ switch(func){
+ case 0:
+ case 2:
+ n = res;
+ res = copy_to_user(ptr, buf, n);
+ if(res != 0)
+ res = -EFAULT;
+ else
+ res = n;
+ break;
+ }
+
+ out:
+ kfree(buf);
+ return(res);
+}
+#endif
+
+int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
+{
+ return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
+ ptr, bytecount));
+}
+
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
new file mode 100644
index 00000000000..e470d28cdf8
--- /dev/null
+++ b/arch/um/sys-i386/ptrace.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/config.h>
+#include <linux/compiler.h>
+#include "linux/sched.h"
+#include "asm/elf.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/sc.h"
+
+void arch_switch(void)
+{
+ update_debugregs(current->thread.arch.debugregs_seq);
+}
+
+int is_syscall(unsigned long addr)
+{
+ unsigned short instr;
+ int n;
+
+ n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
+ if(n){
+ printk("is_syscall : failed to read instruction from 0x%lx\n",
+ addr);
+ return(0);
+ }
+ /* int 0x80 or sysenter */
+ return((instr == 0x80cd) || (instr == 0x340f));
+}
+
+/* determines which flags the user has access to. */
+/* 1 = access 0 = no access */
+#define FLAG_MASK 0x00044dd5
+
+int putreg(struct task_struct *child, int regno, unsigned long value)
+{
+ regno >>= 2;
+ switch (regno) {
+ case FS:
+ if (value && (value & 3) != 3)
+ return -EIO;
+ PT_REGS_FS(&child->thread.regs) = value;
+ return 0;
+ case GS:
+ if (value && (value & 3) != 3)
+ return -EIO;
+ PT_REGS_GS(&child->thread.regs) = value;
+ return 0;
+ case DS:
+ case ES:
+ if (value && (value & 3) != 3)
+ return -EIO;
+ value &= 0xffff;
+ break;
+ case SS:
+ case CS:
+ if ((value & 3) != 3)
+ return -EIO;
+ value &= 0xffff;
+ break;
+ case EFL:
+ value &= FLAG_MASK;
+ value |= PT_REGS_EFLAGS(&child->thread.regs);
+ break;
+ }
+ PT_REGS_SET(&child->thread.regs, regno, value);
+ return 0;
+}
+
+unsigned long getreg(struct task_struct *child, int regno)
+{
+ unsigned long retval = ~0UL;
+
+ regno >>= 2;
+ switch (regno) {
+ case FS:
+ case GS:
+ case DS:
+ case ES:
+ case SS:
+ case CS:
+ retval = 0xffff;
+ /* fall through */
+ default:
+ retval &= PT_REG(&child->thread.regs, regno);
+ }
+ return retval;
+}
+
+struct i387_fxsave_struct {
+ unsigned short cwd;
+ unsigned short swd;
+ unsigned short twd;
+ unsigned short fop;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long mxcsr;
+ long reserved;
+ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
+ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
+ long padding[56];
+};
+
+/*
+ * FPU tag word conversions.
+ */
+
+static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
+{
+ unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+
+ /* Transform each pair of bits into 01 (valid) or 00 (empty) */
+ tmp = ~twd;
+ tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+ /* and move the valid bits to the lower byte. */
+ tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+ tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+ tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+ return tmp;
+}
+
+static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
+{
+ struct _fpxreg *st = NULL;
+ unsigned long twd = (unsigned long) fxsave->twd;
+ unsigned long tag;
+ unsigned long ret = 0xffff0000;
+ int i;
+
+#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
+
+ for ( i = 0 ; i < 8 ; i++ ) {
+ if ( twd & 0x1 ) {
+ st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
+
+ switch ( st->exponent & 0x7fff ) {
+ case 0x7fff:
+ tag = 2; /* Special */
+ break;
+ case 0x0000:
+ if ( !st->significand[0] &&
+ !st->significand[1] &&
+ !st->significand[2] &&
+ !st->significand[3] ) {
+ tag = 1; /* Zero */
+ } else {
+ tag = 2; /* Special */
+ }
+ break;
+ default:
+ if ( st->significand[3] & 0x8000 ) {
+ tag = 0; /* Valid */
+ } else {
+ tag = 2; /* Special */
+ }
+ break;
+ }
+ } else {
+ tag = 3; /* Empty */
+ }
+ ret |= (tag << (2 * i));
+ twd = twd >> 1;
+ }
+ return ret;
+}
+
+/*
+ * FXSR floating point environment conversions.
+ */
+
+#ifdef CONFIG_MODE_TT
+static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf,
+ struct pt_regs *regs)
+{
+ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+ unsigned long env[7];
+ struct _fpreg __user *to;
+ struct _fpxreg *from;
+ int i;
+
+ env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
+ env[1] = (unsigned long)fxsave->swd | 0xffff0000;
+ env[2] = twd_fxsr_to_i387(fxsave);
+ env[3] = fxsave->fip;
+ env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
+ env[5] = fxsave->foo;
+ env[6] = fxsave->fos;
+
+ if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
+ return 1;
+
+ to = &buf->_st[0];
+ from = (struct _fpxreg *) &fxsave->st_space[0];
+ for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+ if ( __copy_to_user( to, from, sizeof(*to) ) )
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static inline int convert_fxsr_to_user(struct _fpstate __user *buf,
+ struct pt_regs *regs)
+{
+ return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
+}
+
+#ifdef CONFIG_MODE_TT
+static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
+ struct _fpstate __user *buf)
+{
+ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+ unsigned long env[7];
+ struct _fpxreg *to;
+ struct _fpreg __user *from;
+ int i;
+
+ if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
+ return 1;
+
+ fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+ fxsave->swd = (unsigned short)(env[1] & 0xffff);
+ fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
+ fxsave->fip = env[3];
+ fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
+ fxsave->fcs = (env[4] & 0xffff);
+ fxsave->foo = env[5];
+ fxsave->fos = env[6];
+
+ to = (struct _fpxreg *) &fxsave->st_space[0];
+ from = &buf->_st[0];
+ for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+ if ( __copy_from_user( to, from, sizeof(*from) ) )
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static inline int convert_fxsr_from_user(struct pt_regs *regs,
+ struct _fpstate __user *buf)
+{
+ return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0));
+}
+
+int get_fpregs(unsigned long buf, struct task_struct *child)
+{
+ int err;
+
+ err = convert_fxsr_to_user((struct _fpstate __user *) buf,
+ &child->thread.regs);
+ if(err) return(-EFAULT);
+ else return(0);
+}
+
+int set_fpregs(unsigned long buf, struct task_struct *child)
+{
+ int err;
+
+ err = convert_fxsr_from_user(&child->thread.regs,
+ (struct _fpstate __user *) buf);
+ if(err) return(-EFAULT);
+ else return(0);
+}
+
+#ifdef CONFIG_MODE_TT
+int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
+{
+ struct pt_regs *regs = &tsk->thread.regs;
+ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+ int err;
+
+ err = __copy_to_user((void __user *) buf, fxsave,
+ sizeof(struct user_fxsr_struct));
+ if(err) return -EFAULT;
+ else return 0;
+}
+#endif
+
+int get_fpxregs(unsigned long buf, struct task_struct *tsk)
+{
+ return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
+}
+
+#ifdef CONFIG_MODE_TT
+int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
+{
+ struct pt_regs *regs = &tsk->thread.regs;
+ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+ int err;
+
+ err = __copy_from_user(fxsave, (void __user *) buf,
+ sizeof(struct user_fxsr_struct) );
+ if(err) return -EFAULT;
+ else return 0;
+}
+#endif
+
+int set_fpxregs(unsigned long buf, struct task_struct *tsk)
+{
+ return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
+}
+
+#ifdef notdef
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+ fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
+ (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
+ fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
+ fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
+ fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
+ fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
+ fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
+ fpu->fos = 0;
+ memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
+ sizeof(fpu->st_space));
+ return(1);
+}
+#endif
+
+#ifdef CONFIG_MODE_TT
+static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
+ struct user_i387_struct *buf)
+{
+ struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
+ unsigned short *to;
+ unsigned short *from;
+ int i;
+
+ memcpy( buf, fpu, 7 * sizeof(long) );
+
+ to = (unsigned short *) &buf->st_space[0];
+ from = (unsigned short *) &fpu->st_space[0];
+ for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
+ memcpy( to, from, 5 * sizeof(unsigned short) );
+ }
+}
+#endif
+
+static inline void copy_fpu_fxsave(struct pt_regs *regs,
+ struct user_i387_struct *buf)
+{
+ (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
+}
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
+{
+ copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
+ return(1);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
new file mode 100644
index 00000000000..7c376c95de5
--- /dev/null
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/stddef.h>
+#include "ptrace_user.h"
+/* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */
+#include <asm/user.h>
+#include "kern_util.h"
+#include "sysdep/thread.h"
+#include "user.h"
+#include "os.h"
+
+int ptrace_getregs(long pid, unsigned long *regs_out)
+{
+ if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
+ return -errno;
+ return 0;
+}
+
+int ptrace_setregs(long pid, unsigned long *regs)
+{
+ if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0)
+ return -errno;
+ return 0;
+}
+
+int ptrace_getfpregs(long pid, unsigned long *regs)
+{
+ if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0)
+ return -errno;
+ return 0;
+}
+
+int ptrace_setfpregs(long pid, unsigned long *regs)
+{
+ if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
+ return -errno;
+ return 0;
+}
+
+static void write_debugregs(int pid, unsigned long *regs)
+{
+ struct user *dummy;
+ int nregs, i;
+
+ dummy = NULL;
+ nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
+ for(i = 0; i < nregs; i++){
+ if((i == 4) || (i == 5)) continue;
+ if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
+ regs[i]) < 0)
+ printk("write_debugregs - ptrace failed on "
+ "register %d, value = 0x%x, errno = %d\n", i,
+ regs[i], errno);
+ }
+}
+
+static void read_debugregs(int pid, unsigned long *regs)
+{
+ struct user *dummy;
+ int nregs, i;
+
+ dummy = NULL;
+ nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
+ for(i = 0; i < nregs; i++){
+ regs[i] = ptrace(PTRACE_PEEKUSR, pid,
+ &dummy->u_debugreg[i], 0);
+ }
+}
+
+/* Accessed only by the tracing thread */
+static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
+static int debugregs_seq = 0;
+
+void arch_enter_kernel(void *task, int pid)
+{
+ read_debugregs(pid, TASK_DEBUGREGS(task));
+ write_debugregs(pid, kernel_debugregs);
+}
+
+void arch_leave_kernel(void *task, int pid)
+{
+ read_debugregs(pid, kernel_debugregs);
+ write_debugregs(pid, TASK_DEBUGREGS(task));
+}
+
+void ptrace_pokeuser(unsigned long addr, unsigned long data)
+{
+ if((addr < offsetof(struct user, u_debugreg[0])) ||
+ (addr > offsetof(struct user, u_debugreg[7])))
+ return;
+ addr -= offsetof(struct user, u_debugreg[0]);
+ addr = addr >> 2;
+ if(kernel_debugregs[addr] == data) return;
+
+ kernel_debugregs[addr] = data;
+ debugregs_seq++;
+}
+
+static void update_debugregs_cb(void *arg)
+{
+ int pid = *((int *) arg);
+
+ write_debugregs(pid, kernel_debugregs);
+}
+
+void update_debugregs(int seq)
+{
+ int me;
+
+ if(seq == debugregs_seq) return;
+
+ me = os_getpid();
+ initial_thread_cb(update_debugregs_cb, &me);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c
new file mode 100644
index 00000000000..467d489c31c
--- /dev/null
+++ b/arch/um/sys-i386/sigcontext.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "kern_util.h"
+
+void sc_to_sc(void *to_ptr, void *from_ptr)
+{
+ struct sigcontext *to = to_ptr, *from = from_ptr;
+
+ memcpy(to, from, sizeof(*to) + sizeof(struct _fpstate));
+ if(from->fpstate != NULL)
+ to->fpstate = (struct _fpstate *) (to + 1);
+}
+
+unsigned long *sc_sigmask(void *sc_ptr)
+{
+ struct sigcontext *sc = sc_ptr;
+ return &sc->oldmask;
+}
+
+int sc_get_fpregs(unsigned long buf, void *sc_ptr)
+{
+ struct sigcontext *sc = sc_ptr;
+ struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf;
+ int err = 0;
+
+ if(from == NULL){
+ err |= clear_user_proc(&to->cw, sizeof(to->cw));
+ err |= clear_user_proc(&to->sw, sizeof(to->sw));
+ err |= clear_user_proc(&to->tag, sizeof(to->tag));
+ err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff));
+ err |= clear_user_proc(&to->cssel, sizeof(to->cssel));
+ err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff));
+ err |= clear_user_proc(&to->datasel, sizeof(to->datasel));
+ err |= clear_user_proc(&to->_st, sizeof(to->_st));
+ }
+ else {
+ err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw));
+ err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw));
+ err |= copy_to_user_proc(&to->tag, &from->tag,
+ sizeof(to->tag));
+ err |= copy_to_user_proc(&to->ipoff, &from->ipoff,
+ sizeof(to->ipoff));
+ err |= copy_to_user_proc(&to->cssel,& from->cssel,
+ sizeof(to->cssel));
+ err |= copy_to_user_proc(&to->dataoff, &from->dataoff,
+ sizeof(to->dataoff));
+ err |= copy_to_user_proc(&to->datasel, &from->datasel,
+ sizeof(to->datasel));
+ err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st));
+ }
+ return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
new file mode 100644
index 00000000000..76ba87254b2
--- /dev/null
+++ b/arch/um/sys-i386/signal.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/signal.h"
+#include "linux/ptrace.h"
+#include "asm/current.h"
+#include "asm/ucontext.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+#include "frame_kern.h"
+#include "signal_user.h"
+#include "sigcontext.h"
+#include "registers.h"
+#include "mode.h"
+
+#ifdef CONFIG_MODE_SKAS
+
+#include "skas.h"
+
+static int copy_sc_from_user_skas(struct pt_regs *regs,
+ struct sigcontext *from)
+{
+ struct sigcontext sc;
+ unsigned long fpregs[HOST_FP_SIZE];
+ int err;
+
+ err = copy_from_user(&sc, from, sizeof(sc));
+ err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
+ if(err)
+ return(err);
+
+ REGS_GS(regs->regs.skas.regs) = sc.gs;
+ REGS_FS(regs->regs.skas.regs) = sc.fs;
+ REGS_ES(regs->regs.skas.regs) = sc.es;
+ REGS_DS(regs->regs.skas.regs) = sc.ds;
+ REGS_EDI(regs->regs.skas.regs) = sc.edi;
+ REGS_ESI(regs->regs.skas.regs) = sc.esi;
+ REGS_EBP(regs->regs.skas.regs) = sc.ebp;
+ REGS_SP(regs->regs.skas.regs) = sc.esp;
+ REGS_EBX(regs->regs.skas.regs) = sc.ebx;
+ REGS_EDX(regs->regs.skas.regs) = sc.edx;
+ REGS_ECX(regs->regs.skas.regs) = sc.ecx;
+ REGS_EAX(regs->regs.skas.regs) = sc.eax;
+ REGS_IP(regs->regs.skas.regs) = sc.eip;
+ REGS_CS(regs->regs.skas.regs) = sc.cs;
+ REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
+ REGS_SS(regs->regs.skas.regs) = sc.ss;
+ regs->regs.skas.fault_addr = sc.cr2;
+ regs->regs.skas.fault_type = FAULT_WRITE(sc.err);
+ regs->regs.skas.trap_type = sc.trapno;
+
+ err = restore_fp_registers(userspace_pid[0], fpregs);
+ if(err < 0){
+ printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
+ "errno = %d\n", err);
+ return(1);
+ }
+
+ return(0);
+}
+
+int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
+ struct pt_regs *regs, unsigned long fault_addr,
+ int fault_type)
+{
+ struct sigcontext sc;
+ unsigned long fpregs[HOST_FP_SIZE];
+ int err;
+
+ sc.gs = REGS_GS(regs->regs.skas.regs);
+ sc.fs = REGS_FS(regs->regs.skas.regs);
+ sc.es = REGS_ES(regs->regs.skas.regs);
+ sc.ds = REGS_DS(regs->regs.skas.regs);
+ sc.edi = REGS_EDI(regs->regs.skas.regs);
+ sc.esi = REGS_ESI(regs->regs.skas.regs);
+ sc.ebp = REGS_EBP(regs->regs.skas.regs);
+ sc.esp = REGS_SP(regs->regs.skas.regs);
+ sc.ebx = REGS_EBX(regs->regs.skas.regs);
+ sc.edx = REGS_EDX(regs->regs.skas.regs);
+ sc.ecx = REGS_ECX(regs->regs.skas.regs);
+ sc.eax = REGS_EAX(regs->regs.skas.regs);
+ sc.eip = REGS_IP(regs->regs.skas.regs);
+ sc.cs = REGS_CS(regs->regs.skas.regs);
+ sc.eflags = REGS_EFLAGS(regs->regs.skas.regs);
+ sc.esp_at_signal = regs->regs.skas.regs[UESP];
+ sc.ss = regs->regs.skas.regs[SS];
+ sc.cr2 = fault_addr;
+ sc.err = TO_SC_ERR(fault_type);
+ sc.trapno = regs->regs.skas.trap_type;
+
+ err = save_fp_registers(userspace_pid[0], fpregs);
+ if(err < 0){
+ printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
+ "errno = %d\n", err);
+ return(1);
+ }
+ to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1));
+ sc.fpstate = to_fp;
+
+ if(err)
+ return(err);
+
+ return(copy_to_user(to, &sc, sizeof(sc)) ||
+ copy_to_user(to_fp, fpregs, sizeof(fpregs)));
+}
+#endif
+
+#ifdef CONFIG_MODE_TT
+
+/* These copy a sigcontext to/from userspace. They copy the fpstate pointer,
+ * blowing away the old, good one. So, that value is saved, and then restored
+ * after the sigcontext copy. In copy_from, the variable holding the saved
+ * fpstate pointer, and the sigcontext that it should be restored to are both
+ * in the kernel, so we can just restore using an assignment. In copy_to, the
+ * saved pointer is in the kernel, but the sigcontext is in userspace, so we
+ * copy_to_user it.
+ */
+int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
+ int fpsize)
+{
+ struct _fpstate *to_fp, *from_fp;
+ unsigned long sigs;
+ int err;
+
+ to_fp = to->fpstate;
+ from_fp = from->fpstate;
+ sigs = to->oldmask;
+ err = copy_from_user(to, from, sizeof(*to));
+ to->oldmask = sigs;
+ to->fpstate = to_fp;
+ if(to_fp != NULL)
+ err |= copy_from_user(to_fp, from_fp, fpsize);
+ return(err);
+}
+
+int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
+ struct sigcontext *from, int fpsize)
+{
+ struct _fpstate *to_fp, *from_fp;
+ int err;
+
+ to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
+ from_fp = from->fpstate;
+ err = copy_to_user(to, from, sizeof(*to));
+ if(from_fp != NULL){
+ err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
+ err |= copy_to_user(to_fp, from_fp, fpsize);
+ }
+ return(err);
+}
+#endif
+
+static int copy_sc_from_user(struct pt_regs *to, void __user *from)
+{
+ int ret;
+
+ ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
+ sizeof(struct _fpstate)),
+ copy_sc_from_user_skas(to, from));
+ return(ret);
+}
+
+static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
+ struct pt_regs *from)
+{
+ return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
+ sizeof(*fp)),
+ copy_sc_to_user_skas(to, fp, from,
+ current->thread.cr2,
+ current->thread.err)));
+}
+
+static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
+ sigset_t *set, unsigned long sp)
+{
+ int err = 0;
+
+ err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
+ err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
+ err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
+ err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs);
+ err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
+ return(err);
+}
+
+struct sigframe
+{
+ char *pretcode;
+ int sig;
+ struct sigcontext sc;
+ struct _fpstate fpstate;
+ unsigned long extramask[_NSIG_WORDS-1];
+ char retcode[8];
+};
+
+struct rt_sigframe
+{
+ char *pretcode;
+ int sig;
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+ struct _fpstate fpstate;
+ char retcode[8];
+};
+
+int setup_signal_stack_sc(unsigned long stack_top, int sig,
+ struct k_sigaction *ka, struct pt_regs *regs,
+ sigset_t *mask)
+{
+ struct sigframe __user *frame;
+ void *restorer;
+ int err = 0;
+
+ stack_top &= -8UL;
+ frame = (struct sigframe *) stack_top - 1;
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ return 1;
+
+ restorer = (void *) frame->retcode;
+ if(ka->sa.sa_flags & SA_RESTORER)
+ restorer = ka->sa.sa_restorer;
+
+ err |= __put_user(restorer, &frame->pretcode);
+ err |= __put_user(sig, &frame->sig);
+ err |= copy_sc_to_user(&frame->sc, NULL, regs);
+ err |= __put_user(mask->sig[0], &frame->sc.oldmask);
+ if (_NSIG_WORDS > 1)
+ err |= __copy_to_user(&frame->extramask, &mask->sig[1],
+ sizeof(frame->extramask));
+
+ /*
+ * This is popl %eax ; movl $,%eax ; int $0x80
+ *
+ * WE DO NOT USE IT ANY MORE! It's only left here for historical
+ * reasons and because gdb uses it as a signature to notice
+ * signal handler stack frames.
+ */
+ err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
+ err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
+ err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
+
+ if(err)
+ return(err);
+
+ PT_REGS_SP(regs) = (unsigned long) frame;
+ PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
+ PT_REGS_EAX(regs) = (unsigned long) sig;
+ PT_REGS_EDX(regs) = (unsigned long) 0;
+ PT_REGS_ECX(regs) = (unsigned long) 0;
+
+ if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+ ptrace_notify(SIGTRAP);
+ return(0);
+}
+
+int setup_signal_stack_si(unsigned long stack_top, int sig,
+ struct k_sigaction *ka, struct pt_regs *regs,
+ siginfo_t *info, sigset_t *mask)
+{
+ struct rt_sigframe __user *frame;
+ void *restorer;
+ int err = 0;
+
+ stack_top &= -8UL;
+ frame = (struct rt_sigframe *) stack_top - 1;
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ return 1;
+
+ restorer = (void *) frame->retcode;
+ if(ka->sa.sa_flags & SA_RESTORER)
+ restorer = ka->sa.sa_restorer;
+
+ err |= __put_user(restorer, &frame->pretcode);
+ err |= __put_user(sig, &frame->sig);
+ err |= __put_user(&frame->info, &frame->pinfo);
+ err |= __put_user(&frame->uc, &frame->puc);
+ err |= copy_siginfo_to_user(&frame->info, info);
+ err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
+ PT_REGS_SP(regs));
+
+ /*
+ * This is movl $,%eax ; int $0x80
+ *
+ * WE DO NOT USE IT ANY MORE! It's only left here for historical
+ * reasons and because gdb uses it as a signature to notice
+ * signal handler stack frames.
+ */
+ err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
+ err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
+ err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
+
+ if(err)
+ return(err);
+
+ PT_REGS_SP(regs) = (unsigned long) frame;
+ PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
+ PT_REGS_EAX(regs) = (unsigned long) sig;
+ PT_REGS_EDX(regs) = (unsigned long) &frame->info;
+ PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
+
+ if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+ ptrace_notify(SIGTRAP);
+ return(0);
+}
+
+long sys_sigreturn(struct pt_regs regs)
+{
+ unsigned long sp = PT_REGS_SP(&current->thread.regs);
+ struct sigframe __user *frame = (struct sigframe *)(sp - 8);
+ sigset_t set;
+ struct sigcontext __user *sc = &frame->sc;
+ unsigned long __user *oldmask = &sc->oldmask;
+ unsigned long __user *extramask = frame->extramask;
+ int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
+
+ if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) ||
+ copy_from_user(&set.sig[1], extramask, sig_size))
+ goto segfault;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if(copy_sc_from_user(&current->thread.regs, sc))
+ goto segfault;
+
+ /* Avoid ERESTART handling */
+ PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
+ return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+
+ segfault:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+long sys_rt_sigreturn(struct pt_regs regs)
+{
+ unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
+ struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4);
+ sigset_t set;
+ struct ucontext __user *uc = &frame->uc;
+ int sig_size = _NSIG_WORDS * sizeof(unsigned long);
+
+ if(copy_from_user(&set, &uc->uc_sigmask, sig_size))
+ goto segfault;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
+ goto segfault;
+
+ /* Avoid ERESTART handling */
+ PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
+ return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+
+ segfault:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
new file mode 100644
index 00000000000..335e2d89504
--- /dev/null
+++ b/arch/um/sys-i386/syscalls.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/shm.h"
+#include "asm/ipc.h"
+#include "asm/mman.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+extern int old_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long offset);
+
+long old_mmap_i386(struct mmap_arg_struct __user *arg)
+{
+ struct mmap_arg_struct a;
+ int err = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+
+ err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+ out:
+ return err;
+}
+
+struct sel_arg_struct {
+ unsigned long n;
+ fd_set __user *inp;
+ fd_set __user *outp;
+ fd_set __user *exp;
+ struct timeval __user *tvp;
+};
+
+long old_select(struct sel_arg_struct __user *arg)
+{
+ struct sel_arg_struct a;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ return -EFAULT;
+ /* sys_select() does the appropriate kernel locking */
+ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+
+/* The i386 version skips reading from %esi, the fourth argument. So we must do
+ * this, too.
+ */
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+ int __user *parent_tid, int unused, int __user *child_tid)
+{
+ long ret;
+
+ /* XXX: normal arch do here this pass, and also pass the regs to
+ * do_fork, instead of NULL. Currently the arch-independent code
+ * ignores these values, while the UML code (actually it's
+ * copy_thread) does the right thing. But this should change,
+ probably. */
+ /*if (!newsp)
+ newsp = UPT_SP(current->thread.regs);*/
+ current->thread.forking = 1;
+ ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+ current->thread.forking = 0;
+ return(ret);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+long sys_ipc (uint call, int first, int second,
+ int third, void __user *ptr, long fifth)
+{
+ int version, ret;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ switch (call) {
+ case SEMOP:
+ return sys_semtimedop(first, (struct sembuf *) ptr, second,
+ NULL);
+ case SEMTIMEDOP:
+ return sys_semtimedop(first, (struct sembuf *) ptr, second,
+ (const struct timespec *) fifth);
+ case SEMGET:
+ return sys_semget (first, second, third);
+ case SEMCTL: {
+ union semun fourth;
+ if (!ptr)
+ return -EINVAL;
+ if (get_user(fourth.__pad, (void **) ptr))
+ return -EFAULT;
+ return sys_semctl (first, second, third, fourth);
+ }
+
+ case MSGSND:
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, third);
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+ if (!ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&tmp,
+ (struct ipc_kludge *) ptr,
+ sizeof (tmp)))
+ return -EFAULT;
+ return sys_msgrcv (first, tmp.msgp, second,
+ tmp.msgtyp, third);
+ }
+ default:
+ panic("msgrcv with version != 0");
+ return sys_msgrcv (first,
+ (struct msgbuf *) ptr,
+ second, fifth, third);
+ }
+ case MSGGET:
+ return sys_msgget ((key_t) first, second);
+ case MSGCTL:
+ return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+ case SHMAT:
+ switch (version) {
+ default: {
+ ulong raddr;
+ ret = do_shmat (first, (char *) ptr, second, &raddr);
+ if (ret)
+ return ret;
+ return put_user (raddr, (ulong *) third);
+ }
+ case 1: /* iBCS2 emulator entry point */
+ if (!segment_eq(get_fs(), get_ds()))
+ return -EINVAL;
+ return do_shmat (first, (char *) ptr, second, (ulong *) third);
+ }
+ case SHMDT:
+ return sys_shmdt ((char *)ptr);
+ case SHMGET:
+ return sys_shmget (first, second, third);
+ case SHMCTL:
+ return sys_shmctl (first, second,
+ (struct shmid_ds *) ptr);
+ default:
+ return -ENOSYS;
+ }
+}
+
+long sys_sigaction(int sig, const struct old_sigaction __user *act,
+ struct old_sigaction __user *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
new file mode 100644
index 00000000000..281fc7b8ca0
--- /dev/null
+++ b/arch/um/sys-i386/sysrq.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "linux/sched.h"
+#include "asm/ptrace.h"
+#include "sysrq.h"
+
+void show_regs(struct pt_regs *regs)
+{
+ printk("\n");
+ printk("EIP: %04lx:[<%08lx>] CPU: %d %s",
+ 0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
+ smp_processor_id(), print_tainted());
+ if (PT_REGS_CS(regs) & 3)
+ printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
+ PT_REGS_SP(regs));
+ printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs),
+ print_tainted());
+ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+ PT_REGS_EAX(regs), PT_REGS_EBX(regs),
+ PT_REGS_ECX(regs),
+ PT_REGS_EDX(regs));
+ printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+ PT_REGS_ESI(regs), PT_REGS_EDI(regs),
+ PT_REGS_EBP(regs));
+ printk(" DS: %04lx ES: %04lx\n",
+ 0xffff & PT_REGS_DS(regs),
+ 0xffff & PT_REGS_ES(regs));
+
+ show_trace((unsigned long *) &regs);
+}
diff --git a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
new file mode 100644
index 00000000000..34860f9ca7b
--- /dev/null
+++ b/arch/um/sys-i386/util/Makefile
@@ -0,0 +1,8 @@
+
+hostprogs-y := mk_sc mk_thread
+always := $(hostprogs-y)
+
+mk_thread-objs := mk_thread_kern.o mk_thread_user.o
+
+HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS)
+HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS)
diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
new file mode 100644
index 00000000000..85cbd30396f
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_sc.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <signal.h>
+#include <linux/stddef.h>
+
+#define SC_OFFSET(name, field) \
+ printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
+ offsetof(struct sigcontext, field))
+
+#define SC_FP_OFFSET(name, field) \
+ printf("#define " name \
+ "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
+ offsetof(struct _fpstate, field))
+
+#define SC_FP_OFFSET_PTR(name, field, type) \
+ printf("#define " name \
+ "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
+ offsetof(struct _fpstate, field))
+
+int main(int argc, char **argv)
+{
+ SC_OFFSET("SC_IP", eip);
+ SC_OFFSET("SC_SP", esp);
+ SC_OFFSET("SC_FS", fs);
+ SC_OFFSET("SC_GS", gs);
+ SC_OFFSET("SC_DS", ds);
+ SC_OFFSET("SC_ES", es);
+ SC_OFFSET("SC_SS", ss);
+ SC_OFFSET("SC_CS", cs);
+ SC_OFFSET("SC_EFLAGS", eflags);
+ SC_OFFSET("SC_EAX", eax);
+ SC_OFFSET("SC_EBX", ebx);
+ SC_OFFSET("SC_ECX", ecx);
+ SC_OFFSET("SC_EDX", edx);
+ SC_OFFSET("SC_EDI", edi);
+ SC_OFFSET("SC_ESI", esi);
+ SC_OFFSET("SC_EBP", ebp);
+ SC_OFFSET("SC_TRAPNO", trapno);
+ SC_OFFSET("SC_ERR", err);
+ SC_OFFSET("SC_CR2", cr2);
+ SC_OFFSET("SC_FPSTATE", fpstate);
+ SC_OFFSET("SC_SIGMASK", oldmask);
+ SC_FP_OFFSET("SC_FP_CW", cw);
+ SC_FP_OFFSET("SC_FP_SW", sw);
+ SC_FP_OFFSET("SC_FP_TAG", tag);
+ SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
+ SC_FP_OFFSET("SC_FP_CSSEL", cssel);
+ SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
+ SC_FP_OFFSET("SC_FP_DATASEL", datasel);
+ SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
+ SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
+ return(0);
+}
diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c
new file mode 100644
index 00000000000..948b1ce8523
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread_kern.c
@@ -0,0 +1,22 @@
+#include "linux/config.h"
+#include "linux/stddef.h"
+#include "linux/sched.h"
+
+extern void print_head(void);
+extern void print_constant_ptr(char *name, int value);
+extern void print_constant(char *name, char *type, int value);
+extern void print_tail(void);
+
+#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
+
+int main(int argc, char **argv)
+{
+ print_head();
+ print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
+#ifdef CONFIG_MODE_TT
+ print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
+#endif
+ print_tail();
+ return(0);
+}
+
diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c
new file mode 100644
index 00000000000..2620cd6aa1f
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread_user.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+void print_head(void)
+{
+ printf("/*\n");
+ printf(" * Generated by mk_thread\n");
+ printf(" */\n");
+ printf("\n");
+ printf("#ifndef __UM_THREAD_H\n");
+ printf("#define __UM_THREAD_H\n");
+ printf("\n");
+}
+
+void print_constant_ptr(char *name, int value)
+{
+ printf("#define %s(task) ((unsigned long *) "
+ "&(((char *) (task))[%d]))\n", name, value);
+}
+
+void print_constant(char *name, char *type, int value)
+{
+ printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
+ value);
+}
+
+void print_tail(void)
+{
+ printf("\n");
+ printf("#endif\n");
+}