Skip to content

Commit 753c0d5

Browse files
yosrym93sean-jc
authored andcommitted
KVM: selftests: Add support for nested NPTs
Implement nCR3 and NPT initialization functions, similar to the EPT equivalents, and create common TDP helpers for enablement checking and initialization. Enable NPT for nested guests by default if the TDP MMU was initialized, similar to VMX. Reuse the PTE masks from the main MMU in the NPT MMU, except for the C and S bits related to confidential VMs. Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251230230150.4150236-17-seanjc@google.com [sean: apply Yosry's fixup for ncr3_gpa] Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 9cb1944 commit 753c0d5

6 files changed

Lines changed: 54 additions & 4 deletions

File tree

tools/testing/selftests/kvm/include/x86/processor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,8 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu *mmu, uint64_t vaddr,
14791479
void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
14801480
uint64_t nr_bytes, int level);
14811481

1482+
void vm_enable_tdp(struct kvm_vm *vm);
1483+
bool kvm_cpu_has_tdp(void);
14821484
void tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size);
14831485
void tdp_identity_map_default_memslots(struct kvm_vm *vm);
14841486
void tdp_identity_map_1g(struct kvm_vm *vm, uint64_t addr, uint64_t size);

tools/testing/selftests/kvm/include/x86/svm_util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct svm_test_data {
2727
void *msr; /* gva */
2828
void *msr_hva;
2929
uint64_t msr_gpa;
30+
31+
/* NPT */
32+
uint64_t ncr3_gpa;
3033
};
3134

3235
static inline void vmmcall(void)
@@ -57,6 +60,12 @@ struct svm_test_data *vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva);
5760
void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp);
5861
void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa);
5962

63+
static inline bool kvm_cpu_has_npt(void)
64+
{
65+
return kvm_cpu_has(X86_FEATURE_NPT);
66+
}
67+
void vm_enable_npt(struct kvm_vm *vm);
68+
6069
int open_sev_dev_path_or_exit(void);
6170

6271
#endif /* SELFTEST_KVM_SVM_UTILS_H */

tools/testing/selftests/kvm/lib/x86/memstress.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
8282
int vcpu_id;
8383

8484
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
85-
TEST_REQUIRE(kvm_cpu_has_ept());
85+
TEST_REQUIRE(kvm_cpu_has_tdp());
8686

87-
vm_enable_ept(vm);
87+
vm_enable_tdp(vm);
8888
for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
8989
vcpu_alloc_vmx(vm, &vmx_gva);
9090

tools/testing/selftests/kvm/lib/x86/processor.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#include "kvm_util.h"
99
#include "pmu.h"
1010
#include "processor.h"
11+
#include "svm_util.h"
1112
#include "sev.h"
13+
#include "vmx.h"
1214

1315
#ifndef NUM_INTERRUPTS
1416
#define NUM_INTERRUPTS 256
@@ -472,6 +474,19 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
472474
}
473475
}
474476

477+
void vm_enable_tdp(struct kvm_vm *vm)
478+
{
479+
if (kvm_cpu_has(X86_FEATURE_VMX))
480+
vm_enable_ept(vm);
481+
else
482+
vm_enable_npt(vm);
483+
}
484+
485+
bool kvm_cpu_has_tdp(void)
486+
{
487+
return kvm_cpu_has_ept() || kvm_cpu_has_npt();
488+
}
489+
475490
void __tdp_map(struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr,
476491
uint64_t size, int level)
477492
{

tools/testing/selftests/kvm/lib/x86/svm.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva)
4646
svm->msr_gpa = addr_gva2gpa(vm, (uintptr_t)svm->msr);
4747
memset(svm->msr_hva, 0, getpagesize());
4848

49+
if (vm->stage2_mmu.pgd_created)
50+
svm->ncr3_gpa = vm->stage2_mmu.pgd;
51+
4952
*p_svm_gva = svm_gva;
5053
return svm;
5154
}
@@ -59,6 +62,22 @@ static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector,
5962
seg->base = base;
6063
}
6164

65+
void vm_enable_npt(struct kvm_vm *vm)
66+
{
67+
struct pte_masks pte_masks;
68+
69+
TEST_ASSERT(kvm_cpu_has_npt(), "KVM doesn't supported nested NPT");
70+
71+
/*
72+
* NPTs use the same PTE format, but deliberately drop the C-bit as the
73+
* per-VM shared vs. private information is only meant for stage-1.
74+
*/
75+
pte_masks = vm->mmu.arch.pte_masks;
76+
pte_masks.c = 0;
77+
78+
tdp_mmu_init(vm, vm->mmu.pgtable_levels, &pte_masks);
79+
}
80+
6281
void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp)
6382
{
6483
struct vmcb *vmcb = svm->vmcb;
@@ -102,6 +121,11 @@ void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_r
102121
vmcb->save.rip = (u64)guest_rip;
103122
vmcb->save.rsp = (u64)guest_rsp;
104123
guest_regs.rdi = (u64)svm;
124+
125+
if (svm->ncr3_gpa) {
126+
ctrl->nested_ctl |= SVM_NESTED_CTL_NP_ENABLE;
127+
ctrl->nested_cr3 = svm->ncr3_gpa;
128+
}
105129
}
106130

107131
/*

tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ static void test_vmx_dirty_log(bool enable_ept)
9393
/* Create VM */
9494
vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
9595
if (enable_ept)
96-
vm_enable_ept(vm);
96+
vm_enable_tdp(vm);
9797

9898
vcpu_alloc_vmx(vm, &vmx_pages_gva);
9999
vcpu_args_set(vcpu, 1, vmx_pages_gva);
@@ -170,7 +170,7 @@ int main(int argc, char *argv[])
170170

171171
test_vmx_dirty_log(/*enable_ept=*/false);
172172

173-
if (kvm_cpu_has_ept())
173+
if (kvm_cpu_has_tdp())
174174
test_vmx_dirty_log(/*enable_ept=*/true);
175175

176176
return 0;

0 commit comments

Comments
 (0)