mirror of
https://github.com/anrieff/libcpuid
synced 2024-12-16 16:35:45 +00:00
parent
ab395f8756
commit
ff5aafb5f4
5 changed files with 137 additions and 0 deletions
|
@ -108,6 +108,7 @@ int need_input = 0,
|
|||
need_version = 0,
|
||||
need_cpulist = 0,
|
||||
need_sgx = 0,
|
||||
need_hypervisor = 0,
|
||||
need_identify = 0;
|
||||
|
||||
#define MAX_REQUESTS 32
|
||||
|
@ -178,6 +179,7 @@ static void usage(void)
|
|||
printf(" --clock-rdtsc - same as --clock, but use RDTSC for clock detection\n");
|
||||
printf(" --cpulist - list all known CPUs\n");
|
||||
printf(" --sgx - list SGX leaf data, if SGX is supported.\n");
|
||||
printf(" --hypervisor - print hypervisor vendor if detected.\n");
|
||||
printf(" --quiet - disable warnings\n");
|
||||
printf(" --outfile=<file> - redirect all output to this file, instead of stdout\n");
|
||||
printf(" --verbose, -v - be extra verbose (more keys increase verbosiness level)\n");
|
||||
|
@ -297,6 +299,11 @@ static int parse_cmdline(int argc, char** argv)
|
|||
need_identify = 1;
|
||||
recog = 1;
|
||||
}
|
||||
if (!strcmp(arg, "--hypervisor")) {
|
||||
need_hypervisor = 1;
|
||||
need_identify = 1;
|
||||
recog = 1;
|
||||
}
|
||||
if (arg[0] == '-' && arg[1] == 'v') {
|
||||
num_vs = 1;
|
||||
while (arg[num_vs] == 'v')
|
||||
|
@ -556,6 +563,33 @@ static void print_sgx_data(const struct cpu_raw_data_t* raw, const struct cpu_id
|
|||
}
|
||||
}
|
||||
|
||||
static void print_hypervisor(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
|
||||
{
|
||||
int i;
|
||||
const char *hypervisor_str = NULL;
|
||||
const hypervisor_vendor_t hypervisor = cpuid_get_hypervisor(raw, data);
|
||||
const struct { const char *name; hypervisor_vendor_t hypervisor; } hypervisors_vendors[NUM_HYPERVISOR_VENDORS] = {
|
||||
{ "none", HYPERVISOR_NONE },
|
||||
{ "FreeBSD bhyve", HYPERVISOR_BHYVE },
|
||||
{ "Microsoft Hyper-V ", HYPERVISOR_HYPERV },
|
||||
{ "KVM", HYPERVISOR_KVM },
|
||||
{ "Parallels", HYPERVISOR_PARALLELS },
|
||||
{ "QEMU", HYPERVISOR_QEMU },
|
||||
{ "VirtualBox", HYPERVISOR_VIRTUALBOX },
|
||||
{ "VMware", HYPERVISOR_VMWARE },
|
||||
{ "Xen", HYPERVISOR_XEN },
|
||||
};
|
||||
for (i = 0; i < NUM_HYPERVISOR_VENDORS; i++)
|
||||
if (hypervisors_vendors[i].hypervisor == hypervisor) {
|
||||
hypervisor_str = hypervisors_vendors[i].name;
|
||||
break;
|
||||
}
|
||||
fprintf(fout, "Hypervisor vendor: %s\n", (hypervisor_str == NULL) ? "unknown" : hypervisor_str);
|
||||
if (hypervisor == HYPERVISOR_NONE)
|
||||
fprintf(fout, "Caution: no hypervisor detected from CPUID bits, but a hypervisor may be hidden.\n"
|
||||
"Refer to https://github.com/anrieff/libcpuid/issues/90#issuecomment-296568713\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int parseres = parse_cmdline(argc, argv);
|
||||
|
@ -762,6 +796,9 @@ int main(int argc, char** argv)
|
|||
if (need_sgx) {
|
||||
print_sgx_data(&raw_array.raw[0], &data.cpu_types[0]);
|
||||
}
|
||||
if (need_hypervisor) {
|
||||
print_hypervisor(&raw_array.raw[0], &data.cpu_types[0]);
|
||||
}
|
||||
|
||||
cpuid_free_raw_data_array(&raw_array);
|
||||
cpuid_free_system_id(&data);
|
||||
|
|
|
@ -568,6 +568,7 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da
|
|||
{ 28, CPU_FEATURE_AVX },
|
||||
{ 29, CPU_FEATURE_F16C },
|
||||
{ 30, CPU_FEATURE_RDRAND },
|
||||
{ 31, CPU_FEATURE_HYPERVISOR },
|
||||
};
|
||||
const struct feature_map_t matchtable_ebx7[] = {
|
||||
{ 3, CPU_FEATURE_BMI1 },
|
||||
|
@ -1180,6 +1181,7 @@ const char* cpu_feature_str(cpu_feature_t feature)
|
|||
{ CPU_FEATURE_AVX512VNNI, "avx512vnni" },
|
||||
{ CPU_FEATURE_AVX512VBMI, "avx512vbmi" },
|
||||
{ CPU_FEATURE_AVX512VBMI2, "avx512vbmi2" },
|
||||
{ CPU_FEATURE_HYPERVISOR, "hypervisor" },
|
||||
};
|
||||
unsigned i, n = COUNT_OF(matchtable);
|
||||
if (n != NUM_CPU_FEATURES) {
|
||||
|
@ -1299,6 +1301,65 @@ void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list)
|
|||
}
|
||||
}
|
||||
|
||||
hypervisor_vendor_t cpuid_get_hypervisor(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
|
||||
{
|
||||
int i, r;
|
||||
uint32_t hypervisor_fn40000000h[NUM_REGS];
|
||||
char hypervisor_str[VENDOR_STR_MAX];
|
||||
struct cpu_id_t mydata;
|
||||
const struct { hypervisor_vendor_t hypervisor; char match[16]; }
|
||||
matchtable[NUM_HYPERVISOR_VENDORS] = {
|
||||
/* source: https://github.com/a0rtega/pafish/blob/master/pafish/cpu.c */
|
||||
{ HYPERVISOR_BHYVE , "bhyve bhyve\0" },
|
||||
{ HYPERVISOR_HYPERV , "Microsoft Hv" },
|
||||
{ HYPERVISOR_KVM , "KVMKVMKVM\0\0\0" },
|
||||
{ HYPERVISOR_PARALLELS , "prl hyperv\0\0" },
|
||||
{ HYPERVISOR_QEMU , "TCGTCGTCGTCG" },
|
||||
{ HYPERVISOR_VIRTUALBOX , "VBoxVBoxVBox" },
|
||||
{ HYPERVISOR_VMWARE , "VMwareVMware" },
|
||||
{ HYPERVISOR_XEN , "XenVMMXenVMM" },
|
||||
};
|
||||
|
||||
if (!data) {
|
||||
if ((r = cpu_identify(raw, data)) < 0)
|
||||
return HYPERVISOR_UNKNOWN;
|
||||
data = &mydata;
|
||||
}
|
||||
|
||||
/* Intel and AMD CPUs have reserved bit 31 of ECX of CPUID leaf 0x1 as the hypervisor present bit
|
||||
Source: https://kb.vmware.com/s/article/1009458 */
|
||||
switch (data->vendor) {
|
||||
case VENDOR_AMD:
|
||||
case VENDOR_INTEL:
|
||||
break;
|
||||
default:
|
||||
return HYPERVISOR_UNKNOWN;
|
||||
}
|
||||
if (!data->flags[CPU_FEATURE_HYPERVISOR])
|
||||
return HYPERVISOR_NONE;
|
||||
|
||||
/* Intel and AMD have also reserved CPUID leaves 0x40000000 - 0x400000FF for software use.
|
||||
Hypervisors can use these leaves to provide an interface to pass information
|
||||
from the hypervisor to the guest operating system running inside a virtual machine.
|
||||
The hypervisor bit indicates the presence of a hypervisor
|
||||
and that it is safe to test these additional software leaves. */
|
||||
memset(hypervisor_fn40000000h, 0, sizeof(hypervisor_fn40000000h));
|
||||
hypervisor_fn40000000h[EAX] = 0x40000000;
|
||||
cpu_exec_cpuid_ext(hypervisor_fn40000000h);
|
||||
|
||||
/* Copy the hypervisor CPUID information leaf */
|
||||
memcpy(hypervisor_str + 0, &hypervisor_fn40000000h[1], 4);
|
||||
memcpy(hypervisor_str + 4, &hypervisor_fn40000000h[2], 4);
|
||||
memcpy(hypervisor_str + 8, &hypervisor_fn40000000h[3], 4);
|
||||
hypervisor_str[12] = '\0';
|
||||
|
||||
/* Determine hypervisor */
|
||||
for (i = 0; i < NUM_HYPERVISOR_VENDORS; i++)
|
||||
if (!strcmp(hypervisor_str, matchtable[i].match))
|
||||
return matchtable[i].hypervisor;
|
||||
return HYPERVISOR_UNKNOWN;
|
||||
}
|
||||
|
||||
void cpuid_free_cpu_list(struct cpu_list_t* list)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -44,3 +44,4 @@ cpuid_free_raw_data_array @40
|
|||
affinity_mask_str @41
|
||||
cpuid_free_system_id @42
|
||||
affinity_mask_str_r @43
|
||||
cpuid_get_hypervisor @44
|
||||
|
|
|
@ -148,6 +148,24 @@ typedef enum {
|
|||
} cpu_purpose_t;
|
||||
#define NUM_CPU_PURPOSES NUM_CPU_PURPOSES
|
||||
|
||||
/**
|
||||
* @brief Hypervisor vendor, as guessed from the CPU_FEATURE_HYPERVISOR flag.
|
||||
*/
|
||||
typedef enum {
|
||||
HYPERVISOR_NONE = 0, /*!< no hypervisor */
|
||||
HYPERVISOR_BHYVE, /*!< FreeBSD bhyve hypervisor */
|
||||
HYPERVISOR_HYPERV, /*!< Microsoft Hyper-V or Windows Virtual PC hypervisor */
|
||||
HYPERVISOR_KVM, /*!< KVM hypervisor */
|
||||
HYPERVISOR_PARALLELS, /*!< Parallels hypervisor */
|
||||
HYPERVISOR_QEMU, /*!< QEMU hypervisor */
|
||||
HYPERVISOR_VIRTUALBOX, /*!< VirtualBox hypervisor */
|
||||
HYPERVISOR_VMWARE, /*!< VMware hypervisor */
|
||||
HYPERVISOR_XEN, /*!< Xen hypervisor */
|
||||
NUM_HYPERVISOR_VENDORS, /*!< Valid hypervisor vendor ids: 0..NUM_HYPERVISOR_VENDORS - 1 */
|
||||
HYPERVISOR_UNKNOWN = -1,
|
||||
} hypervisor_vendor_t;
|
||||
#define NUM_HYPERVISOR_VENDORS NUM_HYPERVISOR_VENDORS
|
||||
|
||||
/**
|
||||
* @brief Contains just the raw CPUID data.
|
||||
*
|
||||
|
@ -591,6 +609,7 @@ typedef enum {
|
|||
CPU_FEATURE_AVX512VNNI, /*!< AVX-512 Vector Neural Network Instructions */
|
||||
CPU_FEATURE_AVX512VBMI, /*!< AVX-512 Vector Bit ManipulationInstructions (version 1) */
|
||||
CPU_FEATURE_AVX512VBMI2, /*!< AVX-512 Vector Bit ManipulationInstructions (version 2) */
|
||||
CPU_FEATURE_HYPERVISOR, /*!< Hypervisor present (always zero on physical CPUs) */
|
||||
/* termination: */
|
||||
NUM_CPU_FEATURES,
|
||||
} cpu_feature_t;
|
||||
|
@ -1167,6 +1186,24 @@ void cpuid_set_verbosiness_level(int level);
|
|||
*/
|
||||
cpu_vendor_t cpuid_get_vendor(void);
|
||||
|
||||
/**
|
||||
* @brief Obtains the hypervisor vendor from CPUID from the current CPU
|
||||
* @param raw - Optional input - a pointer to the raw CPUID data, which is obtained
|
||||
* either by cpuid_get_raw_data or cpuid_deserialize_raw_data.
|
||||
* Can also be NULL, in which case the functions calls
|
||||
* cpuid_get_raw_data itself.
|
||||
* @param data - Optional input - the decoded CPU features/info is written here.
|
||||
* Can also be NULL, in which case the functions calls
|
||||
* cpu_identify itself.
|
||||
* @note If no hypervisor is detected, the hypervisor can be hidden in some cases.
|
||||
* Refer to https://github.com/anrieff/libcpuid/issues/90#issuecomment-296568713.
|
||||
* @returns HYPERVISOR_UNKNOWN if failed,
|
||||
* HYPERVISOR_NONE if no hypervisor detected (or hidden),
|
||||
* otherwise the hypervisor vendor type.
|
||||
* @see hypervisor_vendor_t
|
||||
*/
|
||||
hypervisor_vendor_t cpuid_get_hypervisor(struct cpu_raw_data_t* raw, struct cpu_id_t* data);
|
||||
|
||||
/**
|
||||
* @brief a structure that holds a list of processor names
|
||||
*/
|
||||
|
|
|
@ -41,3 +41,4 @@ cpuid_free_raw_data_array
|
|||
affinity_mask_str
|
||||
cpuid_free_system_id
|
||||
affinity_mask_str_r
|
||||
cpuid_get_hypervisor
|
||||
|
|
Loading…
Reference in a new issue