Skip to contentSkip to conversation

x86_64: basic changes for supporting compatibility mode guest (version 2)

RFC PATCH New Jan Beulich 1 participant 1 message Aug 25, 2006

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/4 x86_64: basic changes for supporting compatibility mode guest (version 2)

This introduces
- a (generic) config setting to turn on compatibility mode support
- support to load a Dom0 32-bit ELF image on 64-bit
- a compatibility guest mode GDT (requires moving the ring 0 selectors to different GDT slots), and the respective selector handling changes
- some initial code path changes to address the needs of a compatibility mode guest

config/x86_64.mk +1 -0
Index: 2006-08-16/config/x86_64.mk
===================================================================
@@ -1,4 +1,5 @@
 CONFIG_X86 := y
+CONFIG_COMPAT := y
 CONFIG_HVM := y
 CONFIG_MIGRATE := y
 CONFIG_XCUTILS := y
xen/arch/x86/boot/x86_64.S +24 -4
Index: 2006-08-16/xen/arch/x86/boot/x86_64.S
===================================================================
@@ -223,15 +223,35 @@ high_start:
         .align PAGE_SIZE, 0
 ENTRY(gdt_table)
         .quad 0x0000000000000000     /* unused */
-        .quad 0x00cf9a000000ffff     /* 0xe008 ring 0 code, compatibility */
-        .quad 0x00af9a000000ffff     /* 0xe010 ring 0 code, 64-bit mode   */
-        .quad 0x00cf92000000ffff     /* 0xe018 ring 0 data                */
+        .quad 0x00af9a000000ffff     /* 0xe008 ring 0 code, 64-bit mode   */
+        .quad 0x00cf92000000ffff     /* 0xe010 ring 0 data                */
+        .quad 0x0000000000000000     /* reserved                          */
         .quad 0x00cffa000000ffff     /* 0xe023 ring 3 code, compatibility */
         .quad 0x00cff2000000ffff     /* 0xe02b ring 3 data                */
         .quad 0x00affa000000ffff     /* 0xe033 ring 3 code, 64-bit mode   */
-        .quad 0x0000000000000000     /* unused                            */
+        .quad 0x00cf9a000000ffff     /* 0xe038 ring 0 code, compatibility */
+        .org gdt_table - FIRST_RESERVED_GDT_BYTE + __TSS(0) * 8
         .fill 4*NR_CPUS,8,0          /* space for TSS and LDT per CPU     */
 
+#ifdef CONFIG_COMPAT
+# define LIMIT(d) (((d) << 16) \
+                   | (((MACH2PHYS_COMPAT_VIRT_END - 1) >> PAGE_SHIFT) & 0xffff) \
+                   | (((MACH2PHYS_COMPAT_VIRT_END - 1) << (32 - PAGE_SHIFT)) & (0xf << 48)))
+        .align PAGE_SIZE, 0
+ENTRY(compat_gdt_table)
+        .quad 0x0000000000000000     /* unused */
+        .quad 0x00af9a000000ffff     /* 0xe008 ring 0 code, 64-bit mode   */
+        .quad 0x00cf92000000ffff     /* 0xe010 ring 0 data                */
+        .quad LIMIT(0x00cfba000000)  /* 0xe019 ring 1 code, compatibility */
+        .quad LIMIT(0x00cfb2000000)  /* 0xe021 ring 1 data                */
+        .quad LIMIT(0x00c0fa000000)  /* 0xe02b ring 3 code, compatibility */
+        .quad LIMIT(0x00c0f2000000)  /* 0xe033 ring 3 data                */
+        .quad 0x00cf9a000000ffff     /* 0xe038 ring 0 code, compatibility */
+        .org compat_gdt_table - FIRST_RESERVED_GDT_BYTE + __TSS(0) * 8
+        .fill 4*NR_CPUS,8,0          /* space for TSS and LDT per CPU     */
+# undef LIMIT
+#endif
+
 /* Initial PML4 -- level-4 page table. */
         .align PAGE_SIZE, 0
 ENTRY(idle_pg_table)
xen/arch/x86/domain.c +105 -35

196 lines not on this page · raw message

xen/arch/x86/domain_build.c +65 -6

127 lines not on this page · raw message

xen/arch/x86/mm.c +6 -2
Index: 2006-08-16/xen/arch/x86/mm.c
===================================================================
@@ -391,7 +391,7 @@ static int alloc_segdesc_page(struct pag
     descs = map_domain_page(page_to_mfn(page));
 
     for ( i = 0; i < 512; i++ )
-        if ( unlikely(!check_descriptor(&descs[i])) )
+        if ( unlikely(!check_descriptor(page_get_owner(page), &descs[i])) )
             goto fail;
 
     unmap_domain_page(descs);
@@ -1746,6 +1746,8 @@ int new_guest_cr3(unsigned long mfn)
             /* Switch to idle pagetable: this VCPU has no active p.t. now. */
             MEM_LOG("New baseptr %lx: slow path via idle pagetables", mfn);
             old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
+            if ( old_base_mfn == pagetable_get_pfn(v->arch.guest_table_user) )
+                v->arch.guest_table_user = pagetable_null();
             v->arch.guest_table = pagetable_null();
             update_pagetables(v);
             write_cr3(__pa(idle_pg_table));
@@ -1770,6 +1772,8 @@ int new_guest_cr3(unsigned long mfn)
 
     old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
     v->arch.guest_table = pagetable_from_pfn(mfn);
+    if ( IS_COMPAT(d) )
+        v->arch.guest_table_user = v->arch.guest_table;
     update_pagetables(v); /* update shadow_table and monitor_table */
 
     write_ptbase(v);
@@ -2882,7 +2886,7 @@ long do_update_descriptor(u64 pa, u64 de
     if ( !VALID_MFN(mfn = gmfn_to_mfn(dom, gmfn)) ||
          (((unsigned int)pa % sizeof(struct desc_struct)) != 0) ||
          !mfn_valid(mfn) ||
-         !check_descriptor(&d) )
+         !check_descriptor(dom, &d) )
     {
         UNLOCK_BIGLOCK(dom);
         return -EINVAL;
xen/arch/x86/traps.c +8 -1
Index: 2006-08-16/xen/arch/x86/traps.c
===================================================================
@@ -1719,6 +1719,13 @@ void set_tss_desc(unsigned int n, void *
         (unsigned long)addr,
         offsetof(struct tss_struct, __cacheline_filler) - 1,
         9);
+#ifdef CONFIG_COMPAT
+    _set_tssldt_desc(
+        compat_gdt_table + __TSS(n) - FIRST_RESERVED_GDT_ENTRY,
+        (unsigned long)addr,
+        offsetof(struct tss_struct, __cacheline_filler) - 1,
+        11);
+#endif
 }
 
 void __init trap_init(void)
@@ -1793,7 +1800,7 @@ long do_set_trap_table(XEN_GUEST_HANDLE(
         if ( cur.address == 0 )
             break;
 
-        fixup_guest_code_selector(cur.cs);
+        fixup_guest_code_selector(current->domain, cur.cs);
 
         memcpy(&dst[cur.vector], &cur, sizeof(cur));
 
xen/arch/x86/x86_32/mm.c +6 -6
Index: 2006-08-16/xen/arch/x86/x86_32/mm.c
===================================================================
@@ -226,7 +226,7 @@ long do_stack_switch(unsigned long ss, u
     int nr = smp_processor_id();
     struct tss_struct *t = &init_tss[nr];
 
-    fixup_guest_stack_selector(ss);
+    fixup_guest_stack_selector(current->domain, ss);
 
     current->arch.guest_context.kernel_ss = ss;
     current->arch.guest_context.kernel_sp = esp;
@@ -237,7 +237,7 @@ long do_stack_switch(unsigned long ss, u
 }
 
 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
-int check_descriptor(struct desc_struct *d)
+int check_descriptor(const struct domain *dom, struct desc_struct *d)
 {
     unsigned long base, limit;
     u32 a = d->a, b = d->b;
@@ -257,8 +257,8 @@ int check_descriptor(struct desc_struct 
      * gates (consider a call gate pointing at another kernel descriptor with 
      * DPL 0 -- this would get the OS ring-0 privileges).
      */
-    if ( (b & _SEGMENT_DPL) < (GUEST_KERNEL_RPL << 13) )
-        d->b = b = (b & ~_SEGMENT_DPL) | (GUEST_KERNEL_RPL << 13);
+    if ( (b & _SEGMENT_DPL) < (GUEST_KERNEL_RPL(dom) << 13) )
+        d->b = b = (b & ~_SEGMENT_DPL) | (GUEST_KERNEL_RPL(dom) << 13);
 
     if ( !(b & _SEGMENT_S) )
     {
@@ -280,8 +280,8 @@ int check_descriptor(struct desc_struct 
 
         /* Validate and fix up the target code selector. */
         cs = a >> 16;
-        fixup_guest_code_selector(cs);
-        if ( !guest_gate_selector_okay(cs) )
+        fixup_guest_code_selector(dom, cs);
+        if ( !guest_gate_selector_okay(dom, cs) )
             goto bad;
         a = d->a = (d->a & 0xffffU) | (cs << 16);
 
xen/arch/x86/x86_32/traps.c +2 -2
Index: 2006-08-16/xen/arch/x86/x86_32/traps.c
===================================================================
@@ -284,7 +284,7 @@ void init_int80_direct_trap(struct vcpu 
      * switch to the Xen stack and we need to swap back to the guest
      * kernel stack before passing control to the system call entry point.
      */
-    if ( TI_GET_IF(ti) || !guest_gate_selector_okay(ti->cs) ||
+    if ( TI_GET_IF(ti) || !guest_gate_selector_okay(v->domain, ti->cs) ||
          supervisor_mode_kernel )
     {
         v->arch.int80_desc.a = v->arch.int80_desc.b = 0;
@@ -314,7 +314,7 @@ static long register_guest_callback(stru
     long ret = 0;
     struct vcpu *v = current;
 
-    fixup_guest_code_selector(reg->address.cs);
+    fixup_guest_code_selector(v->domain, reg->address.cs);
 
     switch ( reg->type )
     {
xen/arch/x86/x86_64/asm-offsets.c +6 -2
Index: 2006-08-16/xen/arch/x86/x86_64/asm-offsets.c
===================================================================
@@ -58,12 +58,16 @@ void __dummy__(void)
     OFFSET(VCPU_thread_flags, struct vcpu, arch.flags);
     OFFSET(VCPU_event_addr, struct vcpu,
            arch.guest_context.event_callback_eip);
+    OFFSET(VCPU_event_sel, struct vcpu,
+           arch.guest_context.event_callback_cs);
     OFFSET(VCPU_failsafe_addr, struct vcpu,
            arch.guest_context.failsafe_callback_eip);
+    OFFSET(VCPU_failsafe_sel, struct vcpu,
+           arch.guest_context.failsafe_callback_cs);
     OFFSET(VCPU_syscall_addr, struct vcpu,
            arch.guest_context.syscall_callback_eip);
-    OFFSET(VCPU_kernel_sp, struct vcpu,
-           arch.guest_context.kernel_sp);
+    OFFSET(VCPU_kernel_sp, struct vcpu, arch.guest_context.kernel_sp);
+    OFFSET(VCPU_kernel_ss, struct vcpu, arch.guest_context.kernel_ss);
     OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags);
     OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt);
     OFFSET(VCPU_flags, struct vcpu, vcpu_flags);
xen/arch/x86/x86_64/mm.c +6 -6
Index: 2006-08-16/xen/arch/x86/x86_64/mm.c
===================================================================
@@ -222,7 +222,7 @@ long subarch_memory_op(int op, XEN_GUEST
 
 long do_stack_switch(unsigned long ss, unsigned long esp)
 {
-    fixup_guest_stack_selector(ss);
+    fixup_guest_stack_selector(current->domain, ss);
     current->arch.guest_context.kernel_ss = ss;
     current->arch.guest_context.kernel_sp = esp;
     return 0;
@@ -282,7 +282,7 @@ long do_set_segment_base(unsigned int wh
 
 
 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
-int check_descriptor(struct desc_struct *d)
+int check_descriptor(const struct domain *dom, struct desc_struct *d)
 {
     u32 a = d->a, b = d->b;
     u16 cs;
@@ -292,8 +292,8 @@ int check_descriptor(struct desc_struct 
         goto good;
 
     /* Check and fix up the DPL. */
-    if ( (b & _SEGMENT_DPL) < (GUEST_KERNEL_RPL << 13) )
-        d->b = b = (b & ~_SEGMENT_DPL) | (GUEST_KERNEL_RPL << 13);
+    if ( (b & _SEGMENT_DPL) < (GUEST_KERNEL_RPL(dom) << 13) )
+        d->b = b = (b & ~_SEGMENT_DPL) | (GUEST_KERNEL_RPL(dom) << 13);
 
     /* All code and data segments are okay. No base/limit checking. */
     if ( (b & _SEGMENT_S) )
@@ -309,8 +309,8 @@ int check_descriptor(struct desc_struct 
 
     /* Validate and fix up the target code selector. */
     cs = a >> 16;
-    fixup_guest_code_selector(cs);
-    if ( !guest_gate_selector_okay(cs) )
+    fixup_guest_code_selector(dom, cs);
+    if ( !guest_gate_selector_okay(dom, cs) )
         goto bad;
     a = d->a = (d->a & 0xffffU) | (cs << 16);
 
xen/arch/x86/x86_64/traps.c +2 -0
Index: 2006-08-16/xen/arch/x86/x86_64/traps.c
===================================================================
@@ -172,6 +172,8 @@ asmlinkage void do_double_fault(struct c
 
 void toggle_guest_mode(struct vcpu *v)
 {
+    if ( IS_COMPAT(v->domain) )
+        return;
     v->arch.flags ^= TF_kernel_mode;
     __asm__ __volatile__ ( "swapgs" );
     update_pagetables(v);
xen/common/Makefile +1 -0
Index: 2006-08-16/xen/common/Makefile
===================================================================
@@ -3,6 +3,7 @@ obj-y += bitmap.o
 obj-y += dom0_ops.o
 obj-y += domain.o
 obj-y += elf.o
+obj-$(CONFIG_COMPAT) += elf32.o
 obj-y += event_channel.o
 obj-y += grant_table.o
 obj-y += kernel.o
xen/common/elf.c +1 -1
Index: 2006-08-16/xen/common/elf.c
===================================================================
@@ -29,7 +29,7 @@ int parseelfimage(struct domain_setup_in
     int h, virt_base_defined, elf_pa_off_defined;
 
     if ( !elf_sanity_check(ehdr) )
-        return -EINVAL;
+        return -ENOSYS;
 
     if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > dsi->image_len )
     {
xen/common/elf32.c new file +16 -0
Index: 2006-08-16/xen/common/elf32.c
===================================================================
@@ -0,0 +1,16 @@
+/******************************************************************************
+ * elf32.c
+ *
+ * Stub to support 32-bit ELF images on 64-bit platforms.
+ */
+
+#include <xen/config.h>
+
+#undef ELFSIZE
+#define ELFSIZE 32
+
+#define parseelfimage parseelf32image
+#define loadelfimage loadelf32image
+#define elf_sanity_check elf32_sanity_check
+
+#include "elf.c"
xen/include/asm-x86/config.h +13 -3
Index: 2006-08-16/xen/include/asm-x86/config.h
===================================================================
@@ -86,6 +86,7 @@ extern unsigned long _end; /* standard E
 #if defined(__x86_64__)
 
 #define CONFIG_X86_64 1
+#define CONFIG_COMPAT 1
 
 #define asmlinkage
 
@@ -175,13 +176,22 @@ extern unsigned long _end; /* standard E
 #define DIRECTMAP_VIRT_START    (PML4_ADDR(262))
 #define DIRECTMAP_VIRT_END      (DIRECTMAP_VIRT_START + PML4_ENTRY_BYTES*2)
 
+#define __HYPERVISOR_COMPAT_VIRT_START 0xF5800000
+#define __MACH2PHYS_COMPAT_VIRT_START  0xF5800000
+#define __MACH2PHYS_COMPAT_VIRT_END    0xF6800000
+#define HYPERVISOR_COMPAT_VIRT_START mk_unsigned_long(__HYPERVISOR_COMPAT_VIRT_START)
+#define MACH2PHYS_COMPAT_VIRT_START  mk_unsigned_long(__MACH2PHYS_COMPAT_VIRT_START)
+#define MACH2PHYS_COMPAT_VIRT_END    mk_unsigned_long(__MACH2PHYS_COMPAT_VIRT_END)
+#define MACH2PHYS_COMPAT_NR_ENTRIES  ((MACH2PHYS_COMPAT_VIRT_END-MACH2PHYS_COMPAT_VIRT_START)>>2)
+#define compat_machine_to_phys_mapping ((unsigned long *)MACH2PHYS_COMPAT_VIRT_START)
+
 #define PGT_base_page_table PGT_l4_page_table
 
-#define __HYPERVISOR_CS64 0xe010
-#define __HYPERVISOR_CS32 0xe008
+#define __HYPERVISOR_CS64 0xe008
+#define __HYPERVISOR_CS32 0xe038
 #define __HYPERVISOR_CS   __HYPERVISOR_CS64
 #define __HYPERVISOR_DS64 0x0000
-#define __HYPERVISOR_DS32 0xe018
+#define __HYPERVISOR_DS32 0xe010
 #define __HYPERVISOR_DS   __HYPERVISOR_DS64
 
 /* For generic assembly code: use macros to define operation/operand sizes. */
xen/include/asm-x86/desc.h +64 -24

138 lines not on this page · raw message

xen/include/asm-x86/ldt.h +2 -1
Index: 2006-08-16/xen/include/asm-x86/ldt.h
===================================================================
@@ -17,7 +17,8 @@ static inline void load_LDT(struct vcpu 
     else
     {
         cpu = smp_processor_id();
-        desc = gdt_table + __LDT(cpu) - FIRST_RESERVED_GDT_ENTRY;
+        desc = (!IS_COMPAT(v->domain) ? gdt_table : compat_gdt_table)
+               + __LDT(cpu) - FIRST_RESERVED_GDT_ENTRY;
         _set_tssldt_desc(desc, LDT_VIRT_START(v), ents*8-1, 2);
         __asm__ __volatile__ ( "lldt %%ax" : : "a" (__LDT(cpu)<<3) );
     }
xen/include/asm-x86/mm.h +1 -1
Index: 2006-08-16/xen/include/asm-x86/mm.h
===================================================================
@@ -254,7 +254,7 @@ static inline int page_is_removable(stru
     ASSERT(((_p)->count_info & PGC_count_mask) != 0);          \
     ASSERT(page_get_owner(_p) == (_d))
 
-int check_descriptor(struct desc_struct *d);
+int check_descriptor(const struct domain *, struct desc_struct *d);
 
 /*
  * The MPT (machine->physical mapping table) is an array of word-sized
xen/include/asm-x86/regs.h +2 -1
Index: 2006-08-16/xen/include/asm-x86/regs.h
===================================================================
@@ -38,7 +38,8 @@ enum EFLAGS {
     ASSERT(diff < STACK_SIZE);                                                \
     /* If a guest frame, it must be have guest privs (unless HVM guest).   */ \
     /* We permit CS==0 which can come from an uninitialised trap entry. */    \
-    ASSERT((diff != 0) || vm86_mode(r) || ((r->cs&3) >= GUEST_KERNEL_RPL) ||  \
+    ASSERT((diff != 0) || vm86_mode(r) ||                                     \
+           ((r->cs&3) >= GUEST_KERNEL_RPL(current->domain)) ||                \
            (r->cs == 0) || hvm_guest(current));                              \
     /* If not a guest frame, it must be a hypervisor frame. */                \
     ASSERT((diff == 0) || (!vm86_mode(r) && (r->cs == __HYPERVISOR_CS)));     \
xen/include/asm-x86/x86_64/regs.h +3 -1
Index: 2006-08-16/xen/include/asm-x86/x86_64/regs.h
===================================================================
@@ -11,7 +11,9 @@
 #define ring_3(r)    (((r)->cs & 3) == 3)
 
 #define guest_kernel_mode(v, r)   \
-    (ring_3(r) && ((v)->arch.flags & TF_kernel_mode))
+    (!IS_COMPAT(v->domain) ? \
+     ring_3(r) && ((v)->arch.flags & TF_kernel_mode) : \
+     ring_1(r))
 
 #define permit_softint(dpl, v, r) \
     ((dpl) >= (guest_kernel_mode(v, r) ? 1 : 3))
xen/include/public/arch-x86_64.h +14 -1
Index: 2006-08-16/xen/include/public/arch-x86_64.h
===================================================================
@@ -176,7 +176,10 @@ DEFINE_XEN_GUEST_HANDLE(trap_info_t);
 
 #ifdef __GNUC__
 /* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */
-#define __DECL_REG(name) union { uint64_t r ## name, e ## name; }
+#define __DECL_REG(name) union { \
+    uint64_t r ## name, e ## name; \
+    uint32_t _e ## name; \
+}
 #else
 /* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */
 #define __DECL_REG(name) uint64_t r ## name
@@ -249,7 +252,17 @@ struct vcpu_guest_context {
     unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
     unsigned long event_callback_eip;
     unsigned long failsafe_callback_eip;
+#ifdef __GNUC__
+    union {
+        unsigned long syscall_callback_eip;
+        struct {
+            unsigned int event_callback_cs;    /* compat CS of event cb     */
+            unsigned int failsafe_callback_cs; /* compat CS of failsafe cb  */
+        };
+    };
+#else
     unsigned long syscall_callback_eip;
+#endif
     unsigned long vm_assist;                /* VMASST_TYPE_* bitmap */
     /* Segment base addresses. */
     uint64_t      fs_base;
xen/include/xen/elf.h +6 -0
Index: 2006-08-16/xen/include/xen/elf.h
===================================================================
@@ -529,6 +529,12 @@ struct domain_setup_info;
 extern int loadelfimage(struct domain_setup_info *);
 extern int parseelfimage(struct domain_setup_info *);
 
+#ifdef CONFIG_COMPAT
+extern int loadelf32image(struct domain_setup_info *);
+extern int parseelf32image(struct domain_setup_info *);
+extern int elf32_sanity_check(Elf32_Ehdr *ehdr);
+#endif
+
 #ifdef Elf_Ehdr
 extern int elf_sanity_check(Elf_Ehdr *ehdr);
 #endif
xen/include/xen/sched.h +10 -0
Index: 2006-08-16/xen/include/xen/sched.h
===================================================================
@@ -404,6 +404,9 @@ extern struct domain *domain_list;
  /* Domain is paused by the hypervisor? */
 #define _DOMF_paused           6
 #define DOMF_paused            (1UL<<_DOMF_paused)
+ /* Domain is a compatibility one? */
+#define _DOMF_compat           7
+#define DOMF_compat            (1UL<<_DOMF_compat)
 
 static inline int vcpu_runnable(struct vcpu *v)
 {
@@ -434,6 +437,13 @@ static inline void vcpu_unblock(struct v
 #define IS_PRIV(_d)                                         \
     (test_bit(_DOMF_privileged, &(_d)->domain_flags))
 
+#ifdef CONFIG_COMPAT
+#define IS_COMPAT(_d)                                       \
+    (test_bit(_DOMF_compat, &(_d)->domain_flags))
+#else
+#define IS_COMPAT(_d) 0
+#endif
+
 #define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist))
 
 #endif /* __SCHED_H__ */

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel