From: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx> Currently in TDX test case init stage, it setup an initial lvl5 boot page table, but VM code support only lvl4 page table. This mismatch make the test cases requiring virtual memory crash. Add below changes to support lvl5 page table for virtual memory: 1. skip finding high memory 2. check X86_CR4_LA57 to decide to initialize lvl5 or lvl4 page table 3. always set X86_CR0_NE for TDX test case Signed-off-by: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx> Reviewed-by: Yu Zhang <yu.c.zhang@xxxxxxxxx> Link: https://lore.kernel.org/r/20220303071907.650203-14-zhenzhong.duan@xxxxxxxxx Co-developed-by: Qian Wen <qian.wen@xxxxxxxxx> Signed-off-by: Qian Wen <qian.wen@xxxxxxxxx> --- lib/x86/setup.c | 5 +++++ lib/x86/vm.c | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/x86/setup.c b/lib/x86/setup.c index de2dee38..311bffad 100644 --- a/lib/x86/setup.c +++ b/lib/x86/setup.c @@ -68,6 +68,11 @@ static struct mbi_bootinfo *bootinfo; #ifdef __x86_64__ void find_highmem(void) { +#ifdef CONFIG_EFI + /* The largest free memory region is already chosen in setup_efi() */ + return; +#endif /* CONFIG_EFI */ + /* Memory above 4 GB is only supported on 64-bit systems. */ if (!(bootinfo->flags & 64)) return; diff --git a/lib/x86/vm.c b/lib/x86/vm.c index 90f73fbb..a7ad80d1 100644 --- a/lib/x86/vm.c +++ b/lib/x86/vm.c @@ -3,8 +3,10 @@ #include "vmalloc.h" #include "alloc_page.h" #include "smp.h" +#include "tdx.h" static pteval_t pte_opt_mask; +static int page_level; pteval_t *install_pte(pgd_t *cr3, int pte_level, @@ -16,7 +18,7 @@ pteval_t *install_pte(pgd_t *cr3, pteval_t *pt = cr3; unsigned offset; - for (level = PAGE_LEVEL; level > pte_level; --level) { + for (level = page_level; level > pte_level; --level) { offset = PGDIR_OFFSET((uintptr_t)virt, level); if (!(pt[offset] & PT_PRESENT_MASK)) { pteval_t *new_pt = pt_page; @@ -49,9 +51,9 @@ struct pte_search find_pte_level(pgd_t *cr3, void *virt, unsigned shift; struct pte_search r; - assert(lowest_level >= 1 && lowest_level <= PAGE_LEVEL); + assert(lowest_level >= 1 && lowest_level <= page_level); - for (r.level = PAGE_LEVEL;; --r.level) { + for (r.level = page_level;; --r.level) { shift = (r.level - 1) * PGDIR_WIDTH + 12; offset = ((uintptr_t)virt >> shift) & PGDIR_MASK; r.pte = &pt[offset]; @@ -185,6 +187,7 @@ void *setup_mmu(phys_addr_t end_of_memory, void *opt_mask) pte_opt_mask = PT_USER_MASK; memset(cr3, 0, PAGE_SIZE); + page_level = !!(read_cr4() & X86_CR4_LA57) ? 5 : PAGE_LEVEL; #ifdef __x86_64__ if (end_of_memory < (1ul << 32)) @@ -201,7 +204,11 @@ void *setup_mmu(phys_addr_t end_of_memory, void *opt_mask) #ifndef __x86_64__ write_cr4(X86_CR4_PSE); #endif - write_cr0(X86_CR0_PG |X86_CR0_PE | X86_CR0_WP); + /* According to TDX module spec 10.6.1 CR0.NE should be 1 */ + if (is_tdx_guest()) + write_cr0(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE); + else + write_cr0(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP); printf("paging enabled\n"); printf("cr0 = %lx\n", read_cr0()); -- 2.25.1