From e37c7d9ae0615b59481ec7ba194d8f954ad8767f Mon Sep 17 00:00:00 2001 From: Dr-Noob Date: Sun, 11 Oct 2020 23:27:19 +0200 Subject: [PATCH] Basic support for virtual machines --- src/cpuid.c | 129 +++++++++++++++++++++++++++++++++++++++++++++----- src/cpuid.h | 24 ++++++++-- src/main.c | 2 +- src/printer.c | 42 ++++++++-------- src/uarch.c | 4 +- 5 files changed, 163 insertions(+), 38 deletions(-) mode change 100644 => 100755 src/cpuid.c diff --git a/src/cpuid.c b/src/cpuid.c old mode 100644 new mode 100755 index de9918c..2d67c81 --- a/src/cpuid.c +++ b/src/cpuid.c @@ -17,8 +17,23 @@ #include "apic.h" #include "uarch.h" -#define VENDOR_INTEL_STRING "GenuineIntel" -#define VENDOR_AMD_STRING "AuthenticAMD" +#define CPU_VENDOR_INTEL_STRING "GenuineIntel" +#define CPU_VENDOR_AMD_STRING "AuthenticAMD" + +#define HV_VENDOR_KVM_STRING "KVMKVMKVM" +#define HV_VENDOR_QEMU_STRING "TCGTCGTCGTCG" +#define HV_VENDOR_HYPERV_STRING "Microsoft Hv" +#define HV_VENDOR_VMWARE_STRING "VMwareVMware" +#define HV_VENDOR_XEN_STRING "XenVMMXenVMM" +#define HV_VENDOR_PARALLELS_STRING "lrpepyh vr" + +#define HV_KVM_STRING "KVM" +#define HV_QEMU_STRING "QEMU" +#define HV_HYPERV_STRING "Microsoft Hyper-V" +#define HV_VMWARE_STRING "VMware" +#define HV_XEN_STRING "Xen" +#define HV_PARALLELS_STRING "Parallels" +#define HV_UNKNOWN_STRING "Unknown" #define STRING_YES "Yes" #define STRING_NO "No" @@ -30,6 +45,7 @@ #define STRING_MEGABYTES "MB" #define CPU_NAME_MAX_LENGTH 64 +#define HYPERVISOR_NAME_MAX_LENGTH 17 #define MASK 0xFF @@ -107,6 +123,25 @@ void get_cpu_vendor_internal(char* name, uint32_t ebx,uint32_t ecx,uint32_t edx) name[__COUNTER__] = (ecx>>24) & MASK; } +void get_hv_vendor_internal(char* name, uint32_t ebx, uint32_t ecx, uint32_t edx) { + uint32_t c = 0; + + name[c++] = ebx & MASK; + name[c++] = (ebx>>8) & MASK; + name[c++] = (ebx>>16) & MASK; + name[c++] = (ebx>>24) & MASK; + + name[c++] = ecx & MASK; + name[c++] = (ecx>>8) & MASK; + name[c++] = (ecx>>16) & MASK; + name[c++] = (ecx>>24) & MASK; + + name[c++] = edx & MASK; + name[c++] = (edx>>8) & MASK; + name[c++] = (edx>>16) & MASK; + name[c++] = (edx>>24) & MASK; +} + char* get_str_cpu_name_internal() { uint32_t eax = 0; uint32_t ebx = 0; @@ -172,9 +207,66 @@ struct uarch* get_cpu_uarch(struct cpuInfo* cpu) { return get_uarch_from_cpuid(cpu, efamily, family, emodel, model, (int)stepping); } +struct hypervisor* get_hp_info(bool hv_present) { + struct hypervisor* hv = malloc(sizeof(struct hypervisor)); + if(!hv_present) { + hv->present = false; + return hv; + } + + hv->present = true; + hv->hv_name = malloc(sizeof(char) * (HYPERVISOR_NAME_MAX_LENGTH+1)); + memset(hv->hv_name, 0, HYPERVISOR_NAME_MAX_LENGTH+1); + + uint32_t eax = 0x40000000; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + char name[13]; + memset(name, 0, 13); + get_hv_vendor_internal(name, ebx, ecx, edx); + + if(strcmp(HV_VENDOR_KVM_STRING, name) == 0) { + hv->hv_vendor = HV_VENDOR_KVM; + strcpy(hv->hv_name, HV_KVM_STRING); + } + else if (strcmp(HV_VENDOR_QEMU_STRING, name) == 0) { + hv->hv_vendor = HV_VENDOR_QEMU; + strcpy(hv->hv_name, HV_QEMU_STRING); + } + else if (strcmp(HV_VENDOR_HYPERV_STRING, name) == 0) { + hv->hv_vendor = HV_VENDOR_HYPERV; + strcpy(hv->hv_name, HV_HYPERV_STRING); + } + else if (strcmp(HV_VENDOR_VMWARE_STRING, name) == 0) { + hv->hv_vendor = HV_VENDOR_VMWARE; + strcpy(hv->hv_name, HV_VMWARE_STRING); + } + else if (strcmp(HV_VENDOR_XEN_STRING, name) == 0) { + hv->hv_vendor = HV_VENDOR_XEN; + strcpy(hv->hv_name, HV_XEN_STRING); + } + else if (strcmp(HV_VENDOR_PARALLELS_STRING, name) == 0) { + hv->hv_vendor = HV_VENDOR_PARALLELS; + strcpy(hv->hv_name, HV_PARALLELS_STRING); + } + else { + hv->hv_vendor = HV_VENDOR_INVALID; + printWarn("Unknown hypervisor vendor: %s", name); + strcpy(hv->hv_name, HV_UNKNOWN_STRING); + } + + return hv; +} + struct cpuInfo* get_cpu_info() { struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); init_cpu_info(cpu); + cpu->hv = malloc(sizeof(struct hypervisor)); + uint32_t eax = 0; uint32_t ebx = 0; uint32_t ecx = 0; @@ -189,12 +281,12 @@ struct cpuInfo* get_cpu_info() { memset(name,0,13); get_cpu_vendor_internal(name, ebx, ecx, edx); - if(strcmp(VENDOR_INTEL_STRING,name) == 0) - cpu->cpu_vendor = VENDOR_INTEL; - else if (strcmp(VENDOR_AMD_STRING,name) == 0) - cpu->cpu_vendor = VENDOR_AMD; + if(strcmp(CPU_VENDOR_INTEL_STRING,name) == 0) + cpu->cpu_vendor = CPU_VENDOR_INTEL; + else if (strcmp(CPU_VENDOR_AMD_STRING,name) == 0) + cpu->cpu_vendor = CPU_VENDOR_AMD; else { - cpu->cpu_vendor = VENDOR_INVALID; + cpu->cpu_vendor = CPU_VENDOR_INVALID; printErr("Unknown CPU vendor: %s", name); return NULL; } @@ -223,6 +315,10 @@ struct cpuInfo* get_cpu_info() { cpu->AVX = (ecx & ((int)1 << 28)) != 0; cpu->FMA3 = (ecx & ((int)1 << 12)) != 0; + + bool hv_present = (ecx & ((int)1 << 31)) != 0; + if((cpu->hv = get_hp_info(hv_present)) == NULL) + return NULL; } else { printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels); @@ -373,7 +469,7 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) { #endif switch(cpu->cpu_vendor) { - case VENDOR_INTEL: + case CPU_VENDOR_INTEL: if (cpu->maxLevels >= 0x00000004) { get_topology_from_apic(cpu, topo); } @@ -385,7 +481,7 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) { topo->smt_supported = 1; } break; - case VENDOR_AMD: + case CPU_VENDOR_AMD: if (cpu->maxExtendedLevels >= 0x80000008) { eax = 0x80000008; cpuid(&eax, &ebx, &ecx, &edx); @@ -449,7 +545,7 @@ struct cache* get_cache_info(struct cpuInfo* cpu) { // We use standart 0x00000004 for Intel // We use extended 0x8000001D for AMD - if(cpu->cpu_vendor == VENDOR_INTEL) { + if(cpu->cpu_vendor == CPU_VENDOR_INTEL) { level = 0x00000004; if(cpu->maxLevels < level) { printErr("Can't read cache information from cpuid (needed level is %d, max is %d)", level, cpu->maxLevels); @@ -586,6 +682,15 @@ struct frequency* get_frequency_info(struct cpuInfo* cpu) { freq->base = eax; freq->max = ebx; + + if(freq->base == 0) { + printWarn("Read base CPU frequency and got 0 MHz"); + freq->base = UNKNOWN_FREQ; + } + if(freq->max == 0) { + printWarn("Read max CPU frequency and got 0 MHz"); + freq->max = UNKNOWN_FREQ; + } } return freq; @@ -705,7 +810,7 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc if(topo->smt_available > 1) snprintf(string, size, "%d cores (%d threads)",topo->physical_cores * topo->sockets, topo->logical_cores * topo->sockets); else { - if(cpu->cpu_vendor == VENDOR_AMD) + if(cpu->cpu_vendor == CPU_VENDOR_AMD) snprintf(string, size, "%d cores (SMT disabled)",topo->physical_cores * topo->sockets); else snprintf(string, size, "%d cores (HT disabled)",topo->physical_cores * topo->sockets); @@ -715,7 +820,7 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc if(topo->smt_available > 1) snprintf(string, size, "%d cores (%d threads)",topo->physical_cores,topo->logical_cores); else { - if(cpu->cpu_vendor == VENDOR_AMD) + if(cpu->cpu_vendor == CPU_VENDOR_AMD) snprintf(string, size, "%d cores (SMT disabled)",topo->physical_cores); else snprintf(string, size, "%d cores (HT disabled)",topo->physical_cores); diff --git a/src/cpuid.h b/src/cpuid.h index 74738e9..32f394c 100644 --- a/src/cpuid.h +++ b/src/cpuid.h @@ -3,10 +3,19 @@ #include -#define VENDOR_EMPTY 0 -#define VENDOR_INTEL 1 -#define VENDOR_AMD 2 -#define VENDOR_INVALID 3 +#define CPU_VENDOR_EMPTY 0 +#define CPU_VENDOR_INTEL 1 +#define CPU_VENDOR_AMD 2 +#define CPU_VENDOR_INVALID 3 + +#define HV_VENDOR_EMPTY 0 +#define HV_VENDOR_KVM 1 +#define HV_VENDOR_QEMU 2 +#define HV_VENDOR_HYPERV 3 +#define HV_VENDOR_VMWARE 4 +#define HV_VENDOR_XEN 5 +#define HV_VENDOR_PARALLELS 6 +#define HV_VENDOR_INVALID 7 #define UNKNOWN_FREQ -1 @@ -14,6 +23,12 @@ typedef int32_t VENDOR; struct frequency; +struct hypervisor { + bool present; + char* hv_name; + VENDOR hv_vendor; +}; + struct cpuInfo { bool AVX; bool AVX2; @@ -39,6 +54,7 @@ struct cpuInfo { uint32_t maxExtendedLevels; struct uarch* arch; + struct hypervisor* hv; }; struct cach { diff --git a/src/main.c b/src/main.c index 129cc67..06a81b0 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ #include "cpuid.h" #include "global.h" -static const char* VERSION = "0.7"; +static const char* VERSION = "0.71"; void print_help(char *argv[]) { printf("Usage: %s [--version] [--help] [--levels] [--style \"fancy\"|\"retro\"|\"legacy\"] [--color \"intel\"|\"amd\"|'R,G,B:R,G,B:R,G,B:R,G,B']\n\n\ diff --git a/src/printer.c b/src/printer.c index fd6cc86..7a507cc 100644 --- a/src/printer.c +++ b/src/printer.c @@ -41,24 +41,26 @@ #define TITLE_PEAK "Peak Performance:" #define TITLE_UARCH "Microarchitecture:" #define TITLE_TECHNOLOGY "Technology:" +#define TITLE_HYPERVISOR "Hypervisor:" -#define MAX_ATTRIBUTE_COUNT 14 +#define MAX_ATTRIBUTE_COUNT 15 #define ATTRIBUTE_NAME 0 -#define ATTRIBUTE_UARCH 1 -#define ATTRIBUTE_TECHNOLOGY 2 -#define ATTRIBUTE_FREQUENCY 3 -#define ATTRIBUTE_SOCKETS 4 -#define ATTRIBUTE_NCORES 5 -#define ATTRIBUTE_NCORES_DUAL 6 -#define ATTRIBUTE_AVX 7 -#define ATTRIBUTE_FMA 8 -#define ATTRIBUTE_L1i 9 -#define ATTRIBUTE_L1d 10 -#define ATTRIBUTE_L2 11 -#define ATTRIBUTE_L3 12 -#define ATTRIBUTE_PEAK 13 +#define ATTRIBUTE_HYPERVISOR 1 +#define ATTRIBUTE_UARCH 2 +#define ATTRIBUTE_TECHNOLOGY 3 +#define ATTRIBUTE_FREQUENCY 4 +#define ATTRIBUTE_SOCKETS 5 +#define ATTRIBUTE_NCORES 6 +#define ATTRIBUTE_NCORES_DUAL 7 +#define ATTRIBUTE_AVX 8 +#define ATTRIBUTE_FMA 9 +#define ATTRIBUTE_L1i 10 +#define ATTRIBUTE_L1d 11 +#define ATTRIBUTE_L2 12 +#define ATTRIBUTE_L3 13 +#define ATTRIBUTE_PEAK 14 -static const char* ATTRIBUTE_FIELDS [MAX_ATTRIBUTE_COUNT] = { TITLE_NAME, TITLE_UARCH, TITLE_TECHNOLOGY, +static const char* ATTRIBUTE_FIELDS [MAX_ATTRIBUTE_COUNT] = { TITLE_NAME, TITLE_HYPERVISOR, TITLE_UARCH, TITLE_TECHNOLOGY, TITLE_FREQUENCY, TITLE_SOCKETS, TITLE_NCORES, TITLE_NCORES_DUAL, TITLE_AVX, @@ -66,7 +68,7 @@ static const char* ATTRIBUTE_FIELDS [MAX_ATTRIBUTE_COUNT] = { TITLE_NAME, TITLE_ TITLE_PEAK, }; -static const int ATTRIBUTE_LIST[MAX_ATTRIBUTE_COUNT] = { ATTRIBUTE_NAME, ATTRIBUTE_UARCH, ATTRIBUTE_TECHNOLOGY, +static const int ATTRIBUTE_LIST[MAX_ATTRIBUTE_COUNT] = { ATTRIBUTE_NAME, ATTRIBUTE_HYPERVISOR, ATTRIBUTE_UARCH, ATTRIBUTE_TECHNOLOGY, ATTRIBUTE_FREQUENCY, ATTRIBUTE_SOCKETS, ATTRIBUTE_NCORES, ATTRIBUTE_NCORES_DUAL, ATTRIBUTE_AVX, ATTRIBUTE_FMA, @@ -127,7 +129,7 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) { art->attributes[i] = NULL; strcpy(art->reset,RESET); - if(cpuVendor == VENDOR_INTEL) { + if(cpuVendor == CPU_VENDOR_INTEL) { COL_FANCY_1 = COL_INTEL_FANCY_1; COL_FANCY_2 = COL_INTEL_FANCY_2; COL_FANCY_3 = COL_INTEL_FANCY_3; @@ -213,7 +215,7 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) { } char tmp[NUMBER_OF_LINES*LINE_SIZE]; - if(cpuVendor == VENDOR_INTEL) strcpy(tmp, INTEL_ASCII); + if(cpuVendor == CPU_VENDOR_INTEL) strcpy(tmp, INTEL_ASCII); else strcpy(tmp, AMD_ASCII); for(int i=0; i < NUMBER_OF_LINES; i++) strncpy(art->art[i], tmp + i*LINE_SIZE, LINE_SIZE); @@ -310,7 +312,7 @@ uint32_t longest_attribute_length(struct ascii* art) { void print_ascii(struct ascii* art) { uint32_t longest_attribute = longest_attribute_length(art); - if(art->vendor == VENDOR_INTEL) + if(art->vendor == CPU_VENDOR_INTEL) print_ascii_intel(art, longest_attribute); else print_ascii_amd(art, longest_attribute); @@ -360,6 +362,8 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f printBug("The number of attributes set is bigger than the max that can be displayed"); return false; } + if(cpu->hv->present) + setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name); print_ascii(art); diff --git a/src/uarch.c b/src/uarch.c index fc5278a..4a53d5a 100644 --- a/src/uarch.c +++ b/src/uarch.c @@ -341,7 +341,7 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin } struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) { - if(cpu->cpu_vendor == VENDOR_INTEL) + if(cpu->cpu_vendor == CPU_VENDOR_INTEL) return get_uarch_from_cpuid_intel(ef, f, em, m, s); else return get_uarch_from_cpuid_amd(ef, f, em, m, s); @@ -352,7 +352,7 @@ bool vpus_are_AVX512(struct cpuInfo* cpu) { } int get_number_of_vpus(struct cpuInfo* cpu) { - if(cpu->cpu_vendor == VENDOR_AMD) + if(cpu->cpu_vendor == CPU_VENDOR_AMD) return 1; switch(cpu->arch->uarch) {