]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86/mmu: move pdptrs out of the MMU
authorPaolo Bonzini <pbonzini@redhat.com>
Sat, 30 May 2026 16:55:45 +0000 (12:55 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 12 Jun 2026 08:43:52 +0000 (10:43 +0200)
PDPTRs are part of the CPU state.  A bit unconventionally, they are
reached via vcpu->arch.walk_mmu instead of being stored in vcpu->arch
directly.  That is nice in principle---it would allow TDP shadow paging
to have its own PDPTRs---but it is not necessary, because EPT has no
PDPTRs and NPT does not cache them.

Since kvm_pdptr_read does not otherwise need the MMU, drop the pdptrs
from the MMU altogether.  There is however something to be careful
about, in that PDPTRs are now not stored separately in root_mmu and
nested_mmu for L1 and L2 guests.  In practice this was already not
an issue:

- for EPT the VMCS0x has to keep them up to date; and for the purpose
  of emulation they are always loaded from the VMCS on vmentry/vmexit,
  thanks to the clearing of dirty and available register bitmaps in
  vmx_switch_vmcs()

- for NPT, VCPU_EXREG_PDPTR is similarly cleared for nNPT, which does
  not cache the PDPTRs; while for non-nNPT the PDPTRs are loaded
  together with the load of CR3.

Note that page table PDPTRs are not affected, since they are stored
in pae_root.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-ID: <20260530165545.25599-6-pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/kvm_cache_regs.h
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c

index 5fdd8cb3680fe9caff192d36514c5e0cd8f54a7c..1238cb002afc4d675eb053e67a145de64de30fa4 100644 (file)
@@ -522,10 +522,7 @@ struct kvm_mmu {
         * the bits spte never used.
         */
        struct rsvd_bits_validate shadow_zero_check;
-
        struct rsvd_bits_validate guest_rsvd_check;
-
-       u64 pdptrs[4]; /* pae */
 };
 
 enum pmc_type {
@@ -883,6 +880,8 @@ struct kvm_vcpu_arch {
         */
        struct kvm_mmu *walk_mmu;
 
+       u64 pdptrs[4]; /* pae */
+
        struct kvm_mmu_memory_cache mmu_pte_list_desc_cache;
        struct kvm_mmu_memory_cache mmu_shadow_page_cache;
        struct kvm_mmu_memory_cache mmu_shadowed_info_cache;
index 6bae5db5a54e926ab957cdc19f380b201651273e..2a93e8c45c1a6db16aba092fbf4053b8423c4116 100644 (file)
@@ -192,12 +192,12 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
        if (!kvm_register_is_available(vcpu, VCPU_REG_PDPTR))
                kvm_x86_call(cache_reg)(vcpu, VCPU_REG_PDPTR);
 
-       return vcpu->arch.walk_mmu->pdptrs[index];
+       return vcpu->arch.pdptrs[index];
 }
 
 static inline void kvm_pdptr_write(struct kvm_vcpu *vcpu, int index, u64 value)
 {
-       vcpu->arch.walk_mmu->pdptrs[index] = value;
+       vcpu->arch.pdptrs[index] = value;
 }
 
 static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask)
index 81e5a889a7942b101818d4cadea5a302903ce8a7..92fc9e0f133f3581bc1c57ca9948fbe56f29c530 100644 (file)
@@ -1537,7 +1537,7 @@ static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
        switch (reg) {
        case VCPU_REG_PDPTR:
                /*
-                * When !npt_enabled, mmu->pdptrs[] is already available since
+                * When !npt_enabled, vcpu->pdptrs[] is already available since
                 * it is always updated per SDM when moving to CRs.
                 */
                if (npt_enabled)
index 9324d608394199e8cfac70d4bb8da2c54d3e40f3..4f81564a8bcb834266803581bc3180aa31203949 100644 (file)
@@ -3366,30 +3366,26 @@ void vmx_flush_tlb_guest(struct kvm_vcpu *vcpu)
 
 void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu)
 {
-       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
-
        if (!kvm_register_is_dirty(vcpu, VCPU_REG_PDPTR))
                return;
 
        if (is_pae_paging(vcpu)) {
-               vmcs_write64(GUEST_PDPTR0, mmu->pdptrs[0]);
-               vmcs_write64(GUEST_PDPTR1, mmu->pdptrs[1]);
-               vmcs_write64(GUEST_PDPTR2, mmu->pdptrs[2]);
-               vmcs_write64(GUEST_PDPTR3, mmu->pdptrs[3]);
+               vmcs_write64(GUEST_PDPTR0, vcpu->arch.pdptrs[0]);
+               vmcs_write64(GUEST_PDPTR1, vcpu->arch.pdptrs[1]);
+               vmcs_write64(GUEST_PDPTR2, vcpu->arch.pdptrs[2]);
+               vmcs_write64(GUEST_PDPTR3, vcpu->arch.pdptrs[3]);
        }
 }
 
 void ept_save_pdptrs(struct kvm_vcpu *vcpu)
 {
-       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
-
        if (WARN_ON_ONCE(!is_pae_paging(vcpu)))
                return;
 
-       mmu->pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
-       mmu->pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
-       mmu->pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
-       mmu->pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
+       vcpu->arch.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
+       vcpu->arch.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
+       vcpu->arch.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
+       vcpu->arch.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
 
        kvm_register_mark_available(vcpu, VCPU_REG_PDPTR);
 }
index e369e291f7a40fd0386db95026523a631f070377..e26bdbdbef6a8377be2216441dab68cd5617bbf8 100644 (file)
@@ -1065,7 +1065,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
        gpa_t real_gpa;
        int i;
        int ret;
-       u64 pdpte[ARRAY_SIZE(mmu->pdptrs)];
+       u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
 
        /*
         * If the MMU is nested, CR3 holds an L2 GPA and needs to be translated
@@ -1094,10 +1094,10 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
         * Marking VCPU_REG_PDPTR dirty doesn't work for !tdp_enabled.
         * Shadow page roots need to be reconstructed instead.
         */
-       if (!tdp_enabled && memcmp(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs)))
+       if (!tdp_enabled && memcmp(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)))
                kvm_mmu_free_roots(vcpu->kvm, mmu, KVM_MMU_ROOT_CURRENT);
 
-       memcpy(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs));
+       memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
        kvm_register_mark_dirty(vcpu, VCPU_REG_PDPTR);
        kvm_make_request(KVM_REQ_LOAD_MMU_PGD, vcpu);
        vcpu->arch.pdptrs_from_userspace = false;