Index | Thread | Search

From:
Hans-Jörg Höxer <hshoexer@genua.de>
Subject:
vmm(4): For SEV-ES use GUEST_INTERRUPT_MASK
To:
<tech@openbsd.org>
Cc:
<Hans-Joerg_Hoexer@genua.de>
Date:
Wed, 30 Apr 2025 16:26:37 +0200

Download raw body.

Thread
Hi,

this is diff 2/3.  As vmm(4) cannot access a SEV-ES guests rflags
register, we have to use the GUEST_INTERRUPT_MASK field from the VMCB
for SEV-ES enabled guests.

Take care,
HJ.

---------------------------------------------------------------
commit 939134e1a692824d0f8d94ea566102637ff2b800
Author: Hans-Joerg Hoexer <hshoexer@genua.de>
Date:   Tue Nov 12 14:55:11 2024 +0100

    vmm(4):  For SEV-ES use GUEST_INTERRUPT_MASK
    
    Due to state encryption we can not determine the state of the
    interrupt enable flag from the FLAGS register.  Therefore the VMCB
    provides at offset 0x68 bit 1 the current state of this flag.
    
    However, only when this is a SEV-ES enabled guest.  Otherwise, we
    have to use the FLAGS register.

diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c
index 3d5c58de71d..28809aa57d2 100644
--- a/sys/arch/amd64/amd64/vmm_machdep.c
+++ b/sys/arch/amd64/amd64/vmm_machdep.c
@@ -98,6 +98,7 @@ int vmx_load_pdptes(struct vcpu *);
 int vmx_handle_exit(struct vcpu *);
 int svm_handle_exit(struct vcpu *);
 int svm_handle_efercr(struct vcpu *, uint64_t);
+int svm_get_iflag(struct vcpu *, uint64_t);
 int svm_handle_msr(struct vcpu *);
 int vmm_handle_xsetbv(struct vcpu *, uint64_t *);
 int vmx_handle_xsetbv(struct vcpu *);
@@ -4149,7 +4150,7 @@ svm_handle_hlt(struct vcpu *vcpu)
 	/* All HLT insns are 1 byte */
 	vcpu->vc_gueststate.vg_rip += 1;
 
-	if (!(rflags & PSL_I)) {
+	if (!svm_get_iflag(vcpu, rflags)) {
 		DPRINTF("%s: guest halted with interrupts disabled\n",
 		    __func__);
 		return (EIO);
@@ -4245,7 +4246,7 @@ svm_handle_exit(struct vcpu *vcpu)
 
 	switch (exit_reason) {
 	case SVM_VMEXIT_VINTR:
-		if (!(rflags & PSL_I)) {
+		if (!svm_get_iflag(vcpu, rflags)) {
 			DPRINTF("%s: impossible interrupt window exit "
 			    "config\n", __func__);
 			ret = EINVAL;
@@ -4369,6 +4370,23 @@ svm_handle_efercr(struct vcpu *vcpu, uint64_t exit_reason)
 	return (0);
 }
 
+/*
+ * svm_get_iflag
+ *
+ * With SEV-ES the hypervisor has no access to the flags register.
+ * Only the the state of the PSL_I is proivded by v_intr_shadow in
+ * the VMCB.
+ */
+int
+svm_get_iflag(struct vcpu *vcpu, uint64_t rflags)
+{
+	struct vmcb		*vmcb = (struct vmcb *)vcpu->vc_control_va;
+
+	if (vcpu->vc_seves)
+		return (vmcb->v_intr_shadow & SMV_GUEST_INTR_MASK);
+	return (rflags & PSL_I);
+}
+
 /*
  * vmx_handle_exit
  *
@@ -6421,7 +6439,7 @@ vcpu_run_svm(struct vcpu *vcpu, struct vm_run_params *vrp)
 			 */
 			ret = svm_handle_exit(vcpu);
 
-			if (vcpu->vc_gueststate.vg_rflags & PSL_I)
+			if (svm_get_iflag(vcpu, vcpu->vc_gueststate.vg_rflags))
 				vcpu->vc_irqready = 1;
 			else
 				vcpu->vc_irqready = 0;
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index 22c60907f1a..22d892ae2f3 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -627,6 +627,8 @@ struct vmcb_segment {
 #define SVM_ENABLE_SEV		(1ULL << 1)
 #define SVM_SEVES_ENABLE	(1ULL << 2)
 
+#define SMV_GUEST_INTR_MASK	(1ULL << 1)
+
 #define SVM_LBRVIRT_ENABLE	(1ULL << 0)
 
 struct vmcb {