From 548224fe4256ea02669f106fe8b3297a22e6b4ad Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 14 Feb 2018 17:37:09 +0000 Subject: [PATCH] Support the use of GDTs in PV guests GDT frames in PV guests need to be page aligned, and like pagetables, mapped read-only. Move gdt[] into __page_aligned_{data,bss} and leave it empty for PV guests to begin with. The PV arch_init_traps() code registers the frame with Xen, and tests wanting to make use of it need to use hypercall_update_descriptor(). Signed-off-by: Andrew Cooper --- arch/x86/desc.c | 14 +++++++++++--- arch/x86/include/arch/desc.h | 2 ++ arch/x86/link.lds.S | 4 ++++ arch/x86/pv/traps.c | 14 ++++++++++++++ include/xtf/hypercall.h | 17 +++++++++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/arch/x86/desc.c b/arch/x86/desc.c index fad8355..e452e09 100644 --- a/arch/x86/desc.c +++ b/arch/x86/desc.c @@ -4,8 +4,15 @@ #include #include -user_desc gdt[NR_GDT_ENTRIES] = +#ifdef CONFIG_HVM +#define gdt_section __page_aligned_data +#else +#define gdt_section __page_aligned_bss +#endif + +user_desc gdt[NR_GDT_ENTRIES] gdt_section = { +#ifdef CONFIG_HVM [GDTE_CS64_DPL0] = INIT_GDTE_SYM(0, 0xfffff, COMMON, CODE, DPL0, R, L), [GDTE_CS32_DPL0] = INIT_GDTE_SYM(0, 0xfffff, COMMON, CODE, DPL0, R, D), [GDTE_DS32_DPL0] = INIT_GDTE_SYM(0, 0xfffff, COMMON, DATA, DPL0, B, W), @@ -16,16 +23,17 @@ user_desc gdt[NR_GDT_ENTRIES] = /* [GDTE_TSS] */ /* [GDTE_TSS + 1] */ +#endif }; +#if defined(CONFIG_HVM) + desc_ptr gdt_ptr = { .limit = sizeof(gdt) - 1, .base = _u(&gdt), }; -#if defined(CONFIG_HVM) - env_gate idt[256]; desc_ptr idt_ptr = diff --git a/arch/x86/include/arch/desc.h b/arch/x86/include/arch/desc.h index f722d82..e218e6e 100644 --- a/arch/x86/include/arch/desc.h +++ b/arch/x86/include/arch/desc.h @@ -54,6 +54,8 @@ struct __packed seg_desc32 { }; uint8_t base2; }; + /* Full width backing integer. */ + uint64_t raw; }; }; diff --git a/arch/x86/link.lds.S b/arch/x86/link.lds.S index 736659a..03c9455 100644 --- a/arch/x86/link.lds.S +++ b/arch/x86/link.lds.S @@ -102,6 +102,10 @@ ASSERT(IS_ALIGNED(pae32_l3_identmap, 32), "pae32_l3_ident misaligned"); ASSERT(IS_ALIGNED(pse_l1_identmap, PAGE_SIZE), "pse_l1_identmap misaligned"); ASSERT(IS_ALIGNED(pse_l2_identmap, PAGE_SIZE), "pse_l2_identmap misaligned"); +#else + +ASSERT(IS_ALIGNED(gdt, PAGE_SIZE), "gdt misaligned"); + #endif /* * Local variables: diff --git a/arch/x86/pv/traps.c b/arch/x86/pv/traps.c index 336da9e..ca0b9a3 100644 --- a/arch/x86/pv/traps.c +++ b/arch/x86/pv/traps.c @@ -96,6 +96,20 @@ void arch_init_traps(void) if ( rc ) panic("Failed to set trap table: %d\n", rc); + /* Register gdt[] with Xen. Need to map it read-only first. */ + if ( hypercall_update_va_mapping( + _u(gdt), pte_from_virt(gdt, PF_SYM(AD, P)), UVMF_INVLPG) ) + panic("Unable to remap gdt[] as read-only\n"); + + unsigned long gdt_frames[] = { + virt_to_mfn(gdt), + }; + BUILD_BUG_ON(NR_GDT_ENTRIES > (PAGE_SIZE / sizeof(user_desc))); + + rc = hypercall_set_gdt(gdt_frames, NR_GDT_ENTRIES); + if ( rc ) + panic("Failed to set gdt: %d\n", rc); + /* PV equivalent of setting tss.{esp0,ss0}. */ rc = hypercall_stack_switch(__KERN_DS, &boot_stack[2 * PAGE_SIZE]); if ( rc ) diff --git a/include/xtf/hypercall.h b/include/xtf/hypercall.h index 9be25da..64473e9 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -3,6 +3,7 @@ #include #include +#include #include #if defined(__x86_64__) @@ -61,11 +62,27 @@ static inline long hypercall_mmu_update(const mmu_update_t reqs[], reqs, count, done, foreigndom); } +static inline long hypercall_set_gdt(const unsigned long *mfns, + unsigned int entries) +{ + return HYPERCALL2(long, __HYPERVISOR_set_gdt, mfns, entries); +} + static inline long hypercall_stack_switch(const unsigned int ss, const void *sp) { return HYPERCALL2(long, __HYPERVISOR_stack_switch, ss, sp); } +static inline long hypercall_update_descriptor(uint64_t maddr, user_desc desc) +{ +#ifdef __x86_64__ + return HYPERCALL2(long, __HYPERVISOR_update_descriptor, maddr, desc.raw); +#else + return HYPERCALL4(long, __HYPERVISOR_update_descriptor, + maddr, maddr >> 32, desc.lo, desc.hi); +#endif +} + static inline long hypercall_memory_op(unsigned int cmd, void *arg) { return HYPERCALL2(long, __HYPERVISOR_memory_op, cmd, arg); -- 2.39.5