* [PATCH 0/6] SEV-SNP restricted injection hypervisor patches
@ 2024-08-07 0:57 Melody Wang
2024-08-07 0:57 ` [PATCH 1/6] x86/sev: Define the #HV doorbell page structure Melody Wang
` (5 more replies)
0 siblings, 6 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
Operating systems may not handle unexpected interrupt or exception sequences.
A malicious hypervisor can inject random interrupt or exception sequences,
putting guest drivers or guest OS kernels into an unexpected state, which could
lead to security issues.
To address this concern, SEV-SNP restricts the injection of interrupts and
exceptions to those only allowed by the guest. Restricted Injection disables
all hypervisor-based interrupt queuing and event injection for all vectors,
allowing only a single vector, #HV (28), which is reserved for SNP guest use
but is never generated by hardware. #HV is only permitted to be injected into
VMSAs that execute with Restricted Injection.
Guests operating with Restricted Injection are expected to communicate with the
hypervisor about events via a software-managed para-virtualization interface.
This interface can utilize #HV injection as a doorbell to inform the guest that
new events have occurred. This patch set implements Restricted Injection on the
KVM side directly into VMPL0.
Overview:
The GHCB 2.0 specification[1] defines #HV doorbell page and the #HV doorbell
page NAE event allows for an SEV-SNP guest to register a doorbell page for use
with the hypervisor injection exception (#HV). When Restricted Injection is
active, only #HV exceptions can be injected into the guest, and the hypervisor
follows the GHCB #HV doorbell communication to inject the exception or
interrupt. Restricted Injection can be enabled by setting the bit in
vmsa_features.
The patchset is rebased on the kvm/next (commit 1773014a975919195be71646fc2c2cad1570fce4).
Testing:
The patchset has been tested with the sev-snp guest, ovmf and qemu supporting
restricted injection.
Four test sets:
1.ls -lr /
2.apt update
3.fio
4.perf
Thanks
Melody
Melody Wang (6):
x86/sev: Define the #HV doorbell page structure
KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event
KVM: SVM: Inject #HV when restricted injection is active
KVM: SVM: Inject NMIs when restricted injection is active
KVM: SVM: Inject MCEs when restricted injection is active
KVM: SVM: Enable restricted injection for an SEV-SNP guest
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/kvm-x86-ops.h | 1 +
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/include/asm/sev-common.h | 1 +
arch/x86/include/asm/svm.h | 41 +++++
arch/x86/include/uapi/asm/kvm.h | 1 +
arch/x86/include/uapi/asm/svm.h | 5 +
arch/x86/kvm/svm/sev.c | 277 ++++++++++++++++++++++++++++-
arch/x86/kvm/svm/svm.c | 44 ++++-
arch/x86/kvm/svm/svm.h | 26 ++-
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 +
14 files changed, 407 insertions(+), 5 deletions(-)
--
2.34.1
[1] https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf
^ permalink raw reply [flat|nested] 10+ messages in thread
* [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
* [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 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
* 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
end of thread, other threads:[~2024-08-07 23:49 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 3/6] KVM: SVM: Inject #HV when restricted injection is active Melody Wang
2024-08-07 0:57 ` [PATCH 4/6] KVM: SVM: Inject NMIs " 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 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
2024-08-07 23:49 ` Thomas Gleixner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).