[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH 17/35] Segment register changes for Xen



1. We clear FS/GS before changing TLS entries and switching LDT, as
otherwise the hypervisor will fail to restore thread-local values on
return to the guest kernel and we take a slow exception path.

2. We allow for the fact that the guest kernel may not run in ring 0.
This requires some abstraction in a few places when setting %cs or
checking privilege level (user vs kernel).

Signed-off-by: Ian Pratt <ian.pratt@xxxxxxxxxxxxx>
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx>
Signed-off-by: Chris Wright <chrisw@xxxxxxxxxxxx>
---
 arch/i386/kernel/process.c                   |    4 +++-
 arch/i386/mm/fault.c                         |    8 +++++---
 include/asm-i386/mach-default/mach_segment.h |    8 ++++++++
 include/asm-i386/mach-default/mach_system.h  |    2 ++
 include/asm-i386/mach-xen/mach_segment.h     |    9 +++++++++
 include/asm-i386/mach-xen/mach_system.h      |    2 ++
 include/asm-i386/mach-xen/setup_arch_post.h  |    2 ++
 include/asm-i386/ptrace.h                    |    6 ++++--
 include/asm-i386/segment.h                   |    2 ++
 9 files changed, 37 insertions(+), 6 deletions(-)

--- linus-2.6.orig/arch/i386/kernel/process.c
+++ linus-2.6/arch/i386/kernel/process.c
@@ -347,7 +347,7 @@ int kernel_thread(int (*fn)(void *), voi
        regs.xes = __USER_DS;
        regs.orig_eax = -1;
        regs.eip = (unsigned long) kernel_thread_helper;
-       regs.xcs = __KERNEL_CS;
+       regs.xcs = get_kernel_cs();
        regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
 
        /* Ok, create the new process.. */
@@ -647,6 +647,8 @@ struct task_struct fastcall * __switch_t
         */
        savesegment(fs, prev->fs);
        savesegment(gs, prev->gs);
+       clearsegment(fs);
+       clearsegment(gs);
 
        /*
         * Load the per-thread Thread-Local Storage descriptor.
--- linus-2.6.orig/arch/i386/mm/fault.c
+++ linus-2.6/arch/i386/mm/fault.c
@@ -28,6 +28,8 @@
 #include <asm/desc.h>
 #include <asm/kdebug.h>
 
+#include <mach_segment.h>
+
 extern void die(const char *,struct pt_regs *,long);
 
 /*
@@ -78,14 +80,14 @@ static inline unsigned long get_segment_
        u32 seg_ar, seg_limit, base, *desc;
 
        /* The standard kernel/user address space limit. */
-       *eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg;
+       *eip_limit = (seg & USER_MODE_MASK) ? USER_DS.seg : KERNEL_DS.seg;
 
        /* Unlikely, but must come before segment checks. */
        if (unlikely((regs->eflags & VM_MASK) != 0))
                return eip + (seg << 4);
        
        /* By far the most common cases. */
-       if (likely(seg == __USER_CS || seg == __KERNEL_CS))
+       if (likely(seg == __USER_CS || seg == get_kernel_cs()))
                return eip;
 
        /* Check the segment exists, is within the current LDT/GDT size,
@@ -400,7 +402,7 @@ good_area:
        switch (error_code & 3) {
                default:        /* 3: write, present */
 #ifdef TEST_VERIFY_AREA
-                       if (regs->cs == KERNEL_CS)
+                       if (regs->cs == get_kernel_cs())
                                printk("WP fault at %08lx\n", regs->eip);
 #endif
                        /* fall through */
--- linus-2.6.orig/include/asm-i386/mach-default/mach_system.h
+++ linus-2.6/include/asm-i386/mach-default/mach_system.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_MACH_SYSTEM_H
 #define __ASM_MACH_SYSTEM_H
 
+#define clearsegment(seg)
+
 /* interrupt control.. */
 #define local_save_flags(x)    do { typecheck(unsigned long,x); __asm__ 
__volatile__("pushfl ; popl %0":"=g" (x): /* no input */); } while (0)
 #define local_irq_restore(x)   do { typecheck(unsigned long,x); __asm__ 
__volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc"); } 
while (0)
--- linus-2.6.orig/include/asm-i386/mach-xen/mach_system.h
+++ linus-2.6/include/asm-i386/mach-xen/mach_system.h
@@ -5,6 +5,8 @@
 
 #include <asm/hypervisor.h>
 
+#define clearsegment(seg) loadsegment(seg, 0)
+
 #ifdef CONFIG_SMP
 #define __vcpu_id smp_processor_id()
 #else
--- linus-2.6.orig/include/asm-i386/mach-xen/setup_arch_post.h
+++ linus-2.6/include/asm-i386/mach-xen/setup_arch_post.h
@@ -26,6 +26,8 @@ static void __init machine_specific_arch
                (struct shared_info *)__va(xen_start_info->shared_info);
        memset(empty_zero_page, 0, sizeof(empty_zero_page));
 
+       HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
+
        HYPERVISOR_set_callbacks(
            __KERNEL_CS, (unsigned long)hypervisor_callback,
            __KERNEL_CS, (unsigned long)failsafe_callback);
--- linus-2.6.orig/include/asm-i386/ptrace.h
+++ linus-2.6/include/asm-i386/ptrace.h
@@ -1,6 +1,8 @@
 #ifndef _I386_PTRACE_H
 #define _I386_PTRACE_H
 
+#include <mach_segment.h>
+
 #define EBX 0
 #define ECX 1
 #define EDX 2
@@ -73,11 +75,11 @@ extern void send_sigtrap(struct task_str
  */
 static inline int user_mode(struct pt_regs *regs)
 {
-       return (regs->xcs & 3) != 0;
+       return (regs->xcs & USER_MODE_MASK) != 0;
 }
 static inline int user_mode_vm(struct pt_regs *regs)
 {
-       return ((regs->xcs & 3) | (regs->eflags & VM_MASK)) != 0;
+       return ((regs->xcs & USER_MODE_MASK) | (regs->eflags & VM_MASK)) != 0;
 }
 #define instruction_pointer(regs) ((regs)->eip)
 #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
--- linus-2.6.orig/include/asm-i386/segment.h
+++ linus-2.6/include/asm-i386/segment.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
+#include <mach_segment.h>
+
 /*
  * The layout of the per-CPU GDT under Linux:
  *
--- /dev/null
+++ linus-2.6/include/asm-i386/mach-default/mach_segment.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_MACH_SEGMENT_H
+#define __ASM_MACH_SEGMENT_H
+
+#define USER_MODE_MASK 3
+
+#define get_kernel_cs() __KERNEL_CS
+
+#endif /* __ASM_MACH_SEGMENT_H */
--- /dev/null
+++ linus-2.6/include/asm-i386/mach-xen/mach_segment.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_MACH_SEGMENT_H
+#define __ASM_MACH_SEGMENT_H
+
+#define USER_MODE_MASK 2
+
+#define get_kernel_cs() \
+       (__KERNEL_CS + (xen_feature(XENFEAT_supervisor_mode_kernel) ? 0 : 1))
+
+#endif /* __ASM_MACH_SEGMENT_H */

--

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.