[PATCH 33/45] KVM: x86: Allow page fault fixup to return errors
From: Paolo Bonzini
Date: Mon Nov 02 2026 - 13:01:48 EST
kvm_fixup_and_inject_pf_error() reflects intercepted hardware page
faults into the guest, walking the guest page tables when necessary
to obtain an error code consistent with the guest's paging rules.
For example, a GPA that exceeds guest.MAXPHYADDR but fits within
host.MAXPHYADDR must cause a reserved-bit fault, even though hardware
does not report one.
Allow the function's callers to propagate memory attribute failures
from the page table walk; subsequent changes will return from
kvm_fixup_and_inject_pf_error() any error from the page-table walk.
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
arch/x86/kvm/vmx/vmx.c | 15 +++++++++++----
arch/x86/kvm/x86.c | 3 ++-
arch/x86/kvm/x86.h | 2 +-
3 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 27cb0d64fb5c..c4511f83d59b 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -5418,10 +5418,14 @@ static int vmx_handle_page_fault(struct kvm_vcpu *vcpu, u32 error_code)
WARN_ON_ONCE(!IS_ENABLED(CONFIG_X86_SGX_KVM) ||
!cpu_feature_enabled(X86_FEATURE_SGX2));
- if (guest_cpu_cap_has(vcpu, X86_FEATURE_SGX2))
- kvm_fixup_and_inject_pf_error(vcpu, cr2, error_code);
- else
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_SGX2)) {
+ int r = kvm_fixup_and_inject_pf_error(vcpu, cr2, error_code);
+
+ if (r)
+ return r;
+ } else {
kvm_inject_gp(vcpu, 0);
+ }
return 1;
}
@@ -5431,7 +5435,10 @@ static int vmx_handle_page_fault(struct kvm_vcpu *vcpu, u32 error_code)
* to the GPA being legal with respect to host.MAXPHYADDR).
*/
if (enable_ept) {
- kvm_fixup_and_inject_pf_error(vcpu, cr2, error_code);
+ int r = kvm_fixup_and_inject_pf_error(vcpu, cr2, error_code);
+
+ if (r)
+ return r;
return 1;
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5818101d1d8a..bb36ca1106e5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10811,7 +10811,7 @@ void kvm_arch_gmem_invalidate_range(struct kvm *kvm, struct kvm_gfn_range *range
#endif
#endif
-void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code)
+int kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code)
{
struct kvm_pagewalk *gva_walk = &vcpu->arch.gva_walk;
struct x86_exception fault;
@@ -10833,6 +10833,7 @@ void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_c
fault.async_page_fault = false;
}
gva_walk->inject_page_fault(vcpu, &fault, true);
+ return 0;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_fixup_and_inject_pf_error);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index cfe96962a4e4..4239765629b0 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -368,7 +368,7 @@ void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu,
struct kvm_queued_exception *ex);
void kvm_handle_exception_payload_quirk(struct kvm_vcpu *vcpu);
-void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code);
+int kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code);
int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type,
void *insn, int insn_len);
int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
--
2.52.0