From 6beb34c3cbd435bc746eebf9bf84388bfd62ac9b Mon Sep 17 00:00:00 2001 From: Yin Fengwei Date: Wed, 10 Jul 2019 11:48:36 +0800 Subject: [PATCH] vm_load: update init gdt preparation Now, we use native gdt saved in boot context for guest and assume it could be put to same address of guest. But it may not be true after the pre-launched VM is introduced. The gdt for guest could be overwritten by guest images. This patch make 32bit protect mode boot not use saved boot context. Insteadly, we use predefined vcpu_regs value for protect guest to initialize the guest bsp registers and copy pre-defined gdt table to a safe place of guest memory to avoid gdt table overwritten by guest images. Tracked-On: #3532 Signed-off-by: Yin Fengwei Reviewed-by: Jason Chen CJ Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vcpu.c | 35 ++++++++++++++++++++++-- hypervisor/common/vm_load.c | 30 ++++++++++++-------- hypervisor/include/arch/x86/guest/vcpu.h | 12 ++++++++ 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index f5d10c925..b235872ba 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -299,7 +299,7 @@ void set_vcpu_regs(struct acrn_vcpu *vcpu, struct acrn_vcpu_regs *vcpu_regs) vcpu_regs->cr0); } -static struct acrn_vcpu_regs realmode_init_regs = { +static struct acrn_vcpu_regs realmode_init_vregs = { .gdt = { .limit = 0xFFFFU, .base = 0UL, @@ -318,9 +318,40 @@ static struct acrn_vcpu_regs realmode_init_regs = { .cr4 = 0UL, }; +static uint64_t init_vgdt[] = { + 0x0UL, + 0x0UL, + 0x00CF9B000000FFFFUL, /* Linear Code */ + 0x00CF93000000FFFFUL, /* Linear Data */ +}; + +static struct acrn_vcpu_regs protect_mode_init_vregs = { + .cs_ar = PROTECTED_MODE_CODE_SEG_AR, + .cs_limit = PROTECTED_MODE_SEG_LIMIT, + .cs_sel = 0x10U, + .cr0 = CR0_ET | CR0_NE | CR0_PE, + .ds_sel = 0x18U, + .ss_sel = 0x18U, + .es_sel = 0x18U, +}; + void reset_vcpu_regs(struct acrn_vcpu *vcpu) { - set_vcpu_regs(vcpu, &realmode_init_regs); + set_vcpu_regs(vcpu, &realmode_init_vregs); +} + +void init_vcpu_protect_mode_regs(struct acrn_vcpu *vcpu, uint64_t vgdt_base_gpa) +{ + struct acrn_vcpu_regs vcpu_regs; + + (void)memcpy_s((void*)&vcpu_regs, sizeof(struct acrn_vcpu_regs), + (void *)&protect_mode_init_vregs, sizeof(struct acrn_vcpu_regs)); + + vcpu_regs.gdt.base = vgdt_base_gpa; + vcpu_regs.gdt.limit = sizeof(init_vgdt) - 1U; + (void)copy_to_gpa(vcpu->vm, &init_vgdt, vgdt_base_gpa, sizeof(init_vgdt)); + + set_vcpu_regs(vcpu, &vcpu_regs); } void set_vcpu_startup_entry(struct acrn_vcpu *vcpu, uint64_t entry) diff --git a/hypervisor/common/vm_load.c b/hypervisor/common/vm_load.c index 0b964be3a..63187835a 100644 --- a/hypervisor/common/vm_load.c +++ b/hypervisor/common/vm_load.c @@ -17,18 +17,22 @@ #define NUM_REMAIN_1G_PAGES 3UL -static void prepare_bsp_gdt(struct acrn_vm *vm) +/* + * We put the guest init gdt after kernel/bootarg/ramdisk images. Suppose this is a + * safe place for guest init gdt of guest whatever the configuration is used by guest. + */ +static uint64_t get_guest_gdt_base_gpa(const struct acrn_vm *vm) { - size_t gdt_len; - uint64_t gdt_base_hpa; + uint64_t new_guest_gdt_base_gpa, guest_kernel_end_gpa, guest_bootargs_end_gpa, guest_ramdisk_end_gpa; - gdt_base_hpa = gpa2hpa(vm, boot_context.gdt.base); - if (boot_context.gdt.base != gdt_base_hpa) { - gdt_len = ((size_t)boot_context.gdt.limit + 1U) / sizeof(uint8_t); - (void)copy_to_gpa(vm, hpa2hva(boot_context.gdt.base), boot_context.gdt.base, gdt_len); - } + guest_kernel_end_gpa = (uint64_t)vm->sw.kernel_info.kernel_load_addr + vm->sw.kernel_info.kernel_size; + guest_bootargs_end_gpa = (uint64_t)vm->sw.bootargs_info.load_addr + vm->sw.bootargs_info.size; + guest_ramdisk_end_gpa = (uint64_t)vm->sw.ramdisk_info.load_addr + vm->sw.ramdisk_info.size; - return; + new_guest_gdt_base_gpa = max(guest_kernel_end_gpa, max(guest_bootargs_end_gpa, guest_ramdisk_end_gpa)); + new_guest_gdt_base_gpa = (new_guest_gdt_base_gpa + 7UL) & ~(8UL - 1UL); + + return new_guest_gdt_base_gpa; } /** @@ -181,8 +185,12 @@ int32_t direct_boot_sw_loader(struct acrn_vm *vm) pr_dbg("Loading guest to run-time location"); - prepare_bsp_gdt(vm); - set_vcpu_regs(vcpu, &boot_context); + /* + * TODO: + * - We need to initialize the guest bsp registers according to + * guest boot mode (real mode vs protect mode) + */ + init_vcpu_protect_mode_regs(vcpu, get_guest_gdt_base_gpa(vcpu->vm)); /* Copy the guest kernel image to its run-time location */ (void)copy_to_gpa(vm, sw_kernel->kernel_src_addr, diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index 775a751f3..3f56a0586 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -603,6 +603,18 @@ void set_vcpu_regs(struct acrn_vcpu *vcpu, struct acrn_vcpu_regs *vcpu_regs); */ void reset_vcpu_regs(struct acrn_vcpu *vcpu); +/** + * @brief Initialize the protect mode vcpu registers + * + * Initialize vCPU's all registers in run_context to initial protece mode values. + * + * @param[inout] vcpu pointer to vcpu data structure + * @param[in] vgdt_base_gpa guest physical address of gdt for guest + * + * @return None + */ +void init_vcpu_protect_mode_regs(struct acrn_vcpu *vcpu, uint64_t vgdt_base_gpa); + /** * @brief set the vCPU startup entry *