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

Hans-Jörg Höxer <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
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
smime.p7s (application/pkcs7-signature, 6.1 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.