From bb0055b491501e16fca3ab61dc7a969effbf48f3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 29 Jun 2023 17:51:04 +0100 Subject: [PATCH] virt-what-cvm: probe for SNP/HCL on HyperV/Azure via CPUID MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When running a confidential VM on Azure (HyperV) we can probe CPUID leaf 0x40000003 to detect if VM isolation is present, and 0x4000000c to detect what kind of isolation is used. Signed-off-by: Daniel P. Berrangé --- virt-what-cvm.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/virt-what-cvm.c b/virt-what-cvm.c index 1e7c50b..a7a224f 100644 --- a/virt-what-cvm.c +++ b/virt-what-cvm.c @@ -70,14 +70,33 @@ static bool dodebug = false; #define CPUID_INTEL_TDX_ENUMERATION 0x21 +/* Requirements for Implementing the Microsoft Hypervisor Interface + * https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs + */ +#define CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS 0x40000000 + +#define CPUID_HYPERV_FEATURES 0x40000003 + +#define CPUID_HYPERV_ISOLATION_CONFIG 0x4000000C + +#define CPUID_HYPERV_MIN 0x40000005 +#define CPUID_HYPERV_MAX 0x4000ffff #define CPUID_SIG_AMD "AuthenticAMD" #define CPUID_SIG_INTEL "GenuineIntel" #define CPUID_SIG_INTEL_TDX "IntelTDX " +#define CPUID_SIG_HYPERV "Microsoft Hv" /* ecx bit 31: set => hyperpvisor, unset => bare metal */ #define CPUID_FEATURE_HYPERVISOR (1 << 31) +/* Linux include/asm-generic/hyperv-tlfs.h */ +#define CPUID_HYPERV_CPU_MANAGEMENT (1 << 12) /* root partition */ +#define CPUID_HYPERV_ISOLATION (1 << 22) /* confidential VM partition */ + +#define CPUID_HYPERV_ISOLATION_TYPE_MASK 0xf +#define CPUID_HYPERV_ISOLATION_TYPE_SNP 2 + /* * This TPM NV data format is not explicitly documented anywhere, * but the header definition is present in code at: @@ -272,6 +291,44 @@ cpu_sig_amd_azure (void) return ret; } +static bool +cpu_sig_amd_hyperv (void) +{ + uint32_t eax, ebx, ecx, edx; + char sig[13]; + uint32_t feat; + + feat = cpuid_leaf (CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS, sig, false); + + if (feat < CPUID_HYPERV_MIN || + feat > CPUID_HYPERV_MAX) + return false; + + if (memcmp (sig, CPUID_SIG_HYPERV, sizeof(sig)) != 0) + return false; + + debug ("CPUID is on hyperv\n"); + eax = CPUID_HYPERV_FEATURES; + ebx = ecx = edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + if (ebx & CPUID_HYPERV_ISOLATION && + !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) { + + eax = CPUID_HYPERV_ISOLATION_CONFIG; + ebx = ecx = edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + + if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == + CPUID_HYPERV_ISOLATION_TYPE_SNP) { + return true; + } + } + + return false; +} + static void cpu_sig_amd (void) { @@ -298,9 +355,10 @@ cpu_sig_amd (void) * exposes a SEV-SNP attestation report as evidence. */ if (!(eax & (1 << 1))) { - debug ("No sev in CPUID, try azure TPM NV\n"); + debug ("No sev in CPUID, try hyperv CPUID/azure TPM NV\n"); - if (cpu_sig_amd_azure()) { + if (cpu_sig_amd_hyperv () || + cpu_sig_amd_azure()) { puts ("amd-sev-snp"); puts ("azure-hcl"); } else { -- 1.8.3.1