[kvm-unit-tests RFC v2 14/18] x86 TDX: Add lvl5 page table support to virtual memory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux