* [PATCH 1/6] x86/sev: Define the #HV doorbell page structure
2024-08-07 0:57 [PATCH 0/6] SEV-SNP restricted injection hypervisor patches Melody Wang
@ 2024-08-07 0:57 ` Melody Wang
2024-08-07 0:57 ` [PATCH 2/6] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Melody Wang
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Melody Wang @ 2024-08-07 0:57 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
Restricted injection is a feature which enforces additional interrupt and event
injection security protections for a SEV-SNP guest. It disables all
hypervisor-based interrupt queuing and event injection of all vectors except
a new exception vector, #HV (28), which is reserved for SNP guest use, but
never generated by hardware. #HV is only allowed to be injected into VMSAs that
execute with Restricted Injection.
The guests running with the SNP restricted injection feature active limit the
host to ringing a doorbell with a #HV exception.
Define two fields in the #HV doorbell page: a pending event field, and an
EOI assist.
Create the structure definition for the #HV doorbell page as per GHCB
specification.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/include/asm/svm.h | 41 ++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index f0dea3750ca9..2b1f4c8daf19 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -516,6 +516,47 @@ struct ghcb {
u32 ghcb_usage;
} __packed;
+/*
+ * Hypervisor doorbell page:
+ *
+ * Used when restricted injection is enabled for a VM. One page in size that
+ * is shared between the guest and hypervisor to communicate exception and
+ * interrupt events.
+ */
+struct hvdb_events {
+ /* First 64 bytes of HV doorbell page defined in GHCB specification */
+ union {
+ struct {
+ /* Interrupt vector being injected */
+ u8 vector;
+
+ /* Non-maskable event field (NMI, etc.) */
+ u8 nm_events;
+ };
+
+ struct {
+ /* Non-maskable event indicators */
+ u16 reserved1: 8,
+ nmi: 1,
+ mce: 1,
+ reserved2: 5,
+ no_further_signal: 1;
+ };
+
+ u16 pending_events;
+ };
+
+ u8 no_eoi_required;
+
+ u8 reserved3[61];
+};
+
+struct hvdb {
+ struct hvdb_events events;
+
+ /* Remainder of the page is for software use */
+ u8 reserved[PAGE_SIZE - sizeof(struct hvdb_events)];
+};
#define EXPECTED_VMCB_SAVE_AREA_SIZE 744
#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 2/6] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event
2024-08-07 0:57 [PATCH 0/6] SEV-SNP restricted injection hypervisor patches Melody Wang
2024-08-07 0:57 ` [PATCH 1/6] x86/sev: Define the #HV doorbell page structure Melody Wang
@ 2024-08-07 0:57 ` Melody Wang
2024-08-07 0:57 ` [PATCH 3/6] KVM: SVM: Inject #HV when restricted injection is active Melody Wang
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Melody Wang @ 2024-08-07 0:57 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
To support the SEV-SNP Restricted Injection feature, the SEV-SNP guest must
register a #HV doorbell page for use with the #HV.
The #HV doorbell page NAE event allows the guest to register a #HV doorbell
page. The NAE event consists of four actions: GET_PREFERRED, SET, QUERY, CLEAR.
Implement the NAE event as per GHCB specification.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/include/uapi/asm/svm.h | 5 +++
arch/x86/kvm/svm/sev.c | 73 +++++++++++++++++++++++++++++++++
arch/x86/kvm/svm/svm.h | 2 +
3 files changed, 80 insertions(+)
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index 1814b413fd57..7905c9be44d1 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -115,6 +115,11 @@
#define SVM_VMGEXIT_AP_CREATE_ON_INIT 0
#define SVM_VMGEXIT_AP_CREATE 1
#define SVM_VMGEXIT_AP_DESTROY 2
+#define SVM_VMGEXIT_HVDB_PAGE 0x80000014
+#define SVM_VMGEXIT_HVDB_GET_PREFERRED 0
+#define SVM_VMGEXIT_HVDB_SET 1
+#define SVM_VMGEXIT_HVDB_QUERY 2
+#define SVM_VMGEXIT_HVDB_CLEAR 3
#define SVM_VMGEXIT_SNP_RUN_VMPL 0x80000018
#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd
#define SVM_VMGEXIT_TERM_REQUEST 0x8000fffe
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 532df12b43c5..19ee3f083cad 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -3409,6 +3409,10 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
control->exit_info_1 == control->exit_info_2)
goto vmgexit_err;
break;
+ case SVM_VMGEXIT_HVDB_PAGE:
+ if (!sev_snp_guest(vcpu->kvm))
+ goto vmgexit_err;
+ break;
default:
reason = GHCB_ERR_INVALID_EVENT;
goto vmgexit_err;
@@ -4124,6 +4128,66 @@ static int snp_handle_ext_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t r
return 1; /* resume guest */
}
+static int sev_snp_hv_doorbell_page(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ struct kvm_host_map hvdb_map;
+ gpa_t hvdb_gpa;
+ u64 request;
+
+ if (!sev_snp_guest(vcpu->kvm))
+ return -EINVAL;
+
+ request = svm->vmcb->control.exit_info_1;
+ hvdb_gpa = svm->vmcb->control.exit_info_2;
+
+ switch (request) {
+ case SVM_VMGEXIT_HVDB_GET_PREFERRED:
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, ~0ULL);
+ break;
+ case SVM_VMGEXIT_HVDB_SET:
+ svm->sev_es.hvdb_gpa = INVALID_PAGE;
+
+ if (!PAGE_ALIGNED(hvdb_gpa)) {
+ vcpu_unimpl(vcpu, "vmgexit: unaligned #HV doorbell page address [%#llx] from guest\n",
+ hvdb_gpa);
+ return -EINVAL;
+ }
+
+ if (!page_address_valid(vcpu, hvdb_gpa)) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid #HV doorbell page address [%#llx] from guest\n",
+ hvdb_gpa);
+ return -EINVAL;
+ }
+
+ /* Map and unmap the GPA just to be sure the GPA is valid */
+ if (kvm_vcpu_map(vcpu, gpa_to_gfn(hvdb_gpa), &hvdb_map)) {
+ /* Unable to map #HV doorbell page from guest */
+ vcpu_unimpl(vcpu, "vmgexit: error mapping #HV doorbell page [%#llx] from guest\n",
+ hvdb_gpa);
+ return -EINVAL;
+ }
+ kvm_vcpu_unmap(vcpu, &hvdb_map, true);
+
+ svm->sev_es.hvdb_gpa = hvdb_gpa;
+ fallthrough;
+ case SVM_VMGEXIT_HVDB_QUERY:
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, svm->sev_es.hvdb_gpa);
+ break;
+ case SVM_VMGEXIT_HVDB_CLEAR:
+ svm->sev_es.hvdb_gpa = INVALID_PAGE;
+ break;
+ default:
+ svm->sev_es.hvdb_gpa = INVALID_PAGE;
+
+ vcpu_unimpl(vcpu, "vmgexit: invalid #HV doorbell page request [%#llx] from guest\n",
+ request);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -4404,6 +4468,14 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
case SVM_VMGEXIT_EXT_GUEST_REQUEST:
ret = snp_handle_ext_guest_req(svm, control->exit_info_1, control->exit_info_2);
break;
+ case SVM_VMGEXIT_HVDB_PAGE:
+ if (sev_snp_hv_doorbell_page(svm)) {
+ ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT);
+ }
+
+ ret = 1;
+ break;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
vcpu_unimpl(vcpu,
"vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
@@ -4571,6 +4643,7 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm)
sev_enc_bit));
mutex_init(&svm->sev_es.snp_vmsa_mutex);
+ svm->sev_es.hvdb_gpa = INVALID_PAGE;
}
void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa)
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 76107c7d0595..f0f14801e122 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -225,6 +225,8 @@ struct vcpu_sev_es_state {
gpa_t snp_vmsa_gpa;
bool snp_ap_waiting_for_reset;
bool snp_has_guest_vmsa;
+
+ gpa_t hvdb_gpa;
};
struct vcpu_svm {
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/6] KVM: SVM: Inject #HV when restricted injection is active
2024-08-07 0:57 [PATCH 0/6] SEV-SNP restricted injection hypervisor patches Melody Wang
2024-08-07 0:57 ` [PATCH 1/6] x86/sev: Define the #HV doorbell page structure Melody Wang
2024-08-07 0:57 ` [PATCH 2/6] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Melody Wang
@ 2024-08-07 0:57 ` Melody Wang
2024-08-07 0:57 ` [PATCH 4/6] KVM: SVM: Inject NMIs " Melody Wang
` (2 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Melody Wang @ 2024-08-07 0:57 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
When restricted injection is active, only #HV exceptions can be injected into
the SEV-SNP guest.
Detect that restricted injection feature is active for the guest, and then
follow the #HV doorbell communication from the GHCB specification to inject the
interrupt or exception.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/include/uapi/asm/kvm.h | 1 +
arch/x86/kvm/svm/sev.c | 153 ++++++++++++++++++++++++++++++++
arch/x86/kvm/svm/svm.c | 19 +++-
arch/x86/kvm/svm/svm.h | 21 ++++-
4 files changed, 190 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index bf57a824f722..f5d85174e658 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -35,6 +35,7 @@
#define MC_VECTOR 18
#define XM_VECTOR 19
#define VE_VECTOR 20
+#define HV_VECTOR 28
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 19ee3f083cad..0d330b3357bc 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5022,3 +5022,156 @@ int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
return level;
}
+
+static void prepare_hv_injection(struct vcpu_svm *svm, struct hvdb *hvdb)
+{
+ if (hvdb->events.no_further_signal)
+ return;
+
+ svm->vmcb->control.event_inj = HV_VECTOR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ SVM_EVTINJ_VALID;
+ svm->vmcb->control.event_inj_err = 0;
+
+ hvdb->events.no_further_signal = 1;
+}
+
+static void unmap_hvdb(struct kvm_vcpu *vcpu, struct kvm_host_map *map)
+{
+ kvm_vcpu_unmap(vcpu, map, true);
+}
+
+static struct hvdb *map_hvdb(struct kvm_vcpu *vcpu, struct kvm_host_map *map)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!VALID_PAGE(svm->sev_es.hvdb_gpa))
+ return NULL;
+
+ if (kvm_vcpu_map(vcpu, gpa_to_gfn(svm->sev_es.hvdb_gpa), map)) {
+ /* Unable to map #HV doorbell page from guest */
+ vcpu_unimpl(vcpu, "snp: error mapping #HV doorbell page [%#llx] from guest\n",
+ svm->sev_es.hvdb_gpa);
+
+ return NULL;
+ }
+
+ return map->hva;
+}
+
+static bool __sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct kvm_host_map hvdb_map;
+ struct hvdb *hvdb;
+
+ hvdb = map_hvdb(vcpu, &hvdb_map);
+ if (!hvdb)
+ return false;
+
+ hvdb->events.vector = vcpu->arch.interrupt.nr;
+
+ prepare_hv_injection(svm, hvdb);
+
+ unmap_hvdb(vcpu, &hvdb_map);
+
+ return true;
+}
+
+bool sev_snp_queue_exception(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!sev_snp_is_rinj_active(vcpu))
+ return false;
+
+ /*
+ * Restricted injection is enabled, only #HV is supported.
+ * If the vector is not HV_VECTOR, do not inject the exception,
+ * then return true to skip the original injection path.
+ */
+ if (WARN_ONCE(vcpu->arch.exception.vector != HV_VECTOR,
+ "restricted injection enabled, exception %u injection not supported\n",
+ vcpu->arch.exception.vector))
+ return true;
+
+ /*
+ * An intercept likely occurred during #HV delivery, so re-inject it
+ * using the current HVDB pending event values.
+ */
+ svm->vmcb->control.event_inj = HV_VECTOR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ SVM_EVTINJ_VALID;
+ svm->vmcb->control.event_inj_err = 0;
+
+ return true;
+}
+
+bool sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
+{
+ if (!sev_snp_is_rinj_active(vcpu))
+ return false;
+
+ return __sev_snp_inject(type, vcpu);
+}
+
+void sev_snp_cancel_injection(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct kvm_host_map hvdb_map;
+ struct hvdb *hvdb;
+
+ if (!sev_snp_is_rinj_active(vcpu))
+ return;
+
+ if (!svm->vmcb->control.event_inj)
+ return;
+
+ if ((svm->vmcb->control.event_inj & SVM_EVTINJ_VEC_MASK) != HV_VECTOR)
+ return;
+
+ /*
+ * Copy the information in the doorbell page into the event injection
+ * fields to complete the cancellation flow.
+ */
+ hvdb = map_hvdb(vcpu, &hvdb_map);
+ if (!hvdb)
+ return;
+
+ if (!hvdb->events.pending_events) {
+ /* No pending events, then event_inj field should be 0 */
+ WARN_ON_ONCE(svm->vmcb->control.event_inj);
+ goto out;
+ }
+
+ /* Copy info back into event_inj field (replaces #HV) */
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID;
+
+ if (hvdb->events.vector)
+ svm->vmcb->control.event_inj |= hvdb->events.vector |
+ SVM_EVTINJ_TYPE_INTR;
+
+ hvdb->events.pending_events = 0;
+
+out:
+ unmap_hvdb(vcpu, &hvdb_map);
+}
+
+bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)
+{
+ struct kvm_host_map hvdb_map;
+ struct hvdb *hvdb;
+ bool blocked;
+
+ /* Indicate interrupts are blocked if doorbell page can't be mapped */
+ hvdb = map_hvdb(vcpu, &hvdb_map);
+ if (!hvdb)
+ return true;
+
+ /* Indicate interrupts blocked based on guest acknowledgment */
+ blocked = !!hvdb->events.vector;
+
+ unmap_hvdb(vcpu, &hvdb_map);
+
+ return blocked;
+}
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d6f252555ab3..a48388d99c97 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -447,6 +447,9 @@ static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu)
svm->soft_int_old_rip = old_rip;
svm->soft_int_next_rip = rip;
+ if (sev_snp_queue_exception(vcpu))
+ return 0;
+
if (nrips)
kvm_rip_write(vcpu, old_rip);
@@ -467,6 +470,9 @@ static void svm_inject_exception(struct kvm_vcpu *vcpu)
svm_update_soft_interrupt_rip(vcpu))
return;
+ if (sev_snp_queue_exception(vcpu))
+ return;
+
svm->vmcb->control.event_inj = ex->vector
| SVM_EVTINJ_VALID
| (ex->has_error_code ? SVM_EVTINJ_VALID_ERR : 0)
@@ -3662,10 +3668,12 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected)
trace_kvm_inj_virq(vcpu->arch.interrupt.nr,
vcpu->arch.interrupt.soft, reinjected);
- ++vcpu->stat.irq_injections;
- svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
- SVM_EVTINJ_VALID | type;
+ if (!sev_snp_inject(INJECT_IRQ, vcpu))
+ svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
+ SVM_EVTINJ_VALID | type;
+
+ ++vcpu->stat.irq_injections;
}
void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode,
@@ -3810,6 +3818,9 @@ bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
if (!gif_set(svm))
return true;
+ if (sev_snp_is_rinj_active(vcpu))
+ return sev_snp_blocked(INJECT_IRQ, vcpu);
+
if (is_guest_mode(vcpu)) {
/* As long as interrupts are being delivered... */
if ((svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK)
@@ -4128,6 +4139,8 @@ static void svm_cancel_injection(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
struct vmcb_control_area *control = &svm->vmcb->control;
+ sev_snp_cancel_injection(vcpu);
+
control->exit_int_info = control->event_inj;
control->exit_int_info_err = control->event_inj_err;
control->event_inj = 0;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index f0f14801e122..95c0a7070bd1 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -41,6 +41,10 @@ extern bool x2avic_enabled;
extern bool vnmi;
extern int lbrv;
+enum inject_type {
+ INJECT_IRQ,
+};
+
/*
* Clean bits in VMCB.
* VMCB_ALL_CLEAN_MASK might also need to
@@ -751,6 +755,17 @@ void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu);
int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order);
void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end);
int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn);
+bool sev_snp_queue_exception(struct kvm_vcpu *vcpu);
+bool sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu);
+void sev_snp_cancel_injection(struct kvm_vcpu *vcpu);
+bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu);
+static inline bool sev_snp_is_rinj_active(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(vcpu->kvm)->sev_info;
+
+ return sev_snp_guest(vcpu->kvm) &&
+ (sev->vmsa_features & SVM_SEV_FEAT_RESTRICTED_INJECTION);
+};
#else
static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
{
@@ -781,7 +796,11 @@ static inline int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
{
return 0;
}
-
+static inline bool sev_snp_queue_exception(struct kvm_vcpu *vcpu) { return false; }
+static inline bool sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu) { return false; }
+static inline void sev_snp_cancel_injection(struct kvm_vcpu *vcpu) {}
+static inline bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu) { return false; }
+static inline bool sev_snp_is_rinj_active(struct kvm_vcpu *vcpu) { return false; }
#endif
/* vmenter.S */
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 4/6] KVM: SVM: Inject NMIs when restricted injection is active
2024-08-07 0:57 [PATCH 0/6] SEV-SNP restricted injection hypervisor patches Melody Wang
` (2 preceding siblings ...)
2024-08-07 0:57 ` [PATCH 3/6] KVM: SVM: Inject #HV when restricted injection is active Melody Wang
@ 2024-08-07 0:57 ` Melody Wang
2024-08-07 1:00 ` Melody Wang
2024-08-07 1:00 ` [PATCH 5/6] KVM: SVM: Inject MCEs " Melody Wang
2024-08-07 1:00 ` [PATCH 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest Melody Wang
5 siblings, 1 reply; 10+ messages in thread
From: Melody Wang @ 2024-08-07 0:57 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
When restricted injection is active, only #HV exceptions can be injected into
the SEV-SNP guest.
Detect that restricted injection feature is active for the guest, and then
follow the #HV doorbell communication from the GHCB specification to inject
NMIs.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/kvm/svm/sev.c | 19 ++++++++++++++++---
arch/x86/kvm/svm/svm.c | 8 ++++++++
arch/x86/kvm/svm/svm.h | 1 +
3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 0d330b3357bc..7f9f35e0e092 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5069,7 +5069,10 @@ static bool __sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
if (!hvdb)
return false;
- hvdb->events.vector = vcpu->arch.interrupt.nr;
+ if (type == INJECT_NMI)
+ hvdb->events.nmi = 1;
+ else
+ hvdb->events.vector = vcpu->arch.interrupt.nr;
prepare_hv_injection(svm, hvdb);
@@ -5147,10 +5150,17 @@ void sev_snp_cancel_injection(struct kvm_vcpu *vcpu)
/* Copy info back into event_inj field (replaces #HV) */
svm->vmcb->control.event_inj = SVM_EVTINJ_VALID;
+ /*
+ * KVM only injects a single event each time (prepare_hv_injection),
+ * so when events.nmi is true, the vector will be zero
+ */
if (hvdb->events.vector)
svm->vmcb->control.event_inj |= hvdb->events.vector |
SVM_EVTINJ_TYPE_INTR;
+ if (hvdb->events.nmi)
+ svm->vmcb->control.event_inj |= SVM_EVTINJ_TYPE_NMI;
+
hvdb->events.pending_events = 0;
out:
@@ -5168,8 +5178,11 @@ bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)
if (!hvdb)
return true;
- /* Indicate interrupts blocked based on guest acknowledgment */
- blocked = !!hvdb->events.vector;
+ /* Indicate NMIs and interrupts blocked based on guest acknowledgment */
+ if (type == INJECT_NMI)
+ blocked = hvdb->events.nmi;
+ else
+ blocked = !!hvdb->events.vector;
unmap_hvdb(vcpu, &hvdb_map);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index a48388d99c97..d9c572344f0c 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3602,6 +3602,9 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ if (sev_snp_inject(INJECT_NMI, vcpu))
+ goto status;
+
svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI;
if (svm->nmi_l1_to_l2)
@@ -3616,6 +3619,8 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu)
svm->nmi_masked = true;
svm_set_iret_intercept(svm);
}
+
+status:
++vcpu->stat.nmi_injections;
}
@@ -3786,6 +3791,9 @@ bool svm_nmi_blocked(struct kvm_vcpu *vcpu)
if (!gif_set(svm))
return true;
+ if (sev_snp_is_rinj_active(vcpu))
+ return sev_snp_blocked(INJECT_NMI, vcpu);
+
if (is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
return false;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 95c0a7070bd1..f60ff6229ff4 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -43,6 +43,7 @@ extern int lbrv;
enum inject_type {
INJECT_IRQ,
+ INJECT_NMI,
};
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 4/6] KVM: SVM: Inject NMIs when restricted injection is active
2024-08-07 0:57 ` [PATCH 4/6] KVM: SVM: Inject NMIs " Melody Wang
@ 2024-08-07 1:00 ` Melody Wang
0 siblings, 0 replies; 10+ messages in thread
From: Melody Wang @ 2024-08-07 1:00 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
When restricted injection is active, only #HV exceptions can be injected into
the SEV-SNP guest.
Detect that restricted injection feature is active for the guest, and then
follow the #HV doorbell communication from the GHCB specification to inject
NMIs.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/kvm/svm/sev.c | 19 ++++++++++++++++---
arch/x86/kvm/svm/svm.c | 8 ++++++++
arch/x86/kvm/svm/svm.h | 1 +
3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 0d330b3357bc..7f9f35e0e092 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5069,7 +5069,10 @@ static bool __sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
if (!hvdb)
return false;
- hvdb->events.vector = vcpu->arch.interrupt.nr;
+ if (type == INJECT_NMI)
+ hvdb->events.nmi = 1;
+ else
+ hvdb->events.vector = vcpu->arch.interrupt.nr;
prepare_hv_injection(svm, hvdb);
@@ -5147,10 +5150,17 @@ void sev_snp_cancel_injection(struct kvm_vcpu *vcpu)
/* Copy info back into event_inj field (replaces #HV) */
svm->vmcb->control.event_inj = SVM_EVTINJ_VALID;
+ /*
+ * KVM only injects a single event each time (prepare_hv_injection),
+ * so when events.nmi is true, the vector will be zero
+ */
if (hvdb->events.vector)
svm->vmcb->control.event_inj |= hvdb->events.vector |
SVM_EVTINJ_TYPE_INTR;
+ if (hvdb->events.nmi)
+ svm->vmcb->control.event_inj |= SVM_EVTINJ_TYPE_NMI;
+
hvdb->events.pending_events = 0;
out:
@@ -5168,8 +5178,11 @@ bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)
if (!hvdb)
return true;
- /* Indicate interrupts blocked based on guest acknowledgment */
- blocked = !!hvdb->events.vector;
+ /* Indicate NMIs and interrupts blocked based on guest acknowledgment */
+ if (type == INJECT_NMI)
+ blocked = hvdb->events.nmi;
+ else
+ blocked = !!hvdb->events.vector;
unmap_hvdb(vcpu, &hvdb_map);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index a48388d99c97..d9c572344f0c 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3602,6 +3602,9 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ if (sev_snp_inject(INJECT_NMI, vcpu))
+ goto status;
+
svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI;
if (svm->nmi_l1_to_l2)
@@ -3616,6 +3619,8 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu)
svm->nmi_masked = true;
svm_set_iret_intercept(svm);
}
+
+status:
++vcpu->stat.nmi_injections;
}
@@ -3786,6 +3791,9 @@ bool svm_nmi_blocked(struct kvm_vcpu *vcpu)
if (!gif_set(svm))
return true;
+ if (sev_snp_is_rinj_active(vcpu))
+ return sev_snp_blocked(INJECT_NMI, vcpu);
+
if (is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
return false;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 95c0a7070bd1..f60ff6229ff4 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -43,6 +43,7 @@ extern int lbrv;
enum inject_type {
INJECT_IRQ,
+ INJECT_NMI,
};
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/6] KVM: SVM: Inject MCEs when restricted injection is active
2024-08-07 0:57 [PATCH 0/6] SEV-SNP restricted injection hypervisor patches Melody Wang
` (3 preceding siblings ...)
2024-08-07 0:57 ` [PATCH 4/6] KVM: SVM: Inject NMIs " Melody Wang
@ 2024-08-07 1:00 ` Melody Wang
2024-08-07 23:30 ` kernel test robot
2024-08-07 1:00 ` [PATCH 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest Melody Wang
5 siblings, 1 reply; 10+ messages in thread
From: Melody Wang @ 2024-08-07 1:00 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
When restricted injection is active, only #HV exceptions can be injected into
the SEV-SNP guest.
Detect that restricted injection feature is active for the guest, and then
follow the #HV doorbell communication from the GHCB specification to inject the
MCEs.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/include/asm/kvm-x86-ops.h | 1 +
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/svm/sev.c | 16 ++++++++++++++--
arch/x86/kvm/svm/svm.c | 17 +++++++++++++++++
arch/x86/kvm/svm/svm.h | 2 ++
arch/x86/kvm/vmx/main.c | 1 +
arch/x86/kvm/vmx/vmx.c | 5 +++++
arch/x86/kvm/vmx/x86_ops.h | 1 +
arch/x86/kvm/x86.c | 7 +++++++
9 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index 68ad4f923664..9e5764a8e031 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -76,6 +76,7 @@ KVM_X86_OP(inject_exception)
KVM_X86_OP(cancel_injection)
KVM_X86_OP(interrupt_allowed)
KVM_X86_OP(nmi_allowed)
+KVM_X86_OP_OPTIONAL(mce_allowed)
KVM_X86_OP(get_nmi_mask)
KVM_X86_OP(set_nmi_mask)
KVM_X86_OP(enable_nmi_window)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 94e7b5a4fafe..cb1608a69144 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1715,6 +1715,7 @@ struct kvm_x86_ops {
void (*cancel_injection)(struct kvm_vcpu *vcpu);
int (*interrupt_allowed)(struct kvm_vcpu *vcpu, bool for_injection);
int (*nmi_allowed)(struct kvm_vcpu *vcpu, bool for_injection);
+ int (*mce_allowed)(struct kvm_vcpu *vcpu);
bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked);
/* Whether or not a virtual NMI is pending in hardware. */
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 7f9f35e0e092..87c493bad93a 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5071,6 +5071,8 @@ static bool __sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
if (type == INJECT_NMI)
hvdb->events.nmi = 1;
+ else if (type == INJECT_MCE)
+ hvdb->events.mce = 1;
else
hvdb->events.vector = vcpu->arch.interrupt.nr;
@@ -5088,6 +5090,11 @@ bool sev_snp_queue_exception(struct kvm_vcpu *vcpu)
if (!sev_snp_is_rinj_active(vcpu))
return false;
+ if (vcpu->arch.exception.vector == MC_VECTOR) {
+ if (__sev_snp_inject(INJECT_MCE, vcpu))
+ return true;
+ }
+
/*
* Restricted injection is enabled, only #HV is supported.
* If the vector is not HV_VECTOR, do not inject the exception,
@@ -5152,7 +5159,7 @@ void sev_snp_cancel_injection(struct kvm_vcpu *vcpu)
/*
* KVM only injects a single event each time (prepare_hv_injection),
- * so when events.nmi is true, the vector will be zero
+ * so when events.nmi is true, the mce and vector will be zero
*/
if (hvdb->events.vector)
svm->vmcb->control.event_inj |= hvdb->events.vector |
@@ -5161,6 +5168,9 @@ void sev_snp_cancel_injection(struct kvm_vcpu *vcpu)
if (hvdb->events.nmi)
svm->vmcb->control.event_inj |= SVM_EVTINJ_TYPE_NMI;
+ if (hvdb->events.mce)
+ svm->vmcb->control.event_inj |= MC_VECTOR | SVM_EVTINJ_TYPE_EXEPT;
+
hvdb->events.pending_events = 0;
out:
@@ -5178,9 +5188,11 @@ bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)
if (!hvdb)
return true;
- /* Indicate NMIs and interrupts blocked based on guest acknowledgment */
+ /* Indicate NMIs, MCEs and interrupts blocked based on guest acknowledgment */
if (type == INJECT_NMI)
blocked = hvdb->events.nmi;
+ else if (type == INJECT_MCE)
+ blocked = hvdb->events.mce;
else
blocked = !!hvdb->events.vector;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d9c572344f0c..1c13c5da6eea 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3867,6 +3867,22 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
return 1;
}
+bool svm_mce_blocked(struct kvm_vcpu *vcpu)
+{
+ if (sev_snp_is_rinj_active(vcpu))
+ return sev_snp_blocked(INJECT_MCE, vcpu);
+
+ return false;
+}
+
+static int svm_mce_allowed(struct kvm_vcpu *vcpu)
+{
+ if (svm_mce_blocked(vcpu))
+ return 0;
+
+ return 1;
+}
+
static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -5066,6 +5082,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
.cancel_injection = svm_cancel_injection,
.interrupt_allowed = svm_interrupt_allowed,
.nmi_allowed = svm_nmi_allowed,
+ .mce_allowed = svm_mce_allowed,
.get_nmi_mask = svm_get_nmi_mask,
.set_nmi_mask = svm_set_nmi_mask,
.enable_nmi_window = svm_enable_nmi_window,
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index f60ff6229ff4..0cf32954589f 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -44,6 +44,7 @@ extern int lbrv;
enum inject_type {
INJECT_IRQ,
INJECT_NMI,
+ INJECT_MCE,
};
/*
@@ -602,6 +603,7 @@ void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
void disable_nmi_singlestep(struct vcpu_svm *svm);
bool svm_smi_blocked(struct kvm_vcpu *vcpu);
bool svm_nmi_blocked(struct kvm_vcpu *vcpu);
+bool svm_mce_blocked(struct kvm_vcpu *vcpu);
bool svm_interrupt_blocked(struct kvm_vcpu *vcpu);
void svm_set_gif(struct vcpu_svm *svm, bool value);
int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code);
diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c
index 0bf35ebe8a1b..c3a49a3b7f21 100644
--- a/arch/x86/kvm/vmx/main.c
+++ b/arch/x86/kvm/vmx/main.c
@@ -84,6 +84,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
.cancel_injection = vmx_cancel_injection,
.interrupt_allowed = vmx_interrupt_allowed,
.nmi_allowed = vmx_nmi_allowed,
+ .mce_allowed = vmx_mce_allowed,
.get_nmi_mask = vmx_get_nmi_mask,
.set_nmi_mask = vmx_set_nmi_mask,
.enable_nmi_window = vmx_enable_nmi_window,
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index f18c2d8c7476..b3dce5d95329 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -5093,6 +5093,11 @@ int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
return !vmx_interrupt_blocked(vcpu);
}
+int vmx_mce_allowed(struct kvm_vcpu *vcpu)
+{
+ return 1;
+}
+
int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
{
void __user *ret;
diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h
index ce3221cd1d01..b2b1a3bb4eb3 100644
--- a/arch/x86/kvm/vmx/x86_ops.h
+++ b/arch/x86/kvm/vmx/x86_ops.h
@@ -92,6 +92,7 @@ void vmx_inject_exception(struct kvm_vcpu *vcpu);
void vmx_cancel_injection(struct kvm_vcpu *vcpu);
int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection);
int vmx_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection);
+int vmx_mce_allowed(struct kvm_vcpu *vcpu);
bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu);
void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked);
void vmx_enable_nmi_window(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ef3d3511e4af..e926fc9d82e6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10487,12 +10487,19 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
}
}
+ if (vcpu->arch.exception.vector == MC_VECTOR) {
+ r = static_call(kvm_x86_mce_allowed)(vcpu);
+ if (!r)
+ goto out_except;
+ }
+
kvm_inject_exception(vcpu);
vcpu->arch.exception.pending = false;
vcpu->arch.exception.injected = true;
can_inject = false;
+out_except:
}
/* Don't inject interrupts if the user asked to avoid doing so */
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH 5/6] KVM: SVM: Inject MCEs when restricted injection is active
2024-08-07 1:00 ` [PATCH 5/6] KVM: SVM: Inject MCEs " Melody Wang
@ 2024-08-07 23:30 ` kernel test robot
0 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2024-08-07 23:30 UTC (permalink / raw)
To: Melody Wang, kvm, linux-kernel, x86
Cc: llvm, oe-kbuild-all, Sean Christopherson, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
Tom Lendacky, Ashish Kalra, Michael Roth, Melody Wang
Hi Melody,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/x86/core]
[also build test WARNING on linus/master v6.11-rc2 next-20240807]
[cannot apply to kvm/queue mst-vhost/linux-next kvm/linux-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Melody-Wang/x86-sev-Define-the-HV-doorbell-page-structure/20240807-090812
base: tip/x86/core
patch link: https://lore.kernel.org/r/ec9b446fe9554effef9a9c5cec348e3f627ff581.1722989996.git.huibo.wang%40amd.com
patch subject: [PATCH 5/6] KVM: SVM: Inject MCEs when restricted injection is active
config: x86_64-buildonly-randconfig-004-20240808 (https://download.01.org/0day-ci/archive/20240808/202408080703.tBFpvbaa-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240808/202408080703.tBFpvbaa-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408080703.tBFpvbaa-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> arch/x86/kvm/x86.c:10503:2: warning: label at end of compound statement is a C23 extension [-Wc23-extensions]
10503 | }
| ^
1 warning generated.
vim +10503 arch/x86/kvm/x86.c
b97f074583736c Maxim Levitsky 2021-02-25 10344
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10345 /*
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10346 * Check for any event (interrupt or exception) that is ready to be injected,
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10347 * and if there is at least one event, inject the event with the highest
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10348 * priority. This handles both "pending" events, i.e. events that have never
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10349 * been injected into the guest, and "injected" events, i.e. events that were
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10350 * injected as part of a previous VM-Enter, but weren't successfully delivered
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10351 * and need to be re-injected.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10352 *
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10353 * Note, this is not guaranteed to be invoked on a guest instruction boundary,
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10354 * i.e. doesn't guarantee that there's an event window in the guest. KVM must
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10355 * be able to inject exceptions in the "middle" of an instruction, and so must
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10356 * also be able to re-inject NMIs and IRQs in the middle of an instruction.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10357 * I.e. for exceptions and re-injected events, NOT invoking this on instruction
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10358 * boundaries is necessary and correct.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10359 *
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10360 * For simplicity, KVM uses a single path to inject all events (except events
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10361 * that are injected directly from L1 to L2) and doesn't explicitly track
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10362 * instruction boundaries for asynchronous events. However, because VM-Exits
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10363 * that can occur during instruction execution typically result in KVM skipping
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10364 * the instruction or injecting an exception, e.g. instruction and exception
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10365 * intercepts, and because pending exceptions have higher priority than pending
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10366 * interrupts, KVM still honors instruction boundaries in most scenarios.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10367 *
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10368 * But, if a VM-Exit occurs during instruction execution, and KVM does NOT skip
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10369 * the instruction or inject an exception, then KVM can incorrecty inject a new
54aa699e8094ef Bjorn Helgaas 2024-01-02 10370 * asynchronous event if the event became pending after the CPU fetched the
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10371 * instruction (in the guest). E.g. if a page fault (#PF, #NPF, EPT violation)
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10372 * occurs and is resolved by KVM, a coincident NMI, SMI, IRQ, etc... can be
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10373 * injected on the restarted instruction instead of being deferred until the
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10374 * instruction completes.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10375 *
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10376 * In practice, this virtualization hole is unlikely to be observed by the
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10377 * guest, and even less likely to cause functional problems. To detect the
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10378 * hole, the guest would have to trigger an event on a side effect of an early
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10379 * phase of instruction execution, e.g. on the instruction fetch from memory.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10380 * And for it to be a functional problem, the guest would need to depend on the
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10381 * ordering between that side effect, the instruction completing, _and_ the
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10382 * delivery of the asynchronous event.
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10383 */
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10384 static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
e746c1f1b94ac9 Sean Christopherson 2022-08-30 10385 bool *req_immediate_exit)
95ba82731374eb Gleb Natapov 2009-04-21 10386 {
28360f88706837 Sean Christopherson 2022-08-30 10387 bool can_inject;
b6b8a1451fc404 Jan Kiszka 2014-03-07 10388 int r;
b6b8a1451fc404 Jan Kiszka 2014-03-07 10389
6c593b5276e6ce Sean Christopherson 2022-08-30 10390 /*
54aa699e8094ef Bjorn Helgaas 2024-01-02 10391 * Process nested events first, as nested VM-Exit supersedes event
6c593b5276e6ce Sean Christopherson 2022-08-30 10392 * re-injection. If there's an event queued for re-injection, it will
6c593b5276e6ce Sean Christopherson 2022-08-30 10393 * be saved into the appropriate vmc{b,s}12 fields on nested VM-Exit.
6c593b5276e6ce Sean Christopherson 2022-08-30 10394 */
6c593b5276e6ce Sean Christopherson 2022-08-30 10395 if (is_guest_mode(vcpu))
6c593b5276e6ce Sean Christopherson 2022-08-30 10396 r = kvm_check_nested_events(vcpu);
6c593b5276e6ce Sean Christopherson 2022-08-30 10397 else
6c593b5276e6ce Sean Christopherson 2022-08-30 10398 r = 0;
b59bb7bdf08ee9 Gleb Natapov 2009-07-09 10399
664f8e26b00c76 Wanpeng Li 2017-08-24 10400 /*
6c593b5276e6ce Sean Christopherson 2022-08-30 10401 * Re-inject exceptions and events *especially* if immediate entry+exit
6c593b5276e6ce Sean Christopherson 2022-08-30 10402 * to/from L2 is needed, as any event that has already been injected
6c593b5276e6ce Sean Christopherson 2022-08-30 10403 * into L2 needs to complete its lifecycle before injecting a new event.
6c593b5276e6ce Sean Christopherson 2022-08-30 10404 *
6c593b5276e6ce Sean Christopherson 2022-08-30 10405 * Don't re-inject an NMI or interrupt if there is a pending exception.
6c593b5276e6ce Sean Christopherson 2022-08-30 10406 * This collision arises if an exception occurred while vectoring the
6c593b5276e6ce Sean Christopherson 2022-08-30 10407 * injected event, KVM intercepted said exception, and KVM ultimately
6c593b5276e6ce Sean Christopherson 2022-08-30 10408 * determined the fault belongs to the guest and queues the exception
6c593b5276e6ce Sean Christopherson 2022-08-30 10409 * for injection back into the guest.
6c593b5276e6ce Sean Christopherson 2022-08-30 10410 *
6c593b5276e6ce Sean Christopherson 2022-08-30 10411 * "Injected" interrupts can also collide with pending exceptions if
6c593b5276e6ce Sean Christopherson 2022-08-30 10412 * userspace ignores the "ready for injection" flag and blindly queues
6c593b5276e6ce Sean Christopherson 2022-08-30 10413 * an interrupt. In that case, prioritizing the exception is correct,
6c593b5276e6ce Sean Christopherson 2022-08-30 10414 * as the exception "occurred" before the exit to userspace. Trap-like
6c593b5276e6ce Sean Christopherson 2022-08-30 10415 * exceptions, e.g. most #DBs, have higher priority than interrupts.
6c593b5276e6ce Sean Christopherson 2022-08-30 10416 * And while fault-like exceptions, e.g. #GP and #PF, are the lowest
6c593b5276e6ce Sean Christopherson 2022-08-30 10417 * priority, they're only generated (pended) during instruction
6c593b5276e6ce Sean Christopherson 2022-08-30 10418 * execution, and interrupts are recognized at instruction boundaries.
6c593b5276e6ce Sean Christopherson 2022-08-30 10419 * Thus a pending fault-like exception means the fault occurred on the
6c593b5276e6ce Sean Christopherson 2022-08-30 10420 * *previous* instruction and must be serviced prior to recognizing any
6c593b5276e6ce Sean Christopherson 2022-08-30 10421 * new events in order to fully complete the previous instruction.
6c593b5276e6ce Sean Christopherson 2022-08-30 10422 */
6c593b5276e6ce Sean Christopherson 2022-08-30 10423 if (vcpu->arch.exception.injected)
b97f074583736c Maxim Levitsky 2021-02-25 10424 kvm_inject_exception(vcpu);
7709aba8f71613 Sean Christopherson 2022-08-30 10425 else if (kvm_is_exception_pending(vcpu))
6c593b5276e6ce Sean Christopherson 2022-08-30 10426 ; /* see above */
6c593b5276e6ce Sean Christopherson 2022-08-30 10427 else if (vcpu->arch.nmi_injected)
896046474f8d2e Wei Wang 2024-05-07 10428 kvm_x86_call(inject_nmi)(vcpu);
6c593b5276e6ce Sean Christopherson 2022-08-30 10429 else if (vcpu->arch.interrupt.injected)
896046474f8d2e Wei Wang 2024-05-07 10430 kvm_x86_call(inject_irq)(vcpu, true);
b6b8a1451fc404 Jan Kiszka 2014-03-07 10431
6c593b5276e6ce Sean Christopherson 2022-08-30 10432 /*
6c593b5276e6ce Sean Christopherson 2022-08-30 10433 * Exceptions that morph to VM-Exits are handled above, and pending
6c593b5276e6ce Sean Christopherson 2022-08-30 10434 * exceptions on top of injected exceptions that do not VM-Exit should
6c593b5276e6ce Sean Christopherson 2022-08-30 10435 * either morph to #DF or, sadly, override the injected exception.
6c593b5276e6ce Sean Christopherson 2022-08-30 10436 */
3b82b8d7fdf7c1 Sean Christopherson 2020-04-22 10437 WARN_ON_ONCE(vcpu->arch.exception.injected &&
3b82b8d7fdf7c1 Sean Christopherson 2020-04-22 10438 vcpu->arch.exception.pending);
3b82b8d7fdf7c1 Sean Christopherson 2020-04-22 10439
1a680e355c9477 Liran Alon 2018-03-23 10440 /*
6c593b5276e6ce Sean Christopherson 2022-08-30 10441 * Bail if immediate entry+exit to/from the guest is needed to complete
6c593b5276e6ce Sean Christopherson 2022-08-30 10442 * nested VM-Enter or event re-injection so that a different pending
6c593b5276e6ce Sean Christopherson 2022-08-30 10443 * event can be serviced (or if KVM needs to exit to userspace).
6c593b5276e6ce Sean Christopherson 2022-08-30 10444 *
6c593b5276e6ce Sean Christopherson 2022-08-30 10445 * Otherwise, continue processing events even if VM-Exit occurred. The
6c593b5276e6ce Sean Christopherson 2022-08-30 10446 * VM-Exit will have cleared exceptions that were meant for L2, but
6c593b5276e6ce Sean Christopherson 2022-08-30 10447 * there may now be events that can be injected into L1.
1a680e355c9477 Liran Alon 2018-03-23 10448 */
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10449 if (r < 0)
a5f6909a71f922 Jim Mattson 2021-06-04 10450 goto out;
95ba82731374eb Gleb Natapov 2009-04-21 10451
7709aba8f71613 Sean Christopherson 2022-08-30 10452 /*
7709aba8f71613 Sean Christopherson 2022-08-30 10453 * A pending exception VM-Exit should either result in nested VM-Exit
7709aba8f71613 Sean Christopherson 2022-08-30 10454 * or force an immediate re-entry and exit to/from L2, and exception
7709aba8f71613 Sean Christopherson 2022-08-30 10455 * VM-Exits cannot be injected (flag should _never_ be set).
7709aba8f71613 Sean Christopherson 2022-08-30 10456 */
7709aba8f71613 Sean Christopherson 2022-08-30 10457 WARN_ON_ONCE(vcpu->arch.exception_vmexit.injected ||
7709aba8f71613 Sean Christopherson 2022-08-30 10458 vcpu->arch.exception_vmexit.pending);
7709aba8f71613 Sean Christopherson 2022-08-30 10459
28360f88706837 Sean Christopherson 2022-08-30 10460 /*
28360f88706837 Sean Christopherson 2022-08-30 10461 * New events, other than exceptions, cannot be injected if KVM needs
28360f88706837 Sean Christopherson 2022-08-30 10462 * to re-inject a previous event. See above comments on re-injecting
28360f88706837 Sean Christopherson 2022-08-30 10463 * for why pending exceptions get priority.
28360f88706837 Sean Christopherson 2022-08-30 10464 */
28360f88706837 Sean Christopherson 2022-08-30 10465 can_inject = !kvm_event_needs_reinjection(vcpu);
28360f88706837 Sean Christopherson 2022-08-30 10466
664f8e26b00c76 Wanpeng Li 2017-08-24 10467 if (vcpu->arch.exception.pending) {
5623f751bd9c43 Sean Christopherson 2022-08-30 10468 /*
5623f751bd9c43 Sean Christopherson 2022-08-30 10469 * Fault-class exceptions, except #DBs, set RF=1 in the RFLAGS
5623f751bd9c43 Sean Christopherson 2022-08-30 10470 * value pushed on the stack. Trap-like exception and all #DBs
5623f751bd9c43 Sean Christopherson 2022-08-30 10471 * leave RF as-is (KVM follows Intel's behavior in this regard;
5623f751bd9c43 Sean Christopherson 2022-08-30 10472 * AMD states that code breakpoint #DBs excplitly clear RF=0).
5623f751bd9c43 Sean Christopherson 2022-08-30 10473 *
5623f751bd9c43 Sean Christopherson 2022-08-30 10474 * Note, most versions of Intel's SDM and AMD's APM incorrectly
5623f751bd9c43 Sean Christopherson 2022-08-30 10475 * describe the behavior of General Detect #DBs, which are
5623f751bd9c43 Sean Christopherson 2022-08-30 10476 * fault-like. They do _not_ set RF, a la code breakpoints.
5623f751bd9c43 Sean Christopherson 2022-08-30 10477 */
d4963e319f1f78 Sean Christopherson 2022-08-30 10478 if (exception_type(vcpu->arch.exception.vector) == EXCPT_FAULT)
664f8e26b00c76 Wanpeng Li 2017-08-24 10479 __kvm_set_rflags(vcpu, kvm_get_rflags(vcpu) |
664f8e26b00c76 Wanpeng Li 2017-08-24 10480 X86_EFLAGS_RF);
664f8e26b00c76 Wanpeng Li 2017-08-24 10481
d4963e319f1f78 Sean Christopherson 2022-08-30 10482 if (vcpu->arch.exception.vector == DB_VECTOR) {
d4963e319f1f78 Sean Christopherson 2022-08-30 10483 kvm_deliver_exception_payload(vcpu, &vcpu->arch.exception);
f10c729ff96528 Jim Mattson 2018-10-16 10484 if (vcpu->arch.dr7 & DR7_GD) {
664f8e26b00c76 Wanpeng Li 2017-08-24 10485 vcpu->arch.dr7 &= ~DR7_GD;
664f8e26b00c76 Wanpeng Li 2017-08-24 10486 kvm_update_dr7(vcpu);
664f8e26b00c76 Wanpeng Li 2017-08-24 10487 }
f10c729ff96528 Jim Mattson 2018-10-16 10488 }
664f8e26b00c76 Wanpeng Li 2017-08-24 10489
fc9708f9726240 Melody Wang 2024-08-07 10490 if (vcpu->arch.exception.vector == MC_VECTOR) {
fc9708f9726240 Melody Wang 2024-08-07 10491 r = static_call(kvm_x86_mce_allowed)(vcpu);
fc9708f9726240 Melody Wang 2024-08-07 10492 if (!r)
fc9708f9726240 Melody Wang 2024-08-07 10493 goto out_except;
fc9708f9726240 Melody Wang 2024-08-07 10494 }
fc9708f9726240 Melody Wang 2024-08-07 10495
b97f074583736c Maxim Levitsky 2021-02-25 10496 kvm_inject_exception(vcpu);
a61d7c5432ac5a Sean Christopherson 2022-05-02 10497
a61d7c5432ac5a Sean Christopherson 2022-05-02 10498 vcpu->arch.exception.pending = false;
a61d7c5432ac5a Sean Christopherson 2022-05-02 10499 vcpu->arch.exception.injected = true;
a61d7c5432ac5a Sean Christopherson 2022-05-02 10500
c6b22f59d694d0 Paolo Bonzini 2020-05-26 10501 can_inject = false;
fc9708f9726240 Melody Wang 2024-08-07 10502 out_except:
1a680e355c9477 Liran Alon 2018-03-23 @10503 }
1a680e355c9477 Liran Alon 2018-03-23 10504
61e5f69ef08379 Maxim Levitsky 2021-08-11 10505 /* Don't inject interrupts if the user asked to avoid doing so */
61e5f69ef08379 Maxim Levitsky 2021-08-11 10506 if (vcpu->guest_debug & KVM_GUESTDBG_BLOCKIRQ)
61e5f69ef08379 Maxim Levitsky 2021-08-11 10507 return 0;
61e5f69ef08379 Maxim Levitsky 2021-08-11 10508
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10509 /*
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10510 * Finally, inject interrupt events. If an event cannot be injected
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10511 * due to architectural conditions (e.g. IF=0) a window-open exit
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10512 * will re-request KVM_REQ_EVENT. Sometimes however an event is pending
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10513 * and can architecturally be injected, but we cannot do it right now:
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10514 * an interrupt could have arrived just now and we have to inject it
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10515 * as a vmexit, or there could already an event in the queue, which is
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10516 * indicated by can_inject. In that case we request an immediate exit
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10517 * in order to make progress and get back here for another iteration.
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10518 * The kvm_x86_ops hooks communicate this by returning -EBUSY.
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10519 */
31e83e21cf00fe Paolo Bonzini 2022-09-29 10520 #ifdef CONFIG_KVM_SMM
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10521 if (vcpu->arch.smi_pending) {
896046474f8d2e Wei Wang 2024-05-07 10522 r = can_inject ? kvm_x86_call(smi_allowed)(vcpu, true) :
896046474f8d2e Wei Wang 2024-05-07 10523 -EBUSY;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10524 if (r < 0)
a5f6909a71f922 Jim Mattson 2021-06-04 10525 goto out;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10526 if (r) {
c43203cab1e2e1 Paolo Bonzini 2016-06-01 10527 vcpu->arch.smi_pending = false;
52797bf9a875c4 Liran Alon 2017-11-15 10528 ++vcpu->arch.smi_count;
ee2cd4b7555e3a Paolo Bonzini 2016-06-01 10529 enter_smm(vcpu);
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10530 can_inject = false;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10531 } else
896046474f8d2e Wei Wang 2024-05-07 10532 kvm_x86_call(enable_smi_window)(vcpu);
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10533 }
31e83e21cf00fe Paolo Bonzini 2022-09-29 10534 #endif
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10535
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10536 if (vcpu->arch.nmi_pending) {
896046474f8d2e Wei Wang 2024-05-07 10537 r = can_inject ? kvm_x86_call(nmi_allowed)(vcpu, true) :
896046474f8d2e Wei Wang 2024-05-07 10538 -EBUSY;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10539 if (r < 0)
a5f6909a71f922 Jim Mattson 2021-06-04 10540 goto out;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10541 if (r) {
7460fb4a340033 Avi Kivity 2011-09-20 10542 --vcpu->arch.nmi_pending;
95ba82731374eb Gleb Natapov 2009-04-21 10543 vcpu->arch.nmi_injected = true;
896046474f8d2e Wei Wang 2024-05-07 10544 kvm_x86_call(inject_nmi)(vcpu);
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10545 can_inject = false;
896046474f8d2e Wei Wang 2024-05-07 10546 WARN_ON(kvm_x86_call(nmi_allowed)(vcpu, true) < 0);
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10547 }
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10548 if (vcpu->arch.nmi_pending)
896046474f8d2e Wei Wang 2024-05-07 10549 kvm_x86_call(enable_nmi_window)(vcpu);
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10550 }
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10551
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10552 if (kvm_cpu_has_injectable_intr(vcpu)) {
896046474f8d2e Wei Wang 2024-05-07 10553 r = can_inject ? kvm_x86_call(interrupt_allowed)(vcpu, true) :
896046474f8d2e Wei Wang 2024-05-07 10554 -EBUSY;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10555 if (r < 0)
a5f6909a71f922 Jim Mattson 2021-06-04 10556 goto out;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10557 if (r) {
bf672720e83cf0 Maxim Levitsky 2023-07-26 10558 int irq = kvm_cpu_get_interrupt(vcpu);
bf672720e83cf0 Maxim Levitsky 2023-07-26 10559
bf672720e83cf0 Maxim Levitsky 2023-07-26 10560 if (!WARN_ON_ONCE(irq == -1)) {
bf672720e83cf0 Maxim Levitsky 2023-07-26 10561 kvm_queue_interrupt(vcpu, irq, false);
896046474f8d2e Wei Wang 2024-05-07 10562 kvm_x86_call(inject_irq)(vcpu, false);
896046474f8d2e Wei Wang 2024-05-07 10563 WARN_ON(kvm_x86_call(interrupt_allowed)(vcpu, true) < 0);
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10564 }
bf672720e83cf0 Maxim Levitsky 2023-07-26 10565 }
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10566 if (kvm_cpu_has_injectable_intr(vcpu))
896046474f8d2e Wei Wang 2024-05-07 10567 kvm_x86_call(enable_irq_window)(vcpu);
95ba82731374eb Gleb Natapov 2009-04-21 10568 }
ee2cd4b7555e3a Paolo Bonzini 2016-06-01 10569
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10570 if (is_guest_mode(vcpu) &&
5b4ac1a1b71373 Paolo Bonzini 2022-09-21 10571 kvm_x86_ops.nested_ops->has_events &&
32f55e475ce2c4 Sean Christopherson 2024-06-07 10572 kvm_x86_ops.nested_ops->has_events(vcpu, true))
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10573 *req_immediate_exit = true;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10574
dea0d5a2fde622 Sean Christopherson 2022-09-30 10575 /*
dea0d5a2fde622 Sean Christopherson 2022-09-30 10576 * KVM must never queue a new exception while injecting an event; KVM
dea0d5a2fde622 Sean Christopherson 2022-09-30 10577 * is done emulating and should only propagate the to-be-injected event
dea0d5a2fde622 Sean Christopherson 2022-09-30 10578 * to the VMCS/VMCB. Queueing a new exception can put the vCPU into an
dea0d5a2fde622 Sean Christopherson 2022-09-30 10579 * infinite loop as KVM will bail from VM-Enter to inject the pending
dea0d5a2fde622 Sean Christopherson 2022-09-30 10580 * exception and start the cycle all over.
dea0d5a2fde622 Sean Christopherson 2022-09-30 10581 *
dea0d5a2fde622 Sean Christopherson 2022-09-30 10582 * Exempt triple faults as they have special handling and won't put the
dea0d5a2fde622 Sean Christopherson 2022-09-30 10583 * vCPU into an infinite loop. Triple fault can be queued when running
dea0d5a2fde622 Sean Christopherson 2022-09-30 10584 * VMX without unrestricted guest, as that requires KVM to emulate Real
dea0d5a2fde622 Sean Christopherson 2022-09-30 10585 * Mode events (see kvm_inject_realmode_interrupt()).
dea0d5a2fde622 Sean Christopherson 2022-09-30 10586 */
dea0d5a2fde622 Sean Christopherson 2022-09-30 10587 WARN_ON_ONCE(vcpu->arch.exception.pending ||
dea0d5a2fde622 Sean Christopherson 2022-09-30 10588 vcpu->arch.exception_vmexit.pending);
a5f6909a71f922 Jim Mattson 2021-06-04 10589 return 0;
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10590
a5f6909a71f922 Jim Mattson 2021-06-04 10591 out:
a5f6909a71f922 Jim Mattson 2021-06-04 10592 if (r == -EBUSY) {
c9d40913ac5a21 Paolo Bonzini 2020-05-22 10593 *req_immediate_exit = true;
a5f6909a71f922 Jim Mattson 2021-06-04 10594 r = 0;
a5f6909a71f922 Jim Mattson 2021-06-04 10595 }
a5f6909a71f922 Jim Mattson 2021-06-04 10596 return r;
95ba82731374eb Gleb Natapov 2009-04-21 10597 }
95ba82731374eb Gleb Natapov 2009-04-21 10598
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest
2024-08-07 0:57 [PATCH 0/6] SEV-SNP restricted injection hypervisor patches Melody Wang
` (4 preceding siblings ...)
2024-08-07 1:00 ` [PATCH 5/6] KVM: SVM: Inject MCEs " Melody Wang
@ 2024-08-07 1:00 ` Melody Wang
2024-08-07 23:49 ` Thomas Gleixner
5 siblings, 1 reply; 10+ messages in thread
From: Melody Wang @ 2024-08-07 1:00 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Tom Lendacky, Ashish Kalra,
Michael Roth, Melody Wang
Enable the restricted injection in an SEV-SNP guest by setting the restricted
injection bit in the VMSA SEV features field (SEV_FEATURES[3]) from QEMU.
Add the restricted injection supporting the hypervisor advertised features.
Co-developed-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Melody Wang <huibo.wang@amd.com>
---
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/sev-common.h | 1 +
arch/x86/kvm/svm/sev.c | 26 +++++++++++++++++++++++++-
3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index dd4682857c12..ff8466405409 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -446,6 +446,7 @@
#define X86_FEATURE_SEV_SNP (19*32+ 4) /* "sev_snp" AMD Secure Encrypted Virtualization - Secure Nested Paging */
#define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* Virtual TSC_AUX */
#define X86_FEATURE_SME_COHERENT (19*32+10) /* AMD hardware-enforced cache coherency */
+#define X86_FEATURE_RESTRICTED_INJECTION (19*32+12) /* AMD SEV Restricted Injection */
#define X86_FEATURE_DEBUG_SWAP (19*32+14) /* "debug_swap" AMD SEV-ES full debug state swap support */
#define X86_FEATURE_SVSM (19*32+28) /* "svsm" SVSM present */
diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
index 98726c2b04f8..f409893ad1a5 100644
--- a/arch/x86/include/asm/sev-common.h
+++ b/arch/x86/include/asm/sev-common.h
@@ -136,6 +136,7 @@ enum psc_op {
#define GHCB_HV_FT_SNP BIT_ULL(0)
#define GHCB_HV_FT_SNP_AP_CREATION BIT_ULL(1)
+#define GHCB_HV_FT_SNP_RINJ (BIT_ULL(2) | GHCB_HV_FT_SNP_AP_CREATION)
#define GHCB_HV_FT_SNP_MULTI_VMPL BIT_ULL(5)
/*
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 87c493bad93a..038a1c8a5ad7 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -39,7 +39,9 @@
#define GHCB_VERSION_DEFAULT 2ULL
#define GHCB_VERSION_MIN 1ULL
-#define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | GHCB_HV_FT_SNP_AP_CREATION)
+#define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | \
+ GHCB_HV_FT_SNP_AP_CREATION | \
+ GHCB_HV_FT_SNP_RINJ)
/* enable/disable SEV support */
static bool sev_enabled = true;
@@ -56,6 +58,10 @@ module_param_named(sev_snp, sev_snp_enabled, bool, 0444);
/* enable/disable SEV-ES DebugSwap support */
static bool sev_es_debug_swap_enabled = true;
module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444);
+
+/* enable/disable SEV-SNP Restricted Injection support */
+static bool sev_snp_restricted_injection_enabled = true;
+module_param_named(restricted_injection, sev_snp_restricted_injection_enabled, bool, 0444);
static u64 sev_supported_vmsa_features;
#define AP_RESET_HOLD_NONE 0
@@ -3078,6 +3084,12 @@ void __init sev_hardware_setup(void)
sev_supported_vmsa_features = 0;
if (sev_es_debug_swap_enabled)
sev_supported_vmsa_features |= SVM_SEV_FEAT_DEBUG_SWAP;
+
+ if (!sev_snp_enabled || !cpu_feature_enabled(X86_FEATURE_RESTRICTED_INJECTION))
+ sev_snp_restricted_injection_enabled = false;
+
+ if (sev_snp_restricted_injection_enabled)
+ sev_supported_vmsa_features |= SVM_SEV_FEAT_RESTRICTED_INJECTION;
}
void sev_hardware_unsetup(void)
@@ -4555,6 +4567,15 @@ void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm)
sev_es_vcpu_after_set_cpuid(svm);
}
+static void sev_snp_init_vmcb(struct vcpu_svm *svm)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(svm->vcpu.kvm)->sev_info;
+
+ /* V_NMI is not supported when Restricted Injection is enabled */
+ if (sev->vmsa_features & SVM_SEV_FEAT_RESTRICTED_INJECTION)
+ svm->vmcb->control.int_ctl &= ~V_NMI_ENABLE_MASK;
+}
+
static void sev_es_init_vmcb(struct vcpu_svm *svm)
{
struct vmcb *vmcb = svm->vmcb01.ptr;
@@ -4612,6 +4633,9 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm)
/* Clear intercepts on selected MSRs */
set_msr_interception(vcpu, svm->msrpm, MSR_EFER, 1, 1);
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_CR_PAT, 1, 1);
+
+ if (sev_snp_guest(vcpu->kvm))
+ sev_snp_init_vmcb(svm);
}
void sev_init_vmcb(struct vcpu_svm *svm)
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest
2024-08-07 1:00 ` [PATCH 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest Melody Wang
@ 2024-08-07 23:49 ` Thomas Gleixner
0 siblings, 0 replies; 10+ messages in thread
From: Thomas Gleixner @ 2024-08-07 23:49 UTC (permalink / raw)
To: Melody Wang, kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, Ingo Molnar, Borislav Petkov,
Dave Hansen, Tom Lendacky, Ashish Kalra, Michael Roth,
Melody Wang
On Wed, Aug 07 2024 at 01:00, Melody Wang wrote:
> diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
> index dd4682857c12..ff8466405409 100644
> --- a/arch/x86/include/asm/cpufeatures.h
> +++ b/arch/x86/include/asm/cpufeatures.h
> @@ -446,6 +446,7 @@
> #define X86_FEATURE_SEV_SNP (19*32+ 4) /* "sev_snp" AMD Secure Encrypted Virtualization - Secure Nested Paging */
> #define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* Virtual TSC_AUX */
> #define X86_FEATURE_SME_COHERENT (19*32+10) /* AMD hardware-enforced cache coherency */
> +#define X86_FEATURE_RESTRICTED_INJECTION (19*32+12) /* AMD SEV Restricted Injection */
Please update the XML for this CPUID leaf at:
https://gitlab.com/x86-cpuid.org/x86-cpuid-db
Thanks,
tglx
^ permalink raw reply [flat|nested] 10+ messages in thread