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

[Xen-devel] [PATCH RFC 4/4] xen: use per-vcpu TSS and stacks for pv domains



Instead of using the TSS and stacks of the physical processor allocate
them per vcpu, map them in the per domain area, and use those.

Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
---
 xen/arch/x86/domain.c        | 45 +++++++++++++++++++++++----
 xen/arch/x86/pv/domain.c     | 72 +++++++++++++++++++++++++++++++++++++++++---
 xen/arch/x86/x86_64/entry.S  |  4 +++
 xen/include/asm-x86/config.h |  9 +++++-
 xen/include/asm-x86/mm.h     |  5 +++
 5 files changed, 124 insertions(+), 11 deletions(-)

diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index c0cb2cae64..952ed7e121 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1582,7 +1582,12 @@ static void _update_runstate_area(struct vcpu *v)
 
 static inline bool need_full_gdt(const struct domain *d)
 {
-    return is_pv_domain(d) && !is_idle_domain(d);
+    return is_pv_32bit_domain(d);
+}
+
+static inline bool need_per_vcpu_data(const struct domain *d)
+{
+    return is_pv_domain(d) && !is_idle_domain(d) && !is_pv_32bit_domain(d);
 }
 
 static void __context_switch(void)
@@ -1657,8 +1662,19 @@ static void __context_switch(void)
 
     write_ptbase(n);
 
-    if ( need_full_gdt(nd) &&
-         ((p->vcpu_id != n->vcpu_id) || !need_full_gdt(pd)) )
+    if ( need_per_vcpu_data(nd) )
+    {
+        gdt = (struct desc_struct *)GDT_VIRT_START(n);
+        gdt[PER_CPU_GDT_ENTRY].a = cpu;
+
+        gdt_desc.limit = LAST_RESERVED_GDT_BYTE;
+        gdt_desc.base = GDT_VIRT_START(n);
+
+        lgdt(&gdt_desc);
+        ltr(TSS_ENTRY << 3);
+    }
+    else 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);
@@ -1673,8 +1689,8 @@ static void __context_switch(void)
     per_cpu(curr_vcpu, cpu) = n;
 }
 
-static void context_switch_irqoff(struct vcpu *prev, struct vcpu *next,
-                                  unsigned int cpu)
+void context_switch_irqoff(struct vcpu *prev, struct vcpu *next,
+                           unsigned int cpu)
 {
     const struct domain *prevd = prev->domain, *nextd = next->domain;
 
@@ -1764,7 +1780,24 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
 
     set_current(next);
 
-    context_switch_irqoff(prev, next, cpu);
+    if ( is_pv_domain(prevd) && !is_pv_32bit_domain(prevd) )
+    {
+        struct desc_struct *gdt = this_cpu(compat_gdt_table) -
+                                  FIRST_RESERVED_GDT_ENTRY;
+        const struct desc_ptr gdtr = {
+            .base = (unsigned long)gdt,
+            .limit = LAST_RESERVED_GDT_BYTE,
+        };
+        void *stack = (struct cpu_info *)(stack_base[cpu] + STACK_SIZE) - 1;
+
+        /* Switch to global accessible gdt and tss. */
+        lgdt(&gdtr);
+        ltr(TSS_ENTRY << 3);
+
+        context_switch_irqoff_stack(prev, next, cpu, stack);
+    }
+    else
+        context_switch_irqoff(prev, next, cpu);
 }
 
 void continue_running(struct vcpu *same)
diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c
index 74e9e667d2..6692aa6922 100644
--- a/xen/arch/x86/pv/domain.c
+++ b/xen/arch/x86/pv/domain.c
@@ -96,10 +96,32 @@ int switch_compat(struct domain *d)
 
 static int pv_create_gdt_ldt_l1tab(struct vcpu *v)
 {
-    return create_perdomain_mapping(v->domain, GDT_VIRT_START(v),
-                                    1U << GDT_LDT_VCPU_SHIFT,
-                                    v->domain->arch.pv_domain.gdt_ldt_l1tab,
-                                    NULL);
+    int rc;
+
+    rc = create_perdomain_mapping(v->domain, GDT_VIRT_START(v),
+                                  1U << GDT_LDT_VCPU_SHIFT,
+                                  v->domain->arch.pv_domain.gdt_ldt_l1tab,
+                                  NULL);
+    if ( !rc && !is_pv_32bit_vcpu(v) )
+    {
+        struct desc_struct *gdt;
+
+        gdt = (struct desc_struct *)GDT_VIRT_START(v) +
+              FIRST_RESERVED_GDT_ENTRY;
+        rc = create_perdomain_mapping(v->domain, (unsigned long)gdt,
+                                      NR_RESERVED_GDT_BYTES,
+                                      NULL, NIL(struct page_info *));
+        if ( !rc )
+        {
+            memcpy(gdt, boot_cpu_gdt_table, NR_RESERVED_GDT_BYTES);
+            _set_tssldt_desc(gdt + TSS_ENTRY - FIRST_RESERVED_GDT_ENTRY,
+                         TSS_START(v),
+                         offsetof(struct tss_struct, __cacheline_filler) - 1,
+                         SYS_DESC_tss_avail);
+        }
+    }
+
+    return rc;
 }
 
 static void pv_destroy_gdt_ldt_l1tab(struct vcpu *v)
@@ -119,6 +141,46 @@ void pv_vcpu_destroy(struct vcpu *v)
     pv_destroy_gdt_ldt_l1tab(v);
     xfree(v->arch.pv_vcpu.trap_ctxt);
     v->arch.pv_vcpu.trap_ctxt = NULL;
+
+    if ( !is_pv_32bit_vcpu(v) )
+        destroy_perdomain_mapping(v->domain, STACKS_START(v),
+                                  STACK_SIZE + PAGE_SIZE);
+}
+
+static int pv_vcpu_init_tss_stacks(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    void *stacks;
+    int rc;
+
+    /* Populate page tables. */
+    rc = create_perdomain_mapping(d, STACKS_START(v), STACK_SIZE + PAGE_SIZE,
+                                  NIL(l1_pgentry_t *), NULL);
+    if ( rc )
+        goto done;
+
+    /* Map TSS. */
+    rc = create_perdomain_mapping(d, TSS_START(v), PAGE_SIZE,
+                                  NULL, NIL(struct page_info *));
+    if ( rc )
+        goto done;
+
+    /* Map stacks. */
+    stacks = (void *)STACKS_START(v);
+    rc = create_perdomain_mapping(d, STACKS_START(v), STACK_SIZE,
+                                  NULL, NIL(struct page_info *));
+    if ( rc )
+        goto done;
+#ifdef MEMORY_GUARD
+    /* Remove guard page. */
+    destroy_perdomain_mapping(d, (unsigned 
long)memguard_get_guard_page(stacks),
+                              PAGE_SIZE);
+#endif
+
+    tss_init((struct tss_struct *)TSS_START(v), STACKS_START(v));
+
+ done:
+    return 0;
 }
 
 int pv_vcpu_initialise(struct vcpu *v)
@@ -157,6 +219,8 @@ int pv_vcpu_initialise(struct vcpu *v)
         if ( (rc = setup_compat_l4(v)) )
             goto done;
     }
+    else
+        rc = pv_vcpu_init_tss_stacks(v);
 
  done:
     if ( rc )
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index 1dd9ccf6a2..997b75167c 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -742,3 +742,7 @@ autogen_stubs: /* Automatically generated stubs. */
 
         .section .init.rodata
         .size autogen_entrypoints, . - autogen_entrypoints
+
+ENTRY(context_switch_irqoff_stack)
+       mov   %rcx, %rsp
+        jmp   context_switch_irqoff
diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index 9ef9d03ca7..46096cc666 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -202,7 +202,7 @@ extern unsigned char boot_edid_info[128];
 /* Slot 260: per-domain mappings (including map cache). */
 #define PERDOMAIN_VIRT_START    (PML4_ADDR(260))
 #define PERDOMAIN_SLOT_MBYTES   (PML4_ENTRY_BYTES >> (20 + PAGETABLE_ORDER))
-#define PERDOMAIN_SLOTS         3
+#define PERDOMAIN_SLOTS         4
 #define PERDOMAIN_VIRT_SLOT(s)  (PERDOMAIN_VIRT_START + (s) * \
                                  (PERDOMAIN_SLOT_MBYTES << 20))
 /* Slot 261: machine-to-phys conversion table (256GB). */
@@ -310,6 +310,13 @@ extern unsigned long xen_phys_start;
 #define ARG_XLAT_START(v)        \
     (ARG_XLAT_VIRT_START + ((v)->vcpu_id << ARG_XLAT_VA_SHIFT))
 
+/* per-vcpu Xen stacks and TSS. The fourth per-domain-mapping sub-area. */
+#define TSS_STACKS_VIRT_START    PERDOMAIN_VIRT_SLOT(3)
+#define TSS_STACKS_VA_SHIFT      (PAGE_SHIFT + STACK_ORDER + 1)
+#define STACKS_START(v)          (TSS_STACKS_VIRT_START +                    \
+                                  ((v)->vcpu_id << TSS_STACKS_VA_SHIFT))
+#define TSS_START(v)             (STACKS_START(v) + STACK_SIZE)
+
 #define NATIVE_VM_ASSIST_VALID   ((1UL << VMASST_TYPE_4gb_segments)        | \
                                   (1UL << VMASST_TYPE_4gb_segments_notify) | \
                                   (1UL << VMASST_TYPE_writable_pagetables) | \
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 84e112b830..6678bf04f5 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -636,4 +636,9 @@ static inline bool arch_mfn_in_directmap(unsigned long mfn)
     return mfn <= (virt_to_mfn(eva - 1) + 1);
 }
 
+void context_switch_irqoff(struct vcpu *prev, struct vcpu *next,
+                           unsigned int cpu);
+void context_switch_irqoff_stack(struct vcpu *prev, struct vcpu *next,
+                                 unsigned int cpu, void *stack);
+
 #endif /* __ASM_X86_MM_H__ */
-- 
2.13.6


_______________________________________________
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®.