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;