linux-um archives
 help / color / mirror / Atom feed
* [uml-devel] [RFC PATCH 4/12] SKAS4 - Host 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, which allows a process to enter a new
mode in which a signal or system call will cause a return to the
original context.

diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 3c34122..0a91cb1 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -20,7 +20,7 @@ extern int kmalloc_ok;
 extern unsigned long alloc_stack(int order, int atomic);
 extern void free_stack(unsigned long stack, int order);
 
-extern int do_signal(void);
+extern void do_signal(void);
 extern void copy_sc(struct uml_pt_regs *regs, void *from);
 extern void interrupt_end(void);
 extern void relay_signal(int sig, struct uml_pt_regs *regs);
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
index 11c0896..510c80f 100644
--- a/arch/um/include/sysdep-i386/ptrace.h
+++ b/arch/um/include/sysdep-i386/ptrace.h
@@ -156,7 +156,7 @@ struct syscall_args {
 	} while (0)
 
 #define UPT_SET_SYSCALL_RETURN(r, res) \
-	REGS_SET_SYSCALL_RETURN((r)->regs, (res))
+	REGS_SET_SYSCALL_RETURN((r)->gp, (res))
 
 #define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
 
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
index 9ea44d1..d3d1dda 100644
--- a/arch/um/include/sysdep-x86_64/ptrace.h
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -225,11 +225,11 @@ struct syscall_args {
 	})
 
 #define UPT_SET_SYSCALL_RETURN(r, res) \
-	REGS_SET_SYSCALL_RETURN((r)->regs, (res))
+	REGS_SET_SYSCALL_RETURN((r)->gp, (res))
 
 #define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
 
-#define UPT_SEGV_IS_FIXABLE(r) REGS_SEGV_IS_FIXABLE(&r->skas)
+#define UPT_SEGV_IS_FIXABLE(r) REGS_SEGV_IS_FIXABLE(&(r)->skas)
 
 #define UPT_FAULTINFO(r) (&(r)->faultinfo)
 
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index e8cb9ff..0963fcd 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -115,7 +115,7 @@ void interrupt_end(void)
 {
 	if (need_resched())
 		schedule();
-	if (test_tsk_thread_flag(current, TIF_SIGPENDING))
+	if (test_thread_flag(TIF_SIGPENDING))
 		do_signal();
 }
 
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index b0fce72..b1fcfde 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -85,8 +85,11 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
 	return err;
 }
 
-static int kern_do_signal(struct pt_regs *regs)
+extern int unvcpu(struct pt_regs *regs, siginfo_t *siginfo);
+
+void do_signal(void)
 {
+	struct pt_regs *regs = &current->thread.regs;
 	struct k_sigaction ka_copy;
 	siginfo_t info;
 	sigset_t *oldset;
@@ -98,6 +101,11 @@ static int kern_do_signal(struct pt_regs *regs)
 		oldset = &current->blocked;
 
 	while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
+		if (test_thread_flag(TIF_VCPU)) {
+			PT_REGS_SET_SYSCALL_RETURN(regs, unvcpu(regs, &info));
+			return;
+		}
+
 		handled_sig = 1;
 		/* Whee!  Actually deliver the signal.  */
 		if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) {
@@ -150,12 +158,6 @@ static int kern_do_signal(struct pt_regs *regs)
 		clear_thread_flag(TIF_RESTORE_SIGMASK);
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
-	return handled_sig;
-}
-
-int do_signal(void)
-{
-	return kern_do_signal(&current->thread.regs);
 }
 
 /*
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index 4e3b820..c677b8e 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -12,12 +12,19 @@
 extern int syscall_table_size;
 #define NR_syscalls (syscall_table_size / sizeof(void *))
 
+extern int unvcpu(struct pt_regs *regs, siginfo_t *siginfo);
+
 void handle_syscall(struct uml_pt_regs *r)
 {
 	struct pt_regs *regs = container_of(r, struct pt_regs, regs);
 	long result;
 	int syscall;
 
+	if (test_thread_flag(TIF_VCPU)) {
+		REGS_SET_SYSCALL_RETURN(r->gp, unvcpu(regs, NULL));
+		return;
+	}
+
 	syscall_trace(r, 0);
 
 	/*
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index a9c2f6f..63c782d 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -1,17 +1,17 @@
 /*
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2000 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "linux/file.h"
-#include "linux/fs.h"
-#include "linux/mm.h"
-#include "linux/sched.h"
-#include "linux/utsname.h"
-#include "asm/current.h"
-#include "asm/mman.h"
-#include "asm/uaccess.h"
-#include "asm/unistd.h"
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <asm/current.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 long sys_fork(void)
 {
@@ -158,3 +158,11 @@ long sys_switch_mm(int fd, long __user *save, long __user *new,
 {
 	return do_switch_mm(fd, save, new, ip, sp, &current->thread.regs);
 }
+
+extern long do_vcpu(int mm_fd, struct vcpu_user __user *new,
+		    struct pt_regs *regs);
+
+long sys_vcpu(int mm_fd, struct vcpu_user __user *new)
+{
+	return do_vcpu(mm_fd, new, &current->thread.regs);
+}
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index cbb7986..21e24ba 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -446,8 +446,14 @@ void userspace(struct uml_pt_regs *regs)
 				       "with signal %d\n", sig);
 				fatal_sigsegv();
 			}
-			pid = userspace_pid[0];
+
+			/*
+			 * userspace_pid can change in in_interrupt since
+			 * PTRACE_SWITCH_MM can cause a process to change
+			 * address spaces
+			 */
 			interrupt_end();
+			pid = userspace_pid[0];
 
 			/* Avoid -ERESTARTSYS handling in host */
 			if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c
index 8b5c216..9bb72fc 100644
--- a/arch/um/sys-x86_64/syscall_table.c
+++ b/arch/um/sys-x86_64/syscall_table.c
@@ -40,6 +40,7 @@
 #define stub_sigaltstack sys_sigaltstack
 #define stub_rt_sigreturn sys_rt_sigreturn
 #define stub_switch_mm sys_switch_mm
+#define stub_vcpu sys_vcpu
 
 #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
 #undef _ASM_X86_64_UNISTD_H_
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 4b87c32..1e2adae 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -371,7 +371,7 @@ ENTRY(system_call)
 	GET_THREAD_INFO(%ebp)
 					# system call tracing in operation / emulation
 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
-	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+	testl $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_VCPU),TI_flags(%ebp)
 	jnz syscall_trace_entry
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index bb573ef..f3f403a 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -244,7 +244,7 @@ ENTRY(system_call_after_swapgs)
 	movq  %rcx,RIP-ARGOFFSET(%rsp)
 	CFI_REL_OFFSET rip,RIP-ARGOFFSET
 	GET_THREAD_INFO(%rcx)
-	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
+	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP|_TIF_VCPU),threadinfo_flags(%rcx)
 	jnz tracesys
 	cmpq $__NR_syscall_max,%rax
 	ja badsys
@@ -323,6 +323,12 @@ tracesys:
 	FIXUP_TOP_OF_STACK %rdi
 	movq %rsp,%rdi
 	call syscall_trace_enter
+	testl %eax, %eax
+	jz 2f
+	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
+	RESTORE_REST
+	jmp int_ret_from_sys_call
+2:
 	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 	cmpq $__NR_syscall_max,%rax
@@ -482,6 +488,23 @@ ENTRY(stub_rt_sigreturn)
 END(stub_rt_sigreturn)
 
 /*
+ * vcpu is special too
+ */
+ENTRY(stub_vcpu)
+	CFI_STARTPROC
+	addq $8, %rsp
+	CFI_ADJUST_CFA_OFFSET	-8
+	SAVE_REST
+	movq %rsp,%rdx
+	FIXUP_TOP_OF_STACK %r11
+	call sys_vcpu
+	movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
+	RESTORE_REST
+	jmp int_ret_from_sys_call
+	CFI_ENDPROC
+END(stub_vcpu)
+
+/*
  * initial frame state for interrupts and exceptions
  */
 	.macro _frame ref
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index de84950..44334e2 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1453,6 +1453,8 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
 	force_sig_info(SIGTRAP, &info, tsk);
 }
 
+extern int unvcpu(struct pt_regs *regs, siginfo_t *siginfo);
+
 /* notification of system call entry/exit
  * - triggered by current->work.syscall_trace
  */
@@ -1489,6 +1491,14 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit)
 			goto out;
 	}
 
+	if (test_thread_flag(TIF_VCPU)) {
+		if (entryexit)
+			return 0;
+
+		regs->ax = unvcpu(regs, NULL);
+		return 1;
+	}
+
 	if (!(current->ptrace & PT_PTRACED))
 		goto out;
 
@@ -1616,11 +1626,18 @@ static void syscall_trace(struct pt_regs *regs)
 	}
 }
 
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+extern int unvcpu(struct pt_regs *regs, siginfo_t *siginfo);
+
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
 	/* do the secure computing check first */
 	secure_computing(regs->orig_ax);
 
+	if (test_thread_flag(TIF_VCPU)) {
+		regs->ax = unvcpu(regs, NULL);
+		return 1;
+	}
+
 	if (test_thread_flag(TIF_SYSCALL_TRACE)
 	    && (current->ptrace & PT_PTRACED))
 		syscall_trace(regs);
@@ -1638,6 +1655,8 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 					    regs->dx, regs->r10);
 		}
 	}
+
+	return 0;
 }
 
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 0157a6f..73b5d21 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -573,6 +573,8 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	return ret;
 }
 
+extern int unvcpu(struct pt_regs *regs, siginfo_t *siginfo);
+
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -603,6 +605,11 @@ static void do_signal(struct pt_regs *regs)
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
+		if (test_thread_flag(TIF_VCPU)) {
+			regs->ax = unvcpu(regs, &info);
+			return;
+		}
+
 		/* Re-enable any watchpoints before delivering the
 		 * signal to user space. The processor register will
 		 * have been cleared if the watchpoint triggered
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 1c83e51..8978b40 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -407,6 +407,8 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	return ret;
 }
 
+extern int unvcpu(struct pt_regs *regs, siginfo_t *siginfo);
+
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -435,6 +437,11 @@ static void do_signal(struct pt_regs *regs)
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
+		if (test_thread_flag(TIF_VCPU)) {
+			regs->ax = unvcpu(regs, &info);
+			return;
+		}
+
 		/* Re-enable any watchpoints before delivering the
 		 * signal to user space. The processor register will
 		 * have been cleared if the watchpoint triggered
diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c
index 23f6aff..d5d54f6 100644
--- a/arch/x86/kernel/sys_i386_32.c
+++ b/arch/x86/kernel/sys_i386_32.c
@@ -273,3 +273,17 @@ asmlinkage long sys_switch_mm(struct pt_regs regs)
 			    (struct __user user_regs *) regs.dx, regs.si,
 			    regs.di, &regs);
 }
+
+extern long do_vcpu(int mm_fd, struct vcpu_user __user *new,
+		    struct pt_regs *regs);
+
+asmlinkage long sys_vcpu(struct pt_regs regs)
+{
+	int err;
+
+	err = do_vcpu(regs.bx, (struct vcpu_user __user *) regs.cx, &regs);
+	if (err)
+		return err;
+
+	return regs.ax;
+}
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index b3c98f5..aab9121 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -262,3 +262,18 @@ asmlinkage long sys_switch_mm(int fd, struct __user user_regs *save,
 {
 	return do_switch_mm(fd, save, new, ip, sp, regs);
 }
+
+extern long do_vcpu(int mm_fd, struct vcpu_user __user *new,
+		    struct pt_regs *regs);
+
+asmlinkage long sys_vcpu(int mm_fd, struct vcpu_user __user *new,
+			 struct pt_regs *regs)
+{
+	int err;
+
+	err = do_vcpu(mm_fd, new, regs);
+	if (err)
+		return err;
+
+	return regs->ax;
+}
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index 27f20f0..5b9803a 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -328,3 +328,4 @@ ENTRY(sys_call_table)
 	.long sys_timerfd_gettime
 	.long sys_new_mm
 	.long sys_switch_mm
+	.long sys_vcpu
diff --git a/include/asm-um/desc.h b/include/asm-um/desc.h
index 4ec34a5..efbabaf 100644
--- a/include/asm-um/desc.h
+++ b/include/asm-um/desc.h
@@ -1,6 +1,11 @@
 #ifndef __UM_DESC_H
 #define __UM_DESC_H
 
+#ifdef CONFIG_64BIT
+#define LM(info) (info)->lm == 0
+#else
+#define LM(info) (1)
+#endif
 /* Taken from asm-i386/desc.h, it's the only thing we need. The rest wouldn't
  * compile, and has never been used. */
 #define LDT_empty(info) (\
@@ -11,6 +16,7 @@
 	(info)->seg_32bit	== 0	&& \
 	(info)->limit_in_pages	== 0	&& \
 	(info)->seg_not_present	== 1	&& \
+	LM(info)			&& \
 	(info)->useable		== 0	)
 
 #endif
diff --git a/include/asm-um/host_ldt-i386.h b/include/asm-um/host_ldt-i386.h
index b27cb0a..e2ad59c 100644
--- a/include/asm-um/host_ldt-i386.h
+++ b/include/asm-um/host_ldt-i386.h
@@ -1,7 +1,8 @@
 #ifndef __ASM_HOST_LDT_I386_H
 #define __ASM_HOST_LDT_I386_H
 
-#include "asm/arch/ldt.h"
+#include <asm/desc.h>
+#include <asm/arch/ldt.h>
 
 /*
  * macros stolen from include/asm-i386/desc.h
@@ -21,14 +22,4 @@
 	((info)->useable << 20) | \
 	0x7000)
 
-#define LDT_empty(info) (\
-	(info)->base_addr	== 0	&& \
-	(info)->limit		== 0	&& \
-	(info)->contents	== 0	&& \
-	(info)->read_exec_only	== 1	&& \
-	(info)->seg_32bit	== 0	&& \
-	(info)->limit_in_pages	== 0	&& \
-	(info)->seg_not_present	== 1	&& \
-	(info)->useable		== 0	)
-
 #endif
diff --git a/include/asm-um/host_ldt-x86_64.h b/include/asm-um/host_ldt-x86_64.h
index 74a63f7..585c162 100644
--- a/include/asm-um/host_ldt-x86_64.h
+++ b/include/asm-um/host_ldt-x86_64.h
@@ -1,7 +1,8 @@
 #ifndef __ASM_HOST_LDT_X86_64_H
 #define __ASM_HOST_LDT_X86_64_H
 
-#include "asm/arch/ldt.h"
+#include <asm/desc.h>
+#include <asm/arch/ldt.h>
 
 /*
  * macros stolen from include/asm-x86_64/desc.h
@@ -24,15 +25,4 @@
 	/* ((info)->lm << 21) | */ \
 	0x7000)
 
-#define LDT_empty(info) (\
-	(info)->base_addr	== 0	&& \
-	(info)->limit		== 0	&& \
-	(info)->contents	== 0	&& \
-	(info)->read_exec_only	== 1	&& \
-	(info)->seg_32bit	== 0	&& \
-	(info)->limit_in_pages	== 0	&& \
-	(info)->seg_not_present	== 1	&& \
-	(info)->useable		== 0	&& \
-	(info)->lm              == 0)
-
 #endif
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 356b83e..6aa19f3 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -83,6 +83,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE	 	5
 #define TIF_SYSCALL_AUDIT	6
 #define TIF_RESTORE_SIGMASK	7
+#define TIF_VCPU		8
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
@@ -91,5 +92,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
+#define _TIF_VCPU		(1 << TIF_VCPU)
 
 #endif
diff --git a/include/asm-x86/thread_info_32.h b/include/asm-x86/thread_info_32.h
index 5bd5082..920c94a 100644
--- a/include/asm-x86/thread_info_32.h
+++ b/include/asm-x86/thread_info_32.h
@@ -142,6 +142,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_DEBUGCTLMSR		22	/* uses thread_struct.debugctlmsr */
 #define TIF_DS_AREA_MSR 	23      /* uses thread_struct.ds_area_msr */
 #define TIF_BTS_TRACE_TS        24      /* record scheduling event timestamps */
+#define TIF_VCPU		25
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
@@ -161,6 +162,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_DEBUGCTLMSR	(1<<TIF_DEBUGCTLMSR)
 #define _TIF_DS_AREA_MSR	(1<<TIF_DS_AREA_MSR)
 #define _TIF_BTS_TRACE_TS	(1<<TIF_BTS_TRACE_TS)
+#define _TIF_VCPU		(1<<TIF_VCPU)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h
index 6c9b214..179d036 100644
--- a/include/asm-x86/thread_info_64.h
+++ b/include/asm-x86/thread_info_64.h
@@ -125,6 +125,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define TIF_DEBUGCTLMSR		25	/* uses thread_struct.debugctlmsr */
 #define TIF_DS_AREA_MSR		26      /* uses thread_struct.ds_area_msr */
 #define TIF_BTS_TRACE_TS	27      /* record scheduling event timestamps */
+#define TIF_VCPU		28
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
@@ -146,6 +147,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define _TIF_DEBUGCTLMSR	(1<<TIF_DEBUGCTLMSR)
 #define _TIF_DS_AREA_MSR	(1<<TIF_DS_AREA_MSR)
 #define _TIF_BTS_TRACE_TS	(1<<TIF_BTS_TRACE_TS)
+#define _TIF_VCPU		(1<<TIF_VCPU)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
diff --git a/include/asm-x86/unistd_32.h b/include/asm-x86/unistd_32.h
index 5f8f291..cadbdb1 100644
--- a/include/asm-x86/unistd_32.h
+++ b/include/asm-x86/unistd_32.h
@@ -334,6 +334,7 @@
 #define __NR_timerfd_gettime	326
 #define __NR_new_mm		327
 #define __NR_switch_mm		328
+#define __NR_vcpu		329
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-x86/unistd_64.h b/include/asm-x86/unistd_64.h
index a674098..51bd17c 100644
--- a/include/asm-x86/unistd_64.h
+++ b/include/asm-x86/unistd_64.h
@@ -643,6 +643,8 @@ __SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
 __SYSCALL(__NR_new_mm, sys_new_mm)
 #define __NR_switch_mm				289
 __SYSCALL(__NR_switch_mm, stub_switch_mm)
+#define __NR_vcpu				290
+__SYSCALL(__NR_vcpu, stub_vcpu)
 
 
 #ifndef __NO_STUBS
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 1f74e1d..5ed65eb 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -193,6 +193,7 @@ extern struct group_info init_groups;
 		[PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),		\
 	},								\
 	.dirties = INIT_PROP_LOCAL_SINGLE(dirties),			\
+	.vcpu		= NULL,						\
 	INIT_IDS							\
 	INIT_TRACE_IRQFLAGS						\
 	INIT_LOCKDEP							\
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7360fde..5759bba 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -65,6 +65,7 @@ struct sched_param {
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/cputime.h>
+#include <asm/ldt.h>
 
 #include <linux/smp.h>
 #include <linux/sem.h>
@@ -991,6 +992,24 @@ struct sched_rt_entity {
 #endif
 };
 
+struct vcpu_user {
+	enum { VCPU_SYSCALL, VCPU_SIGNAL } event;
+	struct user_regs regs;
+	siginfo_t siginfo;
+#if defined(CONFIG_X86_32) && !defined(CONFIG_UML)
+	struct user_desc tls_array[GDT_ENTRY_TLS_ENTRIES];
+#endif
+};
+
+struct vcpu {
+	struct vcpu_user user;
+	struct mm_struct *mm;
+	struct vcpu_user __user *state;
+#if defined(CONFIG_X86_32) && !defined(CONFIG_UML)
+	struct user_desc tls[GDT_ENTRY_TLS_ENTRIES];
+#endif
+};
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	void *stack;
@@ -1103,6 +1122,7 @@ struct task_struct {
   	cputime_t it_prof_expires, it_virt_expires;
 	unsigned long long it_sched_expires;
 	struct list_head cpu_timers[3];
+	struct vcpu *vcpu;
 
 /* process credentials */
 	uid_t uid,euid,suid,fsuid;
diff --git a/kernel/Makefile b/kernel/Makefile
index 6c584c5..0119a37 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
 	    rcupdate.o extable.o params.o posix-timers.o \
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o rwsem.o nsproxy.o srcu.o \
-	    notifier.o ksysfs.o pm_qos_params.o
+	    notifier.o ksysfs.o pm_qos_params.o vcpu.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_check.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --git a/kernel/exit.c b/kernel/exit.c
index 073005b..bda5e7f 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -175,6 +175,11 @@ repeat:
 
 	write_unlock_irq(&tasklist_lock);
 	release_thread(p);
+
+	if (p->vcpu && p->vcpu->mm)
+		mmput(p->vcpu->mm);
+	kfree(p->vcpu);
+
 	call_rcu(&p->rcu, delayed_put_task_struct);
 
 	p = leader;
diff --git a/kernel/fork.c b/kernel/fork.c
index 4ca580a..3b8ed4c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1086,6 +1086,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	clear_tsk_thread_flag(p, TIF_SIGPENDING);
 	init_sigpending(&p->pending);
 
+	p->vcpu = NULL;
+
 	p->utime = cputime_zero;
 	p->stime = cputime_zero;
 	p->gtime = cputime_zero;
diff --git a/kernel/signal.c b/kernel/signal.c
index 6025e33..67b5ec5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1785,6 +1785,9 @@ relock:
 		if (!signr)
 			break; /* will return 0 */
 
+		if (test_thread_flag(TIF_VCPU))
+			break;
+
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			ptrace_signal_deliver(regs, cookie);
 
diff --git a/kernel/vcpu.c b/kernel/vcpu.c
new file mode 100644
index 0000000..5ca259e
--- /dev/null
+++ b/kernel/vcpu.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/desc.h>
+
+extern asmlinkage int sys_get_thread_area(struct user_desc __user *u_info);
+extern asmlinkage int sys_set_thread_area(struct user_desc __user *u_info);
+extern int do_switch(struct task_struct *task, int fd);
+
+long do_vcpu(int mm_fd, struct vcpu_user __user *new, struct pt_regs *regs)
+{
+	mm_segment_t fs;
+	struct vcpu *vcpu;
+	int err;
+
+	if (current->vcpu == NULL) {
+		current->vcpu = kmalloc(sizeof(struct vcpu), GFP_KERNEL);
+		if (current->vcpu == NULL)
+			return -ENOMEM;
+	}
+
+	vcpu = current->vcpu;
+	vcpu->mm = NULL;
+	vcpu->state = new;
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = pt_regs_to_ptrace(&vcpu->user.regs, regs);
+	set_fs(fs);
+	if (err)
+		return err;
+
+	err = ptrace_to_pt_regs(regs, &new->regs);
+	if (err)
+		return err;
+
+#if defined(CONFIG_X86_32) && !defined(CONFIG_UML)
+	{ int i;
+
+	memcpy(vcpu->tls, current->thread.tls_array, sizeof(vcpu->tls));
+	for (i = 0; i < ARRAY_SIZE(new->tls_array); i++){
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+		vcpu->tls[i].entry_number = GDT_ENTRY_TLS_MIN + i;
+		err = sys_get_thread_area(&vcpu->tls[i]);
+		set_fs(fs);
+		if (err)
+			return err;
+
+		err = sys_set_thread_area(&new->tls_array[i]);
+		if (err)
+			return err;
+	}
+	}
+#endif
+
+	if (mm_fd != -1) {
+		vcpu->mm = current->mm;
+		atomic_inc(&vcpu->mm->mm_users);
+
+		err = do_switch(current, mm_fd);
+		if (err)
+			return err;
+	}
+
+#if defined(CONFIG_X86_32) && !defined(CONFIG_UML)
+	loadsegment(gs, current->thread.gs);
+#endif
+	set_thread_flag(TIF_VCPU);
+
+	return 0;
+}
+
+extern void do_switch_mm_struct(struct task_struct *task,
+				struct mm_struct *new);
+
+int unvcpu(struct pt_regs *regs, siginfo_t *siginfo)
+{
+	mm_segment_t fs;
+	struct vcpu *vcpu;
+	int err, event;
+
+	clear_thread_flag(TIF_VCPU);
+
+	vcpu = current->vcpu;
+	if (vcpu->mm != NULL) {
+		do_switch_mm_struct(current, vcpu->mm);
+		mmput(vcpu->mm);
+		vcpu->mm = NULL;
+	}
+
+	err = pt_regs_to_ptrace(&vcpu->state->regs, regs);
+	if (err)
+		return err;
+
+	err = -EFAULT;
+	if ((siginfo != NULL) &&
+	    (copy_to_user(&vcpu->state->siginfo, siginfo,
+			  sizeof(siginfo_t)) != 0))
+		return err;
+
+	event = (siginfo != NULL) ? VCPU_SIGNAL : VCPU_SYSCALL;
+	if (copy_to_user(&vcpu->state->event, &event, sizeof(event)) != 0)
+		return err;
+
+#if defined(CONFIG_X86_32) && !defined(CONFIG_UML)
+	{ int i;
+	for (i = 0; i < ARRAY_SIZE(vcpu->state->tls_array); i++){
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_set_thread_area(&vcpu->tls[i]);
+		set_fs(fs);
+		if (err)
+			return err;
+	}
+	}
+#endif
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = ptrace_to_pt_regs(regs, &vcpu->user.regs);
+	set_fs(fs);
+
+	return err;
+}

-------------------------------------------------------------------------
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 4/12] SKAS4 - Host VCPU support Jeff Dike

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox