Index | Thread | Search

From:
Hans-Jörg Höxer <hshoexer@genua.de>
Subject:
SEV-SNP: Register GHCB with hypervisor and handle #VC for unvalidated pages 4/4
To:
<tech@openbsd.org>
Date:
Tue, 11 Aug 2026 11:37:50 +0200

Download raw body.

Thread
  • Hans-Jörg Höxer:

    SEV-SNP: Register GHCB with hypervisor and handle #VC for unvalidated pages 4/4

Hi,

this is patch 4/4.  With this OpenBSD can run as SEV-SNP enabled guest
on qemu/KVM.

With SNP enabled, the GHCB page need to be registered with the
hypervisor through the GHCB MSR protocol.

When we are SNP enabled guest and touch a page that has not been
validated by us the CPU delivers a #VC with error code
SVM_VMEXIT_PAGE_NOT_VALIDATED.  In that case we panic.

While there, clean up GHCB MSR protocol definitions.

ok? comments?

Take care,
HJ.

---
 sys/arch/amd64/amd64/locore0.S     |  2 +-
 sys/arch/amd64/amd64/machdep.c     | 16 ++++++++++++++--
 sys/arch/amd64/amd64/trap.c        |  8 ++++++++
 sys/arch/amd64/amd64/vmm_machdep.c |  2 +-
 sys/arch/amd64/include/ghcb.h      | 21 +++++++++++++--------
 sys/arch/amd64/include/vmmvar.h    |  1 +
 6 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/sys/arch/amd64/amd64/locore0.S b/sys/arch/amd64/amd64/locore0.S
index f8ba97805ce..1bc71845b19 100644
--- a/sys/arch/amd64/amd64/locore0.S
+++ b/sys/arch/amd64/amd64/locore0.S
@@ -872,7 +872,7 @@ locore_vc_trap32:
 	iret
 
 .Lterminate32:
-	movl	$MSR_PROTO_TERMINATE, %eax
+	movl	$MSR_PROTO_TERMINATION_REQ, %eax
 	movl	$MSR_SEV_GHCB, %ecx
 	wrmsr
 	rep vmmcall
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index ad44bea3162..bf6aed8f6c1 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -1342,6 +1342,7 @@ void
 cpu_init_early_vctrap(paddr_t addr)
 {
 	struct region_descriptor region;
+	uint64_t request, resp;
 
 	extern void Xvctrap_early(void);
 
@@ -1361,8 +1362,19 @@ cpu_init_early_vctrap(paddr_t addr)
 	    GSEL(GCODE_SEL, SEL_KPL));
 	cpu_init_idt();
 
-	/* Tell the hypervisor about our GHCB. */
-	ghcb_paddr = addr;
+	/* For SEV-SNP we have to register GHCB. */
+	if (ISSET(cpu_sev_guestmode, SEV_STAT_SNP_ACTIVE)) {
+		request = (addr & PG_FRAME) | MSR_PROTO_REGISTER_GHCB_PA_REQ;
+		wrmsr(MSR_SEV_GHCB, request);
+		vmgexit();
+		resp = rdmsr(MSR_SEV_GHCB);
+		if (((resp & ~PG_FRAME) != MSR_PROTO_REGISTER_GHCB_PA_RESP) ||
+		    ((resp & PG_FRAME) != (addr & PG_FRAME)))
+			panic("failed to register GHCB");
+	}
+
+	/* Tell vmm(4) about our GHCB. */
+	ghcb_paddr = addr & PG_FRAME;
 	ghcb_vaddr = addr + KERNBASE;
 	memset((void *)ghcb_vaddr, 0, 2 * PAGE_SIZE);
 	wrmsr(MSR_SEV_GHCB, ghcb_paddr);
diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c
index ccd0315186c..23a247accda 100644
--- a/sys/arch/amd64/amd64/trap.c
+++ b/sys/arch/amd64/amd64/trap.c
@@ -463,6 +463,14 @@ vctrap(struct trapframe *frame, int user, int *sig, int *code)
 		else
 			frame->tf_rip += 2;
 		break;
+	case SVM_VMEXIT_PAGE_NOT_VALIDATED: {
+		paddr_t pa;
+		vaddr_t va = rcr2();
+		pmap_extract(pmap_kernel(), va, &pa);
+		panic("page not validated access at 0x%llx on 0x%lx/0x%lx",
+		    frame->tf_rip, va, pa);
+		/* NOTREACHED */
+	    }
 	default:
 		panic("invalid exit code 0x%llx", ghcb_regs.exitcode);
 	}
diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c
index 787b65e29e1..850010abb90 100644
--- a/sys/arch/amd64/amd64/vmm_machdep.c
+++ b/sys/arch/amd64/amd64/vmm_machdep.c
@@ -4523,7 +4523,7 @@ svm_handle_vmgexit(struct vcpu *vcpu)
 		req = (vmcb->v_ghcb_gpa & 0xffffffff);
 
 		/* We only support cpuid and terminate. */
-		if ((req & ~PG_FRAME) == MSR_PROTO_TERMINATE) {
+		if ((req & ~PG_FRAME) == MSR_PROTO_TERMINATION_REQ) {
 			DPRINTF("%s: guest requests termination\n", __func__);
 			return (1);
 		} else if ((req & ~PG_FRAME) != MSR_PROTO_CPUID_REQ)
diff --git a/sys/arch/amd64/include/ghcb.h b/sys/arch/amd64/include/ghcb.h
index a821abdfb23..86d602363da 100644
--- a/sys/arch/amd64/include/ghcb.h
+++ b/sys/arch/amd64/include/ghcb.h
@@ -42,6 +42,19 @@
 
 #define GHCB_MAX			0xFFF
 
+#endif	/* !_LOCORE */
+
+/* Definitions used with the MSR protocol */
+#define MSR_PROTO_CPUID_REQ			0x4
+#define MSR_PROTO_CPUID_RESP			0x5
+#define MSR_PROTO_PREFERRED_GHCB_PA_REQ		0x10
+#define MSR_PROTO_PREFERRED_GHCB_PA_RESP	0x11
+#define MSR_PROTO_REGISTER_GHCB_PA_REQ		0x12
+#define MSR_PROTO_REGISTER_GHCB_PA_RESP		0x13
+#define MSR_PROTO_TERMINATION_REQ		0x100
+
+#ifndef _LOCORE
+
 struct ghcb_sa {
 	uint8_t			v_pad0[0xcb];		/* 000h-0CAh */
 	uint8_t			v_cpl;			/* 0CBh */
@@ -102,14 +115,6 @@ struct ghcb_sync {
 	int			sz_c;
 	int			sz_d;
 };
-#endif /* !_LOCORE */
-
-/* Definitions used with the MSR protocol */
-#define MSR_PROTO_CPUID_REQ	0x4
-#define MSR_PROTO_CPUID_RESP	0x5
-#define MSR_PROTO_TERMINATE	0x100
-
-#ifndef _LOCORE
 
 struct ghcb_psc {
 	struct {
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index 215ee20988f..72ed597bf88 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -264,6 +264,7 @@
 #define SVM_AVIC_INCOMPLETE_IPI			0x401
 #define SVM_AVIC_NOACCEL			0x402
 #define SVM_VMEXIT_VMGEXIT			0x403
+#define SVM_VMEXIT_PAGE_NOT_VALIDATED		0x404
 #define SVM_VMEXIT_INVALID			-1
 
 /*
-- 
2.53.0