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

Reply via email to