]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86: make translate_nested_gpa vendor-specific
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 8 Apr 2026 15:42:02 +0000 (11:42 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Sun, 10 May 2026 12:52:57 +0000 (14:52 +0200)
EPT and NPT have different rules for passing PFERR_USER_MASK to the
nested page table walk.  In particular, for final addresses EPT
uses the U bit of the guest (nGVA->nGPA) walk.

While at it, remove PFERR_USER_MASK from the VMX version of the
function, since it is actually ignored by the tables that
update_permission_bitmask() generates for EPT.

Tested-by: David Riley <d.riley@proxmox.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/hyperv.c
arch/x86/kvm/mmu.h
arch/x86/kvm/svm/nested.c
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/x86.c

index 8f2a1b915df908cc6d2c44833df752221c0de9f6..62dc782b2dd3ccaf018e5fa068686e0c5b5efc23 100644 (file)
@@ -2010,6 +2010,10 @@ struct kvm_x86_nested_ops {
                         struct kvm_nested_state *kvm_state);
        bool (*get_nested_state_pages)(struct kvm_vcpu *vcpu);
        int (*write_log_dirty)(struct kvm_vcpu *vcpu, gpa_t l2_gpa);
+       gpa_t (*translate_nested_gpa)(struct kvm_vcpu *vcpu, gpa_t gpa,
+                                     u64 access,
+                                     struct x86_exception *exception,
+                                     u64 pte_access);
 
        int (*enable_evmcs)(struct kvm_vcpu *vcpu,
                            uint16_t *vmcs_version);
index 53688f7b76eb9f7fc8dc29e10d6ad8ae87bfce27..f35fae3a7b3dd27ebc9c5e1b3a445615d2bfa463 100644 (file)
@@ -2041,7 +2041,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
         * read with kvm_read_guest().
         */
        if (!hc->fast && is_guest_mode(vcpu)) {
-               hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa,
+               hc->ingpa = kvm_x86_ops.nested_ops->translate_nested_gpa(
+                                       vcpu, hc->ingpa,
                                        PFERR_GUEST_FINAL_MASK, NULL, 0);
                if (unlikely(hc->ingpa == INVALID_GPA))
                        return HV_STATUS_INVALID_HYPERCALL_INPUT;
index 635c2e5d8513dc0327f2d221007d21cf9235e860..63be5c5efed98ab97977c4c5f1b2f75fb7c5791c 100644 (file)
@@ -294,10 +294,6 @@ static inline void kvm_update_page_stats(struct kvm *kvm, int level, int count)
        atomic64_add(count, &kvm->stat.pages[level - 1]);
 }
 
-gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access,
-                          struct x86_exception *exception,
-                          u64 pte_access);
-
 static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
                                      struct kvm_mmu *mmu,
                                      gpa_t gpa, u64 access,
@@ -306,8 +302,9 @@ static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
 {
        if (mmu != &vcpu->arch.nested_mmu)
                return gpa;
-       return translate_nested_gpa(vcpu, gpa, access, exception,
-                                   pte_access);
+       return kvm_x86_ops.nested_ops->translate_nested_gpa(vcpu, gpa, access,
+                                                           exception,
+                                                           pte_access);
 }
 
 static inline bool kvm_has_mirrored_tdp(const struct kvm *kvm)
index 961804df5f451c36881e17f60d4564ade0abbd72..df232153eb247f2b6b69aaaa0c97feded8d662e8 100644 (file)
@@ -2071,8 +2071,23 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
        return true;
 }
 
+static gpa_t svm_translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa,
+                                     u64 access,
+                                     struct x86_exception *exception,
+                                     u64 pte_access)
+{
+       struct kvm_mmu *mmu = vcpu->arch.mmu;
+
+       BUG_ON(!mmu_is_nested(vcpu));
+
+       /* NPT walks are always user-walks */
+       access |= PFERR_USER_MASK;
+       return mmu->gva_to_gpa(vcpu, mmu, gpa, access, exception);
+}
+
 struct kvm_x86_nested_ops svm_nested_ops = {
        .leave_nested = svm_leave_nested,
+       .translate_nested_gpa = svm_translate_nested_gpa,
        .is_exception_vmexit = nested_svm_is_exception_vmexit,
        .check_events = svm_check_nested_events,
        .triple_fault = nested_svm_triple_fault,
index 3fe88f29be7a94559f4e081f06e44c752a0c96dc..cd1924c6e07584daf9df46c43db16de1af878b88 100644 (file)
@@ -7438,8 +7438,20 @@ __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *))
        return 0;
 }
 
+static gpa_t vmx_translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa,
+                                     u64 access,
+                                     struct x86_exception *exception,
+                                     u64 pte_access)
+{
+       struct kvm_mmu *mmu = vcpu->arch.mmu;
+
+       BUG_ON(!mmu_is_nested(vcpu));
+       return mmu->gva_to_gpa(vcpu, mmu, gpa, access, exception);
+}
+
 struct kvm_x86_nested_ops vmx_nested_ops = {
        .leave_nested = vmx_leave_nested,
+       .translate_nested_gpa = vmx_translate_nested_gpa,
        .is_exception_vmexit = nested_vmx_is_exception_vmexit,
        .check_events = vmx_check_nested_events,
        .has_events = vmx_has_nested_events,
index 67979b7de5d6160b596f4126d4a578fcae9f2f78..7c6942afae818d1af38d5bdbbd11b55f1a489bf2 100644 (file)
@@ -7848,22 +7848,6 @@ void kvm_get_segment(struct kvm_vcpu *vcpu,
        kvm_x86_call(get_segment)(vcpu, var, seg);
 }
 
-gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access,
-                          struct x86_exception *exception,
-                          u64 pte_access)
-{
-       struct kvm_mmu *mmu = vcpu->arch.mmu;
-       gpa_t t_gpa;
-
-       BUG_ON(!mmu_is_nested(vcpu));
-
-       /* NPT walks are always user-walks */
-       access |= PFERR_USER_MASK;
-       t_gpa  = mmu->gva_to_gpa(vcpu, mmu, gpa, access, exception);
-
-       return t_gpa;
-}
-
 gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva,
                              struct x86_exception *exception)
 {