diff options
Diffstat (limited to 'arch/um/sys-i386')
-rw-r--r-- | arch/um/sys-i386/Makefile | 20 | ||||
-rw-r--r-- | arch/um/sys-i386/bugs.c | 108 | ||||
-rw-r--r-- | arch/um/sys-i386/fault.c | 10 | ||||
-rw-r--r-- | arch/um/sys-i386/ldt.c | 306 | ||||
-rw-r--r-- | arch/um/sys-i386/ptrace.c | 368 | ||||
-rw-r--r-- | arch/um/sys-i386/ptrace_user.c | 100 | ||||
-rw-r--r-- | arch/um/sys-i386/sigcontext.c | 71 | ||||
-rw-r--r-- | arch/um/sys-i386/signal.c | 409 | ||||
-rw-r--r-- | arch/um/sys-i386/stub.S | 9 | ||||
-rw-r--r-- | arch/um/sys-i386/stub_segv.c | 4 | ||||
-rw-r--r-- | arch/um/sys-i386/tls.c | 101 | ||||
-rw-r--r-- | arch/um/sys-i386/unmap.c | 25 | ||||
-rw-r--r-- | arch/um/sys-i386/user-offsets.c | 6 |
13 files changed, 577 insertions, 960 deletions
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 8909b07d9ee..964dc1a04c3 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,23 +1,21 @@ +# +# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) +# + obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \ + ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ sys_call_table.o tls.o -obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o - -subarch-obj-y = lib/bitops.o lib/semaphore.o lib/string.o -subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o -subarch-obj-$(CONFIG_MODULES) += kernel/module.o +subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o +subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o +subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o -USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o +USER_OBJS := bugs.o ptrace_user.o fault.o USER_OBJS += user-offsets.s extra-y += user-offsets.s -extra-$(CONFIG_MODE_TT) += unmap.o - UNPROFILE_OBJS := stub_segv.o CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING) include arch/um/scripts/Makefile.rules - -$(obj)/unmap.%: _c_flags = $(call unprofile,$(KBUILD_CFLAGS)) diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c index 0393e44813e..806895d73bc 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -1,18 +1,15 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <unistd.h> #include <errno.h> +#include <signal.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 "kern_constants.h" #include "os.h" +#include "task.h" +#include "user.h" #define MAXTOKEN 64 @@ -30,18 +27,20 @@ static char token(int fd, char *buf, int len, char stop) do { n = os_read_file(fd, ptr, sizeof(*ptr)); c = *ptr++; - if(n != sizeof(*ptr)){ - if(n == 0) + if (n != sizeof(*ptr)) { + if (n == 0) return 0; - printk("Reading /proc/cpuinfo failed, err = %d\n", -n); - if(n < 0) + printk(UM_KERN_ERR "Reading /proc/cpuinfo failed, " + "err = %d\n", -n); + if (n < 0) return n; else return -EIO; } - } while((c != '\n') && (c != stop) && (ptr < end)); + } while ((c != '\n') && (c != stop) && (ptr < end)); - if(ptr == end){ - printk("Failed to find '%c' in /proc/cpuinfo\n", stop); + if (ptr == end) { + printk(UM_KERN_ERR "Failed to find '%c' in /proc/cpuinfo\n", + stop); return -1; } *(ptr - 1) = '\0'; @@ -54,26 +53,27 @@ static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) char c; scratch[len - 1] = '\0'; - while(1){ + while (1) { c = token(fd, scratch, len - 1, ':'); - if(c <= 0) + if (c <= 0) return 0; - else if(c != ':'){ - printk("Failed to find ':' in /proc/cpuinfo\n"); + else if (c != ':') { + printk(UM_KERN_ERR "Failed to find ':' in " + "/proc/cpuinfo\n"); return 0; } - if(!strncmp(scratch, key, strlen(key))) + 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 " + if (n != sizeof(c)) { + printk(UM_KERN_ERR "Failed to find newline in " "/proc/cpuinfo, err = %d\n", -n); return 0; } - } while(c != '\n'); + } while (c != '\n'); } return 0; } @@ -83,46 +83,50 @@ static int check_cpu_flag(char *feature, int *have_it) char buf[MAXTOKEN], c; int fd, len = ARRAY_SIZE(buf); - printk("Checking for host processor %s support...", feature); + printk(UM_KERN_INFO "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); + if (fd < 0) { + printk(UM_KERN_ERR "Couldn't open /proc/cpuinfo, err = %d\n", + -fd); return 0; } *have_it = 0; - if(!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf))) + if (!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf))) goto out; c = token(fd, buf, len - 1, ' '); - if(c < 0) + if (c < 0) goto out; - else if(c != ' '){ - printk("Failed to find ' ' in /proc/cpuinfo\n"); + else if (c != ' ') { + printk(UM_KERN_ERR "Failed to find ' ' in /proc/cpuinfo\n"); goto out; } - while(1){ + while (1) { c = token(fd, buf, len - 1, ' '); - if(c < 0) + if (c < 0) goto out; - else if(c == '\n') break; + else if (c == '\n') + break; - if(!strcmp(buf, feature)){ + if (!strcmp(buf, feature)) { *have_it = 1; goto out; } } out: - if(*have_it == 0) + if (*have_it == 0) printk("No\n"); - else if(*have_it == 1) + 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 +#if 0 /* + * This doesn't work in tt mode, plus it's causing compilation problems * for some people. */ static void disable_lcall(void) @@ -135,8 +139,9 @@ static void disable_lcall(void) 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); + if (err) + printk(UM_KERN_ERR "Failed to disable lcall7 - errno = %d\n", + errno); } #endif @@ -151,40 +156,41 @@ 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"); + if (os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0) { + printk(UM_KERN_ERR "/proc/cpuinfo not available - skipping CPU " + "capability checks\n"); return; } - if(check_cpu_flag("cmov", &have_it)) + if (check_cpu_flag("cmov", &have_it)) host_has_cmov = have_it; - if(check_cpu_flag("xmm", &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) +int arch_handle_signal(int sig, struct uml_pt_regs *regs) { unsigned char tmp[2]; - /* This is testing for a cmov (0x0f 0x4x) instruction causing a + /* + * This is testing for a cmov (0x0f 0x4x) instruction causing a * SIGILL in init. */ - if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) + 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)) + if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) return 0; - if(host_has_cmov == 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) + else if (host_has_cmov == 1) panic("SIGILL caused by cmov, which this processor claims to " "implement"); - else if(host_has_cmov == -1) + 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"); diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c index 745b4fd49e9..d670f68532f 100644 --- a/arch/um/sys-i386/fault.c +++ b/arch/um/sys-i386/fault.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -15,14 +15,14 @@ struct exception_table_entry 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, union uml_pt_regs *regs) +int arch_fixup(unsigned long address, struct uml_pt_regs *regs) { const struct exception_table_entry *fixup; fixup = search_exception_tables(address); - if(fixup != 0){ + if (fixup != 0) { UPT_IP(regs) = fixup->fixup; - return(1); + return 1; } - return(0); + return 0; } diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index a939a7ef022..67c0958eb98 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -1,106 +1,30 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/types.h" -#include "linux/errno.h" -#include "linux/spinlock.h" -#include "asm/uaccess.h" -#include "asm/smp.h" -#include "asm/ldt.h" +#include "linux/mm.h" #include "asm/unistd.h" -#include "choose-mode.h" -#include "kern.h" -#include "mode_kern.h" #include "os.h" - -extern int modify_ldt(int func, void *ptr, unsigned long bytecount); - -#ifdef CONFIG_MODE_TT - -static long do_modify_ldt_tt(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: /* 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; - } - - 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; - break; - default: - res = -ENOSYS; - goto out; - } - - res = modify_ldt(func, p, bytecount); - if(res < 0) - goto out; - - switch(func){ - case 0: - case 2: - /* Modify_ldt was for reading and returned the number of read - * bytes.*/ - if(copy_to_user(ptr, p, res)) - res = -EFAULT; - break; - } - -out: - kfree(buf); - return res; -} - -#endif - -#ifdef CONFIG_MODE_SKAS - +#include "proc_mm.h" #include "skas.h" #include "skas_ptrace.h" -#include "asm/mmu_context.h" -#include "proc_mm.h" +#include "sysdep/tls.h" + +extern int modify_ldt(int func, void *ptr, unsigned long bytecount); long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, void **addr, int done) { long res; - if(proc_mm){ - /* This is a special handling for the case, that the mm to + if (proc_mm) { + /* + * This is a special handling for the case, that the mm to * modify isn't current->active_mm. * If this is called directly by modify_ldt, * (current->active_mm->context.skas.u == mm_idp) - * will be true. So no call to switch_mm_skas(mm_idp) is done. + * will be true. So no call to __switch_mm(mm_idp) is done. * If this is called in case of init_new_ldt or PTRACE_LDT, * mm_idp won't belong to current->active_mm, but child->mm. * So we need to switch child's mm into our userspace, then @@ -108,12 +32,12 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, * * Note: I'm unsure: should interrupts be disabled here? */ - if(!current->active_mm || current->active_mm == &init_mm || - mm_idp != ¤t->active_mm->context.skas.id) - switch_mm_skas(mm_idp); + if (!current->active_mm || current->active_mm == &init_mm || + mm_idp != ¤t->active_mm->context.id) + __switch_mm(mm_idp); } - if(ptrace_ldt) { + if (ptrace_ldt) { struct ptrace_ldt ldt_op = (struct ptrace_ldt) { .func = func, .ptr = desc, @@ -121,7 +45,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, u32 cpu; int pid; - if(!proc_mm) + if (!proc_mm) pid = mm_idp->u.pid; else { cpu = get_cpu(); @@ -130,7 +54,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op); - if(proc_mm) + if (proc_mm) put_cpu(); } else { @@ -139,7 +63,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, (sizeof(*desc) + sizeof(long) - 1) & ~(sizeof(long) - 1), addr, &stub_addr); - if(!res){ + if (!res) { unsigned long args[] = { func, (unsigned long)stub_addr, sizeof(*desc), @@ -149,13 +73,14 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, } } - if(proc_mm){ - /* This is the second part of special handling, that makes + if (proc_mm) { + /* + * This is the second part of special handling, that makes * PTRACE_LDT possible to implement. */ - if(current->active_mm && current->active_mm != &init_mm && - mm_idp != ¤t->active_mm->context.skas.id) - switch_mm_skas(¤t->active_mm->context.skas.id); + if (current->active_mm && current->active_mm != &init_mm && + mm_idp != ¤t->active_mm->context.id) + __switch_mm(¤t->active_mm->context.id); } return res; @@ -170,21 +95,22 @@ static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) .ptr = kmalloc(bytecount, GFP_KERNEL)}; u32 cpu; - if(ptrace_ldt.ptr == NULL) + if (ptrace_ldt.ptr == NULL) return -ENOMEM; - /* This is called from sys_modify_ldt only, so userspace_pid gives + /* + * This is called from sys_modify_ldt only, so userspace_pid gives * us the right number */ cpu = get_cpu(); res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt); put_cpu(); - if(res < 0) + if (res < 0) goto out; n = copy_to_user(ptr, ptrace_ldt.ptr, res); - if(n != 0) + if (n != 0) res = -EFAULT; out: @@ -209,35 +135,34 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) { int i, err = 0; unsigned long size; - uml_ldt_t * ldt = ¤t->mm->context.skas.ldt; + uml_ldt_t * ldt = ¤t->mm->context.ldt; - if(!ldt->entry_count) + if (!ldt->entry_count) goto out; - if(bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) + if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; err = bytecount; - if(ptrace_ldt){ + if (ptrace_ldt) return read_ldt_from_host(ptr, bytecount); - } down(&ldt->semaphore); - if(ldt->entry_count <= LDT_DIRECT_ENTRIES){ + if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; - if(size > bytecount) + if (size > bytecount) size = bytecount; - if(copy_to_user(ptr, ldt->u.entries, size)) + if (copy_to_user(ptr, ldt->u.entries, size)) err = -EFAULT; bytecount -= size; ptr += size; } else { - for(i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount; - i++){ + for (i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount; + i++) { size = PAGE_SIZE; - if(size > bytecount) + if (size > bytecount) size = bytecount; - if(copy_to_user(ptr, ldt->u.pages[i], size)){ + if (copy_to_user(ptr, ldt->u.pages[i], size)) { err = -EFAULT; break; } @@ -247,10 +172,10 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) } up(&ldt->semaphore); - if(bytecount == 0 || err == -EFAULT) + if (bytecount == 0 || err == -EFAULT) goto out; - if(clear_user(ptr, bytecount)) + if (clear_user(ptr, bytecount)) err = -EFAULT; out: @@ -261,15 +186,16 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount) { int err; - if(bytecount > 5*LDT_ENTRY_SIZE) + if (bytecount > 5*LDT_ENTRY_SIZE) bytecount = 5*LDT_ENTRY_SIZE; err = bytecount; - /* UML doesn't support lcall7 and lcall27. + /* + * UML doesn't support lcall7 and lcall27. * So, we don't really have a default ldt, but emulate * an empty ldt of common host default ldt size. */ - if(clear_user(ptr, bytecount)) + if (clear_user(ptr, bytecount)) err = -EFAULT; return err; @@ -277,60 +203,60 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount) static int write_ldt(void __user * ptr, unsigned long bytecount, int func) { - uml_ldt_t * ldt = ¤t->mm->context.skas.ldt; - struct mm_id * mm_idp = ¤t->mm->context.skas.id; + uml_ldt_t * ldt = ¤t->mm->context.ldt; + struct mm_id * mm_idp = ¤t->mm->context.id; int i, err; struct user_desc ldt_info; struct ldt_entry entry0, *ldt_p; void *addr = NULL; err = -EINVAL; - if(bytecount != sizeof(ldt_info)) + if (bytecount != sizeof(ldt_info)) goto out; err = -EFAULT; - if(copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) + if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) goto out; err = -EINVAL; - if(ldt_info.entry_number >= LDT_ENTRIES) + if (ldt_info.entry_number >= LDT_ENTRIES) goto out; - if(ldt_info.contents == 3){ + if (ldt_info.contents == 3) { if (func == 1) goto out; if (ldt_info.seg_not_present == 0) goto out; } - if(!ptrace_ldt) - down(&ldt->semaphore); + if (!ptrace_ldt) + down(&ldt->semaphore); err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); - if(err) + if (err) goto out_unlock; - else if(ptrace_ldt) { - /* With PTRACE_LDT available, this is used as a flag only */ - ldt->entry_count = 1; - goto out; - } - - if(ldt_info.entry_number >= ldt->entry_count && - ldt_info.entry_number >= LDT_DIRECT_ENTRIES){ - for(i=ldt->entry_count/LDT_ENTRIES_PER_PAGE; - i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number; - i++){ - if(i == 0) + else if (ptrace_ldt) { + /* With PTRACE_LDT available, this is used as a flag only */ + ldt->entry_count = 1; + goto out; + } + + if (ldt_info.entry_number >= ldt->entry_count && + ldt_info.entry_number >= LDT_DIRECT_ENTRIES) { + for (i=ldt->entry_count/LDT_ENTRIES_PER_PAGE; + i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number; + i++) { + if (i == 0) memcpy(&entry0, ldt->u.entries, sizeof(entry0)); ldt->u.pages[i] = (struct ldt_entry *) __get_free_page(GFP_KERNEL|__GFP_ZERO); - if(!ldt->u.pages[i]){ + if (!ldt->u.pages[i]) { err = -ENOMEM; /* Undo the change in host */ memset(&ldt_info, 0, sizeof(ldt_info)); write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); goto out_unlock; } - if(i == 0) { + if (i == 0) { memcpy(ldt->u.pages[0], &entry0, sizeof(entry0)); memcpy(ldt->u.pages[0]+1, ldt->u.entries+1, @@ -339,17 +265,17 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE; } } - if(ldt->entry_count <= ldt_info.entry_number) + if (ldt->entry_count <= ldt_info.entry_number) ldt->entry_count = ldt_info.entry_number + 1; - if(ldt->entry_count <= LDT_DIRECT_ENTRIES) + if (ldt->entry_count <= LDT_DIRECT_ENTRIES) ldt_p = ldt->u.entries + ldt_info.entry_number; else ldt_p = ldt->u.pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] + ldt_info.entry_number%LDT_ENTRIES_PER_PAGE; - if(ldt_info.base_addr == 0 && ldt_info.limit == 0 && - (func == 1 || LDT_empty(&ldt_info))){ + if (ldt_info.base_addr == 0 && ldt_info.limit == 0 && + (func == 1 || LDT_empty(&ldt_info))) { ldt_p->a = 0; ldt_p->b = 0; } @@ -400,7 +326,7 @@ static void ldt_get_host_info(void) spin_lock(&host_ldt_lock); - if(host_ldt_entries != NULL){ + if (host_ldt_entries != NULL) { spin_unlock(&host_ldt_lock); return; } @@ -408,49 +334,49 @@ static void ldt_get_host_info(void) spin_unlock(&host_ldt_lock); - for(i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++); + for (i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++) + ; ldt = (struct ldt_entry *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); - if(ldt == NULL) { - printk("ldt_get_host_info: couldn't allocate buffer for host " - "ldt\n"); + if (ldt == NULL) { + printk(KERN_ERR "ldt_get_host_info: couldn't allocate buffer " + "for host ldt\n"); return; } ret = modify_ldt(0, ldt, (1<<order)*PAGE_SIZE); - if(ret < 0) { - printk("ldt_get_host_info: couldn't read host ldt\n"); + if (ret < 0) { + printk(KERN_ERR "ldt_get_host_info: couldn't read host ldt\n"); goto out_free; } - if(ret == 0) { + if (ret == 0) { /* default_ldt is active, simply write an empty entry 0 */ host_ldt_entries = dummy_list; goto out_free; } - for(i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++){ - if(ldt[i].a != 0 || ldt[i].b != 0) + for (i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++) { + if (ldt[i].a != 0 || ldt[i].b != 0) size++; } - if(size < ARRAY_SIZE(dummy_list)) + if (size < ARRAY_SIZE(dummy_list)) host_ldt_entries = dummy_list; else { size = (size + 1) * sizeof(dummy_list[0]); tmp = kmalloc(size, GFP_KERNEL); - if(tmp == NULL) { - printk("ldt_get_host_info: couldn't allocate host ldt " - "list\n"); + if (tmp == NULL) { + printk(KERN_ERR "ldt_get_host_info: couldn't allocate " + "host ldt list\n"); goto out_free; } host_ldt_entries = tmp; } - for(i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++){ - if(ldt[i].a != 0 || ldt[i].b != 0) { + for (i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++) { + if (ldt[i].a != 0 || ldt[i].b != 0) host_ldt_entries[k++] = i; - } } host_ldt_entries[k] = -1; @@ -458,8 +384,7 @@ out_free: free_pages((unsigned long)ldt, order); } -long init_new_ldt(struct mmu_context_skas * new_mm, - struct mmu_context_skas * from_mm) +long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) { struct user_desc desc; short * num_p; @@ -469,15 +394,15 @@ long init_new_ldt(struct mmu_context_skas * new_mm, struct proc_mm_op copy; - if(!ptrace_ldt) + if (!ptrace_ldt) init_MUTEX(&new_mm->ldt.semaphore); - if(!from_mm){ + if (!from_mm) { memset(&desc, 0, sizeof(desc)); /* * We have to initialize a clean ldt. */ - if(proc_mm) { + if (proc_mm) { /* * If the new mm was created using proc_mm, host's * default-ldt currently is assigned, which normally @@ -485,8 +410,7 @@ long init_new_ldt(struct mmu_context_skas * new_mm, * To remove these gates, we simply write an empty * entry as number 0 to the host. */ - err = write_ldt_entry(&new_mm->id, 1, &desc, - &addr, 1); + err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1); } else{ /* @@ -495,11 +419,11 @@ long init_new_ldt(struct mmu_context_skas * new_mm, * will be reset in the following loop */ ldt_get_host_info(); - for(num_p=host_ldt_entries; *num_p != -1; num_p++){ + for (num_p=host_ldt_entries; *num_p != -1; num_p++) { desc.entry_number = *num_p; err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, *(num_p + 1) == -1); - if(err) + if (err) break; } } @@ -508,8 +432,9 @@ long init_new_ldt(struct mmu_context_skas * new_mm, goto out; } - if(proc_mm){ - /* We have a valid from_mm, so we now have to copy the LDT of + if (proc_mm) { + /* + * We have a valid from_mm, so we now have to copy the LDT of * from_mm to new_mm, because using proc_mm an new mm with * an empty/default LDT was created in new_mm() */ @@ -518,27 +443,27 @@ long init_new_ldt(struct mmu_context_skas * new_mm, { .copy_segments = from_mm->id.u.mm_fd } } ); i = os_write_file(new_mm->id.u.mm_fd, ©, sizeof(copy)); - if(i != sizeof(copy)) - printk("new_mm : /proc/mm copy_segments failed, " - "err = %d\n", -i); + if (i != sizeof(copy)) + printk(KERN_ERR "new_mm : /proc/mm copy_segments " + "failed, err = %d\n", -i); } - if(!ptrace_ldt) { - /* Our local LDT is used to supply the data for + if (!ptrace_ldt) { + /* + * Our local LDT is used to supply the data for * modify_ldt(READLDT), if PTRACE_LDT isn't available, * i.e., we have to use the stub for modify_ldt, which * can't handle the big read buffer of up to 64kB. */ down(&from_mm->ldt.semaphore); - if(from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES){ + if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES) memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries, sizeof(new_mm->ldt.u.entries)); - } - else{ + else { i = from_mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while(i-->0){ + while (i-->0) { page = __get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!page){ + if (!page) { err = -ENOMEM; break; } @@ -557,22 +482,19 @@ long init_new_ldt(struct mmu_context_skas * new_mm, } -void free_ldt(struct mmu_context_skas * mm) +void free_ldt(struct mm_context *mm) { int i; - if(!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES){ + if (!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES) { i = mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while(i-- > 0){ - free_page((long )mm->ldt.u.pages[i]); - } + while (i-- > 0) + free_page((long) mm->ldt.u.pages[i]); } mm->ldt.entry_count = 0; } -#endif int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) { - return CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func, - ptr, bytecount); + return do_modify_ldt_skas(func, ptr, bytecount); } diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index 28bf0115032..9657c89fdf3 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -1,35 +1,26 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <linux/compiler.h> -#include "linux/sched.h" #include "linux/mm.h" -#include "asm/elf.h" -#include "asm/ptrace.h" +#include "linux/sched.h" #include "asm/uaccess.h" -#include "asm/unistd.h" -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" -#include "sysdep/sc.h" +#include "skas.h" -void arch_switch_to_tt(struct task_struct *from, struct task_struct *to) -{ - update_debugregs(to->thread.arch.debugregs_seq); - arch_switch_tls_tt(from, to); -} +extern int arch_switch_tls(struct task_struct *from, struct task_struct *to); -void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) +void arch_switch_to(struct task_struct *from, struct task_struct *to) { - int err = arch_switch_tls_skas(from, to); + int err = arch_switch_tls(from, to); if (!err) return; if (err != -EINVAL) - printk(KERN_WARNING "arch_switch_tls_skas failed, errno %d, not EINVAL\n", -err); + printk(KERN_WARNING "arch_switch_tls failed, errno %d, " + "not EINVAL\n", -err); else - printk(KERN_WARNING "arch_switch_tls_skas failed, errno = EINVAL\n"); + printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n"); } int is_syscall(unsigned long addr) @@ -38,21 +29,21 @@ int is_syscall(unsigned long addr) int n; n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if(n){ + if (n) { /* access_process_vm() grants access to vsyscall and stub, * while copy_from_user doesn't. Maybe access_process_vm is * slow, but that doesn't matter, since it will be called only * in case of singlestepping, if copy_from_user failed. */ n = access_process_vm(current, addr, &instr, sizeof(instr), 0); - if(n != sizeof(instr)) { - printk("is_syscall : failed to read instruction from " - "0x%lx\n", addr); - return(1); + if (n != sizeof(instr)) { + printk(KERN_ERR "is_syscall : failed to read " + "instruction from 0x%lx\n", addr); + return 1; } } /* int 0x80 or sysenter */ - return((instr == 0x80cd) || (instr == 0x340f)); + return (instr == 0x80cd) || (instr == 0x340f); } /* determines which flags the user has access to. */ @@ -96,21 +87,21 @@ int putreg(struct task_struct *child, int regno, unsigned long value) int poke_user(struct task_struct *child, long addr, long data) { - if ((addr & 3) || addr < 0) - return -EIO; - - if (addr < MAX_REG_OFFSET) - return putreg(child, addr, data); + if ((addr & 3) || addr < 0) + return -EIO; - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if((addr == 4) || (addr == 5)) return -EIO; - child->thread.arch.debugregs[addr] = data; - return 0; - } - return -EIO; + if (addr < MAX_REG_OFFSET) + return putreg(child, addr, data); + else if ((addr >= offsetof(struct user, u_debugreg[0])) && + (addr <= offsetof(struct user, u_debugreg[7]))) { + addr -= offsetof(struct user, u_debugreg[0]); + addr = addr >> 2; + if ((addr == 4) || (addr == 5)) + return -EIO; + child->thread.arch.debugregs[addr] = data; + return 0; + } + return -EIO; } unsigned long getreg(struct task_struct *child, int regno) @@ -133,20 +124,20 @@ unsigned long getreg(struct task_struct *child, int regno) return retval; } +/* read the word at location addr in the USER area. */ int peek_user(struct task_struct *child, long addr, long data) { -/* read the word at location addr in the USER area. */ unsigned long tmp; if ((addr & 3) || addr < 0) return -EIO; tmp = 0; /* Default return condition */ - if(addr < MAX_REG_OFFSET){ + if (addr < MAX_REG_OFFSET) { tmp = getreg(child, addr); } - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ + else if ((addr >= offsetof(struct user, u_debugreg[0])) && + (addr <= offsetof(struct user, u_debugreg[7]))) { addr -= offsetof(struct user, u_debugreg[0]); addr = addr >> 2; tmp = child->thread.arch.debugregs[addr]; @@ -154,277 +145,68 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long __user *) data); } -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 ) +int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { - 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; -} + int err, n, cpu = ((struct thread_info *) child->stack)->cpu; + long fpregs[HOST_FP_SIZE]; -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; + BUG_ON(sizeof(*buf) != sizeof(fpregs)); + err = save_fp_registers(userspace_pid[cpu], fpregs); + if (err) + return err; -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); + n = copy_to_user((void *) buf, fpregs, sizeof(fpregs)); + if(n > 0) + return -EFAULT; - 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; + return n; } -/* - * 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) +int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { - 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; + int n, cpu = ((struct thread_info *) child->stack)->cpu; + long fpregs[HOST_FP_SIZE]; - 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; + BUG_ON(sizeof(*buf) != sizeof(fpregs)); + n = copy_from_user(fpregs, (void *) buf, sizeof(fpregs)); + if (n > 0) + return -EFAULT; - 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; + return restore_fp_registers(userspace_pid[cpu], fpregs); } -#endif -static inline int convert_fxsr_to_user(struct _fpstate __user *buf, - struct pt_regs *regs) +int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) { - return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); -} + int err, n, cpu = ((struct thread_info *) child->stack)->cpu; + long fpregs[HOST_XFP_SIZE]; -#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; + BUG_ON(sizeof(*buf) != sizeof(fpregs)); + err = save_fpx_registers(userspace_pid[cpu], fpregs); + if (err) + return err; - 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]; + n = copy_to_user((void *) buf, fpregs, sizeof(fpregs)); + if(n > 0) + return -EFAULT; - 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); + return n; } -#endif -#ifdef CONFIG_MODE_TT -static inline void copy_fpu_fxsave_tt(struct pt_regs *regs, - struct user_i387_struct *buf) +int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) { - struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs)); - unsigned short *to; - unsigned short *from; - int i; + int n, cpu = ((struct thread_info *) child->stack)->cpu; + long fpregs[HOST_XFP_SIZE]; - memcpy( buf, fpu, 7 * sizeof(long) ); + BUG_ON(sizeof(*buf) != sizeof(fpregs)); + n = copy_from_user(fpregs, (void *) buf, sizeof(fpregs)); + if (n > 0) + return -EFAULT; - 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) ); - } + return restore_fpx_registers(userspace_pid[cpu], fpregs); } -#endif -static inline void copy_fpu_fxsave(struct pt_regs *regs, - struct user_i387_struct *buf) +long subarch_ptrace(struct task_struct *child, long request, long addr, + long data) { - (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0); + return -EIO; } - -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 index 40ff0c831bd..5cf97bc229b 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -1,20 +1,10 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> -#include <stddef.h> #include <errno.h> -#include <unistd.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" -#include "uml-config.h" +#include <sys/ptrace.h> int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -43,89 +33,3 @@ int ptrace_setfpregs(long pid, unsigned long *regs) return -errno; return 0; } - -#ifdef UML_CONFIG_MODE_TT - -static void write_debugregs(int pid, unsigned long *regs) -{ - struct user *dummy; - int nregs, i; - - dummy = NULL; - nregs = ARRAY_SIZE(dummy->u_debugreg); - 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%lx, 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 = ARRAY_SIZE(dummy->u_debugreg); - 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 }; - -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)); -} - -#ifdef UML_CONFIG_PT_PROXY -/* Accessed only by the tracing thread */ -static int debugregs_seq; - -/* Only called by the ptrace proxy */ -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); -} - -/* Optimized out in its header when not defined */ -void update_debugregs(int seq) -{ - int me; - - if(seq == debugregs_seq) return; - - me = os_getpid(); - initial_thread_cb(update_debugregs_cb, &me); -} -#endif - -#endif diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c deleted file mode 100644 index 467d489c31c..00000000000 --- a/arch/um/sys-i386/sigcontext.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 index 1cbf95f6858..0147227ce18 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -1,189 +1,293 @@ /* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.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 "asm/uaccess.h" +#include "asm/ucontext.h" #include "frame_kern.h" -#include "sigcontext.h" -#include "registers.h" -#include "mode.h" - -#ifdef CONFIG_MODE_SKAS - #include "skas.h" -void copy_sc(union uml_pt_regs *regs, void *from) +void copy_sc(struct uml_pt_regs *regs, void *from) { struct sigcontext *sc = from; - REGS_GS(regs->skas.regs) = sc->gs; - REGS_FS(regs->skas.regs) = sc->fs; - REGS_ES(regs->skas.regs) = sc->es; - REGS_DS(regs->skas.regs) = sc->ds; - REGS_EDI(regs->skas.regs) = sc->edi; - REGS_ESI(regs->skas.regs) = sc->esi; - REGS_EBP(regs->skas.regs) = sc->ebp; - REGS_SP(regs->skas.regs) = sc->esp; - REGS_EBX(regs->skas.regs) = sc->ebx; - REGS_EDX(regs->skas.regs) = sc->edx; - REGS_ECX(regs->skas.regs) = sc->ecx; - REGS_EAX(regs->skas.regs) = sc->eax; - REGS_IP(regs->skas.regs) = sc->eip; - REGS_CS(regs->skas.regs) = sc->cs; - REGS_EFLAGS(regs->skas.regs) = sc->eflags; - REGS_SS(regs->skas.regs) = sc->ss; + REGS_GS(regs->gp) = sc->gs; + REGS_FS(regs->gp) = sc->fs; + REGS_ES(regs->gp) = sc->es; + REGS_DS(regs->gp) = sc->ds; + REGS_EDI(regs->gp) = sc->edi; + REGS_ESI(regs->gp) = sc->esi; + REGS_EBP(regs->gp) = sc->ebp; + REGS_SP(regs->gp) = sc->esp; + REGS_EBX(regs->gp) = sc->ebx; + REGS_EDX(regs->gp) = sc->edx; + REGS_ECX(regs->gp) = sc->ecx; + REGS_EAX(regs->gp) = sc->eax; + REGS_IP(regs->gp) = sc->eip; + REGS_CS(regs->gp) = sc->cs; + REGS_EFLAGS(regs->gp) = sc->eflags; + REGS_SS(regs->gp) = sc->ss; } -static int copy_sc_from_user_skas(struct pt_regs *regs, - struct sigcontext __user *from) +/* + * FPU tag word conversions. + */ + +static inline unsigned short twd_i387_to_fxsr(unsigned short twd) { - struct sigcontext sc; - unsigned long fpregs[HOST_FP_SIZE]; - int err; + 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; +} - err = copy_from_user(&sc, from, sizeof(sc)); - err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs)); - if(err) - return err; +static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_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; +} - copy_sc(®s->regs, &sc); +static int convert_fxsr_to_user(struct _fpstate __user *buf, + struct user_fxsr_struct *fxsave) +{ + unsigned long env[7]; + struct _fpreg __user *to; + struct _fpxreg *from; + int i; + + env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; + env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; + 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; - 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 err; - } + to = &buf->_st[0]; + from = (struct _fpxreg *) &fxsave->st_space[0]; + for (i = 0; i < 8; i++, to++, from++) { + unsigned long __user *t = (unsigned long __user *)to; + unsigned long *f = (unsigned long *)from; + if (__put_user(*f, t) || + __put_user(*(f + 1), t + 1) || + __put_user(from->exponent, &to->exponent)) + return 1; + } return 0; } -int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp, - struct pt_regs *regs, unsigned long sp) +static int convert_fxsr_from_user(struct user_fxsr_struct *fxsave, + struct _fpstate __user *buf) { - struct sigcontext sc; - unsigned long fpregs[HOST_FP_SIZE]; - struct faultinfo * fi = ¤t->thread.arch.faultinfo; - int err; + unsigned long env[7]; + struct _fpxreg *to; + struct _fpreg __user *from; + int i; - 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 = sp; - 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 = fi->cr2; - sc.err = fi->error_code; - sc.trapno = fi->trap_no; - - err = save_fp_registers(userspace_pid[0], fpregs); - if(err < 0){ - printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, " - "errno = %d\n", err); + if (copy_from_user( env, buf, 7 * sizeof(long))) return 1; - } - to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (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)); + 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] & 0xffff0000ul) >> 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++) { + unsigned long *t = (unsigned long *)to; + unsigned long __user *f = (unsigned long __user *)from; + + if (__get_user(*t, f) || + __get_user(*(t + 1), f + 1) || + __get_user(to->exponent, &from->exponent)) + return 1; + } + return 0; } -#endif -#ifdef CONFIG_MODE_TT +extern int have_fpx_regs; -/* 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 __user *from, - int fpsize) +static int copy_sc_from_user(struct pt_regs *regs, + struct sigcontext __user *from) { - struct _fpstate *to_fp; - struct _fpstate __user *from_fp; - unsigned long sigs; + struct sigcontext sc; int err; - to_fp = to->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) - err |= copy_from_user(to_fp, from_fp, fpsize); - return err; + err = copy_from_user(&sc, from, sizeof(sc)); + if (err) + return err; + + copy_sc(®s->regs, &sc); + if (have_fpx_regs) { + struct user_fxsr_struct fpx; + + err = copy_from_user(&fpx, &sc.fpstate->_fxsr_env[0], + sizeof(struct user_fxsr_struct)); + if (err) + return 1; + + err = convert_fxsr_from_user(&fpx, sc.fpstate); + if (err) + return 1; + + err = restore_fpx_registers(userspace_pid[current_thread->cpu], + (unsigned long *) &fpx); + if (err < 0) { + printk(KERN_ERR "copy_sc_from_user - " + "restore_fpx_registers failed, errno = %d\n", + -err); + return 1; + } + } + else { + struct user_i387_struct fp; + + err = copy_from_user(&fp, sc.fpstate, + sizeof(struct user_i387_struct)); + if (err) + return 1; + + err = restore_fp_registers(userspace_pid[current_thread->cpu], + (unsigned long *) &fp); + if (err < 0) { + printk(KERN_ERR "copy_sc_from_user - " + "restore_fp_registers failed, errno = %d\n", + -err); + return 1; + } + } + + return 0; } -int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp, - struct sigcontext *from, int fpsize, unsigned long sp) +static int copy_sc_to_user(struct sigcontext __user *to, + struct _fpstate __user *to_fp, struct pt_regs *regs, + unsigned long sp) { - struct _fpstate __user *to_fp; - struct _fpstate *from_fp; + struct sigcontext sc; + struct faultinfo * fi = ¤t->thread.arch.faultinfo; int err; - to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1)); - from_fp = from->fpstate; - err = copy_to_user(to, from, sizeof(*to)); + sc.gs = REGS_GS(regs->regs.gp); + sc.fs = REGS_FS(regs->regs.gp); + sc.es = REGS_ES(regs->regs.gp); + sc.ds = REGS_DS(regs->regs.gp); + sc.edi = REGS_EDI(regs->regs.gp); + sc.esi = REGS_ESI(regs->regs.gp); + sc.ebp = REGS_EBP(regs->regs.gp); + sc.esp = sp; + sc.ebx = REGS_EBX(regs->regs.gp); + sc.edx = REGS_EDX(regs->regs.gp); + sc.ecx = REGS_ECX(regs->regs.gp); + sc.eax = REGS_EAX(regs->regs.gp); + sc.eip = REGS_IP(regs->regs.gp); + sc.cs = REGS_CS(regs->regs.gp); + sc.eflags = REGS_EFLAGS(regs->regs.gp); + sc.esp_at_signal = regs->regs.gp[UESP]; + sc.ss = regs->regs.gp[SS]; + sc.cr2 = fi->cr2; + sc.err = fi->error_code; + sc.trapno = fi->trap_no; - /* The SP in the sigcontext is the updated one for the signal - * delivery. The sp passed in is the original, and this needs - * to be restored, so we stick it in separately. - */ - err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); + to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); + sc.fpstate = to_fp; - if(from_fp != NULL){ - err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); - err |= copy_to_user(to_fp, from_fp, fpsize); + if (have_fpx_regs) { + struct user_fxsr_struct fpx; + + err = save_fpx_registers(userspace_pid[current_thread->cpu], + (unsigned long *) &fpx); + if (err < 0){ + printk(KERN_ERR "copy_sc_to_user - save_fpx_registers " + "failed, errno = %d\n", err); + return 1; + } + + err = convert_fxsr_to_user(to_fp, &fpx); + if (err) + return 1; + + err |= __put_user(fpx.swd, &to_fp->status); + err |= __put_user(X86_FXSR_MAGIC, &to_fp->magic); + if (err) + return 1; + + if (copy_to_user(&to_fp->_fxsr_env[0], &fpx, + sizeof(struct user_fxsr_struct))) + return 1; } - return err; -} -#endif - -static int copy_sc_from_user(struct pt_regs *to, void __user *from) -{ - int ret; + else { + struct user_i387_struct fp; - 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; -} + err = save_fp_registers(userspace_pid[current_thread->cpu], + (unsigned long *) &fp); + if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) + return 1; + } -static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp, - struct pt_regs *from, unsigned long sp) -{ - return CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), - sizeof(*fp), sp), - copy_sc_to_user_skas(to, fp, from, sp)); + return copy_to_user(to, &sc, sizeof(sc)); } -static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, - sigset_t *set, unsigned long sp) +static int copy_ucontext_to_user(struct ucontext __user *uc, + struct _fpstate __user *fp, sigset_t *set, + unsigned long sp) { int err = 0; @@ -233,7 +337,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, return 1; restorer = frame->retcode; - if(ka->sa.sa_flags & SA_RESTORER) + if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; /* Update SP now because the page fault handler refuses to extend @@ -265,7 +369,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); - if(err) + if (err) goto err; PT_REGS_SP(regs) = (unsigned long) frame; @@ -298,7 +402,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, return 1; restorer = frame->retcode; - if(ka->sa.sa_flags & SA_RESTORER) + if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; /* See comment above about why this is here */ @@ -323,7 +427,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); - if(err) + if (err) goto err; PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; @@ -350,8 +454,8 @@ long sys_sigreturn(struct pt_regs regs) 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)) + 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); @@ -361,7 +465,7 @@ long sys_sigreturn(struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if(copy_sc_from_user(¤t->thread.regs, sc)) + if (copy_sc_from_user(¤t->thread.regs, sc)) goto segfault; /* Avoid ERESTART handling */ @@ -376,12 +480,13 @@ long sys_sigreturn(struct pt_regs regs) long sys_rt_sigreturn(struct pt_regs regs) { unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4); + struct rt_sigframe __user *frame = + (struct rt_sigframe __user *) (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)) + if (copy_from_user(&set, &uc->uc_sigmask, sig_size)) goto segfault; sigdelsetmask(&set, ~_BLOCKABLE); @@ -391,7 +496,7 @@ long sys_rt_sigreturn(struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) + if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) goto segfault; /* Avoid ERESTART handling */ diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S index 6a70d9ab5c2..e730772c401 100644 --- a/arch/um/sys-i386/stub.S +++ b/arch/um/sys-i386/stub.S @@ -1,4 +1,5 @@ #include "uml-config.h" +#include "as-layout.h" .globl syscall_stub .section .__syscall_stub, "x" @@ -6,7 +7,7 @@ .globl batch_syscall_stub batch_syscall_stub: /* load pointer to first operation */ - mov $(UML_CONFIG_STUB_DATA+8), %esp + mov $(ASM_STUB_DATA+8), %esp again: /* load length of additional data */ @@ -14,12 +15,12 @@ again: /* if(length == 0) : end of list */ /* write possible 0 to header */ - mov %eax, UML_CONFIG_STUB_DATA+4 + mov %eax, ASM_STUB_DATA+4 cmpl $0, %eax jz done /* save current pointer */ - mov %esp, UML_CONFIG_STUB_DATA+4 + mov %esp, ASM_STUB_DATA+4 /* skip additional data */ add %eax, %esp @@ -45,7 +46,7 @@ again: done: /* save return value */ - mov %eax, UML_CONFIG_STUB_DATA + mov %eax, ASM_STUB_DATA /* stop */ int3 diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c index 2355dc19c46..b3999cb76bf 100644 --- a/arch/um/sys-i386/stub_segv.c +++ b/arch/um/sys-i386/stub_segv.c @@ -6,6 +6,7 @@ #include <signal.h> #include <sys/select.h> /* The only way I can see to get sigset_t */ #include <asm/unistd.h> +#include "as-layout.h" #include "uml-config.h" #include "sysdep/stub.h" #include "sysdep/sigcontext.h" @@ -17,8 +18,7 @@ stub_segv_handler(int sig) struct sigcontext *sc = (struct sigcontext *) (&sig + 1); int pid; - GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), - sc); + GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), sc); pid = stub_syscall0(__NR_getpid); stub_syscall2(__NR_kill, pid, SIGUSR1); diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c index fea8e5e15cc..b02266ab5c5 100644 --- a/arch/um/sys-i386/tls.c +++ b/arch/um/sys-i386/tls.c @@ -3,25 +3,12 @@ * Licensed under the GPL */ -#include "linux/kernel.h" +#include "linux/percpu.h" #include "linux/sched.h" -#include "linux/slab.h" -#include "linux/types.h" #include "asm/uaccess.h" -#include "asm/ptrace.h" -#include "asm/segment.h" -#include "asm/smp.h" -#include "asm/desc.h" -#include "choose-mode.h" -#include "kern.h" -#include "kern_util.h" -#include "mode_kern.h" #include "os.h" -#include "mode.h" - -#ifdef CONFIG_MODE_SKAS #include "skas.h" -#endif +#include "sysdep/tls.h" /* * If needed we can detect when it's uninitialized. @@ -31,8 +18,7 @@ static int host_supports_tls = -1; int host_gdt_entry_tls_min; -#ifdef CONFIG_MODE_SKAS -int do_set_thread_area_skas(struct user_desc *info) +int do_set_thread_area(struct user_desc *info) { int ret; u32 cpu; @@ -43,7 +29,7 @@ int do_set_thread_area_skas(struct user_desc *info) return ret; } -int do_get_thread_area_skas(struct user_desc *info) +int do_get_thread_area(struct user_desc *info) { int ret; u32 cpu; @@ -53,7 +39,6 @@ int do_get_thread_area_skas(struct user_desc *info) put_cpu(); return ret; } -#endif /* * sys_get_thread_area: get a yet unused TLS descriptor index. @@ -82,7 +67,8 @@ static inline void clear_user_desc(struct user_desc* info) /* Postcondition: LDT_empty(info) returns true. */ memset(info, 0, sizeof(*info)); - /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain + /* + * Check the LDT_empty or the i386 sys_get_thread_area code - we obtain * indeed an empty user_desc. */ info->read_exec_only = 1; @@ -97,10 +83,13 @@ static int load_TLS(int flags, struct task_struct *to) int idx; for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { - struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; + struct uml_tls_struct* curr = + &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; - /* Actually, now if it wasn't flushed it gets cleared and - * flushed to the host, which will clear it.*/ + /* + * Actually, now if it wasn't flushed it gets cleared and + * flushed to the host, which will clear it. + */ if (!curr->present) { if (!curr->flushed) { clear_user_desc(&curr->tls); @@ -124,7 +113,8 @@ out: return ret; } -/* Verify if we need to do a flush for the new process, i.e. if there are any +/* + * Verify if we need to do a flush for the new process, i.e. if there are any * present desc's, only if they haven't been flushed. */ static inline int needs_TLS_update(struct task_struct *task) @@ -133,10 +123,13 @@ static inline int needs_TLS_update(struct task_struct *task) int ret = 0; for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { - struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; + struct uml_tls_struct* curr = + &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; - /* Can't test curr->present, we may need to clear a descriptor - * which had a value. */ + /* + * Can't test curr->present, we may need to clear a descriptor + * which had a value. + */ if (curr->flushed) continue; ret = 1; @@ -145,7 +138,8 @@ static inline int needs_TLS_update(struct task_struct *task) return ret; } -/* On a newly forked process, the TLS descriptors haven't yet been flushed. So +/* + * On a newly forked process, the TLS descriptors haven't yet been flushed. So * we mark them as such and the first switch_to will do the job. */ void clear_flushed_tls(struct task_struct *task) @@ -153,10 +147,13 @@ void clear_flushed_tls(struct task_struct *task) int i; for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { - struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; + struct uml_tls_struct* curr = + &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; - /* Still correct to do this, if it wasn't present on the host it - * will remain as flushed as it was. */ + /* + * Still correct to do this, if it wasn't present on the host it + * will remain as flushed as it was. + */ if (!curr->present) continue; @@ -164,40 +161,33 @@ void clear_flushed_tls(struct task_struct *task) } } -/* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a +/* + * In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a * common host process. So this is needed in SKAS0 too. * * However, if each thread had a different host process (and this was discussed * for SMP support) this won't be needed. * * And this will not need be used when (and if) we'll add support to the host - * SKAS patch. */ + * SKAS patch. + */ -int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) +int arch_switch_tls(struct task_struct *from, struct task_struct *to) { if (!host_supports_tls) return 0; - /* We have no need whatsoever to switch TLS for kernel threads; beyond + /* + * We have no need whatsoever to switch TLS for kernel threads; beyond * that, that would also result in us calling os_set_thread_area with - * userspace_pid[cpu] == 0, which gives an error. */ + * userspace_pid[cpu] == 0, which gives an error. + */ if (likely(to->mm)) return load_TLS(O_FORCE, to); return 0; } -int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) -{ - if (!host_supports_tls) - return 0; - - if (needs_TLS_update(to)) - return load_TLS(0, to); - - return 0; -} - static int set_tls_entry(struct task_struct* task, struct user_desc *info, int idx, int flushed) { @@ -251,17 +241,20 @@ static int get_tls_entry(struct task_struct* task, struct user_desc *info, int i *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; out: - /* Temporary debugging check, to make sure that things have been + /* + * Temporary debugging check, to make sure that things have been * flushed. This could be triggered if load_TLS() failed. */ - if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { + if (unlikely(task == current && + !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { printk(KERN_ERR "get_tls_entry: task with pid %d got here " "without flushed TLS.", current->pid); } return 0; clear: - /* When the TLS entry has not been set, the values read to user in the + /* + * When the TLS entry has not been set, the values read to user in the * tls_array are 0 (because it's cleared at boot, see * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. */ @@ -293,7 +286,7 @@ asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) return -EFAULT; } - ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info); + ret = do_set_thread_area(&info); if (ret) return ret; return set_tls_entry(current, &info, idx, 1); @@ -363,8 +356,10 @@ out: } -/* XXX: This part is probably common to i386 and x86-64. Don't create a common - * file for now, do that when implementing x86-64 support.*/ +/* + * XXX: This part is probably common to i386 and x86-64. Don't create a common + * file for now, do that when implementing x86-64 support. + */ static int __init __setup_host_supports_tls(void) { check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); diff --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c deleted file mode 100644 index 1b0ad0e4adc..00000000000 --- a/arch/um/sys-i386/unmap.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <linux/mman.h> -#include <asm/unistd.h> - -static int errno; - -static inline _syscall2(int,munmap,void *,start,size_t,len) -static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) -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) == (void*) -1 ){ - return(-1); - } - if(munmap(from, size) < 0){ - return(-1); - } - return(0); -} diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c index 29118cf5ff2..514241526a1 100644 --- a/arch/um/sys-i386/user-offsets.c +++ b/arch/um/sys-i386/user-offsets.c @@ -2,9 +2,9 @@ #include <stddef.h> #include <signal.h> #include <sys/poll.h> +#include <sys/user.h> #include <sys/mman.h> #include <asm/ptrace.h> -#include <asm/user.h> #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -48,8 +48,8 @@ void foo(void) OFFSET(HOST_SC_FP_ST, _fpstate, _st); OFFSET(HOST_SC_FXSR_ENV, _fpstate, _fxsr_env); - DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_i387_struct)); - DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fxsr_struct)); + DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_fpregs_struct)); + DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fpxregs_struct)); DEFINE(HOST_IP, EIP); DEFINE(HOST_SP, UESP); |