[PATCH Part1 RFC v2 12/20] x86/compressed: Register GHCB memory when SEV-SNP is active

From: Brijesh Singh
Date: Fri Apr 30 2021 - 08:17:24 EST


The SEV-SNP guest is required to perform GHCB GPA registration. This is
because the hypervisor may prefer that a guest use a consistent and/or
specific GPA for the GHCB associated with a vCPU. For more information,
see the GHCB specification.

If hypervisor can not work with the guest provided GPA then terminate the
guest boot.

Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx>
---
arch/x86/boot/compressed/sev.c | 4 ++++
arch/x86/include/asm/sev-common.h | 12 ++++++++++++
arch/x86/kernel/sev-shared.c | 16 ++++++++++++++++
3 files changed, 32 insertions(+)

diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index 4f215d0c9f76..07b9529d7d95 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -206,6 +206,10 @@ static bool early_setup_sev_es(void)
/* Initialize lookup tables for the instruction decoder */
inat_init_tables();

+ /* SEV-SNP guest requires the GHCB GPA must be registered */
+ if (sev_snp_enabled())
+ snp_register_ghcb(__pa(&boot_ghcb_page));
+
return true;
}

diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
index 733fca403ae5..7487d4768ef0 100644
--- a/arch/x86/include/asm/sev-common.h
+++ b/arch/x86/include/asm/sev-common.h
@@ -88,6 +88,18 @@
#define GHCB_MSR_PSC_RSVD_MASK 0xfffffULL
#define GHCB_MSR_PSC_RESP_VAL(val) ((val) >> GHCB_MSR_PSC_ERROR_POS)

+/* GHCB GPA Register */
+#define GHCB_MSR_GPA_REG_REQ 0x012
+#define GHCB_MSR_GPA_REG_VALUE_POS 12
+#define GHCB_MSR_GPA_REG_VALUE_MASK 0xfffffffffffffULL
+#define GHCB_MSR_GPA_REQ_VAL(v) \
+ (((v) << GHCB_MSR_GPA_REG_VALUE_POS) | GHCB_MSR_GPA_REG_REQ)
+
+#define GHCB_MSR_GPA_REG_RESP 0x013
+#define GHCB_MSR_GPA_REG_RESP_VAL(v) ((v) >> GHCB_MSR_GPA_REG_VALUE_POS)
+#define GHCB_MSR_GPA_REG_ERROR 0xfffffffffffffULL
+#define GHCB_MSR_GPA_INVALID ~0ULL
+
/* SNP Page State Change NAE event */
#define VMGEXIT_PSC_MAX_ENTRY 253
#define VMGEXIT_PSC_INVALID_HEADER 0x100000001
diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
index 085d3d724bc8..140c5bc07fc2 100644
--- a/arch/x86/kernel/sev-shared.c
+++ b/arch/x86/kernel/sev-shared.c
@@ -81,6 +81,22 @@ static bool ghcb_get_hv_features(void)
return true;
}

+static void snp_register_ghcb(unsigned long paddr)
+{
+ unsigned long pfn = paddr >> PAGE_SHIFT;
+ u64 val;
+
+ sev_es_wr_ghcb_msr(GHCB_MSR_GPA_REQ_VAL(pfn));
+ VMGEXIT();
+
+ val = sev_es_rd_ghcb_msr();
+
+ /* If the response GPA is not ours then abort the guest */
+ if ((GHCB_RESP_CODE(val) != GHCB_MSR_GPA_REG_RESP) ||
+ (GHCB_MSR_GPA_REG_RESP_VAL(val) != pfn))
+ sev_es_terminate(1, GHCB_TERM_REGISTER);
+}
+
static bool sev_es_negotiate_protocol(void)
{
u64 val;
--
2.17.1