Download raw body.
SEV-SNP: Register GHCB and handle #VC for unvalidated
Hi,
that's the final diff with required "glue" to enable SEV-SNP guest
support.
With SNP enabled, the GHCB page needs to be registered with the
hypervisor through the GHCB MSR protocol.
When we are an 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.
vctrap() now takes the faulting address as an additional argument,
so vctrap_early() has to pass %cr2 in %r8. While there, also zero the
arguments sig and code: vctrap_early() is always in kernel mode, so
user is zero and they are never used.
ok?
Take care,
HJ.
---
sys/arch/amd64/amd64/machdep.c | 16 ++++++++++++++--
sys/arch/amd64/amd64/trap.c | 21 +++++++++++++++++----
sys/arch/amd64/amd64/vector.S | 3 +++
sys/arch/amd64/include/vmmvar.h | 1 +
4 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index ed3aed4d361..066281cb181 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -1345,6 +1345,7 @@ void
cpu_init_early_vctrap(paddr_t addr)
{
struct region_descriptor region;
+ uint64_t request, resp;
extern void Xvctrap_early(void);
@@ -1364,8 +1365,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 68cdf4c1b23..5cb25f5720c 100644
--- a/sys/arch/amd64/amd64/trap.c
+++ b/sys/arch/amd64/amd64/trap.c
@@ -98,7 +98,7 @@
int upageflttrap(struct trapframe *, uint64_t);
int kpageflttrap(struct trapframe *, uint64_t);
#ifdef AMDSEV
-int vctrap(struct trapframe *, int, int *, int *);
+int vctrap(struct trapframe *, int, int *, int *, uint64_t);
#endif
void kerntrap(struct trapframe *);
void usertrap(struct trapframe *);
@@ -305,7 +305,7 @@ kpageflttrap(struct trapframe *frame, uint64_t cr2)
#ifdef AMDSEV
int
-vctrap(struct trapframe *frame, int user, int *sig, int *code)
+vctrap(struct trapframe *frame, int user, int *sig, int *code, uint64_t cr2)
{
uint8_t *rip = (uint8_t *)(frame->tf_rip);
uint64_t port;
@@ -466,6 +466,19 @@ vctrap(struct trapframe *frame, int user, int *sig, int *code)
else
frame->tf_rip += 2;
break;
+ case SVM_VMEXIT_PAGE_NOT_VALIDATED: {
+ struct pmap *pm;
+ paddr_t pa;
+ vaddr_t va = (vaddr_t)cr2;
+
+ pm = user ? curproc->p_vmspace->vm_map.pmap : pmap_kernel();
+ if (!pmap_extract(pm, va, &pa))
+ panic("page not validated: rip 0x%llx va 0x%lx "
+ "(unmapped)", frame->tf_rip, va);
+ panic("page not validated: rip 0x%llx va 0x%lx pa 0x%lx",
+ frame->tf_rip, va, pa);
+ /* NOTREACHED */
+ }
default:
panic("invalid exit code 0x%llx", ghcb_regs.exitcode);
}
@@ -551,7 +564,7 @@ kerntrap(struct trapframe *frame)
#ifdef AMDSEV
case T_VC:
- if (vctrap(frame, 0, NULL, NULL))
+ if (vctrap(frame, 0, NULL, NULL, cr2))
return;
goto we_re_toast;
#endif
@@ -636,7 +649,7 @@ usertrap(struct trapframe *frame)
break;
#ifdef AMDSEV
case T_VC:
- if (vctrap(frame, 1, &sig, &code))
+ if (vctrap(frame, 1, &sig, &code, cr2))
goto out;
break;
#endif
diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S
index ff7be54de50..3c21002d298 100644
--- a/sys/arch/amd64/amd64/vector.S
+++ b/sys/arch/amd64/amd64/vector.S
@@ -560,6 +560,9 @@ IDTVEC(vctrap_early)
cld
movq %rsp, %rdi
movq $0x0, %rsi
+ movq $0x0, %rdx
+ movq $0x0, %rcx
+ movq %cr2, %r8
call vctrap
movq $0,-8(%rsp)
INTRFASTEXIT
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index 287632bb574..df99e6b7a37 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -268,6 +268,7 @@ struct vm;
#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.47.3
SEV-SNP: Register GHCB and handle #VC for unvalidated