* [RFC PATCH v5 1/8] x86/sev: Define the #HV doorbell page structure
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 2/8] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Melody Wang
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
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 | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index aa63431ba92c..3b77eaac3d07 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -253,6 +253,39 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
#define SVM_TSC_RATIO_MAX 0x000000ffffffffffULL
#define SVM_TSC_RATIO_DEFAULT 0x0100000000ULL
+/*
+ * 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 {
+ /* Non-maskable event indicators */
+ u16 vector: 8,
+ nmi: 1,
+ mce: 1,
+ reserved2: 5,
+ no_further_signal: 1;
+ };
+
+ u16 pending_events;
+ };
+
+ u8 no_eoi_required;
+
+ u8 reserved3[61];
+} __packed;
+
+struct hvdb {
+ struct hvdb_events events;
+
+ /* Remainder of the page is for software use */
+ u8 reserved[PAGE_SIZE - sizeof(struct hvdb_events)];
+} __packed;
/* AVIC */
#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFFULL)
@@ -569,6 +602,8 @@ static inline void __unused_size_checks(void)
BUILD_BUG_ON(sizeof(struct vmcb_control_area) != EXPECTED_VMCB_CONTROL_AREA_SIZE);
BUILD_BUG_ON(offsetof(struct vmcb, save) != EXPECTED_VMCB_CONTROL_AREA_SIZE);
BUILD_BUG_ON(sizeof(struct ghcb) != EXPECTED_GHCB_SIZE);
+ BUILD_BUG_ON(sizeof(struct hvdb_events) != 64);
+ BUILD_BUG_ON(sizeof(struct hvdb) != 4096);
/* Check offsets of reserved fields */
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v5 2/8] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 1/8] x86/sev: Define the #HV doorbell page structure Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 3/8] KVM: SVM: Inject #HV when Restricted Injection is active Melody Wang
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
To support Restricted Injection, the SEV-SNP guest must register
a doorbell page for use with #HV.
The #HV doorbell page NAE event allows the guest to register a doorbell
page. This event consists of four actions: GET_PREFERRED, SET, QUERY,
CLEAR. Implement it per the 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 | 68 +++++++++++++++++++++++++++++++++
arch/x86/kvm/svm/svm.c | 3 ++
arch/x86/kvm/svm/svm.h | 2 +
4 files changed, 78 insertions(+)
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index 010a45c9f614..d84a13ac4627 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -117,6 +117,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 0x80000014ull
+#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 0x80000018ull
#define SVM_VMGEXIT_SAVIC 0x8000001aull
#define SVM_VMGEXIT_SAVIC_REGISTER_GPA 0
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 5705723f1f41..da07fe476f3d 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -4346,6 +4346,68 @@ 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)) {
+ vcpu_unimpl(vcpu, "vmgexit: error mapping #HV doorbell page [%#llx] from guest\n",
+ hvdb_gpa);
+ return -EINVAL;
+ }
+ kvm_vcpu_unmap(vcpu, &hvdb_map);
+
+ svm->sev_es.hvdb_gpa = hvdb_gpa;
+ fallthrough;
+ case SVM_VMGEXIT_HVDB_QUERY:
+ if (svm->sev_es.hvdb_gpa == INVALID_PAGE)
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, 0);
+ else
+ 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;
@@ -4497,6 +4559,7 @@ static bool is_snp_only_vmgexit(u64 exit_code)
case SVM_VMGEXIT_GUEST_REQUEST:
case SVM_VMGEXIT_EXT_GUEST_REQUEST:
case SVM_VMGEXIT_PSC:
+ case SVM_VMGEXIT_HVDB_PAGE:
return true;
default:
return false;
@@ -4680,6 +4743,11 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
return snp_handle_ext_guest_req(svm, control->exit_info_1,
control->exit_info_2);
+ case SVM_VMGEXIT_HVDB_PAGE:
+ if (sev_snp_hv_doorbell_page(svm))
+ svm_vmgexit_bad_input(svm, GHCB_ERR_INVALID_INPUT);
+
+ return 1;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
/*
* Note, the _guest_ is reporting an unsupported #VC, i.e. this
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 7d59d301e1e5..da7abf0c39fe 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1291,6 +1291,9 @@ static void __svm_vcpu_reset(struct kvm_vcpu *vcpu)
svm->nmi_masked = false;
svm->awaiting_iret_completion = false;
+
+ if (is_sev_snp_guest(vcpu))
+ svm->sev_es.hvdb_gpa = INVALID_PAGE;
}
static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index e958943b8162..f212f2e68d87 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -276,6 +276,8 @@ struct vcpu_sev_es_state {
gpa_t snp_guest_vmsa_gpa;
bool snp_ap_waiting_for_reset;
bool snp_has_guest_vmsa;
+
+ gpa_t hvdb_gpa;
};
struct vcpu_svm {
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v5 3/8] KVM: SVM: Inject #HV when Restricted Injection is active
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 1/8] x86/sev: Define the #HV doorbell page structure Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 2/8] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 4/8] KVM: SVM: Inject NMIs " Melody Wang
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
When Restricted Injection is active, only #HV exceptions can be injected
into the SEV-SNP guest.
Detect that, 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/asm/kvm-x86-ops.h | 1 +
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/i8259.c | 45 +++--
arch/x86/kvm/irq.c | 51 +++++-
arch/x86/kvm/irq.h | 3 +
arch/x86/kvm/lapic.c | 34 +++-
arch/x86/kvm/lapic.h | 1 +
arch/x86/kvm/svm/sev.c | 253 +++++++++++++++++++++++++++++
arch/x86/kvm/svm/svm.c | 24 ++-
arch/x86/kvm/svm/svm.h | 28 ++++
10 files changed, 421 insertions(+), 21 deletions(-)
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index e213c9ae3e30..2074c2050c55 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -96,6 +96,7 @@ KVM_X86_OP_OPTIONAL_RET0(set_tss_addr)
KVM_X86_OP_OPTIONAL_RET0(set_identity_map_addr)
KVM_X86_OP_OPTIONAL_RET0(get_mt_mask)
KVM_X86_OP_OPTIONAL_RET0(tdp_has_smep)
+KVM_X86_OP_OPTIONAL_RET0(is_noack_required)
KVM_X86_OP(load_mmu_pgd)
KVM_X86_OP_OPTIONAL_RET0(set_external_spte)
KVM_X86_OP_OPTIONAL(free_external_spt)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 3af7395c2430..4de443140c53 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1618,7 +1618,7 @@ struct kvm_x86_ops {
void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
-
+ bool (*is_noack_required)(struct kvm_vcpu *vcpu);
const bool x2apic_icr_is_split;
const unsigned long required_apicv_inhibits;
bool allow_apicv_in_x2apic_without_x2apic_virtualization;
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 6a942ac622d5..63853a612a83 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -229,7 +229,7 @@ static inline void pic_intack(struct kvm_kpic_state *s, int irq)
}
-int kvm_pic_read_irq(struct kvm *kvm)
+static int __kvm_pic_read_irq(struct kvm *kvm, unsigned int *pending, bool ack)
{
int irq, irq2, intno;
struct kvm_pic *s = kvm->arch.vpic;
@@ -239,32 +239,57 @@ int kvm_pic_read_irq(struct kvm *kvm)
pic_lock(s);
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
- pic_intack(&s->pics[0], irq);
+ if (ack)
+ pic_intack(&s->pics[0], irq);
if (irq == 2) {
irq2 = pic_get_irq(&s->pics[1]);
- if (irq2 >= 0)
- pic_intack(&s->pics[1], irq2);
- else
+ if (irq2 >= 0) {
+ if (ack)
+ pic_intack(&s->pics[1], irq2);
+ intno = s->pics[1].irq_base + irq2;
+ } else {
/*
* spurious IRQ on slave controller
*/
- irq2 = 7;
- intno = s->pics[1].irq_base + irq2;
+ if (ack) {
+ irq2 = 7;
+ intno = s->pics[1].irq_base + irq2;
+ } else {
+ intno = -1;
+ }
+ }
} else
intno = s->pics[0].irq_base + irq;
} else {
/*
* spurious IRQ on host controller
*/
- irq = 7;
- intno = s->pics[0].irq_base + irq;
+ if (ack) {
+ irq = 7;
+ intno = s->pics[0].irq_base + irq;
+ } else {
+ intno = -1;
+ }
}
- pic_update_irq(s);
+
+ if (ack)
+ pic_update_irq(s);
+ else
+ *pending = hweight8(s->pics[0].irr) + hweight8(s->pics[1].irr);
pic_unlock(s);
return intno;
}
+int kvm_pic_read_irq(struct kvm *kvm)
+{
+ return __kvm_pic_read_irq(kvm, 0, true);
+}
+int kvm_pic_read_irq_noack(struct kvm *kvm, unsigned int *pending)
+{
+ return __kvm_pic_read_irq(kvm, pending, false);
+}
+
static void kvm_pic_reset(struct kvm_kpic_state *s)
{
int irq;
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 871977288272..061a6fee9261 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -125,7 +125,7 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_has_interrupt);
* Read pending interrupt(from non-APIC source)
* vector and intack.
*/
-int kvm_cpu_get_extint(struct kvm_vcpu *v)
+static int __kvm_cpu_get_extint(struct kvm_vcpu *v, unsigned int *pending, bool ack)
{
if (!kvm_cpu_has_extint(v)) {
WARN_ON(!lapic_in_kernel(v));
@@ -141,31 +141,68 @@ int kvm_cpu_get_extint(struct kvm_vcpu *v)
#endif
#ifdef CONFIG_KVM_IOAPIC
- if (pic_in_kernel(v->kvm))
- return kvm_pic_read_irq(v->kvm); /* PIC */
+ if (pic_in_kernel(v->kvm)) {
+ if (ack)
+ return kvm_pic_read_irq(v->kvm); /* PIC */
+ else
+ return kvm_pic_read_irq_noack(v->kvm, pending); /* PIC */
+ }
#endif
WARN_ON_ONCE(!irqchip_split(v->kvm));
return get_userspace_extint(v);
}
+
+int kvm_cpu_get_extint(struct kvm_vcpu *v)
+{
+ return __kvm_cpu_get_extint(v, 0, true);
+}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_get_extint);
+int kvm_cpu_get_extint_noack(struct kvm_vcpu *v, unsigned int *pending)
+{
+ return __kvm_cpu_get_extint(v, pending, false);
+}
/*
* Read pending interrupt vector and intack.
*/
-int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
+static int __kvm_cpu_get_interrupt(struct kvm_vcpu *v, unsigned int *pending, bool ack)
{
- int vector = kvm_cpu_get_extint(v);
+ int vector;
+
+ if (ack)
+ vector = kvm_cpu_get_extint(v);
+ else
+ vector = kvm_cpu_get_extint_noack(v, pending);
if (vector != -1)
return vector; /* PIC */
- vector = kvm_apic_has_interrupt(v); /* APIC */
- if (vector != -1)
+ if (ack)
+ vector = kvm_apic_has_interrupt(v); /* APIC */
+ else
+ vector = kvm_apic_has_interrupt_noack(v, pending); /* APIC */
+
+ if (ack && vector != -1)
kvm_apic_ack_interrupt(v, vector);
return vector;
}
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
+{
+ bool ack = kvm_x86_call(is_noack_required)(v) ? false : true;
+
+ return __kvm_cpu_get_interrupt(v, 0, ack);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_get_interrupt);
+
+int kvm_cpu_get_interrupt_noack(struct kvm_vcpu *v, unsigned int *pending)
+{
+
+ return __kvm_cpu_get_interrupt(v, pending, false);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_get_interrupt_noack);
+
void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
{
if (lapic_in_kernel(vcpu))
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index a74f03858004..2e917d089f1e 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -64,6 +64,7 @@ struct kvm_pic {
int kvm_pic_init(struct kvm *kvm);
void kvm_pic_destroy(struct kvm *kvm);
int kvm_pic_read_irq(struct kvm *kvm);
+int kvm_pic_read_irq_noack(struct kvm *kvm, unsigned int *pending);
void kvm_pic_update_irq(struct kvm_pic *s);
int kvm_pic_set_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
int irq_source_id, int level, bool line_status);
@@ -116,7 +117,9 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v);
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_cpu_has_extint(struct kvm_vcpu *v);
int kvm_cpu_get_extint(struct kvm_vcpu *v);
+int kvm_cpu_get_extint_noack(struct kvm_vcpu *v, unsigned int *pending);
int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_get_interrupt_noack(struct kvm_vcpu *v, unsigned int *pending);
static inline void kvm_warn_on_lost_irq(struct kvm_vcpu *vcpu)
{
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index e1f3cea14765..037a4599d6f1 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -757,6 +757,23 @@ void kvm_apic_clear_irr(struct kvm_vcpu *vcpu, int vec)
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_clear_irr);
+static unsigned int apic_count_irr(struct kvm_lapic *apic)
+{
+ unsigned int count = 0;
+ u32 reg;
+
+ if (!apic->irr_pending)
+ return 0;
+
+ for (int i = 1; i < 8; i++) {
+ reg = kvm_lapic_get_reg(apic, APIC_IRR + i * 0x10);
+ if (reg)
+ count += hweight32(reg);
+ }
+
+ return count;
+}
+
static void *apic_vector_to_isr(int vec, struct kvm_lapic *apic)
{
return apic->regs + APIC_ISR + APIC_VECTOR_TO_REG_OFFSET(vec);
@@ -3172,7 +3189,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
return -ENOMEM;
}
-int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
+static int __kvm_apic_has_interrupt(struct kvm_vcpu *vcpu, unsigned int *pending, bool ack)
{
struct kvm_lapic *apic = vcpu->arch.apic;
u32 ppr;
@@ -3183,11 +3200,26 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
if (apic->guest_apic_protected)
return -1;
+ if (!ack) {
+ *pending = apic_count_irr(apic);
+ return apic_search_irr(apic);
+
__apic_update_ppr(apic, &ppr);
return apic_has_interrupt_for_ppr(apic, ppr);
}
+
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
+{
+ return __kvm_apic_has_interrupt(vcpu, 0, true);
+}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_has_interrupt);
+int kvm_apic_has_interrupt_noack(struct kvm_vcpu *vcpu, unsigned int *pending)
+{
+ return __kvm_apic_has_interrupt(vcpu, pending, false);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_has_interrupt_noack);
+
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
{
u32 lvt0 = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LVT0);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index bd1098c89d99..8530a6333bdd 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -127,6 +127,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);
void kvm_free_lapic(struct kvm_vcpu *vcpu);
int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
+int kvm_apic_has_interrupt_noack(struct kvm_vcpu *vcpu, unsigned int *pending);
void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector);
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
int kvm_apic_accept_events(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index da07fe476f3d..e4a074df7434 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -36,6 +36,8 @@
#include "svm_ops.h"
#include "cpuid.h"
#include "trace.h"
+#include "lapic.h"
+#include "irq.h"
#define GHCB_VERSION_MAX 2ULL
#define GHCB_VERSION_MIN 1ULL
@@ -4387,6 +4389,8 @@ static int sev_snp_hv_doorbell_page(struct vcpu_svm *svm)
kvm_vcpu_unmap(vcpu, &hvdb_map);
svm->sev_es.hvdb_gpa = hvdb_gpa;
+ svm->sev_es.pending_vector = 0;
+ svm->sev_es.no_eoi_required = 0;
fallthrough;
case SVM_VMGEXIT_HVDB_QUERY:
if (svm->sev_es.hvdb_gpa == INVALID_PAGE)
@@ -4396,6 +4400,8 @@ static int sev_snp_hv_doorbell_page(struct vcpu_svm *svm)
break;
case SVM_VMGEXIT_HVDB_CLEAR:
svm->sev_es.hvdb_gpa = INVALID_PAGE;
+ svm->sev_es.pending_vector = 0;
+ svm->sev_es.no_eoi_required = 0;
break;
default:
svm->sev_es.hvdb_gpa = INVALID_PAGE;
@@ -5474,3 +5480,250 @@ void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa)
free_page((unsigned long)vmsa);
}
+
+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);
+}
+
+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)) {
+ vcpu_unimpl(vcpu, "snp: error mapping #HV doorbell page [%#llx] from guest\n",
+ svm->sev_es.hvdb_gpa);
+
+ return NULL;
+ }
+
+ return map->hva;
+}
+
+void sev_snp_handle_ri_ack(struct kvm_vcpu *vcpu, struct hvdb *hvdb, int num_pending)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ /* Guest ack interrupt, move it from irr to isr */
+ if (svm->sev_es.pending_vector && !hvdb->events.vector) {
+ kvm_apic_ack_interrupt(vcpu, svm->sev_es.pending_vector);
+ svm->sev_es.pending_vector = 0;
+ }
+
+ /*
+ * no_eoi_required was set last time, means maybe an EOI is pending for the
+ * interrupt it was just acked by the guest, if the guest cleared
+ * no_eoi_requirement that means guest will not wrmsr EOI but let the hypervisor
+ * send a EOI for it, this way, the VMEXIT which is expensive is saved.
+ */
+ if (svm->sev_es.no_eoi_required &&
+ !hvdb->events.no_eoi_required &&
+ !svm->sev_es.pending_vector) {
+ kvm_lapic_set_eoi(vcpu);
+ svm->sev_es.no_eoi_required = 0;
+ }
+ /*
+ * If there is only one interrupt pending in IRR, no_eoi_required should be set,
+ * and the host should record it. If there is multiple interrupt pending in IRR,
+ * no_eoi_required should not be set since some interrupts need to be delovered
+ * immediately.
+ */
+ if (num_pending == 1) {
+ hvdb->events.no_eoi_required = 1;
+ svm->sev_es.no_eoi_required = 1;
+ } else {
+ hvdb->events.no_eoi_required = 0;
+ svm->sev_es.no_eoi_required = 0;
+ }
+}
+
+static void __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) {
+ WARN_ONCE(1, "Restricted Injection enabled, hvdb page mapping failed\n");
+ return;
+ }
+
+ hvdb->events.vector = vcpu->arch.interrupt.nr;
+ svm->sev_es.pending_vector = vcpu->arch.interrupt.nr;
+
+ prepare_hv_injection(svm, hvdb);
+
+ unmap_hvdb(vcpu, &hvdb_map);
+}
+
+static void __sev_snp_reinject(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) {
+ WARN_ONCE(1, "Restricted Injection enabled, hvdb page mapping failed\n");
+ return;
+ }
+
+ prepare_hv_injection(svm, hvdb);
+
+ unmap_hvdb(vcpu, &hvdb_map);
+}
+
+
+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 vector %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)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!sev_snp_is_rinj_active(vcpu))
+ return false;
+
+ if (svm->sev_es.cancel_flag) {
+ __sev_snp_reinject(vcpu);
+ svm->sev_es.cancel_flag = false;
+ return true;
+ }
+
+ __sev_snp_inject(type, vcpu);
+
+ return true;
+}
+
+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 (WARN_ONCE((svm->vmcb->control.event_inj & SVM_EVTINJ_VEC_MASK) != HV_VECTOR,
+ "Restricted Injection enabled, %u vector not supported\n",
+ svm->vmcb->control.event_inj & SVM_EVTINJ_VEC_MASK))
+ 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.no_further_signal = 0;
+ svm->sev_es.cancel_flag = true;
+
+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;
+ int irq;
+
+ /* 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 */
+ if (type == INJECT_IRQ) {
+ irq = kvm_cpu_get_interrupt(vcpu);
+ if (irq < hvdb->events.vector && hvdb->events.vector)
+ blocked = !!hvdb->events.vector;
+ else
+ blocked = false;
+ }
+
+ unmap_hvdb(vcpu, &hvdb_map);
+
+ return blocked;
+}
+
+void sev_snp_update_ri_status(struct kvm_vcpu *vcpu)
+{
+ struct kvm_host_map hvdb_map;
+ struct hvdb *hvdb;
+ unsigned int num_pending;
+
+ if (!sev_snp_is_rinj_active(vcpu))
+ return;
+
+ hvdb = map_hvdb(vcpu, &hvdb_map);
+ if (!hvdb)
+ return;
+
+ kvm_cpu_get_interrupt_noack(vcpu, &num_pending);
+ sev_snp_handle_ri_ack(vcpu, hvdb, num_pending);
+
+ unmap_hvdb(vcpu, &hvdb_map);
+}
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index da7abf0c39fe..601807a8f2fa 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -397,6 +397,9 @@ static void svm_inject_exception(struct kvm_vcpu *vcpu)
svm_update_soft_interrupt_rip(vcpu, ex->vector))
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)
@@ -3875,9 +3878,11 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected)
}
trace_kvm_inj_virq(intr->nr, intr->soft, reinjected);
- ++vcpu->stat.irq_injections;
- svm->vmcb->control.event_inj = intr->nr | SVM_EVTINJ_VALID | type;
+ if (!sev_snp_inject(INJECT_IRQ, vcpu))
+ svm->vmcb->control.event_inj = intr->nr | SVM_EVTINJ_VALID | type;
+
+ ++vcpu->stat.irq_injections;
}
static void svm_fixup_nested_rips(struct kvm_vcpu *vcpu)
@@ -4052,6 +4057,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)
@@ -4090,6 +4098,14 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
return 1;
}
+static bool svm_is_noack_required(struct kvm_vcpu *vcpu)
+{
+ if (!sev_snp_is_rinj_active(vcpu))
+ return false;
+
+ return true;
+}
+
static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -4415,6 +4431,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;
@@ -4646,6 +4664,7 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
svm_complete_interrupts(vcpu);
+ sev_snp_update_ri_status(vcpu);
/*
* Update the cache after completing interrupts to get an accurate
* NextRIP, e.g. when re-injecting a soft interrupt.
@@ -5407,6 +5426,7 @@ struct kvm_x86_ops svm_x86_ops __initdata = {
.enable_nmi_window = svm_enable_nmi_window,
.enable_irq_window = svm_enable_irq_window,
.update_cr8_intercept = svm_update_cr8_intercept,
+ .is_noack_required = svm_is_noack_required,
.x2apic_icr_is_split = true,
.set_virtual_apic_mode = avic_refresh_virtual_apic_mode,
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index f212f2e68d87..f0db48d62fcf 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -58,6 +58,10 @@ extern int tsc_aux_uret_slot __ro_after_init;
extern struct kvm_x86_ops svm_x86_ops __initdata;
+enum inject_type {
+ INJECT_IRQ,
+};
+
/*
* Clean bits in VMCB.
* VMCB_ALL_CLEAN_MASK might also need to
@@ -278,6 +282,9 @@ struct vcpu_sev_es_state {
bool snp_has_guest_vmsa;
gpa_t hvdb_gpa;
+ u8 pending_vector;
+ u8 no_eoi_required;
+ bool cancel_flag;
};
struct vcpu_svm {
@@ -1019,6 +1026,19 @@ void sev_gmem_invalidate_range(struct kvm *kvm, struct kvm_gfn_range *range);
int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private);
struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu);
void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa);
+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);
+void sev_snp_update_ri_status(struct kvm_vcpu *vcpu);
+void sev_snp_handle_ri_ack(struct kvm_vcpu *vcpu, struct hvdb *hvdb, int num_pending);
+static inline bool sev_snp_is_rinj_active(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sev_info *sev = to_kvm_sev_info(vcpu->kvm);
+
+ return is_sev_snp_guest(vcpu) &&
+ (sev->vmsa_features & SVM_SEV_FEAT_RESTRICTED_INJECTION);
+};
#else
static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
{
@@ -1046,6 +1066,14 @@ static inline struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu)
return NULL;
}
static inline void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa) {}
+
+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 void sev_snp_update_ri_status(struct kvm_vcpu *vcpu)i {};
+static inline void sev_snp_handle_ri_ack(struct kvm_vcpu *vcpu, struct hvdb *hvdb, int num_pending) {};
+static inline bool sev_snp_is_rinj_active(struct kvm_vcpu *vcpu) { return false; }
#endif
/* vmenter.S */
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v5 4/8] KVM: SVM: Inject NMIs when Restricted Injection is active
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (2 preceding siblings ...)
2026-11-09 3:18 ` [RFC PATCH v5 3/8] KVM: SVM: Inject #HV when Restricted Injection is active Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 5/8] KVM: SVM: Inject MCEs " Melody Wang
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
When Restricted Injection is active, only #HV exceptions can be injected
into the SEV-SNP guest.
Detect that, 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 | 14 +++++++++++---
arch/x86/kvm/svm/svm.c | 8 ++++++++
arch/x86/kvm/svm/svm.h | 1 +
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index e4a074df7434..f80dfd876d5e 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5565,8 +5565,12 @@ static void __sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
return;
}
- hvdb->events.vector = vcpu->arch.interrupt.nr;
- svm->sev_es.pending_vector = vcpu->arch.interrupt.nr;
+ if (type == INJECT_NMI) {
+ hvdb->events.nmi = 1;
+ } else if (type == INJECT_IRQ) {
+ hvdb->events.vector = vcpu->arch.interrupt.nr;
+ svm->sev_es.pending_vector = vcpu->arch.interrupt.nr;
+ }
prepare_hv_injection(svm, hvdb);
@@ -5675,6 +5679,8 @@ void sev_snp_cancel_injection(struct kvm_vcpu *vcpu)
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.no_further_signal = 0;
svm->sev_es.cancel_flag = true;
@@ -5696,7 +5702,9 @@ bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)
return true;
/* Indicate interrupts blocked based on guest acknowledgment */
- if (type == INJECT_IRQ) {
+ if (type == INJECT_NMI)
+ blocked = hvdb->events.nmi;
+ else if (type == INJECT_IRQ) {
irq = kvm_cpu_get_interrupt(vcpu);
if (irq < hvdb->events.vector && hvdb->events.vector)
blocked = !!hvdb->events.vector;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 601807a8f2fa..75e86592f1c9 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3795,6 +3795,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)
@@ -3809,6 +3812,8 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu)
svm->nmi_masked = true;
svm_set_iret_intercept(svm);
}
+
+status:
++vcpu->stat.nmi_injections;
}
@@ -4025,6 +4030,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 f0db48d62fcf..2909f57508de 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -60,6 +60,7 @@ extern struct kvm_x86_ops svm_x86_ops __initdata;
enum inject_type {
INJECT_IRQ,
+ INJECT_NMI,
};
/*
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v5 5/8] KVM: SVM: Inject MCEs when Restricted Injection is active
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (3 preceding siblings ...)
2026-11-09 3:18 ` [RFC PATCH v5 4/8] KVM: SVM: Inject NMIs " Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 7/8] KVM: SVM: Add support for the SEV-SNP #HV IPI NAE event Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 8/8] KVM: SVM: Enable Restricted Injection for an SEV-SNP guest Melody Wang
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
When Restricted Injection is active, only #HV exceptions can be injected
into the SEV-SNP guest.
Detect that, 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 | 17 +++++++++++++++--
arch/x86/kvm/svm/svm.c | 17 +++++++++++++++++
arch/x86/kvm/svm/svm.h | 2 ++
arch/x86/kvm/vmx/main.c | 10 ++++++++++
arch/x86/kvm/vmx/vmx.c | 5 +++++
arch/x86/kvm/vmx/x86_ops.h | 1 +
arch/x86/kvm/x86.c | 6 ++++++
9 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index 2074c2050c55..e3da9fb0b2b6 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -80,6 +80,7 @@ KVM_X86_OP(inject_exception)
KVM_X86_OP(cancel_injection)
KVM_X86_OP(interrupt_allowed)
KVM_X86_OP(nmi_allowed)
+KVM_X86_OP(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 4de443140c53..fa83477ebcab 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1606,6 +1606,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 f80dfd876d5e..6a1262c274ff 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5565,7 +5565,9 @@ static void __sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
return;
}
- if (type == INJECT_NMI) {
+ if (type == INJECT_MCE) {
+ hvdb->events.mce = 1;
+ } else if (type == INJECT_NMI) {
hvdb->events.nmi = 1;
} else if (type == INJECT_IRQ) {
hvdb->events.vector = vcpu->arch.interrupt.nr;
@@ -5602,6 +5604,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) {
+ __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,
@@ -5682,6 +5689,10 @@ 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.no_further_signal = 0;
svm->sev_es.cancel_flag = true;
@@ -5702,7 +5713,9 @@ bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)
return true;
/* Indicate interrupts blocked based on guest acknowledgment */
- if (type == INJECT_NMI)
+ if (type == INJECT_MCE)
+ blocked = hvdb->events.mce;
+ else if (type == INJECT_NMI)
blocked = hvdb->events.nmi;
else if (type == INJECT_IRQ) {
irq = kvm_cpu_get_interrupt(vcpu);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 75e86592f1c9..ad99b2b1b07b 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4114,6 +4114,22 @@ static bool svm_is_noack_required(struct kvm_vcpu *vcpu)
return true;
}
+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);
@@ -5429,6 +5445,7 @@ 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 2909f57508de..e19b398a3df5 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -61,6 +61,7 @@ extern struct kvm_x86_ops svm_x86_ops __initdata;
enum inject_type {
INJECT_IRQ,
INJECT_NMI,
+ INJECT_MCE,
};
/*
@@ -826,6 +827,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 4c52ab8d0786..e083e2965cd9 100644
--- a/arch/x86/kvm/vmx/main.c
+++ b/arch/x86/kvm/vmx/main.c
@@ -828,6 +828,15 @@ static void vt_cancel_hv_timer(struct kvm_vcpu *vcpu)
}
#endif
+static int vt_mce_allowed(struct kvm_vcpu *vcpu)
+{
+ if (is_td_vcpu(vcpu))
+ return 0;
+
+ return vmx_mce_allowed(vcpu);
+}
+
+
static void vt_setup_mce(struct kvm_vcpu *vcpu)
{
if (is_td_vcpu(vcpu))
@@ -962,6 +971,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
.cancel_injection = vt_op(cancel_injection),
.interrupt_allowed = vt_op(interrupt_allowed),
.nmi_allowed = vt_op(nmi_allowed),
+ .mce_allowed = vt_op(mce_allowed),
.get_nmi_mask = vt_op(get_nmi_mask),
.set_nmi_mask = vt_op(set_nmi_mask),
.enable_nmi_window = vt_op(enable_nmi_window),
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 612ab07d4100..2b391c282b51 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -5273,6 +5273,11 @@ int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
return 1;
}
+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 054fd14bb2e1..f68316638f21 100644
--- a/arch/x86/kvm/vmx/x86_ops.h
+++ b/arch/x86/kvm/vmx/x86_ops.h
@@ -93,6 +93,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 79468ddfe473..1492a06a6935 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7673,6 +7673,12 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
kvm_update_dr7(vcpu);
}
+ if (vcpu->arch.exception.vector == MC_VECTOR) {
+ r = static_call(kvm_x86_mce_allowed)(vcpu);
+ if (!r)
+ goto out;
+ }
+
kvm_inject_exception(vcpu);
vcpu->arch.exception.pending = false;
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v5 7/8] KVM: SVM: Add support for the SEV-SNP #HV IPI NAE event
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (4 preceding siblings ...)
2026-11-09 3:18 ` [RFC PATCH v5 5/8] KVM: SVM: Inject MCEs " Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
2026-11-09 3:18 ` [RFC PATCH v5 8/8] KVM: SVM: Enable Restricted Injection for an SEV-SNP guest Melody Wang
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
The #HV IPI NAE event allows the guest to send an IPI to other vCPUs in
the guest when Restricted Injection is enabled. 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 | 1 +
arch/x86/kvm/lapic.c | 12 ++++++++++++
arch/x86/kvm/lapic.h | 2 ++
arch/x86/kvm/svm/sev.c | 21 +++++++++++++++++++++
4 files changed, 36 insertions(+)
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index d84a13ac4627..1c0165e9db16 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -122,6 +122,7 @@
#define SVM_VMGEXIT_HVDB_SET 1
#define SVM_VMGEXIT_HVDB_QUERY 2
#define SVM_VMGEXIT_HVDB_CLEAR 3
+#define SVM_VMGEXIT_HV_IPI 0x80000015ull
#define SVM_VMGEXIT_SNP_RUN_VMPL 0x80000018ull
#define SVM_VMGEXIT_SAVIC 0x8000001aull
#define SVM_VMGEXIT_SAVIC_REGISTER_GPA 0
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 037a4599d6f1..3a83bdd13b5a 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -3673,3 +3673,15 @@ void kvm_lapic_exit(void)
static_key_deferred_flush(&apic_sw_disabled);
WARN_ON(static_branch_unlikely(&apic_sw_disabled.key));
}
+
+int kvm_xapic_x2apic_send_ipi(struct kvm_vcpu *vcpu, u64 data)
+{
+ struct kvm_lapic *apic = vcpu->arch.apic;
+
+ if (!kvm_lapic_enabled(vcpu))
+ return 1;
+
+ kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32));
+ return 0;
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_xapic_x2apic_send_ipi);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 8530a6333bdd..e5e6730bfcca 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -194,6 +194,8 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
int kvm_lapic_set_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len);
void kvm_lapic_exit(void);
+int kvm_xapic_x2apic_send_ipi(struct kvm_vcpu *vcpu, u64 data);
+
u64 kvm_x2apic_disable_read_intercept_reg_mask(struct kvm_vcpu *vcpu);
static inline void kvm_lapic_set_irr(int vec, struct kvm_lapic *apic)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 9aafa6167ae6..b7c2993f8c63 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -4414,6 +4414,22 @@ static int sev_snp_hv_doorbell_page(struct vcpu_svm *svm)
return 0;
}
+static int sev_snp_hv_ipi(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ u64 icr_info;
+
+ if (!is_sev_snp_guest(vcpu))
+ return -EINVAL;
+
+ icr_info = svm->vmcb->control.exit_info_1;
+
+ if (kvm_xapic_x2apic_send_ipi(vcpu, icr_info))
+ return -EINVAL;
+
+ return 0;
+}
+
static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -4566,6 +4582,7 @@ static bool is_snp_only_vmgexit(u64 exit_code)
case SVM_VMGEXIT_EXT_GUEST_REQUEST:
case SVM_VMGEXIT_PSC:
case SVM_VMGEXIT_HVDB_PAGE:
+ case SVM_VMGEXIT_HV_IPI:
return true;
default:
return false;
@@ -4754,6 +4771,10 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
svm_vmgexit_bad_input(svm, GHCB_ERR_INVALID_INPUT);
return 1;
+ case SVM_VMGEXIT_HV_IPI:
+ if (sev_snp_hv_ipi(svm))
+ svm_vmgexit_bad_input(svm, GHCB_ERR_INVALID_INPUT);
+ return 1;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
/*
* Note, the _guest_ is reporting an unsupported #VC, i.e. this
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v5 8/8] KVM: SVM: Enable Restricted Injection for an SEV-SNP guest
2026-11-09 3:18 [RFC PATCH v5 0/8] Add SEV-SNP restricted injection hypervisor support Melody Wang
` (5 preceding siblings ...)
2026-11-09 3:18 ` [RFC PATCH v5 7/8] KVM: SVM: Add support for the SEV-SNP #HV IPI NAE event Melody Wang
@ 2026-11-09 3:18 ` Melody Wang
6 siblings, 0 replies; 8+ messages in thread
From: Melody Wang @ 2026-11-09 3:18 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: LKML, kvm, Joerg Roedel, x86, Melody Wang, Thomas Lendacky
Enable Restricted Injection in an SEV-SNP guest by setting the
corresponding bit in the VMSA SEV features field (SEV_FEATURES[3]) from
QEMU.
Add Restricted Injection to the supported hypervisor 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 | 21 ++++++++++++++++++++-
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index f70ee74b5f92..c491c355fabd 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -466,6 +466,7 @@
#define X86_FEATURE_SNP_SECURE_TSC (19*32+ 8) /* SEV-SNP Secure TSC */
#define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* Virtual TSC_AUX */
#define X86_FEATURE_SME_COHERENT (19*32+10) /* hardware-enforced cache coherency */
+#define X86_FEATURE_RESTRICTED_INJECTION (19*32+12) /* Restricted Injection */
#define X86_FEATURE_DEBUG_SWAP (19*32+14) /* "debug_swap" SEV-ES full debug state swap support */
#define X86_FEATURE_RMPREAD (19*32+21) /* RMPREAD instruction */
#define X86_FEATURE_SEGMENTED_RMP (19*32+23) /* Segmented RMP support */
diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
index 01a6e4dbe423..ee17a3541b55 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 b7c2993f8c63..a7b290d3fd42 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -42,7 +42,9 @@
#define GHCB_VERSION_MAX 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)
/*
* The GHCB spec essentially states that all non-zero error codes other than
@@ -3261,6 +3263,9 @@ void __init sev_hardware_setup(void)
if (sev_snp_enabled && tsc_khz && cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC))
sev_supported_vmsa_features |= SVM_SEV_FEAT_SECURE_TSC;
+
+ if (sev_snp_enabled && cpu_feature_enabled(X86_FEATURE_RESTRICTED_INJECTION))
+ sev_supported_vmsa_features |= SVM_SEV_FEAT_RESTRICTED_INJECTION;
}
void sev_hardware_unsetup(void)
@@ -4862,10 +4867,22 @@ void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm)
vcpu->arch.reserved_gpa_bits &= ~(1UL << (best->ebx & 0x3f));
}
+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;
+ svm->vmcb->control.int_ctl &= ~V_GIF_ENABLE_MASK;
+ }
+}
+
static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event)
{
struct kvm_sev_info *sev = to_kvm_sev_info(svm->vcpu.kvm);
struct vmcb *vmcb = svm->vmcb01.ptr;
+ struct kvm_vcpu *vcpu = &svm->vcpu;
svm->vmcb->control.misc_ctl |= SVM_MISC_ENABLE_SEV_ES;
@@ -4932,6 +4949,8 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event)
set_ghcb_msr(svm, GHCB_MSR_SEV_INFO((__u64)sev->ghcb_version,
GHCB_VERSION_MIN,
sev_enc_bit));
+ if (sev_snp_guest(vcpu->kvm))
+ sev_snp_init_vmcb(svm);
}
void sev_init_vmcb(struct vcpu_svm *svm, bool init_event)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread