From: "Xin Li (Intel)" <xin@zytor.com>
To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org
Cc: seanjc@google.com, pbonzini@redhat.com, corbet@lwn.net,
tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com,
luto@kernel.org, peterz@infradead.org, andrew.cooper3@citrix.com,
xin@zytor.com
Subject: [PATCH v3 01/27] KVM: x86: Use a dedicated flow for queueing re-injected exceptions
Date: Mon, 30 Sep 2024 22:00:44 -0700 [thread overview]
Message-ID: <20241001050110.3643764-2-xin@zytor.com> (raw)
In-Reply-To: <20241001050110.3643764-1-xin@zytor.com>
From: Sean Christopherson <seanjc@google.com>
Open code the filling of vcpu->arch.exception in kvm_requeue_exception()
instead of bouncing through kvm_multiple_exception(), as re-injection
doesn't actually share that much code with "normal" injection, e.g. the
VM-Exit interception check, payload delivery, and nested exception code
is all bypassed as those flows only apply during initial injection.
When FRED comes along, the special casing will only get worse, as FRED
explicitly tracks nested exceptions and essentially delivers the payload
on the stack frame, i.e. re-injection will need more inputs, and normal
injection will have yet more code that needs to be bypassed when KVM is
re-injecting an exception.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
Tested-by: Shan Kang <shan.kang@intel.com>
---
arch/x86/include/asm/kvm_host.h | 4 +-
arch/x86/kvm/svm/svm.c | 15 +++---
arch/x86/kvm/vmx/vmx.c | 16 +++---
arch/x86/kvm/x86.c | 89 ++++++++++++++++-----------------
4 files changed, 63 insertions(+), 61 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6d9f763a7bb9..43b08d12cb32 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -2112,8 +2112,8 @@ int kvm_emulate_rdpmc(struct kvm_vcpu *vcpu);
void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr);
void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr, unsigned long payload);
-void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr);
-void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
+void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned int nr,
+ bool has_error_code, u32 error_code);
void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault);
void kvm_inject_emulated_page_fault(struct kvm_vcpu *vcpu,
struct x86_exception *fault);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 9df3e1e5ae81..d9e2568bcd54 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4112,20 +4112,23 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu)
vcpu->arch.nmi_injected = true;
svm->nmi_l1_to_l2 = nmi_l1_to_l2;
break;
- case SVM_EXITINTINFO_TYPE_EXEPT:
+ case SVM_EXITINTINFO_TYPE_EXEPT: {
+ u32 error_code = 0;
+
/*
* Never re-inject a #VC exception.
*/
if (vector == X86_TRAP_VC)
break;
- if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
- u32 err = svm->vmcb->control.exit_int_info_err;
- kvm_requeue_exception_e(vcpu, vector, err);
+ if (exitintinfo & SVM_EXITINTINFO_VALID_ERR)
+ error_code = svm->vmcb->control.exit_int_info_err;
- } else
- kvm_requeue_exception(vcpu, vector);
+ kvm_requeue_exception(vcpu, vector,
+ exitintinfo & SVM_EXITINTINFO_VALID_ERR,
+ error_code);
break;
+ }
case SVM_EXITINTINFO_TYPE_INTR:
kvm_queue_interrupt(vcpu, vector, false);
break;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 1a4438358c5e..6a93f5edbc0d 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7136,13 +7136,17 @@ static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu,
case INTR_TYPE_SOFT_EXCEPTION:
vcpu->arch.event_exit_inst_len = vmcs_read32(instr_len_field);
fallthrough;
- case INTR_TYPE_HARD_EXCEPTION:
- if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
- u32 err = vmcs_read32(error_code_field);
- kvm_requeue_exception_e(vcpu, vector, err);
- } else
- kvm_requeue_exception(vcpu, vector);
+ case INTR_TYPE_HARD_EXCEPTION: {
+ u32 error_code = 0;
+
+ if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK)
+ error_code = vmcs_read32(error_code_field);
+
+ kvm_requeue_exception(vcpu, vector,
+ idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK,
+ error_code);
break;
+ }
case INTR_TYPE_SOFT_INTR:
vcpu->arch.event_exit_inst_len = vmcs_read32(instr_len_field);
fallthrough;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 83fe0a78146f..e8de9f4734a6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -833,9 +833,9 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int vecto
ex->payload = payload;
}
-static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
- unsigned nr, bool has_error, u32 error_code,
- bool has_payload, unsigned long payload, bool reinject)
+static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned int nr,
+ bool has_error, u32 error_code,
+ bool has_payload, unsigned long payload)
{
u32 prev_nr;
int class1, class2;
@@ -843,13 +843,10 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
kvm_make_request(KVM_REQ_EVENT, vcpu);
/*
- * If the exception is destined for L2 and isn't being reinjected,
- * morph it to a VM-Exit if L1 wants to intercept the exception. A
- * previously injected exception is not checked because it was checked
- * when it was original queued, and re-checking is incorrect if _L1_
- * injected the exception, in which case it's exempt from interception.
+ * If the exception is destined for L2, morph it to a VM-Exit if L1
+ * wants to intercept the exception.
*/
- if (!reinject && is_guest_mode(vcpu) &&
+ if (is_guest_mode(vcpu) &&
kvm_x86_ops.nested_ops->is_exception_vmexit(vcpu, nr, error_code)) {
kvm_queue_exception_vmexit(vcpu, nr, has_error, error_code,
has_payload, payload);
@@ -858,28 +855,9 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
if (!vcpu->arch.exception.pending && !vcpu->arch.exception.injected) {
queue:
- if (reinject) {
- /*
- * On VM-Entry, an exception can be pending if and only
- * if event injection was blocked by nested_run_pending.
- * In that case, however, vcpu_enter_guest() requests an
- * immediate exit, and the guest shouldn't proceed far
- * enough to need reinjection.
- */
- WARN_ON_ONCE(kvm_is_exception_pending(vcpu));
- vcpu->arch.exception.injected = true;
- if (WARN_ON_ONCE(has_payload)) {
- /*
- * A reinjected event has already
- * delivered its payload.
- */
- has_payload = false;
- payload = 0;
- }
- } else {
- vcpu->arch.exception.pending = true;
- vcpu->arch.exception.injected = false;
- }
+ vcpu->arch.exception.pending = true;
+ vcpu->arch.exception.injected = false;
+
vcpu->arch.exception.has_error_code = has_error;
vcpu->arch.exception.vector = nr;
vcpu->arch.exception.error_code = error_code;
@@ -920,29 +898,52 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
{
- kvm_multiple_exception(vcpu, nr, false, 0, false, 0, false);
+ kvm_multiple_exception(vcpu, nr, false, 0, false, 0);
}
EXPORT_SYMBOL_GPL(kvm_queue_exception);
-void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr)
-{
- kvm_multiple_exception(vcpu, nr, false, 0, false, 0, true);
-}
-EXPORT_SYMBOL_GPL(kvm_requeue_exception);
void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr,
unsigned long payload)
{
- kvm_multiple_exception(vcpu, nr, false, 0, true, payload, false);
+ kvm_multiple_exception(vcpu, nr, false, 0, true, payload);
}
EXPORT_SYMBOL_GPL(kvm_queue_exception_p);
static void kvm_queue_exception_e_p(struct kvm_vcpu *vcpu, unsigned nr,
u32 error_code, unsigned long payload)
{
- kvm_multiple_exception(vcpu, nr, true, error_code,
- true, payload, false);
+ kvm_multiple_exception(vcpu, nr, true, error_code, true, payload);
+}
+
+void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned int nr,
+ bool has_error_code, u32 error_code)
+{
+
+ /*
+ * On VM-Entry, an exception can be pending if and only if event
+ * injection was blocked by nested_run_pending. In that case, however,
+ * vcpu_enter_guest() requests an immediate exit, and the guest
+ * shouldn't proceed far enough to need reinjection.
+ */
+ WARN_ON_ONCE(kvm_is_exception_pending(vcpu));
+
+ /*
+ * Do not check for interception when injecting an event for L2, as the
+ * exception was checked for intercept when it was original queued, and
+ * re-checking is incorrect if _L1_ injected the exception, in which
+ * case it's exempt from interception.
+ */
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
+ vcpu->arch.exception.injected = true;
+ vcpu->arch.exception.has_error_code = has_error_code;
+ vcpu->arch.exception.vector = nr;
+ vcpu->arch.exception.error_code = error_code;
+ vcpu->arch.exception.has_payload = false;
+ vcpu->arch.exception.payload = 0;
}
+EXPORT_SYMBOL_GPL(kvm_requeue_exception);
int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err)
{
@@ -1013,16 +1014,10 @@ void kvm_inject_nmi(struct kvm_vcpu *vcpu)
void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
{
- kvm_multiple_exception(vcpu, nr, true, error_code, false, 0, false);
+ kvm_multiple_exception(vcpu, nr, true, error_code, false, 0);
}
EXPORT_SYMBOL_GPL(kvm_queue_exception_e);
-void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
-{
- kvm_multiple_exception(vcpu, nr, true, error_code, false, 0, true);
-}
-EXPORT_SYMBOL_GPL(kvm_requeue_exception_e);
-
/*
* Checks if cpl <= required_cpl; if true, return true. Otherwise queue
* a #GP and return false.
--
2.46.2
next prev parent reply other threads:[~2024-10-01 5:02 UTC|newest]
Thread overview: 81+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-01 5:00 [PATCH v3 00/27] Enable FRED with KVM VMX Xin Li (Intel)
2024-10-01 5:00 ` Xin Li (Intel) [this message]
2024-10-01 5:00 ` [PATCH v3 02/27] KVM: VMX: Don't modify guest XFD_ERR if CR0.TS=1 Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 03/27] KVM: VMX: Add support for the secondary VM exit controls Xin Li (Intel)
2024-10-21 8:28 ` Chao Gao
2024-10-21 17:03 ` Xin Li
2024-10-22 2:47 ` Chao Gao
2024-10-22 16:30 ` Xin Li
2025-02-25 17:28 ` Sean Christopherson
2024-10-01 5:00 ` [PATCH v3 04/27] KVM: VMX: Initialize FRED VM entry/exit controls in vmcs_config Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 05/27] KVM: VMX: Disable FRED if FRED consistency checks fail Xin Li (Intel)
2024-10-22 8:48 ` Chao Gao
2024-10-22 16:21 ` Xin Li
2024-11-26 15:32 ` Borislav Petkov
2024-11-26 18:53 ` Xin Li
2024-11-26 19:04 ` Borislav Petkov
2024-10-01 5:00 ` [PATCH v3 06/27] x86/cea: Export per CPU variable cea_exception_stacks Xin Li (Intel)
2024-10-01 16:12 ` Dave Hansen
2024-10-01 17:51 ` Xin Li
2024-10-01 18:18 ` Dave Hansen
2024-10-01 5:00 ` [PATCH v3 07/27] KVM: VMX: Initialize VMCS FRED fields Xin Li (Intel)
2024-10-22 9:06 ` Chao Gao
2024-10-22 16:18 ` Xin Li
2024-10-01 5:00 ` [PATCH v3 08/27] KVM: x86: Use KVM-governed feature framework to track "FRED enabled" Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 09/27] KVM: VMX: Do not use MAX_POSSIBLE_PASSTHROUGH_MSRS in array definition Xin Li (Intel)
2024-11-26 18:02 ` Borislav Petkov
2024-11-26 19:22 ` Xin Li
2024-11-26 20:06 ` Borislav Petkov
2024-11-27 6:46 ` Xin Li
2024-11-27 6:55 ` Borislav Petkov
2024-11-27 7:02 ` Xin Li
2024-11-27 7:10 ` Borislav Petkov
2024-11-27 7:32 ` Xin Li
2024-11-27 7:58 ` Borislav Petkov
2024-10-01 5:00 ` [PATCH v3 10/27] KVM: VMX: Set FRED MSR interception Xin Li (Intel)
2024-11-13 11:31 ` Chao Gao
2024-10-01 5:00 ` [PATCH v3 11/27] KVM: VMX: Save/restore guest FRED RSP0 Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 12/27] KVM: VMX: Add support for FRED context save/restore Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 13/27] KVM: x86: Add a helper to detect if FRED is enabled for a vCPU Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 14/27] KVM: VMX: Pass XFD_ERR as pseudo-payload when injecting #NM Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 15/27] KVM: VMX: Virtualize FRED event_data Xin Li (Intel)
2024-10-01 5:00 ` [PATCH v3 16/27] KVM: VMX: Virtualize FRED nested exception tracking Xin Li (Intel)
2024-10-24 6:24 ` Chao Gao
2024-10-25 8:04 ` Xin Li
2024-10-28 6:33 ` Chao Gao
2024-12-05 7:16 ` Xin Li
2024-10-01 5:01 ` [PATCH v3 17/27] KVM: x86: Mark CR4.FRED as not reserved when guest can use FRED Xin Li (Intel)
2024-10-24 7:18 ` Chao Gao
2024-12-12 18:48 ` Xin Li
2024-12-12 19:05 ` Sean Christopherson
2024-12-13 18:43 ` Xin Li
2024-10-01 5:01 ` [PATCH v3 18/27] KVM: VMX: Dump FRED context in dump_vmcs() Xin Li (Intel)
2024-10-24 7:23 ` Chao Gao
2024-10-24 16:50 ` Xin Li
2024-10-01 5:01 ` [PATCH v3 19/27] KVM: x86: Allow FRED/LKGS to be advertised to guests Xin Li (Intel)
2024-10-01 5:01 ` [PATCH v3 20/27] KVM: x86: Allow WRMSRNS " Xin Li (Intel)
2025-02-25 15:41 ` Sean Christopherson
2024-10-01 5:01 ` [PATCH v3 21/27] KVM: VMX: Invoke vmx_set_cpu_caps() before nested setup Xin Li (Intel)
2024-10-24 7:49 ` Chao Gao
2024-10-25 7:34 ` Xin Li
2025-02-25 16:01 ` Sean Christopherson
2024-10-01 5:01 ` [PATCH v3 22/27] KVM: nVMX: Add support for the secondary VM exit controls Xin Li (Intel)
2024-10-01 5:01 ` [PATCH v3 23/27] KVM: nVMX: Add a prerequisite to SHADOW_FIELD_R[OW] macros Xin Li (Intel)
2024-10-01 5:01 ` [PATCH v3 24/27] KVM: nVMX: Add a prerequisite to existence of VMCS fields Xin Li (Intel)
2025-02-25 16:22 ` Sean Christopherson
2025-02-25 16:37 ` Xin Li
2025-02-25 19:32 ` Sean Christopherson
2024-10-01 5:01 ` [PATCH v3 25/27] KVM: nVMX: Add FRED " Xin Li (Intel)
2024-10-24 7:42 ` Chao Gao
2024-10-25 7:25 ` Xin Li
2024-10-28 9:07 ` Chao Gao
2024-10-28 18:27 ` Sean Christopherson
2024-10-29 17:40 ` Xin Li
2024-10-01 5:01 ` [PATCH v3 26/27] KVM: nVMX: Add VMCS FRED states checking Xin Li (Intel)
2024-10-01 5:01 ` [PATCH v3 27/27] KVM: nVMX: Allow VMX FRED controls Xin Li (Intel)
2025-02-19 0:26 ` [PATCH v3 00/27] Enable FRED with KVM VMX Xin Li
2025-02-25 15:24 ` Sean Christopherson
2025-02-25 17:04 ` Xin Li
2025-02-25 17:35 ` Sean Christopherson
2025-02-25 18:48 ` Xin Li
2025-02-28 17:06 ` Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241001050110.3643764-2-xin@zytor.com \
--to=xin@zytor.com \
--cc=andrew.cooper3@citrix.com \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=kvm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=seanjc@google.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®