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

[Xen-devel] [PATCH RFC 33/44] x86/smp: Use the percpu GDT/LDT mappings



This is unfortunately quite invasive, because of the impact on the context
switch path.

PV vcpus gain an array of ldt and gdt ptes (replacing gdt_frames[]), which map
the frames loaded by HYPERCALL_set_gdt, or faulted in for the LDT.  Each
present PTE here which isn't a read-only mapping of zero_page holds a type
reference.

When context switching to a vcpu which needs a full GDT or LDT, the ptes are
copied in from the above arrays, while if context switching away from vcpu
which needs a full GDT or LDT, the ptes are reset back to default values.  As
a side effect, the GDT/LDT create/destroy functions need to adjust the percpu
mappings if they are running in current context.

Overall, the GDT and LDT base addresses are always the same, and this depend
on the context switch logic happening before write_ptbase(), so the TLB flush
removes any stale mappings.  While altering load_LDT()'s behaviour to cope,
introduce lazy loading to avoid executing lldt in the common case.

The arch_{get,set}_info_guest() functions need adjusting to cope with the fact
that they will now find references to zero_page in the ptes, which need
skipping.

Loading of GDTR now happens once at boot, in early_switch_to_idle().  As the
base address is now constant and always mapped, we can remove lgdt() calls
from the context switch path and EFI Runtime Services path.  Finally,
HOST_GDTR_BASE in the VMCS needs to be adjusted, and moves into
construct_vmcs().

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
v2:
 * Fix pv_destroy_ldt() to release the correct references when there were
   outstanding LDT frames at domain destruction.
---
 xen/arch/x86/cpu/common.c           |  7 ----
 xen/arch/x86/domain.c               | 72 +++++++++++++++++++++----------------
 xen/arch/x86/domctl.c               | 13 +++++--
 xen/arch/x86/hvm/vmx/vmcs.c         |  4 +--
 xen/arch/x86/pv/descriptor-tables.c | 30 ++++++++++------
 xen/arch/x86/pv/emulate.h           |  4 +--
 xen/arch/x86/pv/mm.c                |  3 +-
 xen/arch/x86/setup.c                | 10 ++++--
 xen/arch/x86/traps.c                | 36 ++-----------------
 xen/common/efi/runtime.c            | 20 -----------
 xen/include/asm-x86/config.h        |  2 ++
 xen/include/asm-x86/domain.h        | 17 +++++----
 xen/include/asm-x86/ldt.h           | 15 +++++---
 13 files changed, 110 insertions(+), 123 deletions(-)

diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index 14743b6..decdcd5 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -653,11 +653,6 @@ void load_system_tables(void)
        struct desc_struct *compat_gdt =
                this_cpu(compat_gdt_table) - FIRST_RESERVED_GDT_ENTRY;
 
-       const struct desc_ptr gdtr = {
-               .base = (unsigned long)gdt,
-               .limit = LAST_RESERVED_GDT_BYTE,
-       };
-
        *tss = (struct tss_struct){
                /* Main stack for interrupts/exceptions. */
                .rsp0 = stack_bottom,
@@ -693,9 +688,7 @@ void load_system_tables(void)
                offsetof(struct tss_struct, __cacheline_filler) - 1,
                SYS_DESC_tss_busy);
 
-       lgdt(&gdtr);
        ltr(TSS_ENTRY << 3);
-       lldt(0);
 
        /*
         * Bottom-of-stack must be 16-byte aligned!
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 4671c9b..2d665c6 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -67,6 +67,7 @@
 #include <asm/pv/mm.h>
 
 DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
+DEFINE_PER_CPU(unsigned int, ldt_ents);
 
 static void default_idle(void);
 void (*pm_idle) (void) __read_mostly = default_idle;
@@ -917,8 +918,13 @@ int arch_set_info_guest(
             fail = compat_pfn_to_cr3(pfn) != c.cmp->ctrlreg[3];
         }
 
-        for ( i = 0; i < ARRAY_SIZE(v->arch.pv_vcpu.gdt_frames); ++i )
-            fail |= v->arch.pv_vcpu.gdt_frames[i] != c(gdt_frames[i]);
+        for ( i = 0; i < MAX_PV_GDT_FRAMES; ++i )
+        {
+            paddr_t addr = pfn_to_paddr(c(gdt_frames[i])) ?: __pa(zero_page);
+
+            fail |= l1e_get_paddr(v->arch.pv_vcpu.gdt_l1es[i]) != addr;
+        }
+
         fail |= v->arch.pv_vcpu.gdt_ents != c(gdt_ents);
 
         fail |= v->arch.pv_vcpu.ldt_base != c(ldt_base);
@@ -1015,10 +1021,10 @@ int arch_set_info_guest(
         rc = (int)pv_set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
     else
     {
-        unsigned long gdt_frames[ARRAY_SIZE(v->arch.pv_vcpu.gdt_frames)];
+        unsigned long gdt_frames[MAX_PV_GDT_FRAMES];
         unsigned int nr_frames = DIV_ROUND_UP(c.cmp->gdt_ents, 512);
 
-        if ( nr_frames > ARRAY_SIZE(v->arch.pv_vcpu.gdt_frames) )
+        if ( nr_frames > MAX_PV_GDT_FRAMES )
             return -EINVAL;
 
         for ( i = 0; i < nr_frames; ++i )
@@ -1579,15 +1585,18 @@ static inline bool need_full_gdt(const struct domain *d)
     return is_pv_domain(d) && !is_idle_domain(d);
 }
 
+static bool needs_ldt(const struct vcpu *v)
+{
+    return is_pv_vcpu(v) && v->arch.pv_vcpu.ldt_ents;
+}
+
 static void __context_switch(void)
 {
     struct cpu_user_regs *stack_regs = guest_cpu_user_regs();
-    unsigned int          cpu = smp_processor_id();
+    unsigned int          cpu = smp_processor_id(), i;
     struct vcpu          *p = per_cpu(curr_vcpu, cpu);
     struct vcpu          *n = current;
     struct domain        *pd = p->domain, *nd = n->domain;
-    struct desc_struct   *gdt;
-    struct desc_ptr       gdt_desc;
 
     ASSERT(p != n);
     ASSERT(cpumask_empty(n->vcpu_dirty_cpumask));
@@ -1627,38 +1636,41 @@ static void __context_switch(void)
 
     psr_ctxt_switch_to(nd);
 
-    gdt = !is_pv_32bit_domain(nd) ? per_cpu(gdt_table, cpu) :
-                                    per_cpu(compat_gdt_table, cpu);
+    /* Load a full new GDT if the new vcpu needs one. */
     if ( need_full_gdt(nd) )
     {
-        unsigned long mfn = virt_to_mfn(gdt);
-        l1_pgentry_t *pl1e = pv_gdt_ptes(n);
-        unsigned int i;
+        memcpy(pv_gdt_ptes, n->arch.pv_vcpu.gdt_l1es,
+               sizeof(n->arch.pv_vcpu.gdt_l1es));
 
-        for ( i = 0; i < NR_RESERVED_GDT_PAGES; i++ )
-            l1e_write(pl1e + FIRST_RESERVED_GDT_PAGE + i,
-                      l1e_from_pfn(mfn + i, __PAGE_HYPERVISOR_RW));
+        l1e_write(&pv_gdt_ptes[FIRST_RESERVED_GDT_PAGE],
+                  l1e_from_pfn(virt_to_mfn(!is_pv_32bit_domain(nd)
+                                           ? per_cpu(gdt_table, cpu)
+                                           : per_cpu(compat_gdt_table, cpu)),
+                               __PAGE_HYPERVISOR_RW));
     }
-
-    if ( need_full_gdt(pd) &&
-         ((p->vcpu_id != n->vcpu_id) || !need_full_gdt(nd)) )
+    /* or clobber a previous full GDT. */
+    else if ( need_full_gdt(pd) )
     {
-        gdt_desc.limit = LAST_RESERVED_GDT_BYTE;
-        gdt_desc.base  = (unsigned long)(gdt - FIRST_RESERVED_GDT_ENTRY);
+        l1_pgentry_t zero_l1e = l1e_from_paddr(__pa(zero_page),
+                                               __PAGE_HYPERVISOR_RO);
+
+        for ( i = 0; i < FIRST_RESERVED_GDT_PAGE; ++i )
+            pv_gdt_ptes[i] = zero_l1e;
 
-        lgdt(&gdt_desc);
+        l1e_write(&pv_gdt_ptes[FIRST_RESERVED_GDT_PAGE],
+                  l1e_from_pfn(virt_to_mfn(per_cpu(gdt_table, cpu)),
+                               __PAGE_HYPERVISOR_RW));
     }
 
-    write_ptbase(n);
+    /* Load the LDT frames if needed. */
+    if ( needs_ldt(n) )
+        memcpy(pv_ldt_ptes, n->arch.pv_vcpu.ldt_l1es,
+               sizeof(n->arch.pv_vcpu.ldt_l1es));
+    /* or clobber the previous LDT. */
+    else if ( needs_ldt(p) )
+        memset(pv_ldt_ptes, 0, sizeof(n->arch.pv_vcpu.ldt_l1es));
 
-    if ( need_full_gdt(nd) &&
-         ((p->vcpu_id != n->vcpu_id) || !need_full_gdt(pd)) )
-    {
-        gdt_desc.limit = LAST_RESERVED_GDT_BYTE;
-        gdt_desc.base = GDT_VIRT_START(n);
-
-        lgdt(&gdt_desc);
-    }
+    write_ptbase(n);
 
     load_LDT(n);
 
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 36ab235..28c7b04 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1642,8 +1642,17 @@ void arch_get_info_guest(struct vcpu *v, 
vcpu_guest_context_u c)
     {
         c(ldt_base = v->arch.pv_vcpu.ldt_base);
         c(ldt_ents = v->arch.pv_vcpu.ldt_ents);
-        for ( i = 0; i < ARRAY_SIZE(v->arch.pv_vcpu.gdt_frames); ++i )
-            c(gdt_frames[i] = v->arch.pv_vcpu.gdt_frames[i]);
+
+        for ( i = 0; i < MAX_PV_GDT_FRAMES; ++i )
+        {
+            paddr_t addr = l1e_get_paddr(v->arch.pv_vcpu.gdt_l1es[i]);
+
+            if ( addr == __pa(zero_page) )
+                break;
+
+            c(gdt_frames[i] = paddr_to_pfn(addr));
+        }
+
         BUILD_BUG_ON(ARRAY_SIZE(c.nat->gdt_frames) !=
                      ARRAY_SIZE(c.cmp->gdt_frames));
         for ( ; i < ARRAY_SIZE(c.nat->gdt_frames); ++i )
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index f99f1bb..795210f 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -802,9 +802,6 @@ static void vmx_set_host_env(struct vcpu *v)
 {
     unsigned int cpu = smp_processor_id();
 
-    __vmwrite(HOST_GDTR_BASE,
-              (unsigned long)(this_cpu(gdt_table) - FIRST_RESERVED_GDT_ENTRY));
-
     __vmwrite(HOST_TR_BASE, (unsigned long)&per_cpu(init_tss, cpu));
 
     __vmwrite(HOST_SYSENTER_ESP, get_stack_bottom());
@@ -1134,6 +1131,7 @@ static int construct_vmcs(struct vcpu *v)
 
     /* Host system tables. */
     __vmwrite(HOST_IDTR_BASE, PERCPU_IDT_MAPPING);
+    __vmwrite(HOST_GDTR_BASE, PERCPU_GDT_MAPPING);
 
     /* Host data selectors. */
     __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
diff --git a/xen/arch/x86/pv/descriptor-tables.c 
b/xen/arch/x86/pv/descriptor-tables.c
index 77f9851..6b0bfbf 100644
--- a/xen/arch/x86/pv/descriptor-tables.c
+++ b/xen/arch/x86/pv/descriptor-tables.c
@@ -37,7 +37,7 @@
  */
 bool pv_destroy_ldt(struct vcpu *v)
 {
-    l1_pgentry_t *pl1e = pv_ldt_ptes(v);
+    l1_pgentry_t *pl1e = v->arch.pv_vcpu.ldt_l1es;
     unsigned int i, mappings_dropped = 0;
     struct page_info *page;
 
@@ -58,12 +58,22 @@ bool pv_destroy_ldt(struct vcpu *v)
         put_page_and_type(page);
     }
 
+    /* Clobber the live LDT. */
+    if ( v == current )
+    {
+        if ( mappings_dropped )
+            memset(pv_ldt_ptes, 0, sizeof(v->arch.pv_vcpu.ldt_l1es));
+        else
+            ASSERT(memcmp(pv_ldt_ptes, v->arch.pv_vcpu.ldt_l1es,
+                          sizeof(v->arch.pv_vcpu.ldt_l1es)) == 0);
+    }
+
     return mappings_dropped;
 }
 
 void pv_destroy_gdt(struct vcpu *v)
 {
-    l1_pgentry_t *pl1e = pv_gdt_ptes(v);
+    l1_pgentry_t *pl1e = v->arch.pv_vcpu.gdt_l1es;
     mfn_t zero_mfn = _mfn(virt_to_mfn(zero_page));
     l1_pgentry_t zero_l1e = l1e_from_mfn(zero_mfn, __PAGE_HYPERVISOR_RO);
     unsigned int i;
@@ -79,15 +89,13 @@ void pv_destroy_gdt(struct vcpu *v)
              !mfn_eq(mfn, zero_mfn) )
             put_page_and_type(mfn_to_page(mfn));
 
-        l1e_write(&pl1e[i], zero_l1e);
-        v->arch.pv_vcpu.gdt_frames[i] = 0;
+        pl1e[i] = zero_l1e;
     }
 }
 
 long pv_set_gdt(struct vcpu *v, unsigned long *frames, unsigned int entries)
 {
     struct domain *d = v->domain;
-    l1_pgentry_t *pl1e;
     unsigned int i, nr_frames = DIV_ROUND_UP(entries, 512);
 
     ASSERT(v == current || cpumask_empty(v->vcpu_dirty_cpumask));
@@ -116,12 +124,14 @@ long pv_set_gdt(struct vcpu *v, unsigned long *frames, 
unsigned int entries)
 
     /* Install the new GDT. */
     v->arch.pv_vcpu.gdt_ents = entries;
-    pl1e = pv_gdt_ptes(v);
     for ( i = 0; i < nr_frames; i++ )
-    {
-        v->arch.pv_vcpu.gdt_frames[i] = frames[i];
-        l1e_write(&pl1e[i], l1e_from_pfn(frames[i], __PAGE_HYPERVISOR_RW));
-    }
+        v->arch.pv_vcpu.gdt_l1es[i] =
+            l1e_from_pfn(frames[i], __PAGE_HYPERVISOR_RW);
+
+    /* Update the live GDT if in context. */
+    if ( v == current )
+        memcpy(pv_gdt_ptes, v->arch.pv_vcpu.gdt_l1es,
+               sizeof(v->arch.pv_vcpu.gdt_l1es));
 
     return 0;
 
diff --git a/xen/arch/x86/pv/emulate.h b/xen/arch/x86/pv/emulate.h
index 9d58794..80530e7 100644
--- a/xen/arch/x86/pv/emulate.h
+++ b/xen/arch/x86/pv/emulate.h
@@ -20,9 +20,7 @@ static inline int pv_emul_is_mem_write(const struct 
x86_emulate_state *state,
 /* Return a pointer to the GDT/LDT descriptor referenced by sel. */
 static inline const struct desc_struct *gdt_ldt_desc_ptr(unsigned int sel)
 {
-    const struct vcpu *curr = current;
-    const struct desc_struct *tbl = (void *)
-        ((sel & X86_XEC_TI) ? LDT_VIRT_START(curr) : GDT_VIRT_START(curr));
+    const struct desc_struct *tbl = (sel & X86_XEC_TI) ? pv_ldt : pv_gdt;
 
     return &tbl[sel >> 3];
 }
diff --git a/xen/arch/x86/pv/mm.c b/xen/arch/x86/pv/mm.c
index d293724..6da9990 100644
--- a/xen/arch/x86/pv/mm.c
+++ b/xen/arch/x86/pv/mm.c
@@ -122,10 +122,11 @@ bool pv_map_ldt_shadow_page(unsigned int offset)
         return false;
     }
 
-    pl1e = &pv_ldt_ptes(curr)[offset >> PAGE_SHIFT];
+    pl1e = &pv_ldt_ptes[offset >> PAGE_SHIFT];
     l1e_add_flags(gl1e, _PAGE_RW);
 
     l1e_write(pl1e, gl1e);
+    curr->arch.pv_vcpu.ldt_l1es[offset >> PAGE_SHIFT] = gl1e;
 
     return true;
 }
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 80efef0..39d1592 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -244,13 +244,17 @@ void early_switch_to_idle(bool bsp)
     unsigned long cr4 = read_cr4();
 
     /*
-     * VT-x hardwires the IDT limit at 0xffff on VMExit.
+     * VT-x hardwires the GDT and IDT limit at 0xffff on VMExit.
      *
      * We don't wish to reload on vcpu context switch, so have arranged for
      * nothing else to live within 64k of the base.  Unilaterally setting the
      * limit to 0xffff avoids leaking whether HVM vcpus are running to PV
-     * guests via SIDT.
+     * guests via SGDT/SIDT.
      */
+    const struct desc_ptr gdtr = {
+        .base = PERCPU_GDT_MAPPING,
+        .limit = 0xffff,
+    };
     const struct desc_ptr idtr = {
         .base = PERCPU_IDT_MAPPING,
         .limit = 0xffff,
@@ -272,7 +276,9 @@ void early_switch_to_idle(bool bsp)
     per_cpu(curr_ptbase, cpu) = v->arch.cr3;
     per_cpu(curr_extended_directmap, cpu) = true;
 
+    lgdt(&gdtr);
     lidt(&idtr);
+    lldt(0);
 
     if ( likely(!bsp) ) /* BSP IST setup deferred. */
         enable_each_ist(idt_tables[cpu]);
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 2f1540e..eeabb4a 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1136,36 +1136,6 @@ static int handle_ldt_mapping_fault(unsigned int offset,
     return EXCRET_fault_fixed;
 }
 
-static int handle_gdt_ldt_mapping_fault(unsigned long offset,
-                                        struct cpu_user_regs *regs)
-{
-    struct vcpu *curr = current;
-    /* Which vcpu's area did we fault in, and is it in the ldt sub-area? */
-    unsigned int is_ldt_area = (offset >> (GDT_LDT_VCPU_VA_SHIFT-1)) & 1;
-    unsigned int vcpu_area   = (offset >> GDT_LDT_VCPU_VA_SHIFT);
-
-    /*
-     * If the fault is in another vcpu's area, it cannot be due to
-     * a GDT/LDT descriptor load. Thus we can reasonably exit immediately, and
-     * indeed we have to since pv_map_ldt_shadow_page() works correctly only on
-     * accesses to a vcpu's own area.
-     */
-    if ( vcpu_area != curr->vcpu_id )
-        return 0;
-
-    /* Byte offset within the gdt/ldt sub-area. */
-    offset &= (1UL << (GDT_LDT_VCPU_VA_SHIFT-1)) - 1UL;
-
-    if ( likely(is_ldt_area) )
-        return handle_ldt_mapping_fault(offset, regs);
-
-    /* GDT fault: handle the fault as #GP(selector). */
-    regs->error_code = offset & ~(X86_XEC_EXT | X86_XEC_IDT | X86_XEC_TI);
-    (void)do_general_protection(regs);
-
-    return EXCRET_fault_fixed;
-}
-
 #define IN_HYPERVISOR_RANGE(va) \
     (((va) >= HYPERVISOR_VIRT_START) && ((va) < HYPERVISOR_VIRT_END))
 
@@ -1316,9 +1286,9 @@ static int fixup_page_fault(unsigned long addr, struct 
cpu_user_regs *regs)
     if ( unlikely(IN_HYPERVISOR_RANGE(addr)) )
     {
         if ( !(regs->error_code & (PFEC_user_mode | PFEC_reserved_bit)) &&
-             (addr >= GDT_LDT_VIRT_START) && (addr < GDT_LDT_VIRT_END) )
-            return handle_gdt_ldt_mapping_fault(
-                addr - GDT_LDT_VIRT_START, regs);
+             (addr >= PERCPU_LDT_MAPPING) && (addr < PERCPU_LDT_MAPPING_END) )
+            return handle_ldt_mapping_fault(addr - PERCPU_LDT_MAPPING, regs);
+
         return 0;
     }
 
diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c
index fe6d3af..3e46ac6 100644
--- a/xen/common/efi/runtime.c
+++ b/xen/common/efi/runtime.c
@@ -100,17 +100,6 @@ struct efi_rs_state efi_rs_enter(void)
     /* prevent fixup_page_fault() from doing anything */
     irq_enter();
 
-    if ( is_pv_vcpu(current) && !is_idle_vcpu(current) )
-    {
-        struct desc_ptr gdt_desc = {
-            .limit = LAST_RESERVED_GDT_BYTE,
-            .base  = (unsigned long)(per_cpu(gdt_table, smp_processor_id()) -
-                                     FIRST_RESERVED_GDT_ENTRY)
-        };
-
-        lgdt(&gdt_desc);
-    }
-
     write_cr3(virt_to_maddr(efi_l4_pgtable));
     this_cpu(curr_extended_directmap) = true;
 
@@ -124,15 +113,6 @@ void efi_rs_leave(struct efi_rs_state *state)
 
     this_cpu(curr_extended_directmap) = paging_mode_external(current->domain);
     write_cr3(state->cr3);
-    if ( is_pv_vcpu(current) && !is_idle_vcpu(current) )
-    {
-        struct desc_ptr gdt_desc = {
-            .limit = LAST_RESERVED_GDT_BYTE,
-            .base  = GDT_VIRT_START(current)
-        };
-
-        lgdt(&gdt_desc);
-    }
     irq_exit();
     efi_rs_on_cpu = NR_CPUS;
     spin_unlock(&efi_rs_lock);
diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index dfe1f03..62549a8 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -304,7 +304,9 @@ extern unsigned long xen_phys_start;
 
 #define PERCPU_GDT_LDT_L1ES      (PERCPU_LINEAR_START + MB(8) + KB(12))
 #define PERCPU_GDT_MAPPING       (PERCPU_LINEAR_START + MB(10))
+#define PERCPU_GDT_MAPPING_END   (PERCPU_GDT_MAPPING + 0x10000)
 #define PERCPU_LDT_MAPPING       (PERCPU_LINEAR_START + MB(11))
+#define PERCPU_LDT_MAPPING_END   (PERCPU_LDT_MAPPING + 0x10000)
 
 /* GDT/LDT shadow mapping area. The first per-domain-mapping sub-area. */
 #define GDT_LDT_VCPU_SHIFT       5
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index be0f61c..108b3a4 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,18 +396,21 @@ struct arch_domain
 
 #define has_arch_pdevs(d)    (!list_empty(&(d)->arch.pdev_list))
 
-#define gdt_ldt_pt_idx(v) \
-      ((v)->vcpu_id >> (PAGETABLE_ORDER - GDT_LDT_VCPU_SHIFT))
-#define pv_gdt_ptes(v) \
-    ((v)->domain->arch.pv_domain.gdt_ldt_l1tab[gdt_ldt_pt_idx(v)] + \
-     (((v)->vcpu_id << GDT_LDT_VCPU_SHIFT) & (L1_PAGETABLE_ENTRIES - 1)))
-#define pv_ldt_ptes(v) (pv_gdt_ptes(v) + 16)
+#define pv_gdt ((struct desc_struct *)PERCPU_GDT_MAPPING)
+#define pv_ldt ((struct desc_struct *)PERCPU_LDT_MAPPING)
+
+#define pv_gdt_ptes \
+    ((l1_pgentry_t *)PERCPU_GDT_LDT_L1ES + l1_table_offset(PERCPU_GDT_MAPPING))
+#define pv_ldt_ptes \
+    ((l1_pgentry_t *)PERCPU_GDT_LDT_L1ES + l1_table_offset(PERCPU_LDT_MAPPING))
 
 struct pv_vcpu
 {
     struct trap_info *trap_ctxt;
 
-    unsigned long gdt_frames[FIRST_RESERVED_GDT_PAGE];
+#define MAX_PV_GDT_FRAMES FIRST_RESERVED_GDT_PAGE
+    l1_pgentry_t gdt_l1es[MAX_PV_GDT_FRAMES];
+    l1_pgentry_t ldt_l1es[16];
     unsigned long ldt_base;
     unsigned int gdt_ents, ldt_ents;
 
diff --git a/xen/include/asm-x86/ldt.h b/xen/include/asm-x86/ldt.h
index 6fbce93..f28a895 100644
--- a/xen/include/asm-x86/ldt.h
+++ b/xen/include/asm-x86/ldt.h
@@ -4,21 +4,26 @@
 
 #ifndef __ASSEMBLY__
 
+DECLARE_PER_CPU(unsigned int, ldt_ents);
+
 static inline void load_LDT(struct vcpu *v)
 {
-    struct desc_struct *desc;
     unsigned int ents = is_pv_vcpu(v) && v->arch.pv_vcpu.ldt_ents;
+    unsigned int *this_ldt_ents = &this_cpu(ldt_ents);
+
+    if ( likely(ents == *this_ldt_ents) )
+        return;
 
     if ( ents == 0 )
         lldt(0);
     else
     {
-        desc = (!is_pv_32bit_vcpu(v)
-                ? this_cpu(gdt_table) : this_cpu(compat_gdt_table))
-               + LDT_ENTRY - FIRST_RESERVED_GDT_ENTRY;
-        _set_tssldt_desc(desc, LDT_VIRT_START(v), ents*8-1, SYS_DESC_ldt);
+        _set_tssldt_desc(&pv_gdt[LDT_ENTRY], PERCPU_LDT_MAPPING,
+                         ents * 8 - 1, SYS_DESC_ldt);
         lldt(LDT_ENTRY << 3);
     }
+
+    *this_ldt_ents = ents;
 }
 
 #endif /* !__ASSEMBLY__ */
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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