This patch implements sys_vcpu support in UML.

diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 0a91cb1..3421c47 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -22,7 +22,7 @@ extern void free_stack(unsigned long stack, int order);
 
 extern void do_signal(void);
 extern void copy_sc(struct uml_pt_regs *regs, void *from);
-extern void interrupt_end(void);
+extern int interrupt_end(void);
 extern void relay_signal(int sig, struct uml_pt_regs *regs);
 
 extern unsigned long segv(struct faultinfo fi, unsigned long ip,
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 32c799e..309dd51 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -265,6 +265,7 @@ extern int is_skas_winch(int pid, int fd, void *data);
 extern int start_userspace(unsigned long stub_stack);
 extern int copy_context_skas0(unsigned long stack, int pid);
 extern void userspace(struct uml_pt_regs *regs);
+extern void vcpu_userspace(struct uml_pt_regs *regs, int mm_fd);
 extern int map_stub_pages(int fd, unsigned long code, unsigned long data,
                          unsigned long stack);
 extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h
index ea56428..590fcff 100644
--- a/arch/um/include/skas/skas.h
+++ b/arch/um/include/skas/skas.h
@@ -15,15 +15,18 @@
 #ifdef UML_CONFIG_X86_32
 #define __NR_new_mm             327
 #define __NR_switch_mm          328
+#define __NR_vcpu              329
 #else
 #define __NR_new_mm             288
 #define __NR_switch_mm          289
+#define __NR_vcpu              290
 #endif
 
 #define PTRACE_SWITCH_MM 34
 
 #ifndef __ASSEMBLY__
 
+#include <asm/user.h>
 #include "sysdep/ptrace.h"
 
 #define STUB_ADDR(x) (STUB_CODE + (unsigned long) (x) - \
@@ -36,6 +39,7 @@ extern int skas_needs_stub;
 extern int have_switch_mm;
 extern int have_ptrace_switch_mm;
 extern int have_siginfo_segv;
+extern int have_vcpu;
 extern int self_mm_fd;
 
 extern int user_thread(unsigned long stack, int flags);
@@ -48,7 +52,18 @@ extern unsigned long current_stub_stack(void);
 
 #ifndef __KERNEL__
 #include <errno.h>
-#include <asm/user.h>
+#include <asm/ldt.h>
+#include "siginfo_segv.h"
+
+#ifdef UML_CONFIG_X86_32
+#define GDT_ENTRY_TLS_ENTRIES 3
+
+struct vcpu_arch {
+       struct user_desc tls_array[GDT_ENTRY_TLS_ENTRIES];
+};
+#else
+struct vcpu_arch { };
+#endif
 
 struct user_regs {
        unsigned long regs[MAX_REG_NR];
@@ -61,6 +76,13 @@ struct user_regs {
 #endif
 };
 
+struct vcpu_user {
+       enum { VCPU_SYSCALL, VCPU_SIGNAL } event;
+       struct user_regs regs;
+       siginfo_t siginfo;
+       struct vcpu_arch arch;
+};
+
 static inline long new_mm(void)
 {
        int ret = syscall(__NR_new_mm, 0, 0, 0, 0, 0, 0);
@@ -83,6 +105,27 @@ static inline long switch_mm(int mm_fd, struct user_regs 
*save_regs,
 
        return 0;
 }
+
+static inline long vcpu(long mm_fd, struct vcpu_user *vcpu)
+{
+       int ret = syscall(__NR_vcpu, mm_fd, vcpu, 0, 0, 0, 0);
+
+       if (ret < 0)
+               return -errno;
+
+       return ret;
+}
+
+static inline int get_thread_area(struct user_desc *u_info)
+{
+       int ret = syscall(__NR_get_thread_area, u_info, 0, 0, 0, 0, 0);
+
+       if (ret < 0)
+               return -errno;
+
+       return ret;
+}
+
 #endif
 
 #endif
diff --git a/arch/um/include/sysdep-i386/tls.h 
b/arch/um/include/sysdep-i386/tls.h
index 918fd3c..844f0c2 100644
--- a/arch/um/include/sysdep-i386/tls.h
+++ b/arch/um/include/sysdep-i386/tls.h
@@ -1,7 +1,7 @@
 #ifndef _SYSDEP_TLS_H
 #define _SYSDEP_TLS_H
 
-# ifndef __KERNEL__
+#ifndef __KERNEL__
 
 /* Change name to avoid conflicts with the original one from <asm/ldt.h>, which
  * may be named user_desc (but in 2.4 and in header matching its API was named
@@ -19,13 +19,19 @@ typedef struct um_dup_user_desc {
        unsigned int  useable:1;
 } user_desc_t;
 
-# else /* __KERNEL__ */
+#else /* __KERNEL__ */
 
-#  include <asm/ldt.h>
+#include <asm/host_ldt.h>
 typedef struct user_desc user_desc_t;
 
 # endif /* __KERNEL__ */
 
+struct uml_tls_struct {
+       user_desc_t tls;
+       unsigned flushed:1;
+       unsigned present:1;
+};
+
 #define GDT_ENTRY_TLS_MIN_I386 6
 #define GDT_ENTRY_TLS_MIN_X86_64 12
 
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h 
b/arch/um/include/sysdep-x86_64/ptrace.h
index d3d1dda..18ad3a8 100644
--- a/arch/um/include/sysdep-x86_64/ptrace.h
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -233,8 +233,6 @@ struct syscall_args {
 
 #define UPT_FAULTINFO(r) (&(r)->faultinfo)
 
-static inline void arch_init_registers(int pid)
-{
-}
+extern void arch_init_registers(int pid);
 
 #endif
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 0963fcd..7f07ad3 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -111,12 +111,13 @@ void *_switch_to(void *prev, void *next, void *last)
 
 }
 
-void interrupt_end(void)
+int interrupt_end(void)
 {
        if (need_resched())
                schedule();
        if (test_thread_flag(TIF_SIGPENDING))
                do_signal();
+       return current->mm->context.id.u.mm_fd;
 }
 
 void exit_thread(void)
@@ -152,7 +153,11 @@ void new_thread_handler(void)
        if (n == 1) {
                /* Handle any immediate reschedules or signals */
                interrupt_end();
-               userspace(&current->thread.regs.regs);
+               if (have_vcpu)
+                       vcpu_userspace(&current->thread.regs.regs,
+                                      current->mm->context.id.u.mm_fd);
+               else
+                       userspace(&current->thread.regs.regs);
        }
        else do_exit(0);
 }
@@ -176,7 +181,11 @@ void fork_handler(void)
        /* Handle any immediate reschedules or signals */
        interrupt_end();
 
-       userspace(&current->thread.regs.regs);
+       if (have_vcpu)
+               vcpu_userspace(&current->thread.regs.regs,
+                              current->mm->context.id.u.mm_fd);
+       else
+               userspace(&current->thread.regs.regs);
 }
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index 2c8583c..6b19d0a 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -3,8 +3,8 @@
  * Licensed under the GPL
  */
 
-#include <signal.h>
 #include <sched.h>
+#include <signal.h>
 #include <asm/unistd.h>
 #include <sys/time.h>
 #include "as-layout.h"
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 32e84d7..ec82db3 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -55,7 +55,8 @@ int __init start_uml(void)
 {
        stack_protections((unsigned long) &cpu0_irqstack);
        set_sigstack(cpu0_irqstack, THREAD_SIZE);
-       if (proc_mm || have_switch_mm) {
+
+       if (!have_vcpu && (proc_mm || have_switch_mm)) {
                userspace_pid[0] = start_userspace(0);
                if (userspace_pid[0] < 0) {
                        printf("start_uml - start_userspace returned %d\n",
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 42a3026..73b1dff 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -6,7 +6,6 @@
 #include <stddef.h>
 #include <unistd.h>
 #include <errno.h>
-#include <signal.h>
 #include <string.h>
 #include <sys/mman.h>
 #include "init.h"
@@ -122,11 +121,12 @@ static long do_syscall_stub(struct mm_id *mm_idp, void 
**addr)
        return ret;
 }
 
+static struct user_regs return_regs;
+
 long do_syscall_stub_skas4(struct mm_id *mm_idp, void **addr, unsigned long ip,
                           unsigned long sp)
 {
        long ret;
-       struct user_regs return_regs;
        unsigned long *ptr;
        int err;
        sigset_t sigs, old;
@@ -221,9 +221,10 @@ long syscall_stub_data(struct mm_id *mm_idp, unsigned long 
*data,
                return ret;
 
        stack = check_init_stack(mm_idp, *addr);
-       *stack++ = data_count * sizeof(long);
+       *stack = data_count;
+       *addr = stack++;
 
-       memcpy(stack, data, data_count * sizeof(long));
+       memcpy(stack, data, data_count);
 
        *stub_addr = (void *)(((unsigned long) stack & ~UM_KERN_PAGE_MASK) +
                              STUB_DATA);
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 23a9b42..593df24 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -358,6 +358,85 @@ int start_userspace(unsigned long stub_stack)
        return err;
 }
 
+#ifdef UML_CONFIG_X86_32
+extern void init_vcpu_tls(struct user_desc *tls);
+
+static void arch_init_vcpu(struct vcpu_arch *vcpu)
+{
+       init_vcpu_tls(vcpu->tls_array);
+}
+#else
+static void arch_init_vcpu(struct vcpu_arch *vcpu)
+{
+}
+#endif
+
+extern unsigned long fp_regs[FP_SIZE];
+
+void vcpu_userspace(struct uml_pt_regs *regs, int mm_fd)
+{
+       struct vcpu_user vcpu_state;
+       int err;
+
+       memcpy(&vcpu_state.regs.fpregs, fp_regs, sizeof(fp_regs));
+       vcpu_state.regs.fp_state = &vcpu_state.regs.fpregs;
+       while (1) {
+               memcpy(&vcpu_state.regs.regs, &regs->gp,
+                      sizeof(vcpu_state.regs.regs));
+               arch_init_vcpu(&vcpu_state.arch);
+
+               err = vcpu(mm_fd, &vcpu_state);
+               if (err)
+                       panic("userspace - could not resume userspace process, "
+                             "errno = %d\n", errno);
+
+               regs->is_user = 1;
+               memcpy(&regs->gp, &vcpu_state.regs.regs,
+                      sizeof(vcpu_state.regs.regs));
+
+               UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
+               if (vcpu_state.event == VCPU_SYSCALL) {
+                       UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp);
+                       handle_syscall(regs);
+               }
+               else if (vcpu_state.event == VCPU_SIGNAL){
+                       int sig = vcpu_state.siginfo.si_signo;
+                       switch(sig) {
+                       case SIGSEGV:
+                               GET_FAULTINFO_FROM_SI(regs->faultinfo,
+                                                     vcpu_state.siginfo);
+                               (*sig_info[SIGSEGV])(SIGSEGV, regs);
+                               break;
+                       case SIGTRAP:
+                               relay_signal(SIGTRAP, regs);
+                               break;
+                       case SIGVTALRM:
+                               block_signals();
+                               (*sig_info[sig])(sig, regs);
+                               unblock_signals();
+                               break;
+                       case SIGIO:
+                       case SIGILL:
+                       case SIGBUS:
+                       case SIGFPE:
+                       case SIGWINCH:
+                               block_signals();
+                               (*sig_info[sig])(sig, regs);
+                               unblock_signals();
+                               break;
+                       default:
+                               printk(UM_KERN_ERR "userspace - child stopped "
+                                      "with signal %d\n", sig);
+                       }
+                       /* Avoid -ERESTARTSYS handling in host */
+                       if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
+                               PT_SYSCALL_NR(regs->gp) = -1;
+               }
+
+               mm_fd = interrupt_end();
+       }
+}
+
 void userspace(struct uml_pt_regs *regs)
 {
        struct itimerval timer;
@@ -778,8 +857,11 @@ void reboot_skas(void)
 void __switch_mm(struct mm_id *mm_idp)
 {
        int err;
-
        /* FIXME: need cpu pid in __switch_mm */
+
+       if (have_vcpu)
+               return;
+
        if (proc_mm) {
                err = ptrace(OLD_PTRACE_SWITCH_MM, userspace_pid[0], 0,
                             mm_idp->u.mm_fd);
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 021d41c..28a7984 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -29,6 +29,7 @@
 #include "skas.h"
 #include "skas_ptrace.h"
 #include "sysdep/sigcontext.h"
+#include "user.h"
 
 static int ptrace_child(void)
 {
@@ -165,6 +166,9 @@ static int disable_siginfo_segv;
 int have_ptrace_switch_mm;
 static int disable_ptrace_switch_mm;
 
+int have_vcpu;
+static int disable_vcpu;
+
 int skas_needs_stub;
 
 static int __init skas0_cmd_param(char *str, int* add)
@@ -176,6 +180,7 @@ static int __init skas0_cmd_param(char *str, int* add)
        disable_switch_mm = 1;
        disable_siginfo_segv = 1;
        disable_ptrace_switch_mm = 1;
+       disable_vcpu = 1;
 
        return 0;
 }
@@ -503,7 +508,7 @@ static void __init can_do_skas3(void)
 
 static void *fault_address;
 
-static int check_fault_info(struct faultinfo *fi)
+static __init int check_fault_info(struct faultinfo *fi)
 {
        return (FAULT_ADDRESS(*fi) == (unsigned long) fault_address) &&
                FAULT_WRITE(*fi) && SEGV_IS_FIXABLE(fi);
@@ -637,7 +642,7 @@ int self_mm_fd;
 
 static int switch_mm_works;
 
-static void after_switch(void)
+static __init void after_switch(void)
 {
        /*
         * If we are really in a new address space, setting this to
@@ -804,13 +809,88 @@ static int __init check_ptrace_switch_mm(void)
        return 0;
 }
 
+#ifdef UML_CONFIG_X86_32
+extern int host_gdt_entry_tls_min;
+extern void host_tls_support(void);
+
+static __init int init_vcpu_arch(struct vcpu_arch *vcpu){
+       struct user_desc *tls = vcpu->tls_array;
+       int i, err;
+
+       host_tls_support();
+       memset(tls, 0, sizeof(vcpu->tls_array));
+       for (i = 0; i < ARRAY_SIZE(vcpu->tls_array); i++) {
+               tls[i].entry_number = host_gdt_entry_tls_min + i;
+               err = get_thread_area(&tls[i]);
+               if (err) {
+                       perror("get_thread_area");
+                       return err;
+               }
+       }
+       return 0;
+}
+#else
+static int init_vcpu_arch(struct vcpu_arch *vcpu){
+       return 0;
+}
+#endif
+
+static struct vcpu_user vcpu_data;
+
+static __init int check_vcpu(void)
+{
+       void *stack;
+       int err;
+
+       non_fatal("\tvcpu ... ");
+
+       stack = mmap(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
+                    MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+       if (stack == MAP_FAILED)
+               goto bad;
+
+       get_safe_registers(vcpu_data.regs.regs);
+       vcpu_data.regs.regs[REGS_IP_INDEX] = (unsigned long) ptrace_child;
+       vcpu_data.regs.regs[REGS_SP_INDEX] = (unsigned long) stack +
+               UM_KERN_PAGE_SIZE - sizeof(void *);
+
+       if (init_vcpu_arch(&vcpu_data.arch))
+               goto bad;
+
+       err = vcpu(-1, &vcpu_data);
+       munmap(stack, UM_KERN_PAGE_SIZE);
+       if (err) {
+               non_fatal("vcpu failed with errno %d\n", err);
+               goto bad;
+       }
+
+       if (vcpu_data.event != VCPU_SYSCALL) {
+               non_fatal("vcpu returned with event = %d\n", vcpu_data.event);
+               goto bad;
+       }
+
+       non_fatal("OK\n");
+
+       if (disable_vcpu)
+               non_fatal("vcpu support disabled on command line\n");
+       else
+               have_vcpu = 1;
+
+       return 1;
+
+ bad:
+       non_fatal("Failed\n");
+       return 0;
+}
+
 static int __init can_do_skas4(void)
 {
        int ret;
 
        non_fatal("Checking for SKAS4 support in the host:\n");
 
-       ret = check_switch_mm() && check_ptrace_switch_mm() && check_siginfo();
+       ret = check_switch_mm() && check_ptrace_switch_mm() && check_siginfo()
+               && check_vcpu();
        if (ret)
                skas_needs_stub = 1;
 
diff --git a/arch/um/os-Linux/sys-i386/registers.c 
b/arch/um/os-Linux/sys-i386/registers.c
index b613473..6dfd56f 100644
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -4,10 +4,16 @@
  * Licensed under the GPL
  */
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <errno.h>
+#include <asm/ldt.h>
+#include <sys/syscall.h>
+#include <unistd.h>
 #include "kern_constants.h"
 #include "longjmp.h"
 #include "user.h"
+#include "skas.h"
 #include "sysdep/ptrace_user.h"
 
 int save_fp_registers(int pid, unsigned long *fp_regs)
@@ -72,12 +78,32 @@ int put_fp_registers(int pid, unsigned long *regs)
                return restore_fp_registers(pid, regs);
 }
 
+extern int host_gdt_entry_tls_min;
+
+#define GDT_ENTRY_TLS_ENTRIES 3
+#define GDT_ENTRY_TLS_MIN 6
+#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
+
+struct user_desc tls[GDT_ENTRY_TLS_ENTRIES];
+
+unsigned long fp_regs[FP_SIZE];
+
 void arch_init_registers(int pid)
 {
-       unsigned long fpx_regs[HOST_XFP_SIZE];
-       int err;
+       struct user_desc *entry;
+       int err, i;
 
-       err = ptrace(PTRACE_GETFPXREGS, pid, 0, fpx_regs);
+       for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) {
+               entry = &tls[i];
+               entry->entry_number = i + GDT_ENTRY_TLS_MIN;
+               err = get_thread_area(entry);
+               if (err) {
+                       perror("get_thread_area");
+                       exit(1);
+               }
+       }
+
+       err = ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs);
        if (!err)
                return;
 
@@ -87,3 +113,4 @@ void arch_init_registers(int pid)
 
        have_fpx_regs = 0;
 }
+
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c 
b/arch/um/os-Linux/sys-x86_64/registers.c
index 594d97a..43731fe 100644
--- a/arch/um/os-Linux/sys-x86_64/registers.c
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 - 2007 Jeff Dike ([EMAIL PROTECTED],linux.intel}.com)
+ * Copyright (C) 2006 - 2008 Jeff Dike ([EMAIL PROTECTED],linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -10,6 +10,7 @@
 #include "kern_constants.h"
 #include "longjmp.h"
 #include "user.h"
+#include "sysdep/ptrace_user.h"
 
 int save_fp_registers(int pid, unsigned long *fp_regs)
 {
@@ -50,3 +51,15 @@ int put_fp_registers(int pid, unsigned long *regs)
 {
        return restore_fp_registers(pid, regs);
 }
+
+unsigned long fp_regs[FP_SIZE];
+
+void arch_init_registers(int pid)
+{
+       int err;
+
+       err = ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs);
+       if(err)
+               panic("arch_init_registers : PTRACE_GETFPREGS failed, "
+                     "errno = %d", errno);
+}
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index fd0c25a..68251f2 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -164,6 +164,8 @@ static int convert_fxsr_from_user(struct user_fxsr_struct 
*fxsave,
 
 extern int have_fpx_regs;
 
+extern unsigned long fp_regs[FP_SIZE];
+
 static int copy_sc_from_user(struct pt_regs *regs,
                             struct sigcontext __user *from)
 {
@@ -177,24 +179,12 @@ static int copy_sc_from_user(struct pt_regs *regs,
        pid = userspace_pid[current_thread_info()->cpu];
        copy_sc(&regs->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;
+               struct user_fxsr_struct *fpx =
+                       (struct user_fxsr_struct *) &fp_regs;
 
-               err = convert_fxsr_from_user(&fpx, sc.fpstate);
+               err = convert_fxsr_from_user(fpx, sc.fpstate);
                if (err)
                        return 1;
-
-               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",
-                              -err);
-                       return 1;
-               }
        }
        else {
                struct user_i387_struct fp;
@@ -250,25 +240,19 @@ static int copy_sc_to_user(struct sigcontext __user *to,
 
        pid = userspace_pid[current_thread_info()->cpu];
        if (have_fpx_regs) {
-               struct user_fxsr_struct 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);
-                       return 1;
-               }
+               struct user_fxsr_struct *fpx =
+                       (struct user_fxsr_struct *) &fp_regs;
 
-               err = convert_fxsr_to_user(to_fp, &fpx);
+               err = convert_fxsr_to_user(to_fp, fpx);
                if (err)
                        return 1;
 
-               err |= __put_user(fpx.swd, &to_fp->status);
+               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,
+               if (copy_to_user(&to_fp->_fxsr_env[0], fpx,
                                 sizeof(struct user_fxsr_struct)))
                        return 1;
        }
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index c6c7131..a45d7ab 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -6,10 +6,19 @@
 #include "linux/percpu.h"
 #include "linux/sched.h"
 #include "asm/uaccess.h"
+#include <asm/unistd.h>
+#include <asm/segment.h>
+#include "kern.h"
 #include "os.h"
 #include "skas.h"
 #include "sysdep/tls.h"
 
+void copy_tls(struct user_desc *to)
+{
+       memcpy(to, current->thread.arch.tls_array,
+              sizeof(current->thread.arch.tls_array));
+}
+
 /*
  * If needed we can detect when it's uninitialized.
  *
@@ -18,11 +27,14 @@
 static int host_supports_tls = -1;
 int host_gdt_entry_tls_min;
 
-int do_set_thread_area(struct user_desc *info)
+static int do_set_thread_area(struct user_desc *info)
 {
        int ret;
        u32 cpu;
 
+       if(have_vcpu)
+               return 0;
+
        cpu = get_cpu();
        ret = os_set_thread_area(info, userspace_pid[cpu]);
        put_cpu();
@@ -300,6 +312,7 @@ int sys_set_thread_area(struct user_desc __user *user_desc)
        ret = do_set_thread_area(&info);
        if (ret)
                return ret;
+
        return set_tls_entry(current, &info, idx, 1);
 }
 
@@ -366,31 +379,38 @@ out:
        return ret;
 }
 
+extern struct user_desc tls[GDT_ENTRY_TLS_ENTRIES];
+
 /*
  * 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)
+void __init host_tls_support(void)
 {
        check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min);
        if (host_supports_tls) {
-               printk(KERN_INFO "Host TLS support detected\n");
-               printk(KERN_INFO "Detected host type: ");
+               printf("Host TLS support detected\n");
+               printf("Detected host type: ");
                switch (host_gdt_entry_tls_min) {
                case GDT_ENTRY_TLS_MIN_I386:
-                       printk(KERN_CONT "i386");
+                       printf("i386\n");
                        break;
                case GDT_ENTRY_TLS_MIN_X86_64:
-                       printk(KERN_CONT "x86_64");
+                       printf("x86_64\n");
                        break;
                }
-               printk(KERN_CONT " (GDT indexes %d to %d)\n",
-                      host_gdt_entry_tls_min,
+               printf(" (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");
-       return 0;
+               printf("Host TLS support NOT detected! "
+                      "TLS support inside UML will not work\n");
 }
 
-__initcall(__setup_host_supports_tls);
+void init_vcpu_tls(struct user_desc *to)
+{
+       struct uml_tls_struct *tls = current->thread.arch.tls_array;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(current->thread.arch.tls_array); i++)
+               to[i] = tls[i].tls;
+}
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 1a899a7..1e426f8 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -42,6 +42,8 @@ void copy_sc(struct uml_pt_regs *regs, void *from)
 #undef GETREG
 }
 
+static unsigned long fp_regs[HOST_FP_SIZE];
+
 static int copy_sc_from_user(struct pt_regs *regs,
                             struct sigcontext __user *from,
                             struct _fpstate __user *fpp)
@@ -81,13 +83,17 @@ static int copy_sc_from_user(struct pt_regs *regs,
        if (err)
                return 1;
 
-       err = restore_fp_registers(userspace_pid[current_thread_info()->cpu],
-                                  (unsigned long *) &fp);
-       if (err < 0) {
-               printk(KERN_ERR "copy_sc_from_user - "
-                      "restore_fp_registers failed, errno = %d\n",
-                      -err);
-               return 1;
+       if (have_vcpu)
+               memcpy(fp_regs, &fp, sizeof(fp_regs));
+       else {
+               err = 
restore_fp_registers(userspace_pid[current_thread_info()->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;
@@ -143,14 +149,18 @@ static int copy_sc_to_user(struct sigcontext __user *to,
        if (err)
                return 1;
 
-       err = save_fp_registers(userspace_pid[current_thread_info()->cpu],
-                               (unsigned long *) &fp);
-       if (err < 0) {
-               printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
-                      "failed, errno = %d\n", -err);
-               return 1;
+       if (have_vcpu)
+               memcpy(&fp, fp_regs, sizeof(fp));
+       else {
+               err = 
save_fp_registers(userspace_pid[current_thread_info()->cpu],
+                                       (unsigned long *) &fp);
+               if (err < 0) {
+                       printk(KERN_ERR "copy_sc_from_user - "
+                              "restore_fp_registers failed, errno = %d\n",
+                              -err);
+                       return 1;
+               }
        }
-
        if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
                return 1;
 
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
index e861ad6..fbbc903 100644
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -28,61 +28,78 @@ asmlinkage long sys_uname64(struct new_utsname __user * 
name)
 
 long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
 {
-       unsigned long *ptr = addr, tmp;
-       long ret;
-       int pid = userspace_pid[0];
+       long ret = 0;
+
+       if (have_vcpu) {
+               unsigned long *regs = task->thread.regs.regs.gp;
+               switch (code) {
+               case ARCH_SET_FS:
+                       task->thread.arch.fs = (unsigned long) addr;
+                       regs[HOST_FS_BASE] = (unsigned long) addr;
+                       break;
+               case ARCH_SET_GS:
+                       regs[HOST_GS_BASE] = (unsigned long) addr;
+                       break;
+               case ARCH_GET_FS:
+                       ret = put_user(regs[HOST_FS_BASE], addr);
+                       break;
+               case ARCH_GET_GS:
+                       ret = put_user(regs[HOST_GS_BASE], addr);
+                       break;
+               }
+       } else {
+               unsigned long *ptr = addr, tmp;
+               int pid = userspace_pid[0];
 
-       /*
-        * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
-        * be safe), we need to call arch_prctl on the host because
-        * setting %fs may result in something else happening (like a
-        * GDT or thread.fs being set instead).  So, we let the host
-        * fiddle the registers and thread struct and restore the
-        * registers afterwards.
-        *
-        * So, the saved registers are stored to the process (this
-        * needed because a stub may have been the last thing to run),
-        * arch_prctl is run on the host, then the registers are read
-        * back.
-        */
-       switch (code) {
-       case ARCH_SET_FS:
-       case ARCH_SET_GS:
-               ret = restore_registers(pid, &current->thread.regs.regs);
-               if (ret)
-                       return ret;
-               break;
-       case ARCH_GET_FS:
-       case ARCH_GET_GS:
                /*
-                * With these two, we read to a local pointer and
-                * put_user it to the userspace pointer that we were
-                * given.  If addr isn't valid (because it hasn't been
-                * faulted in or is just bogus), we want put_user to
-                * fault it in (or return -EFAULT) instead of having
-                * the host return -EFAULT.
+                * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
+                * be safe), we need to call arch_prctl on the host because
+                * setting %fs may result in something else happening (like a
+                * GDT or thread.fs being set instead).  So, we let the host
+                * fiddle the registers and thread struct and restore the
+                * registers afterwards.
+                *
+                * So, the saved registers are stored to the process (this
+                * needed because a stub may have been the last thing to run),
+                * arch_prctl is run on the host, then the registers are read
+                * back.
                 */
-               ptr = &tmp;
-       }
-
-       ret = os_arch_prctl(pid, code, ptr);
-       if (ret)
-               return ret;
+               switch (code) {
+               case ARCH_SET_FS:
+               case ARCH_SET_GS:
+                       restore_registers(pid, &current->thread.regs.regs);
+                       break;
+               case ARCH_GET_FS:
+               case ARCH_GET_GS:
+                       /*
+                        * With these two, we read to a local pointer and
+                        * put_user it to the userspace pointer that we were
+                        * given.  If addr isn't valid (because it hasn't been
+                        * faulted in or is just bogus), we want put_user to
+                        * fault it in (or return -EFAULT) instead of having
+                        * the host return -EFAULT.
+                        */
+                       ptr = &tmp;
+               }
 
-       switch (code) {
-       case ARCH_SET_FS:
-               current->thread.arch.fs = (unsigned long) ptr;
-               ret = save_registers(pid, &current->thread.regs.regs);
-               break;
-       case ARCH_SET_GS:
-               ret = save_registers(pid, &current->thread.regs.regs);
-               break;
-       case ARCH_GET_FS:
-               ret = put_user(tmp, addr);
-               break;
-       case ARCH_GET_GS:
-               ret = put_user(tmp, addr);
-               break;
+               ret = os_arch_prctl(pid, code, ptr);
+               if (ret)
+                       return ret;
+               switch (code) {
+               case ARCH_SET_FS:
+                       current->thread.arch.fs = (unsigned long) ptr;
+                       save_registers(pid, &current->thread.regs.regs);
+                       break;
+               case ARCH_SET_GS:
+                       save_registers(pid, &current->thread.regs.regs);
+                       break;
+               case ARCH_GET_FS:
+                       ret = put_user(tmp, addr);
+                       break;
+               case ARCH_GET_GS:
+                       ret = put_user(tmp, addr);
+                       break;
+               }
        }
 
        return ret;
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
index a2b7fe1..d7bca3e 100644
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -1,25 +1,19 @@
 /*
- * Copyright (C) 2002 Jeff Dike ([EMAIL PROTECTED])
+ * Copyright (C) 2002 - 2008 Jeff Dike ([EMAIL PROTECTED],linux.intel}.com)
  * Licensed under the GPL
  */
 
 #ifndef __UM_PROCESSOR_I386_H
 #define __UM_PROCESSOR_I386_H
 
-#include "linux/string.h"
-#include "asm/host_ldt.h"
-#include "asm/segment.h"
-
-extern int host_has_cmov;
-
-/* include faultinfo structure */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/host_ldt.h>
+#include <asm/segment.h>
 #include "sysdep/faultinfo.h"
+#include "sysdep/tls.h"
 
-struct uml_tls_struct {
-       struct user_desc tls;
-       unsigned flushed:1;
-       unsigned present:1;
-};
+extern int host_has_cmov;
 
 struct arch_thread {
        struct uml_tls_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
@@ -38,8 +32,12 @@ struct arch_thread {
 
 static inline void arch_flush_thread(struct arch_thread *thread)
 {
+       int i;
+
        /* Clear any TLS still hanging */
        memset(&thread->tls_array, 0, sizeof(thread->tls_array));
+       for (i = 0; i < ARRAY_SIZE(thread->tls_array); i++)
+               thread->tls_array[i].tls.entry_number = GDT_ENTRY_TLS_MIN + i;
 }
 
 static inline void arch_copy_thread(struct arch_thread *from,

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft 
Defy all challenges. Microsoft(R) Visual Studio 2008. 
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
User-mode-linux-user mailing list
User-mode-linux-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-user

Reply via email to