1 /* virt-what-cvm-helper: Are we running inside confidential VM
2 * Copyright (C) 2023 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 static bool dodebug = false;
32 #define debug(...) do { if (dodebug) fprintf(stderr, __VA_ARGS__); } while(0)
35 #define CPUID_PROCESSOR_INFO_AND_FEATURE_BITS 0x1
38 * AMD64 Architecture Programmer’s Manual Volume 3:
39 * General-Purpose and System Instructions.
40 * Chapter: E4.1 - Maximum Extended Function Number and Vendor String
41 * https://www.amd.com/system/files/TechDocs/24594.pdf
43 #define CPUID_GET_HIGHEST_FUNCTION 0x80000000
46 * AMD64 Architecture Programmer’s Manual Volume 3:
47 * General-Purpose and System Instructions.
48 * Chapter: E4.17 - Encrypted Memory Capabilities
49 * https://www.amd.com/system/files/TechDocs/24594.pdf
51 #define CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES 0x8000001f
54 * AMD64 Architecture Programmer’s Manual Volume 3:
55 * General-Purpose and System Instructions.
56 * Chapter: 15.34.10 - SEV_STATUS MSR
57 * https://www.amd.com/system/files/TechDocs/24593.pdf
59 #define MSR_AMD64_SEV 0xc0010131
62 * Intel® TDX Module v1.5 Base Architecture Specification
64 * https://www.intel.com/content/www/us/en/content-details/733575/intel-tdx-module-v1-5-base-architecture-specification.html
67 #define CPUID_INTEL_TDX_ENUMERATION 0x21
69 /* Requirements for Implementing the Microsoft Hypervisor Interface
70 * https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
72 #define CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS 0x40000000
74 #define CPUID_HYPERV_FEATURES 0x40000003
76 #define CPUID_HYPERV_ISOLATION_CONFIG 0x4000000C
78 #define CPUID_HYPERV_MIN 0x40000005
79 #define CPUID_HYPERV_MAX 0x4000ffff
81 #define CPUID_SIG_AMD "AuthenticAMD"
82 #define CPUID_SIG_INTEL "GenuineIntel"
83 #define CPUID_SIG_INTEL_TDX "IntelTDX "
84 #define CPUID_SIG_HYPERV "Microsoft Hv"
86 /* ecx bit 31: set => hyperpvisor, unset => bare metal */
87 #define CPUID_FEATURE_HYPERVISOR (1 << 31)
89 /* Linux include/asm-generic/hyperv-tlfs.h */
90 #define CPUID_HYPERV_CPU_MANAGEMENT (1 << 12) /* root partition */
91 #define CPUID_HYPERV_ISOLATION (1 << 22) /* confidential VM partition */
93 #define CPUID_HYPERV_ISOLATION_TYPE_MASK 0xf
94 #define CPUID_HYPERV_ISOLATION_TYPE_SNP 2
96 #if defined(__x86_64__)
98 /* Copied from the Linux kernel definition in
99 * arch/x86/include/asm/processor.h
102 cpuid (uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
104 debug("CPUID func %x %x\n", *eax, *ecx);
105 asm volatile ("cpuid"
106 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
107 : "0" (*eax), "2" (*ecx)
109 debug("CPUID result %x %x %x %x\n", *eax, *ebx, *ecx, *edx);
114 cpuid_leaf (uint32_t eax, char *sig, bool swapped)
116 uint32_t *sig32 = (uint32_t *) sig;
119 cpuid (&eax, &sig32[0], &sig32[2], &sig32[1]);
121 cpuid (&eax, &sig32[0], &sig32[1], &sig32[2]);
122 sig[12] = 0; /* \0-terminate the string to make string comparison possible */
123 debug("CPUID sig %s\n", sig);
127 #define MSR_DEVICE "/dev/cpu/0/msr"
133 int fd = open (MSR_DEVICE, O_RDONLY);
135 debug ("Cannot open MSR device %s", MSR_DEVICE);
139 if (pread (fd, &ret, sizeof(ret), index) != sizeof(ret))
144 debug ("MSR %llx result %llx\n", (unsigned long long)index,
145 (unsigned long long)ret);
150 cpu_sig_amd_hyperv (void)
152 uint32_t eax, ebx, ecx, edx;
156 feat = cpuid_leaf (CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS, sig, false);
158 if (feat < CPUID_HYPERV_MIN ||
159 feat > CPUID_HYPERV_MAX)
162 if (memcmp (sig, CPUID_SIG_HYPERV, sizeof(sig)) != 0)
165 debug ("CPUID is on hyperv\n");
166 eax = CPUID_HYPERV_FEATURES;
169 cpuid(&eax, &ebx, &ecx, &edx);
171 if (ebx & CPUID_HYPERV_ISOLATION &&
172 !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) {
174 eax = CPUID_HYPERV_ISOLATION_CONFIG;
176 cpuid(&eax, &ebx, &ecx, &edx);
178 if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) ==
179 CPUID_HYPERV_ISOLATION_TYPE_SNP) {
190 uint32_t eax, ebx, ecx, edx;
193 eax = CPUID_GET_HIGHEST_FUNCTION;
196 cpuid (&eax, &ebx, &ecx, &edx);
198 if (eax < CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES)
201 eax = CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES;
204 cpuid (&eax, &ebx, &ecx, &edx);
206 /* bit 1 == CPU supports SEV feature
208 * Note, HyperV/Azure blocks this CPUID leaf from its SEV-SNP
209 * guests. We already did an alternative detection mechanism
210 * in such VMs, so should not even be running this code.
212 if (!(eax & (1 << 1))) {
213 debug ("No sev in CPUID, try hyperv CPUID\n");
215 if (cpu_sig_amd_hyperv ()) {
216 puts ("amd-sev-snp");
219 debug("No hyperv CPUID\n");
224 msrval = msr (MSR_AMD64_SEV);
226 /* Test reverse order, since the SEV-SNP bit implies
227 * the SEV-ES bit, which implies the SEV bit */
228 if (msrval & (1 << 2)) {
229 puts ("amd-sev-snp");
230 } else if (msrval & (1 << 1)) {
232 } else if (msrval & (1 << 0)) {
240 uint32_t eax, ebx, ecx, edx;
243 eax = CPUID_GET_HIGHEST_FUNCTION;
246 cpuid (&eax, &ebx, &ecx, &edx);
247 debug ("CPUID max function: %x %x %x %x\n", eax, ebx, ecx,edx);
249 if (eax < CPUID_INTEL_TDX_ENUMERATION)
252 memset (sig, 0, sizeof sig);
253 cpuid_leaf (CPUID_INTEL_TDX_ENUMERATION, sig, true);
255 if (memcmp (sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0)
262 uint32_t eax, ebx, ecx, edx;
265 eax = CPUID_PROCESSOR_INFO_AND_FEATURE_BITS;
268 cpuid(&eax, &ebx, &ecx, &edx);
270 is_hv = ecx & CPUID_FEATURE_HYPERVISOR;
272 debug ("CPUID is hypervisor: %s\n", is_hv ? "yes" : "no");
281 /* Skip everything on bare metal */
285 memset (sig, 0, sizeof sig);
286 cpuid_leaf (0, sig, true);
288 if (memcmp (sig, CPUID_SIG_AMD, sizeof(sig)) == 0)
290 else if (memcmp (sig, CPUID_SIG_INTEL, sizeof(sig)) == 0)
299 /* nothing for other architectures */
305 main(int argc, char **argv)
310 int option_index = 0;
311 static struct option long_options[] = {
312 {"debug", no_argument, 0, 'd' },
313 {"version", no_argument, 0, 'v' },
314 {"help", no_argument, 0, 'h'},
318 c = getopt_long(argc, argv, "dvh",
319 long_options, &option_index);
328 fprintf(stdout, "%s\n", PACKAGE_VERSION);
333 fprintf(c == 'h' ? stdout : stderr,
334 "Usage: %s [--debug|-d] [--help|-h] [--version|-v]\n",
336 exit(c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);