Extend the existing sev_exitlib with helpers for handling pvalidate instructions and issuing page-state changes via the GHCB MSR protocol. Subsequent SEV-SNP-related tests will make use of these in guest code. Signed-off-by: Michael Roth <michael.roth@xxxxxxx> --- .../kvm/include/x86_64/sev_exitlib.h | 6 ++ .../selftests/kvm/lib/x86_64/sev_exitlib.c | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h b/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h index 4b67b4004dfa..5c7356f9e925 100644 --- a/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h +++ b/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h @@ -8,7 +8,13 @@ #ifndef SELFTEST_KVM_SEV_EXITLIB_H #define SELFTEST_KVM_SEV_EXITLIB_H +#define PVALIDATE_NO_UPDATE 255 + int sev_es_handle_vc(void *ghcb, u64 ghcb_gpa, struct ex_regs *regs); void sev_es_terminate(int reason); +void snp_register_ghcb(u64 ghcb_gpa); +void snp_psc_set_shared(u64 gpa); +void snp_psc_set_private(u64 gpa); +int snp_pvalidate(void *ptr, bool rmp_psize, bool validate); #endif /* SELFTEST_KVM_SEV_EXITLIB_H */ diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c b/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c index b3f7b0297e5b..546b402d5015 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c +++ b/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c @@ -51,6 +51,19 @@ #define GHCB_REG_GPA_RESP(resp) ((resp) & GENMASK_ULL(11, 0)) #define GHCB_REG_GPA_RESP_VAL(resp) ((resp) >> 12) +/* GHCB MSR protocol for Page State Change */ +#define GHCB_PSC_REQ_PRIVATE 1 +#define GHCB_PSC_REQ_SHARED 2 +#define GHCB_PSC_REQ_PSMASH 3 +#define GHCB_PSC_REQ_UNSMASH 4 +#define GHCB_PSC_REQ_CODE 0x14UL +#define GHCB_PSC_REQ(gfn, op) \ + (((unsigned long)((op) & 0xf) << 52) | \ + ((unsigned long)((gfn) & ~(1ULL << 40)) << 12) | \ + GHCB_PSC_REQ_CODE) +#define GHCB_PSC_RESP_CODE 0x15UL +#define GHCB_PSC_RESP(resp) ((resp) & GENMASK_ULL(11, 0)) + /* GHCB format/accessors */ struct ghcb { @@ -247,3 +260,67 @@ int sev_es_handle_vc(void *ghcb, u64 ghcb_gpa, struct ex_regs *regs) return handle_vc_cpuid(ghcb, ghcb_gpa, regs); } + +void snp_register_ghcb(u64 ghcb_gpa) +{ + u64 gfn = ghcb_gpa >> PAGE_SHIFT; + u64 resp; + + sev_es_wrmsr_ghcb(GHCB_REG_GPA_REQ(gfn)); + VMGEXIT(); + + resp = sev_es_rdmsr_ghcb(); + if (GHCB_REG_GPA_RESP(resp) != GHCB_REG_GPA_RESP_CODE || + GHCB_REG_GPA_RESP_VAL(resp) != gfn) + sev_es_terminate(GHCB_TERMINATE_REASON_UNSPEC); +} + +static void snp_psc_request(u64 gfn, int op) +{ + u64 resp; + + sev_es_wrmsr_ghcb(GHCB_PSC_REQ(gfn, op)); + VMGEXIT(); + + resp = sev_es_rdmsr_ghcb(); + if (GHCB_PSC_RESP(resp) != GHCB_PSC_RESP_CODE) + sev_es_terminate(GHCB_TERMINATE_REASON_UNSPEC); +} + +void snp_psc_set_shared(u64 gpa) +{ + snp_psc_request(gpa >> PAGE_SHIFT, GHCB_PSC_REQ_SHARED); +} + +void snp_psc_set_private(u64 gpa) +{ + snp_psc_request(gpa >> PAGE_SHIFT, GHCB_PSC_REQ_PRIVATE); +} + +/* From arch/x86/include/asm/asm.h */ +#ifdef __GCC_ASM_FLAG_OUTPUTS__ +# define CC_SET(c) "\n\t/* output condition code " #c "*/\n" +# define CC_OUT(c) "=@cc" #c +#else +# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n" +# define CC_OUT(c) [_cc_ ## c] "=qm" +#endif + +int snp_pvalidate(void *ptr, bool rmp_psize, bool validate) +{ + uint64_t gva = (uint64_t)ptr; + bool no_rmpupdate; + int rc; + + /* "pvalidate" mnemonic support in binutils 2.36 and newer */ + asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t" + CC_SET(c) + : CC_OUT(c) (no_rmpupdate), "=a"(rc) + : "a"(gva), "c"(rmp_psize), "d"(validate) + : "memory", "cc"); + + if (no_rmpupdate) + return PVALIDATE_NO_UPDATE; + + return rc; +} -- 2.25.1