@@ -158,10 +158,10 @@ bool kvm_is_tdp_enabled(void)
158158
159159void virt_arch_pgd_alloc (struct kvm_vm * vm )
160160{
161- TEST_ASSERT (vm -> mode == VM_MODE_PXXV48_4K , "Attempt to use "
162- "unknown or unsupported guest mode, mode: 0x%x" , vm -> mode );
161+ TEST_ASSERT (vm -> mode == VM_MODE_PXXVYY_4K ,
162+ "Unknown or unsupported guest mode: 0x%x" , vm -> mode );
163163
164- /* If needed, create page map l4 table. */
164+ /* If needed, create the top-level page table. */
165165 if (!vm -> pgd_created ) {
166166 vm -> pgd = vm_alloc_page_table (vm );
167167 vm -> pgd_created = true;
@@ -218,11 +218,11 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
218218void __virt_pg_map (struct kvm_vm * vm , uint64_t vaddr , uint64_t paddr , int level )
219219{
220220 const uint64_t pg_size = PG_LEVEL_SIZE (level );
221- uint64_t * pml4e , * pdpe , * pde ;
222- uint64_t * pte ;
221+ uint64_t * pte = & vm -> pgd ;
222+ int current_level ;
223223
224- TEST_ASSERT (vm -> mode == VM_MODE_PXXV48_4K ,
225- "Unknown or unsupported guest mode, mode : 0x%x" , vm -> mode );
224+ TEST_ASSERT (vm -> mode == VM_MODE_PXXVYY_4K ,
225+ "Unknown or unsupported guest mode: 0x%x" , vm -> mode );
226226
227227 TEST_ASSERT ((vaddr % pg_size ) == 0 ,
228228 "Virtual address not aligned,\n"
@@ -243,20 +243,17 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
243243 * Allocate upper level page tables, if not already present. Return
244244 * early if a hugepage was created.
245245 */
246- pml4e = virt_create_upper_pte (vm , & vm -> pgd , vaddr , paddr , PG_LEVEL_512G , level );
247- if (* pml4e & PTE_LARGE_MASK )
248- return ;
249-
250- pdpe = virt_create_upper_pte (vm , pml4e , vaddr , paddr , PG_LEVEL_1G , level );
251- if (* pdpe & PTE_LARGE_MASK )
252- return ;
253-
254- pde = virt_create_upper_pte (vm , pdpe , vaddr , paddr , PG_LEVEL_2M , level );
255- if (* pde & PTE_LARGE_MASK )
256- return ;
246+ for (current_level = vm -> pgtable_levels ;
247+ current_level > PG_LEVEL_4K ;
248+ current_level -- ) {
249+ pte = virt_create_upper_pte (vm , pte , vaddr , paddr ,
250+ current_level , level );
251+ if (* pte & PTE_LARGE_MASK )
252+ return ;
253+ }
257254
258255 /* Fill in page table entry. */
259- pte = virt_get_pte (vm , pde , vaddr , PG_LEVEL_4K );
256+ pte = virt_get_pte (vm , pte , vaddr , PG_LEVEL_4K );
260257 TEST_ASSERT (!(* pte & PTE_PRESENT_MASK ),
261258 "PTE already present for 4k page at vaddr: 0x%lx" , vaddr );
262259 * pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK );
@@ -289,6 +286,8 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
289286
290287 for (i = 0 ; i < nr_pages ; i ++ ) {
291288 __virt_pg_map (vm , vaddr , paddr , level );
289+ sparsebit_set_num (vm -> vpages_mapped , vaddr >> vm -> page_shift ,
290+ nr_bytes / PAGE_SIZE );
292291
293292 vaddr += pg_size ;
294293 paddr += pg_size ;
@@ -310,40 +309,38 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level)
310309uint64_t * __vm_get_page_table_entry (struct kvm_vm * vm , uint64_t vaddr ,
311310 int * level )
312311{
313- uint64_t * pml4e , * pdpe , * pde ;
312+ int va_width = 12 + (vm -> pgtable_levels ) * 9 ;
313+ uint64_t * pte = & vm -> pgd ;
314+ int current_level ;
314315
315316 TEST_ASSERT (!vm -> arch .is_pt_protected ,
316317 "Walking page tables of protected guests is impossible" );
317318
318- TEST_ASSERT (* level >= PG_LEVEL_NONE && * level < PG_LEVEL_NUM ,
319+ TEST_ASSERT (* level >= PG_LEVEL_NONE && * level <= vm -> pgtable_levels ,
319320 "Invalid PG_LEVEL_* '%d'" , * level );
320321
321- TEST_ASSERT (vm -> mode == VM_MODE_PXXV48_4K , "Attempt to use "
322- "unknown or unsupported guest mode, mode: 0x%x" , vm -> mode );
322+ TEST_ASSERT (vm -> mode == VM_MODE_PXXVYY_4K ,
323+ "Unknown or unsupported guest mode: 0x%x" , vm -> mode );
323324 TEST_ASSERT (sparsebit_is_set (vm -> vpages_valid ,
324325 (vaddr >> vm -> page_shift )),
325326 "Invalid virtual address, vaddr: 0x%lx" ,
326327 vaddr );
327328 /*
328- * Based on the mode check above there are 48 bits in the vaddr, so
329- * shift 16 to sign extend the last bit (bit-47),
329+ * Check that the vaddr is a sign-extended va_width value.
330330 */
331- TEST_ASSERT (vaddr == (((int64_t )vaddr << 16 ) >> 16 ),
332- "Canonical check failed. The virtual address is invalid." );
333-
334- pml4e = virt_get_pte (vm , & vm -> pgd , vaddr , PG_LEVEL_512G );
335- if (vm_is_target_pte (pml4e , level , PG_LEVEL_512G ))
336- return pml4e ;
337-
338- pdpe = virt_get_pte (vm , pml4e , vaddr , PG_LEVEL_1G );
339- if (vm_is_target_pte (pdpe , level , PG_LEVEL_1G ))
340- return pdpe ;
341-
342- pde = virt_get_pte (vm , pdpe , vaddr , PG_LEVEL_2M );
343- if (vm_is_target_pte (pde , level , PG_LEVEL_2M ))
344- return pde ;
331+ TEST_ASSERT (vaddr ==
332+ (((int64_t )vaddr << (64 - va_width ) >> (64 - va_width ))),
333+ "Canonical check failed. The virtual address is invalid." );
334+
335+ for (current_level = vm -> pgtable_levels ;
336+ current_level > PG_LEVEL_4K ;
337+ current_level -- ) {
338+ pte = virt_get_pte (vm , pte , vaddr , current_level );
339+ if (vm_is_target_pte (pte , level , current_level ))
340+ return pte ;
341+ }
345342
346- return virt_get_pte (vm , pde , vaddr , PG_LEVEL_4K );
343+ return virt_get_pte (vm , pte , vaddr , PG_LEVEL_4K );
347344}
348345
349346uint64_t * vm_get_page_table_entry (struct kvm_vm * vm , uint64_t vaddr )
@@ -526,7 +523,8 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
526523{
527524 struct kvm_sregs sregs ;
528525
529- TEST_ASSERT_EQ (vm -> mode , VM_MODE_PXXV48_4K );
526+ TEST_ASSERT (vm -> mode == VM_MODE_PXXVYY_4K ,
527+ "Unknown or unsupported guest mode: 0x%x" , vm -> mode );
530528
531529 /* Set mode specific system register values. */
532530 vcpu_sregs_get (vcpu , & sregs );
@@ -540,6 +538,8 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
540538 sregs .cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR ;
541539 if (kvm_cpu_has (X86_FEATURE_XSAVE ))
542540 sregs .cr4 |= X86_CR4_OSXSAVE ;
541+ if (vm -> pgtable_levels == 5 )
542+ sregs .cr4 |= X86_CR4_LA57 ;
543543 sregs .efer |= (EFER_LME | EFER_LMA | EFER_NX );
544544
545545 kvm_seg_set_unusable (& sregs .ldt );
0 commit comments