* [uml-devel] [RFC PATCH 12/12] SKAS4 - Guest vcpu support
@ 2008-05-15 20:11 Jeff Dike
0 siblings, 0 replies; only message in thread
From: Jeff Dike @ 2008-05-15 20:11 UTC (permalink / raw)
To: uml-user, uml-devel
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(¤t->thread.regs.regs);
+ if (have_vcpu)
+ vcpu_userspace(¤t->thread.regs.regs,
+ current->mm->context.id.u.mm_fd);
+ else
+ userspace(¤t->thread.regs.regs);
}
else do_exit(0);
}
@@ -176,7 +181,11 @@ void fork_handler(void)
/* Handle any immediate reschedules or signals */
interrupt_end();
- userspace(¤t->thread.regs.regs);
+ if (have_vcpu)
+ vcpu_userspace(¤t->thread.regs.regs,
+ current->mm->context.id.u.mm_fd);
+ else
+ userspace(¤t->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, ®s->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(®s->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 (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2006 - 2008 Jeff Dike (jdike@{addtoit,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(®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;
+ 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, ¤t->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, ¤t->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, ¤t->thread.regs.regs);
- break;
- case ARCH_SET_GS:
- ret = save_registers(pid, ¤t->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, ¤t->thread.regs.regs);
+ break;
+ case ARCH_SET_GS:
+ save_registers(pid, ¤t->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 (jdike@karaya.com)
+ * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,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-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2008-05-15 20:11 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-15 20:11 [uml-devel] [RFC PATCH 12/12] SKAS4 - Guest vcpu support Jeff Dike
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.