From 9aa9a774571ce54f404761f7f41803c200b54db7 Mon Sep 17 00:00:00 2001 From: Mingqiang Chi Date: Tue, 3 Apr 2018 18:45:29 +0800 Subject: [PATCH] mmu:create temporary page tables for guest at run time Before this patch, guest temporary page tables were generated by hardcode at compile time, HV will copy this page tables to guest before guest launch. This patch creates temporary page tables at runtime for the range of 0~4G, and create page tables to cover new range(511G~511G+16M) with trusty requirement. Signed-off-by: Mingqiang Chi Reviewed-by: Jason Chen CJ Acked-by: Eddie Dong --- hypervisor/arch/x86/cpu_secondary.S | 32 ------ hypervisor/arch/x86/ept.c | 15 --- hypervisor/arch/x86/guest/guest.c | 129 +++++++++++++++++++++++++ hypervisor/arch/x86/guest/vcpu.c | 5 +- hypervisor/arch/x86/trusty.c | 3 - hypervisor/arch/x86/vmx.c | 2 +- hypervisor/common/vm_load.c | 2 +- hypervisor/include/arch/x86/cpu.h | 3 + hypervisor/include/arch/x86/guest/vm.h | 2 +- hypervisor/include/arch/x86/mmu.h | 2 +- hypervisor/include/arch/x86/trusty.h | 4 + 11 files changed, 143 insertions(+), 56 deletions(-) diff --git a/hypervisor/arch/x86/cpu_secondary.S b/hypervisor/arch/x86/cpu_secondary.S index acb23bc5d..35df24f4a 100644 --- a/hypervisor/arch/x86/cpu_secondary.S +++ b/hypervisor/arch/x86/cpu_secondary.S @@ -162,36 +162,4 @@ cpu_secondary_pdt_addr: address = address + 0x200000 .endr - -/******************************************************************* - * GUEST initial 4G page table - * - * guest starts with long mode, HV needs to prepare Guest identity - * mapped page table. - * - * guest page tables covers 4G size, with 2M page size. - * - * HV copy this page table (6 pages) to guest address - * CPU_Boot_Page_Tables_Start_VM before executing guest instruction. - * - ******************************************************************/ - .align CPU_PAGE_SIZE - .global CPU_Boot_Page_Tables_Start_VM -CPU_Boot_Page_Tables_Start_VM: - .quad vm_cpu_pdpt_addr + (IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT) - .align CPU_PAGE_SIZE -vm_cpu_pdpt_addr: - address = 0 - .rept 4 - .quad vm_cpu_pdt_addr + address + (IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT) - address = address + CPU_PAGE_SIZE - .endr - .align CPU_PAGE_SIZE -vm_cpu_pdt_addr: - address = 0 - .rept 2048 - .quad address + (IA32E_PDPTE_PS_BIT | IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT) - address = address + 0x200000 - .endr - .end diff --git a/hypervisor/arch/x86/ept.c b/hypervisor/arch/x86/ept.c index 6c34666ff..5bc46be26 100644 --- a/hypervisor/arch/x86/ept.c +++ b/hypervisor/arch/x86/ept.c @@ -41,21 +41,6 @@ #define ACRN_DBG_EPT 6 -void *create_guest_paging(struct vm *vm) -{ - void *hva_dest; - void *hva_src; - - /* copy guest identity mapped 4G page table to guest */ - hva_dest = GPA2HVA(vm, - (uint64_t)CPU_Boot_Page_Tables_Start_VM); - hva_src = (void *)(_ld_cpu_secondary_reset_load - + (CPU_Boot_Page_Tables_Start_VM - - _ld_cpu_secondary_reset_start)); - /* 2MB page size, need to copy 6 pages */ - memcpy_s(hva_dest, 6 * CPU_PAGE_SIZE, hva_src, 6 * CPU_PAGE_SIZE); - return (void *)CPU_Boot_Page_Tables_Start_VM; -} static uint64_t find_next_table(uint32_t table_offset, void *table_base) { diff --git a/hypervisor/arch/x86/guest/guest.c b/hypervisor/arch/x86/guest/guest.c index 6371b5b58..7f2e57f68 100644 --- a/hypervisor/arch/x86/guest/guest.c +++ b/hypervisor/arch/x86/guest/guest.c @@ -335,3 +335,132 @@ int prepare_vm0_memmap_and_e820(struct vm *vm) CONFIG_RAM_SIZE, MAP_UNMAP, 0); return 0; } + +/******************************************************************* + * GUEST initial page table + * + * guest starts with long mode, HV needs to prepare Guest identity + * mapped page table. + * For SOS: + * Guest page tables cover 0~4G space with 2M page size, will use + * 6 pages memory for page tables. + * For UOS(Trusty not enabled): + * Guest page tables cover 0~4G space with 2M page size, will use + * 6 pages memory for page tables. + * For UOS(Trusty enabled): + * Guest page tables cover 0~4G and trusy memory space with 2M page size, + * will use 7 pages memory for page tables. + * This API assume that the trusty memory is remapped to guest physical address + * of 511G to 511G + 16MB + * + * FIXME: here using hard code GUEST_INIT_PAGE_TABLE_START as guest init page + * table gpa start, and it will occupy at most GUEST_INIT_PT_PAGE_NUM pages. + * Some check here: + * - guest page table space should not override cpu_secondary_reset code area + * (it's a little tricky here, as under current identical mapping, HV & SOS + * share same memory under 1M; under uefi boot mode, the defered AP startup + * need cpu_secondary_reset code area which reserved by uefi stub keep there + * no change even after SOS startup) + * - guest page table space should not override possible RSDP fix segment + * + * Anyway, it's a tmp solution, the init page tables should be totally removed + * after guest realmode/32bit no paging mode got supported. + ******************************************************************/ +#define GUEST_INIT_PAGE_TABLE_SKIP_SIZE 0x8000UL +#define GUEST_INIT_PAGE_TABLE_START (CONFIG_LOW_RAM_START + \ + GUEST_INIT_PAGE_TABLE_SKIP_SIZE) +#define GUEST_INIT_PT_PAGE_NUM 7 +#define RSDP_F_ADDR 0xE0000 +uint64_t create_guest_initial_paging(struct vm *vm) +{ + uint64_t i = 0; + uint64_t entry = 0; + uint64_t entry_num = 0; + uint64_t pdpt_base_paddr = 0; + uint64_t pd_base_paddr = 0; + uint64_t table_present = 0; + uint64_t table_offset = 0; + void *addr = NULL; + void *pml4_addr = GPA2HVA(vm, GUEST_INIT_PAGE_TABLE_START); + + _Static_assert((GUEST_INIT_PAGE_TABLE_START + 7 * PAGE_SIZE_4K) < + RSDP_F_ADDR, "RSDP fix segment could be override"); + + if (GUEST_INIT_PAGE_TABLE_SKIP_SIZE < + (unsigned long)&_ld_cpu_secondary_reset_size) { + panic("guest init PTs override cpu_secondary_reset code"); + } + + /* Using continuous memory for guest page tables, the total 4K page + * number for it(without trusty) is GUEST_INIT_PT_PAGE_NUM-1. + * here make sure they are init as 0 (page entry no present) + */ + memset(pml4_addr, 0, PAGE_SIZE_4K * GUEST_INIT_PT_PAGE_NUM-1); + + /* Write PML4E */ + table_present = (IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT); + /* PML4 used 1 page, skip it to fetch PDPT */ + pdpt_base_paddr = GUEST_INIT_PAGE_TABLE_START + PAGE_SIZE_4K; + entry = pdpt_base_paddr | table_present; + MEM_WRITE64(pml4_addr, entry); + + /* Write PDPTE, PDPT used 1 page, skip it to fetch PD */ + pd_base_paddr = pdpt_base_paddr + PAGE_SIZE_4K; + addr = pml4_addr + PAGE_SIZE_4K; + /* Guest page tables cover 0~4G space with 2M page size */ + for (i = 0; i < 4; i++) { + entry = ((pd_base_paddr + (i * PAGE_SIZE_4K)) + | table_present); + MEM_WRITE64(addr, entry); + addr += IA32E_COMM_ENTRY_SIZE; + } + + /* Write PDE, PT used 4 pages */ + table_present = (IA32E_PDPTE_PS_BIT + | IA32E_COMM_P_BIT + | IA32E_COMM_RW_BIT); + /* Totally 2048(512*4) entries with 2M page size for 0~4G*/ + entry_num = IA32E_NUM_ENTRIES * 4; + addr = pml4_addr + 2 * PAGE_SIZE_4K; + for (i = 0; i < entry_num; i++) { + entry = (i * (1 << MMU_PDE_PAGE_SHIFT)) | table_present; + MEM_WRITE64(addr, entry); + addr += IA32E_COMM_ENTRY_SIZE; + } + + /* For UOS, if trusty is enabled, + * need to setup tempory page table for trusty + * FIXME: this is a tempory solution for trusty enabling, + * the final solution is that vSBL will setup guest page tables + */ + if (vm->sworld_control.sworld_enabled && !is_vm0(vm)) { + /* clear page entry for trusty */ + memset(pml4_addr + 6 * PAGE_SIZE_4K, 0, PAGE_SIZE_4K); + + /* Write PDPTE for trusy memory, PD will use 7th page */ + pd_base_paddr = GUEST_INIT_PAGE_TABLE_START + + (6 * PAGE_SIZE_4K); + table_offset = + IA32E_PDPTE_INDEX_CALC(TRUSTY_EPT_REBASE_GPA); + addr = (pml4_addr + PAGE_SIZE_4K + table_offset); + table_present = (IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT); + entry = (pd_base_paddr | table_present); + MEM_WRITE64(addr, entry); + + /* Write PDE for trusty with 2M page size */ + entry_num = TRUSTY_MEMORY_SIZE / (1 << MMU_PDE_PAGE_SHIFT); + addr = pml4_addr + 6 * PAGE_SIZE_4K; + table_present = (IA32E_PDPTE_PS_BIT + | IA32E_COMM_P_BIT + | IA32E_COMM_RW_BIT); + for (i = 0; i < entry_num; i++) { + entry = (TRUSTY_EPT_REBASE_GPA + + (i * (1 << MMU_PDE_PAGE_SHIFT))) + | table_present; + MEM_WRITE64(addr, entry); + addr += IA32E_COMM_ENTRY_SIZE; + } + } + + return GUEST_INIT_PAGE_TABLE_START; +} diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index ab5815e14..185904fbd 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -98,9 +98,10 @@ int create_vcpu(int cpu_id, struct vm *vm, struct vcpu **rtn_vcpu_handle) /* Is this VCPU a VM BSP, create page hierarchy for this VM */ if (is_vcpu_bsp(vcpu)) { /* Set up temporary guest page tables */ - vm->arch_vm.guest_pml4 = create_guest_paging(vm); + vm->arch_vm.guest_init_pml4 = create_guest_initial_paging(vm); pr_info("VM *d VCPU %d CR3: 0x%016llx ", - vm->attr.id, vcpu->vcpu_id, vm->arch_vm.guest_pml4); + vm->attr.id, vcpu->vcpu_id, + vm->arch_vm.guest_init_pml4); } /* Allocate VMCS region for this VCPU */ diff --git a/hypervisor/arch/x86/trusty.c b/hypervisor/arch/x86/trusty.c index 01e21c6bf..e18a748cc 100644 --- a/hypervisor/arch/x86/trusty.c +++ b/hypervisor/arch/x86/trusty.c @@ -38,9 +38,6 @@ _Static_assert(NR_WORLD == 2, "Only 2 Worlds supported!"); -/* Trusty EPT rebase gpa: 511G */ -#define TRUSTY_EPT_REBASE_GPA (511ULL*1024ULL*1024ULL*1024ULL) - #define TRUSTY_VERSION 1 struct trusty_startup_param { diff --git a/hypervisor/arch/x86/vmx.c b/hypervisor/arch/x86/vmx.c index 8632da846..adda2db36 100644 --- a/hypervisor/arch/x86/vmx.c +++ b/hypervisor/arch/x86/vmx.c @@ -270,7 +270,7 @@ static void init_guest_state(struct vcpu *vcpu) } else if (get_vcpu_mode(vcpu) == PAGE_PROTECTED_MODE) { cur_context->cr0 = ((uint64_t)CR0_PG | CR0_PE | CR0_NE); cur_context->cr4 = ((uint64_t)CR4_PSE | CR4_PAE | CR4_MCE | CR4_VMXE); - cur_context->cr3 = (uint64_t)vm->arch_vm.guest_pml4 | CR3_PWT; + cur_context->cr3 = vm->arch_vm.guest_init_pml4 | CR3_PWT; } value = cur_context->cr0; diff --git a/hypervisor/common/vm_load.c b/hypervisor/common/vm_load.c index 5827475cf..493ac3ff0 100644 --- a/hypervisor/common/vm_load.c +++ b/hypervisor/common/vm_load.c @@ -124,7 +124,7 @@ int load_guest(struct vm *vm, struct vcpu *vcpu) pr_info("VCPU%d Entry: 0x%llx, RSI: 0x%016llx, cr3: 0x%016llx", vcpu->vcpu_id, vcpu->entry_addr, cur_context->guest_cpu_regs.regs.rsi, - vm->arch_vm.guest_pml4); + vm->arch_vm.guest_init_pml4); return ret; } diff --git a/hypervisor/include/arch/x86/cpu.h b/hypervisor/include/arch/x86/cpu.h index 43a882a61..9bd305fa9 100644 --- a/hypervisor/include/arch/x86/cpu.h +++ b/hypervisor/include/arch/x86/cpu.h @@ -43,6 +43,9 @@ #define CPU_PAGE_SIZE 0x1000 #define CPU_PAGE_MASK 0xFFFFFFFFFFFFF000 +#define MMU_PTE_PAGE_SHIFT CPU_PAGE_SHIFT +#define MMU_PDE_PAGE_SHIFT 21 + /* Define CPU stack alignment */ #define CPU_STACK_ALIGN 16 diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index a76c4e030..0f2bc8b2d 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -113,7 +113,7 @@ struct vm_state_info { }; struct vm_arch { - void *guest_pml4; /* Guest pml4 */ + uint64_t guest_init_pml4;/* Guest init pml4 */ /* EPT hierarchy for Normal World */ uint64_t nworld_eptp; /* EPT hierarchy for Secure World diff --git a/hypervisor/include/arch/x86/mmu.h b/hypervisor/include/arch/x86/mmu.h index 8867c0c48..94be437b0 100644 --- a/hypervisor/include/arch/x86/mmu.h +++ b/hypervisor/include/arch/x86/mmu.h @@ -381,7 +381,7 @@ extern uint8_t CPU_Boot_Page_Tables_Start_VM[]; /* External Interfaces */ int is_ept_supported(void); -void *create_guest_paging(struct vm *vm); +uint64_t create_guest_initial_paging(struct vm *vm); void destroy_ept(struct vm *vm); uint64_t gpa2hpa(struct vm *vm, uint64_t gpa); uint64_t gpa2hpa_check(struct vm *vm, uint64_t gpa, diff --git a/hypervisor/include/arch/x86/trusty.h b/hypervisor/include/arch/x86/trusty.h index 68a4eb7e7..482e55f88 100644 --- a/hypervisor/include/arch/x86/trusty.h +++ b/hypervisor/include/arch/x86/trusty.h @@ -36,6 +36,10 @@ #define MMC_PROD_NAME_WITH_PSN_LEN 15 #define BUP_MKHI_BOOTLOADER_SEED_LEN 64 +/* Trusty EPT rebase gpa: 511G */ +#define TRUSTY_EPT_REBASE_GPA (511ULL*1024ULL*1024ULL*1024ULL) +#define TRUSTY_MEMORY_SIZE 0x01000000 + /* Structure of seed info */ struct seed_info { uint8_t cse_svn;