summaryrefslogtreecommitdiff
path: root/arch/um/sys-i386
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/sys-i386')
-rw-r--r--arch/um/sys-i386/Makefile6
-rw-r--r--arch/um/sys-i386/kernel-offsets.c1
-rw-r--r--arch/um/sys-i386/ldt.c114
-rw-r--r--arch/um/sys-i386/signal.c2
-rw-r--r--arch/um/sys-i386/stub.S51
-rw-r--r--arch/um/sys-i386/stub_segv.c29
-rw-r--r--arch/um/sys-i386/unmap.c2
7 files changed, 149 insertions, 56 deletions
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 095bcdb0b9cc..4ca2a229da49 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,6 @@
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 \
- sys_call_table.o
+ ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+ syscalls.o sysrq.o sys_call_table.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
@@ -16,6 +16,8 @@ semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
+$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS))
+
subdir- := util
include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-i386/kernel-offsets.c b/arch/um/sys-i386/kernel-offsets.c
index 9f8ecd1fdd96..a1070af2bcd8 100644
--- a/arch/um/sys-i386/kernel-offsets.c
+++ b/arch/um/sys-i386/kernel-offsets.c
@@ -2,6 +2,7 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/time.h>
+#include <linux/elf.h>
#include <asm/page.h>
#define DEFINE(sym, val) \
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index dc755b0b9db8..bd3c34aa52e5 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -4,96 +4,106 @@
*/
#include "linux/config.h"
+#include "linux/sched.h"
#include "linux/slab.h"
+#include "linux/types.h"
#include "asm/uaccess.h"
#include "asm/ptrace.h"
+#include "asm/smp.h"
+#include "asm/ldt.h"
#include "choose-mode.h"
#include "kern.h"
+#include "mode_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 */
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
-int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
+static int do_modify_ldt_tt(int func, void *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.h"
#include "skas_ptrace.h"
-int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount)
+static int do_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
{
struct ptrace_ldt ldt;
- void *buf;
- int res, n;
+ u32 cpu;
+ int res;
- buf = kmalloc(bytecount, GFP_KERNEL);
- if(buf == NULL)
- return(-ENOMEM);
+ ldt = ((struct ptrace_ldt) { .func = func,
+ .ptr = ptr,
+ .bytecount = bytecount });
- res = 0;
+ cpu = get_cpu();
+ res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, (unsigned long) &ldt);
+ put_cpu();
+
+ return res;
+}
+#endif
+
+int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
+{
+ struct user_desc info;
+ int res = 0;
+ void *buf = NULL;
+ void *p = NULL; /* What we pass to host. */
switch(func){
case 1:
- case 0x11:
- res = copy_from_user(buf, ptr, bytecount);
- break;
- }
+ case 0x11: /* write_ldt */
+ /* Do this check now to avoid overflows. */
+ if (bytecount != sizeof(struct user_desc)) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if(copy_from_user(&info, ptr, sizeof(info))) {
+ res = -EFAULT;
+ goto out;
+ }
- if(res != 0){
- res = -EFAULT;
+ p = &info;
+ break;
+ case 0:
+ case 2: /* read_ldt */
+
+ /* The use of info avoids kmalloc on the write case, not on the
+ * read one. */
+ buf = kmalloc(bytecount, GFP_KERNEL);
+ if (!buf) {
+ res = -ENOMEM;
+ goto out;
+ }
+ p = buf;
+ default:
+ res = -ENOSYS;
goto out;
}
- ldt = ((struct ptrace_ldt) { .func = func,
- .ptr = buf,
- .bytecount = bytecount });
-#warning Need to look up userspace_pid by cpu
- res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
+ res = CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func,
+ p, bytecount);
if(res < 0)
goto out;
switch(func){
case 0:
case 2:
- n = res;
- res = copy_to_user(ptr, buf, n);
- if(res != 0)
+ /* Modify_ldt was for reading and returned the number of read
+ * bytes.*/
+ if(copy_to_user(ptr, p, res))
res = -EFAULT;
- else
- res = n;
break;
}
- out:
+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));
+ return res;
}
-
-
-
-/*
- * 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
index 4efc69a039d7..16bc19928b3c 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -122,9 +122,9 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
int err;
to_fp = to->fpstate;
- from_fp = from->fpstate;
sigs = to->oldmask;
err = copy_from_user(to, from, sizeof(*to));
+ from_fp = to->fpstate;
to->oldmask = sigs;
to->fpstate = to_fp;
if(to_fp != NULL)
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
new file mode 100644
index 000000000000..6a70d9ab5c29
--- /dev/null
+++ b/arch/um/sys-i386/stub.S
@@ -0,0 +1,51 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+
+ .globl batch_syscall_stub
+batch_syscall_stub:
+ /* load pointer to first operation */
+ mov $(UML_CONFIG_STUB_DATA+8), %esp
+
+again:
+ /* load length of additional data */
+ mov 0x0(%esp), %eax
+
+ /* if(length == 0) : end of list */
+ /* write possible 0 to header */
+ mov %eax, UML_CONFIG_STUB_DATA+4
+ cmpl $0, %eax
+ jz done
+
+ /* save current pointer */
+ mov %esp, UML_CONFIG_STUB_DATA+4
+
+ /* skip additional data */
+ add %eax, %esp
+
+ /* load syscall-# */
+ pop %eax
+
+ /* load syscall params */
+ pop %ebx
+ pop %ecx
+ pop %edx
+ pop %esi
+ pop %edi
+ pop %ebp
+
+ /* execute syscall */
+ int $0x80
+
+ /* check return value */
+ pop %ebx
+ cmp %ebx, %eax
+ je again
+
+done:
+ /* save return value */
+ mov %eax, UML_CONFIG_STUB_DATA
+
+ /* stop */
+ int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
new file mode 100644
index 000000000000..1e88b275edac
--- /dev/null
+++ b/arch/um/sys-i386/stub_segv.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <asm/signal.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
+
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ sc);
+
+ __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
+ __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
+ "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Load pointer to sigcontext into esp, since we need to leave
+ * the stack in its original form when we do the sigreturn here, by
+ * hand.
+ */
+ __asm__("mov %0,%%esp ; movl %1, %%eax ; "
+ "int $0x80" : : "a" (sc), "g" (__NR_sigreturn));
+}
diff --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c
index 136875263d27..1b0ad0e4adcd 100644
--- a/arch/um/sys-i386/unmap.c
+++ b/arch/um/sys-i386/unmap.c
@@ -15,7 +15,7 @@ int switcheroo(int fd, int prot, void *from, void *to, int size)
if(munmap(to, size) < 0){
return(-1);
}
- if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
+ if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){
return(-1);
}
if(munmap(from, size) < 0){