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