Skip to content

Commit

Permalink
Basic support for virtual machines
Browse files Browse the repository at this point in the history
  • Loading branch information
Dr-Noob committed Oct 11, 2020
1 parent aa5f0a8 commit e37c7d9
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 38 deletions.
129 changes: 117 additions & 12 deletions src/cpuid.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -30,6 +45,7 @@
#define STRING_MEGABYTES "MB"

#define CPU_NAME_MAX_LENGTH 64
#define HYPERVISOR_NAME_MAX_LENGTH 17

#define MASK 0xFF

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
24 changes: 20 additions & 4 deletions src/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,32 @@

#include <stdint.h>

#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

typedef int32_t VENDOR;

struct frequency;

struct hypervisor {
bool present;
char* hv_name;
VENDOR hv_vendor;
};

struct cpuInfo {
bool AVX;
bool AVX2;
Expand All @@ -39,6 +54,7 @@ struct cpuInfo {
uint32_t maxExtendedLevels;

struct uarch* arch;
struct hypervisor* hv;
};

struct cach {
Expand Down
2 changes: 1 addition & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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\
Expand Down
42 changes: 23 additions & 19 deletions src/printer.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,34 @@
#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,
TITLE_FMA, TITLE_L1i, TITLE_L1d, TITLE_L2, TITLE_L3,
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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions src/uarch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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) {
Expand Down

0 comments on commit e37c7d9

Please sign in to comment.