xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Xen-devel <xen-devel@lists.xen.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Subject: [PATCH RFC 33/44] x86/smp: Use the percpu GDT/LDT mappings
Date: Thu, 4 Jan 2018 20:21:58 +0000	[thread overview]
Message-ID: <1515097329-31902-34-git-send-email-andrew.cooper3@citrix.com> (raw)
In-Reply-To: <1515097329-31902-1-git-send-email-andrew.cooper3@citrix.com>

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@citrix.com>
---
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@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

  parent reply	other threads:[~2018-01-04 20:21 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-04 20:21 [PATCH FAIRLY-RFC 00/44] x86: Prerequisite work for a Xen KAISER solution Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 01/44] passthrough/vtd: Don't DMA to the stack in queue_invalidate_wait() Andrew Cooper
2018-01-05  9:21   ` Jan Beulich
2018-01-05  9:33     ` Andrew Cooper
2018-01-16  6:41   ` Tian, Kevin
2018-01-04 20:21 ` [PATCH RFC 02/44] x86/idt: Factor out enabling and disabling of ISTs Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 03/44] x86/pv: Rename invalidate_shadow_ldt() to pv_destroy_ldt() Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 04/44] x86/boot: Introduce cpu_smpboot_bsp() to dynamically allocate BSP state Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 05/44] x86/boot: Move arch_init_memory() earlier in the boot sequence Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 06/44] x86/boot: Allocate percpu pagetables for the idle vcpus Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 07/44] x86/boot: Use " Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 08/44] x86/pv: Avoid an opencoded mov to %cr3 in toggle_guest_mode() Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 09/44] x86/mm: Track the current %cr3 in a per_cpu variable Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 10/44] x86/pt-shadow: Initial infrastructure for L4 PV pagetable shadowing Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 11/44] x86/pt-shadow: Always set _PAGE_ACCESSED on L4e updates Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 12/44] x86/fixmap: Temporarily add a percpu fixmap range Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 13/44] x86/pt-shadow: Shadow L4 tables from 64bit PV guests Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 14/44] x86/mm: Added safety checks that pagetables aren't shared Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 15/44] x86: Rearrange the virtual layout to introduce a PERCPU linear slot Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 16/44] xen/ipi: Introduce arch_ipi_param_ok() to check IPI parameters Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 17/44] x86/smp: Infrastructure for allocating and freeing percpu pagetables Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 18/44] x86/mm: Maintain the correct percpu mappings on context switch Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 19/44] x86/boot: Defer TSS/IST setup until later during boot on the BSP Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 20/44] x86/smp: Allocate a percpu linear range for the IDT Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 21/44] x86/smp: Switch to using the percpu IDT mappings Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 22/44] x86/mm: Track whether the current cr3 has a short or extended directmap Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 23/44] x86/smp: Allocate percpu resources for map_domain_page() to use Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 24/44] x86/mapcache: Reimplement map_domain_page() from scratch Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 25/44] x86/fixmap: Drop percpu fixmap range Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 26/44] x86/pt-shadow: Maintain a small cache of shadowed frames Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 27/44] x86/smp: Allocate a percpu linear range for the compat translation area Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 28/44] x86/xlat: Use the percpu " Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 29/44] x86/smp: Allocate percpu resources for the GDT and LDT Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 30/44] x86/pv: Break handle_ldt_mapping_fault() out of handle_gdt_ldt_mapping_fault() Andrew Cooper
2018-01-04 20:21 ` [PATCH RFC 31/44] x86/pv: Drop support for paging out the LDT Andrew Cooper
2018-01-24 11:04   ` Jan Beulich
2018-01-04 20:21 ` [PATCH RFC 32/44] x86: Always reload the LDT on vcpu context switch Andrew Cooper
2018-01-04 20:21 ` Andrew Cooper [this message]
2018-01-04 20:21 ` [PATCH RFC 34/44] x86: Drop the PERDOMAIN mappings Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 35/44] x86/smp: Allocate the stack in the percpu range Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 36/44] x86/monitor: Capture Xen's intent to use monitor at boot time Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 37/44] x86/misc: Move some IPI parameters off the stack Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 38/44] x86/mca: Move __HYPERVISOR_mca " Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 39/44] x86/smp: Introduce get_smp_ipi_buf() and take more " Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 40/44] x86/boot: Switch the APs to the percpu pagetables before entering C Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 41/44] x86/smp: Switch to using the percpu stacks Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 42/44] x86/smp: Allocate a percpu linear range for the TSS Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 43/44] x86/smp: Use the percpu TSS mapping Andrew Cooper
2018-01-04 20:22 ` [PATCH RFC 44/44] misc debugging Andrew Cooper
2018-01-05  7:48 ` [PATCH FAIRLY-RFC 00/44] x86: Prerequisite work for a Xen KAISER solution Juergen Gross
2018-01-05  9:26   ` Andrew Cooper
2018-01-05  9:39     ` Juergen Gross
2018-01-05  9:56       ` Andrew Cooper
2018-01-05 14:11       ` George Dunlap
2018-01-05 14:17         ` Juergen Gross
2018-01-05 14:21           ` George Dunlap
2018-01-05 14:28             ` Jan Beulich
2018-01-05 14:27         ` Jan Beulich
2018-01-05 14:35           ` Andrew Cooper
2018-01-08 11:41             ` George Dunlap
2018-01-09 23:14   ` Stefano Stabellini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1515097329-31902-34-git-send-email-andrew.cooper3@citrix.com \
    --to=andrew.cooper3@citrix.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).