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/bug.c1
-rw-r--r--arch/um/sys-i386/bugs.c201
-rw-r--r--arch/um/sys-i386/ldt.c19
-rw-r--r--arch/um/sys-i386/ptrace.c6
-rw-r--r--arch/um/sys-i386/ptrace_user.c14
-rw-r--r--arch/um/sys-i386/signal.c18
-rw-r--r--arch/um/sys-i386/stub.S8
-rw-r--r--arch/um/sys-i386/stub_segv.c19
-rw-r--r--arch/um/sys-i386/sys_call_table.S5
-rw-r--r--arch/um/sys-i386/tls.c41
10 files changed, 99 insertions, 233 deletions
diff --git a/arch/um/sys-i386/bug.c b/arch/um/sys-i386/bug.c
index a4360b5207d..8d4f273f121 100644
--- a/arch/um/sys-i386/bug.c
+++ b/arch/um/sys-i386/bug.c
@@ -4,6 +4,7 @@
*/
#include <linux/uaccess.h>
+#include <asm/errno.h>
/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
* that's not relevant in skas mode.
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
index 806895d73bc..a74442d1376 100644
--- a/arch/um/sys-i386/bugs.c
+++ b/arch/um/sys-i386/bugs.c
@@ -3,171 +3,47 @@
* Licensed under the GPL
*/
-#include <errno.h>
#include <signal.h>
-#include <string.h>
#include "kern_constants.h"
-#include "os.h"
+#include "kern_util.h"
+#include "longjmp.h"
#include "task.h"
#include "user.h"
-
-#define MAXTOKEN 64
+#include "sysdep/ptrace.h"
/* Set during early boot */
int host_has_cmov = 1;
-int host_has_xmm = 0;
+static jmp_buf cmov_test_return;
-static char token(int fd, char *buf, int len, char stop)
+static void cmov_sigill_test_handler(int sig)
{
- 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(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));
-
- if (ptr == end) {
- printk(UM_KERN_ERR "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(UM_KERN_ERR "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(UM_KERN_ERR "Failed to find newline in "
- "/proc/cpuinfo, err = %d\n", -n);
- return 0;
- }
- } while (c != '\n');
- }
- return 0;
+ host_has_cmov = 0;
+ longjmp(cmov_test_return, 1);
}
-static int check_cpu_flag(char *feature, int *have_it)
-{
- char buf[MAXTOKEN], c;
- int fd, len = ARRAY_SIZE(buf);
-
- 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(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)))
- goto out;
-
- c = token(fd, buf, len - 1, ' ');
- if (c < 0)
- goto out;
- else if (c != ' ') {
- printk(UM_KERN_ERR "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)
+void arch_check_bugs(void)
{
- struct modify_ldt_ldt_s ldt;
- int err;
+ struct sigaction old, new;
- 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(UM_KERN_ERR "Failed to disable lcall7 - errno = %d\n",
- errno);
-}
-#endif
+ printk(UM_KERN_INFO "Checking for host processor cmov support...");
+ new.sa_handler = cmov_sigill_test_handler;
-void arch_init_thread(void)
-{
-#if 0
- disable_lcall();
-#endif
-}
+ /* Make sure that SIGILL is enabled after the handler longjmps back */
+ new.sa_flags = SA_NODEFER;
+ sigemptyset(&new.sa_mask);
+ sigaction(SIGILL, &new, &old);
-void arch_check_bugs(void)
-{
- int have_it;
+ if (setjmp(cmov_test_return) == 0) {
+ unsigned long foo = 0;
+ __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo));
+ printk(UM_KERN_CONT "Yes\n");
+ } else
+ printk(UM_KERN_CONT "No\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))
- host_has_cmov = have_it;
- if (check_cpu_flag("xmm", &have_it))
- host_has_xmm = have_it;
+ sigaction(SIGILL, &old, &new);
}
-int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+void arch_examine_signal(int sig, struct uml_pt_regs *regs)
{
unsigned char tmp[2];
@@ -176,24 +52,25 @@ int arch_handle_signal(int sig, struct uml_pt_regs *regs)
* SIGILL in init.
*/
if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
- return 0;
+ return;
+
+ if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
+ printk(UM_KERN_ERR "SIGILL in init, could not read "
+ "instructions!\n");
+ return;
+ }
- 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;
+ return;
if (host_has_cmov == 0)
- panic("SIGILL caused by cmov, which this processor doesn't "
- "implement, boot a filesystem compiled for older "
- "processors");
+ printk(UM_KERN_ERR "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;
+ printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+ "processor claims to implement");
+ else
+ printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)",
+ host_has_cmov);
}
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 67c0958eb98..a34263e6b08 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -3,8 +3,9 @@
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "asm/unistd.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/unistd.h>
#include "os.h"
#include "proc_mm.h"
#include "skas.h"
@@ -146,7 +147,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
if (ptrace_ldt)
return read_ldt_from_host(ptr, bytecount);
- down(&ldt->semaphore);
+ mutex_lock(&ldt->lock);
if (ldt->entry_count <= LDT_DIRECT_ENTRIES) {
size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES;
if (size > bytecount)
@@ -170,7 +171,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
ptr += size;
}
}
- up(&ldt->semaphore);
+ mutex_unlock(&ldt->lock);
if (bytecount == 0 || err == -EFAULT)
goto out;
@@ -228,7 +229,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
}
if (!ptrace_ldt)
- down(&ldt->semaphore);
+ mutex_lock(&ldt->lock);
err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1);
if (err)
@@ -288,7 +289,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
err = 0;
out_unlock:
- up(&ldt->semaphore);
+ mutex_unlock(&ldt->lock);
out:
return err;
}
@@ -395,7 +396,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
if (!ptrace_ldt)
- init_MUTEX(&new_mm->ldt.semaphore);
+ mutex_init(&new_mm->ldt.lock);
if (!from_mm) {
memset(&desc, 0, sizeof(desc));
@@ -455,7 +456,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
* 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);
+ mutex_lock(&from_mm->ldt.lock);
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));
@@ -474,7 +475,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
}
}
new_mm->ldt.entry_count = from_mm->ldt.entry_count;
- up(&from_mm->ldt.semaphore);
+ mutex_unlock(&from_mm->ldt.lock);
}
out:
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index bd3da8a61f6..6b4499906a6 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -8,11 +8,11 @@
#include "asm/uaccess.h"
#include "skas.h"
-extern int arch_switch_tls(struct task_struct *from, struct task_struct *to);
+extern int arch_switch_tls(struct task_struct *to);
-void arch_switch_to(struct task_struct *from, struct task_struct *to)
+void arch_switch_to(struct task_struct *to)
{
- int err = arch_switch_tls(from, to);
+ int err = arch_switch_tls(to);
if (!err)
return;
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 5cf97bc229b..0b10c3e7402 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -19,17 +19,3 @@ int ptrace_setregs(long pid, unsigned long *regs)
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;
-}
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 19053d46cb6..fd0c25ad6af 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -168,12 +168,13 @@ static int copy_sc_from_user(struct pt_regs *regs,
struct sigcontext __user *from)
{
struct sigcontext sc;
- int err;
+ int err, pid;
err = copy_from_user(&sc, from, sizeof(sc));
if (err)
return err;
+ pid = userspace_pid[current_thread_info()->cpu];
copy_sc(&regs->regs, &sc);
if (have_fpx_regs) {
struct user_fxsr_struct fpx;
@@ -187,8 +188,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
if (err)
return 1;
- err = restore_fpx_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fpx);
+ err = restore_fpx_registers(pid, (unsigned long *) &fpx);
if (err < 0) {
printk(KERN_ERR "copy_sc_from_user - "
"restore_fpx_registers failed, errno = %d\n",
@@ -204,8 +204,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
if (err)
return 1;
- err = restore_fp_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fp);
+ err = restore_fp_registers(pid, (unsigned long *) &fp);
if (err < 0) {
printk(KERN_ERR "copy_sc_from_user - "
"restore_fp_registers failed, errno = %d\n",
@@ -223,7 +222,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
{
struct sigcontext sc;
struct faultinfo * fi = &current->thread.arch.faultinfo;
- int err;
+ int err, pid;
sc.gs = REGS_GS(regs->regs.gp);
sc.fs = REGS_FS(regs->regs.gp);
@@ -249,11 +248,11 @@ static int copy_sc_to_user(struct sigcontext __user *to,
to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
sc.fpstate = to_fp;
+ pid = userspace_pid[current_thread_info()->cpu];
if (have_fpx_regs) {
struct user_fxsr_struct fpx;
- err = save_fpx_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fpx);
+ err = save_fpx_registers(pid, (unsigned long *) &fpx);
if (err < 0){
printk(KERN_ERR "copy_sc_to_user - save_fpx_registers "
"failed, errno = %d\n", err);
@@ -276,8 +275,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
else {
struct user_i387_struct fp;
- err = save_fp_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fp);
+ err = save_fp_registers(pid, (unsigned long *) &fp);
if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
return 1;
}
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
index e730772c401..7699e89f660 100644
--- a/arch/um/sys-i386/stub.S
+++ b/arch/um/sys-i386/stub.S
@@ -7,7 +7,7 @@
.globl batch_syscall_stub
batch_syscall_stub:
/* load pointer to first operation */
- mov $(ASM_STUB_DATA+8), %esp
+ mov $(STUB_DATA+8), %esp
again:
/* load length of additional data */
@@ -15,12 +15,12 @@ again:
/* if(length == 0) : end of list */
/* write possible 0 to header */
- mov %eax, ASM_STUB_DATA+4
+ mov %eax, STUB_DATA+4
cmpl $0, %eax
jz done
/* save current pointer */
- mov %esp, ASM_STUB_DATA+4
+ mov %esp, STUB_DATA+4
/* skip additional data */
add %eax, %esp
@@ -46,7 +46,7 @@ again:
done:
/* save return value */
- mov %eax, ASM_STUB_DATA
+ mov %eax, STUB_DATA
/* stop */
int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
index b3999cb76bf..28ccf737a79 100644
--- a/arch/um/sys-i386/stub_segv.c
+++ b/arch/um/sys-i386/stub_segv.c
@@ -1,32 +1,17 @@
/*
- * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#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"
-#include "sysdep/faultinfo.h"
void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig)
{
struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
- int pid;
GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), sc);
- pid = stub_syscall0(__NR_getpid);
- stub_syscall2(__NR_kill, pid, 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__ __volatile__("mov %0,%%esp ; movl %1, %%eax ; "
- "int $0x80" : : "a" (sc), "g" (__NR_sigreturn));
+ trap_myself();
}
diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S
index 12d4148dba3..00e5f5203ee 100644
--- a/arch/um/sys-i386/sys_call_table.S
+++ b/arch/um/sys-i386/sys_call_table.S
@@ -9,4 +9,9 @@
#define old_mmap old_mmap_i386
+.section .rodata,"a"
+
#include "../../x86/kernel/syscall_table_32.S"
+
+ENTRY(syscall_table_size)
+.long .-sys_call_table
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index fcaff86b000..c6c7131e563 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -26,6 +26,11 @@ int do_set_thread_area(struct user_desc *info)
cpu = get_cpu();
ret = os_set_thread_area(info, userspace_pid[cpu]);
put_cpu();
+
+ if (ret)
+ printk(KERN_ERR "PTRACE_SET_THREAD_AREA failed, err = %d, "
+ "index = %d\n", ret, info->entry_number);
+
return ret;
}
@@ -37,6 +42,11 @@ int do_get_thread_area(struct user_desc *info)
cpu = get_cpu();
ret = os_get_thread_area(info, userspace_pid[cpu]);
put_cpu();
+
+ if (ret)
+ printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, "
+ "index = %d\n", ret, info->entry_number);
+
return ret;
}
@@ -172,7 +182,7 @@ void clear_flushed_tls(struct task_struct *task)
* SKAS patch.
*/
-int arch_switch_tls(struct task_struct *from, struct task_struct *to)
+int arch_switch_tls(struct task_struct *to)
{
if (!host_supports_tls)
return 0;
@@ -225,7 +235,8 @@ out:
}
/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */
-static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx)
+static int get_tls_entry(struct task_struct *task, struct user_desc *info,
+ int idx)
{
struct thread_struct *t = &task->thread;
@@ -263,7 +274,7 @@ clear:
goto out;
}
-asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
+int sys_set_thread_area(struct user_desc __user *user_desc)
{
struct user_desc info;
int idx, ret;
@@ -298,7 +309,7 @@ asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
* i386. However the only possible error are caused by bugs.
*/
int ptrace_set_thread_area(struct task_struct *child, int idx,
- struct user_desc __user *user_desc)
+ struct user_desc __user *user_desc)
{
struct user_desc info;
@@ -311,7 +322,7 @@ int ptrace_set_thread_area(struct task_struct *child, int idx,
return set_tls_entry(child, &info, idx, 0);
}
-asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc)
+int sys_get_thread_area(struct user_desc __user *user_desc)
{
struct user_desc info;
int idx, ret;
@@ -355,10 +366,9 @@ out:
return ret;
}
-
/*
- * 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.
+ * This code is really i386-only, but it detects and logs x86_64 GDT indexes
+ * if a 32-bit UML is running on a 64-bit host.
*/
static int __init __setup_host_supports_tls(void)
{
@@ -367,13 +377,16 @@ static int __init __setup_host_supports_tls(void)
printk(KERN_INFO "Host TLS support detected\n");
printk(KERN_INFO "Detected host type: ");
switch (host_gdt_entry_tls_min) {
- case GDT_ENTRY_TLS_MIN_I386:
- printk("i386\n");
- break;
- case GDT_ENTRY_TLS_MIN_X86_64:
- printk("x86_64\n");
- break;
+ case GDT_ENTRY_TLS_MIN_I386:
+ printk(KERN_CONT "i386");
+ break;
+ case GDT_ENTRY_TLS_MIN_X86_64:
+ printk(KERN_CONT "x86_64");
+ break;
}
+ printk(KERN_CONT " (GDT indexes %d to %d)\n",
+ host_gdt_entry_tls_min,
+ host_gdt_entry_tls_min + GDT_ENTRY_TLS_ENTRIES);
} else
printk(KERN_ERR " Host TLS support NOT detected! "
"TLS support inside UML will not work\n");