Download raw body.
SEV-ES: vmm(4): GHCB MSR protocol for CPUID
Hi,
my last two diffs for vmm(4) and SEV-ES:
When a SEV-ES guest is in locore, it will not be able yet to use a
GHCB to communicate with vmm(4). Therefore, AMD specifies a "GHCB
MSR protocol" that uses the lowere 12 bits of the GHCB MSR to request
services from vmm(4). Guest writes to the GHCB MSR will show up in
the v_ghcb_gpa member of the VMCB and are thus accesible by vmm(4).
The response of vmm(4) can be provided by writing it to the VMCB.
In locore a SEV-ES guest will need to request CPUID from vmm(4)
using the GHCB MSR protocol. This diff provides this service.
Take care,
HJ.
---------------------------------------------------------------------------
commit 8278f4051b90ee94e19db25d019100a736ee7317
Author: Hans-Joerg Hoexer <hshoexer@genua.de>
Date: Mon Nov 18 13:59:19 2024 +0100
vmm(4): GHCB MSR protocol for CPUID
When a SEV-ES guest is in locore, it will not be able yet to use a
GHCB to communicate with vmm(4). Therefore, AMD specifies a "GHCB
MSR protocol" that uses the lowere 12 bits of the GHCB MSR to request
services from vmm(4). Guest writes to the GHCB MSR will show up in
the v_ghcb_gpa member of the VMCB and are thus accesible by vmm(4).
The response of vmm(4) can be provided by writing it to the VMCB.
In locore a SEV-ES guest will need to request CPUID from vmm(4)
using the GHCB MSR protocol. This diff provides this service.
diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c
index 9049bc6340d..2e90b7340f2 100644
--- a/sys/arch/amd64/amd64/vmm_machdep.c
+++ b/sys/arch/amd64/amd64/vmm_machdep.c
@@ -4514,13 +4514,67 @@ svm_handle_gexit(struct vcpu *vcpu)
struct vm *vm = vcpu->vc_parent;
struct ghcb_sa *ghcb;
paddr_t ghcb_gpa, ghcb_hpa;
+ uint32_t req, resp;
+ uint64_t result;
int syncout, error = 0;
- if (vcpu->vc_svm_ghcb_va == 0) {
+ if (vcpu->vc_svm_ghcb_va == 0 && (vmcb->v_ghcb_gpa & ~PG_FRAME) == 0 &&
+ (vmcb->v_ghcb_gpa & PG_FRAME) != 0) {
+ /*
+ * Guest provides a valid guest physcial address
+ * for GHCB and it is not set yet -> assign it.
+ *
+ * We only accept a GHCB once; we decline re-definition.
+ */
ghcb_gpa = vmcb->v_ghcb_gpa & PG_FRAME;
if (!pmap_extract(vm->vm_map->pmap, ghcb_gpa, &ghcb_hpa))
return (EINVAL);
vcpu->vc_svm_ghcb_va = (vaddr_t)PMAP_DIRECT_MAP(ghcb_hpa);
+ } else if ((vmcb->v_ghcb_gpa & ~PG_FRAME) != 0) {
+ /*
+ * Low bits in use, thus must be a MSR protocol
+ * request.
+ */
+ req = (vmcb->v_ghcb_gpa & 0xffffffff);
+
+ /* we only support cpuid */
+ if ((req & ~PG_FRAME) != MSR_PROTO_CPUID_REQ)
+ return (EINVAL);
+
+ /* Emulate CPUID */
+ vmcb->v_exitcode = SVM_VMEXIT_CPUID;
+ vmcb->v_rax = vmcb->v_ghcb_gpa >> 32;
+ vcpu->vc_gueststate.vg_rax = 0;
+ vcpu->vc_gueststate.vg_rbx = 0;
+ vcpu->vc_gueststate.vg_rcx = 0;
+ vcpu->vc_gueststate.vg_rdx = 0;
+ error = vmm_handle_cpuid(vcpu);
+ if (error)
+ goto out;
+
+ switch (req >> 30) {
+ case 0: /* eax: emulate cpuid and return eax */
+ result = vmcb->v_rax;
+ break;
+ case 1: /* return ebx */
+ result = vcpu->vc_gueststate.vg_rbx;
+ break;
+ case 2: /* return ecx */
+ result = vcpu->vc_gueststate.vg_rcx;
+ break;
+ case 3: /* return edx */
+ result = vcpu->vc_gueststate.vg_rdx;
+ break;
+ default:
+ DPRINTF("%s: unknown request 0x%x\n", __func__, req);
+ return (EINVAL);
+ }
+
+ /* build response */
+ resp = MSR_PROTO_CPUID_RESP | (req & 0xc0000000);
+ vmcb->v_ghcb_gpa = (result << 32) | resp;
+
+ return (0);
}
/* Verify GHCB and synchronize guest state information. */
diff --git a/sys/arch/amd64/include/ghcb.h b/sys/arch/amd64/include/ghcb.h
index 802bf7f015e..954e1fa3e3b 100644
--- a/sys/arch/amd64/include/ghcb.h
+++ b/sys/arch/amd64/include/ghcb.h
@@ -101,6 +101,12 @@ struct ghcb_sync {
};
+/* Definitions used with the MSR protocol */
+#define MSR_PROTO_CPUID_REQ 0x4
+#define MSR_PROTO_CPUID_RESP 0x5
+#define MSR_PROTO_TERMINATE 0x100
+
+
void ghcb_clear(struct ghcb_sa *);
int ghcb_valbm_set(uint8_t *, int);
int ghcb_valbm_isset(uint8_t *, int);
SEV-ES: vmm(4): GHCB MSR protocol for CPUID