Download raw body.
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
SEV-SNP: Register GHCB with hypervisor and handle #VC for unvalidated pages 4/4