* [PATCH v2 1/6] x86/sev: Define the #HV doorbell page structure
2024-09-10 6:03 [PATCH v2 0/6] Add SEV-SNP restricted injection hypervisor support Melody Wang
@ 2024-09-10 6:03 ` Melody Wang
2024-09-10 6:03 ` [PATCH v2 2/6] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Melody Wang
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Melody Wang @ 2024-09-10 6:03 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, 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] 9+ messages in thread* [PATCH v2 2/6] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event
2024-09-10 6:03 [PATCH v2 0/6] Add SEV-SNP restricted injection hypervisor support Melody Wang
2024-09-10 6:03 ` [PATCH v2 1/6] x86/sev: Define the #HV doorbell page structure Melody Wang
@ 2024-09-10 6:03 ` Melody Wang
2024-09-10 6:03 ` [PATCH v2 3/6] KVM: SVM: Inject #HV when restricted injection is active Melody Wang
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Melody Wang @ 2024-09-10 6:03 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, 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 714c517dd4b7..e65867ea768d 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -3410,6 +3410,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;
@@ -4125,6 +4129,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;
@@ -4405,6 +4469,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",
@@ -4572,6 +4644,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] 9+ messages in thread* [PATCH v2 3/6] KVM: SVM: Inject #HV when restricted injection is active
2024-09-10 6:03 [PATCH v2 0/6] Add SEV-SNP restricted injection hypervisor support Melody Wang
2024-09-10 6:03 ` [PATCH v2 1/6] x86/sev: Define the #HV doorbell page structure Melody Wang
2024-09-10 6:03 ` [PATCH v2 2/6] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Melody Wang
@ 2024-09-10 6:03 ` Melody Wang
2024-09-22 21:56 ` Lai Jiangshan
2024-09-10 6:03 ` [PATCH v2 4/6] KVM: SVM: Inject NMIs " Melody Wang
` (2 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Melody Wang @ 2024-09-10 6:03 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, 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 e65867ea768d..f7623fa64307 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5023,3 +5023,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] 9+ messages in thread* Re: [PATCH v2 3/6] KVM: SVM: Inject #HV when restricted injection is active
2024-09-10 6:03 ` [PATCH v2 3/6] KVM: SVM: Inject #HV when restricted injection is active Melody Wang
@ 2024-09-22 21:56 ` Lai Jiangshan
0 siblings, 0 replies; 9+ messages in thread
From: Lai Jiangshan @ 2024-09-22 21:56 UTC (permalink / raw)
To: Melody Wang
Cc: kvm, linux-kernel, x86, Sean Christopherson, Paolo Bonzini,
Tom Lendacky, Ashish Kalra, Michael Roth
Hello
On Tue, Sep 10, 2024 at 2:05 PM Melody Wang <huibo.wang@amd.com> wrote:
> +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;
old_vector = hvdb->events.vector;
> +
> + hvdb->events.vector = vcpu->arch.interrupt.nr;
> +
> + prepare_hv_injection(svm, hvdb);
The specification recommends saving an HV injection on the following condition:
if (!(type == INJECT_IRQ && old_vector))
prepare_hv_injection(svm, hvdb)
If PendingEvent.Vector was previously non-zero, because the guest has
not yet chosen to acknowledge the interrupt, the previous vector
number can be overwritten by the new vector number without sending
another #HV (regardless of the value of PendingEvent.NoFurtherSignal),
because the guest should already have been informed that a vector was
pending.
> +
> + unmap_hvdb(vcpu, &hvdb_map);
> +
> + return true;
> +}
> +
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 4/6] KVM: SVM: Inject NMIs when restricted injection is active
2024-09-10 6:03 [PATCH v2 0/6] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (2 preceding siblings ...)
2024-09-10 6:03 ` [PATCH v2 3/6] KVM: SVM: Inject #HV when restricted injection is active Melody Wang
@ 2024-09-10 6:03 ` Melody Wang
2024-09-10 6:03 ` [PATCH v2 5/6] KVM: SVM: Inject MCEs " Melody Wang
2024-09-10 6:03 ` [PATCH v2 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest Melody Wang
5 siblings, 0 replies; 9+ messages in thread
From: Melody Wang @ 2024-09-10 6:03 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, 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 f7623fa64307..9102f7e39c52 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5070,7 +5070,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);
@@ -5148,10 +5151,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:
@@ -5169,8 +5179,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] 9+ messages in thread* [PATCH v2 5/6] KVM: SVM: Inject MCEs when restricted injection is active
2024-09-10 6:03 [PATCH v2 0/6] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (3 preceding siblings ...)
2024-09-10 6:03 ` [PATCH v2 4/6] KVM: SVM: Inject NMIs " Melody Wang
@ 2024-09-10 6:03 ` Melody Wang
2024-09-22 22:01 ` Lai Jiangshan
2024-09-10 6:03 ` [PATCH v2 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest Melody Wang
5 siblings, 1 reply; 9+ messages in thread
From: Melody Wang @ 2024-09-10 6:03 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, 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 | 8 ++++++++
9 files changed, 50 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 9102f7e39c52..0b898b16026b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5072,6 +5072,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;
@@ -5089,6 +5091,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,
@@ -5153,7 +5160,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 |
@@ -5162,6 +5169,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:
@@ -5179,9 +5189,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 70219e406987..2007598af873 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10485,6 +10485,12 @@ 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;
@@ -10493,6 +10499,8 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
can_inject = false;
}
+out_except:
+
/* Don't inject interrupts if the user asked to avoid doing so */
if (vcpu->guest_debug & KVM_GUESTDBG_BLOCKIRQ)
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 5/6] KVM: SVM: Inject MCEs when restricted injection is active
2024-09-10 6:03 ` [PATCH v2 5/6] KVM: SVM: Inject MCEs " Melody Wang
@ 2024-09-22 22:01 ` Lai Jiangshan
0 siblings, 0 replies; 9+ messages in thread
From: Lai Jiangshan @ 2024-09-22 22:01 UTC (permalink / raw)
To: Melody Wang
Cc: kvm, linux-kernel, x86, Sean Christopherson, Paolo Bonzini,
Tom Lendacky, Ashish Kalra, Michael Roth
Hello
On Tue, Sep 10, 2024 at 2:06 PM Melody Wang <huibo.wang@amd.com> wrote:
> @@ -5153,7 +5160,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
> */
This comment seems ambiguous, and in the following code,
events.nmi/mce/vector appears to be able to be true simultaneously,
rather than being mutually exclusive.
> if (hvdb->events.vector)
> svm->vmcb->control.event_inj |= hvdb->events.vector |
> @@ -5162,6 +5169,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;
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 6/6] KVM: SVM: Enable restricted injection for an SEV-SNP guest
2024-09-10 6:03 [PATCH v2 0/6] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (4 preceding siblings ...)
2024-09-10 6:03 ` [PATCH v2 5/6] KVM: SVM: Inject MCEs " Melody Wang
@ 2024-09-10 6:03 ` Melody Wang
5 siblings, 0 replies; 9+ messages in thread
From: Melody Wang @ 2024-09-10 6:03 UTC (permalink / raw)
To: kvm, linux-kernel, x86
Cc: Sean Christopherson, Paolo Bonzini, 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 0b898b16026b..bad50378c898 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
@@ -3079,6 +3085,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)
@@ -4556,6 +4568,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;
@@ -4613,6 +4634,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] 9+ messages in thread