From 5148962fa30625dbf25b264efcbb72e26fffa3bc Mon Sep 17 00:00:00 2001 From: Dr-Noob Date: Mon, 31 Aug 2020 13:18:25 +0200 Subject: [PATCH] Add code to detect CPU microarchitecture (Intel only, at the moment) --- Makefile | 4 +- src/cpuid.c | 20 ++++++ src/cpuid.h | 2 + src/uarch.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/uarch.h | 10 +++ 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 src/uarch.c create mode 100644 src/uarch.h diff --git a/Makefile b/Makefile index 7a92dc6..adfaf8a 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ CXXFLAGS=-Wall -Wextra -Werror -pedantic -fstack-protector-all -pedantic -std=c9 SANITY_FLAGS=-Wfloat-equal -Wshadow -Wpointer-arith -Wstrict-overflow=5 -Wformat=2 SRC_DIR=src/ -SOURCE=$(SRC_DIR)main.c $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)printer.c $(SRC_DIR)args.c $(SRC_DIR)global.c -HEADERS=$(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)printer.h $(SRC_DIR)ascii.h $(SRC_DIR)args.h $(SRC_DIR)global.h +SOURCE=$(SRC_DIR)main.c $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)printer.c $(SRC_DIR)args.c $(SRC_DIR)global.c $(SRC_DIR)uarch.c +HEADERS=$(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)printer.h $(SRC_DIR)ascii.h $(SRC_DIR)args.h $(SRC_DIR)global.h $(SRC_DIR)uarch.h ifneq ($(OS),Windows_NT) SOURCE += $(SRC_DIR)udev.c diff --git a/src/cpuid.c b/src/cpuid.c index 096bcf8..93df053 100644 --- a/src/cpuid.c +++ b/src/cpuid.c @@ -15,6 +15,7 @@ #include "cpuid_asm.h" #include "global.h" #include "apic.h" +#include "uarch.h" #define VENDOR_INTEL_STRING "GenuineIntel" #define VENDOR_AMD_STRING "AuthenticAMD" @@ -165,6 +166,23 @@ char* get_str_cpu_name_internal() { return name; } +struct uarch* get_cpu_uarch() { + uint32_t eax = 0x00000001; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + uint32_t stepping = eax & 0xF; + uint32_t model = (eax >> 4) & 0xF; + uint32_t emodel = (eax >> 16) & 0xF; + uint32_t family = (eax >> 8) & 0xF; + uint32_t efamily = (eax >> 20) & 0xFF; + + return get_uarch_from_cpuid(efamily, family, emodel, model, (int)stepping); +} + struct cpuInfo* get_cpu_info() { struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); init_cpu_info(cpu); @@ -258,6 +276,8 @@ struct cpuInfo* get_cpu_info() { sprintf(cpu->cpu_name,"Unknown"); printWarn("Can't read cpu name from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000004, cpu->maxExtendedLevels); } + + cpu->arch = get_cpu_uarch(cpu); return cpu; } diff --git a/src/cpuid.h b/src/cpuid.h index 21ec95e..f82fab0 100644 --- a/src/cpuid.h +++ b/src/cpuid.h @@ -37,6 +37,8 @@ struct cpuInfo { uint32_t maxLevels; // Max cpuids extended levels uint32_t maxExtendedLevels; + + struct uarch* arch; }; struct cach { diff --git a/src/uarch.c b/src/uarch.c new file mode 100644 index 0000000..9f839f1 --- /dev/null +++ b/src/uarch.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include + +#include "uarch.h" + +/* + * - Intel Microcode Revision Guidance (MRG): + * https://www.intel.com/content/dam/www/public/us/en/documents/corporate-information/SA00270-microcode-update-guidance.pdf + * - cpuid codes are based on Todd Allen's cpuid program + * http://www.etallen.com/cpuid.html + */ +typedef uint32_t MICROARCH; + +// No stepping +#define NS 0 + +// Unknown manufacturing process +#define UNK -1 + +#define UARCH_UNKNOWN 0x000 +#define UARCH_P5 0x001 +#define UARCH_P6 0x002 +#define UARCH_DOTHAN 0x003 +#define UARCH_YONAH 0x004 +#define UARCH_MEROM 0x005 +#define UARCH_PENYR 0x006 +#define UARCH_NEHALEM 0x007 +#define UARCH_WESTMERE 0x008 +#define UARCH_BONNELL 0x009 +#define UARCH_SALTWELL 0x010 +#define UARCH_SANDY_BRIDGE 0x011 +#define UARCH_SILVERMONT 0x012 +#define UARCH_IVY_BRIDGE 0x013 +#define UARCH_HASWELL 0x014 +#define UARCH_BROADWELL 0x015 +#define UARCH_AIRMONT 0x016 +#define UARCH_KABY_LAKE 0x017 +#define UARCH_SKYLAKE 0x018 +#define UARCH_CASCADE_LAKE 0x019 +#define UARCH_COOPER_LAKE 0x020 +#define UARCH_KNIGHTS_LANDING 0x021 +#define UARCH_KNIGHTS_MILL 0x022 +#define UARCH_GOLDMONT 0x023 +#define UARCH_PALM_COVE 0x024 +#define UARCH_SUNNY_COVE 0x025 +#define UARCH_GOLDMONT_PLUS 0x026 +#define UARCH_TREMONT 0x027 +#define UARCH_WILLOW_COVE 0x028 +#define UARCH_COFFE_LAKE 0x029 +#define UARCH_ITANIUM 0x030 +#define UARCH_KNIGHTS_FERRY 0x031 +#define UARCH_KNIGHTS_CORNER 0x032 +#define UARCH_WILLAMETTE 0x033 +#define UARCH_NORTHWOOD 0x034 +#define UARCH_PRESCOTT 0x035 +#define UARCH_CEDAR_MILL 0x036 +#define UARCH_ITANIUM2 0x037 + +struct uarch { + MICROARCH uarch; + char* uarch_str; + int32_t process; // measured in nanometers +}; + +#define UARCH_START if (false) {} +#define CHECK_UARCH(arch, ef_, f_, em_, m_, s_, str, uarch, process) \ + else if (ef_ == ef && f_ == f && em_ == em && m_ == m && (s_ == NS || s_ == s)) fill_uarch(arch, str, uarch, process); +#define UARCH_END else { arch->uarch = UARCH_UNKNOWN; } + +void fill_uarch(struct uarch* arch, char* str, MICROARCH u, uint32_t process) { + arch->uarch_str = malloc(sizeof(char) * strlen(str)); + strcpy(arch->uarch_str, str); + arch->uarch = u; + arch->process= process; +} + +// inspired in Todd Allen's decode_uarch_intel +struct uarch* get_uarch_from_cpuid(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) { + struct uarch* arch = malloc(sizeof(struct uarch)); + + // EF: Extended Family // + // F: Family // + // EM: Extended Model // + // M: Model // + // S: Stepping // + // ----------------------------------------------------------------------------- // + // EF F EM M S // + UARCH_START + CHECK_UARCH(arch, 0, 5, 0, 0, NS, "P5", UARCH_P5, 800) + CHECK_UARCH(arch, 0, 5, 0, 1, NS, "P5", UARCH_P5, 800) + CHECK_UARCH(arch, 0, 5, 0, 2, NS, "P5", UARCH_P5, UNK) + CHECK_UARCH(arch, 0, 5, 0, 3, NS, "P5", UARCH_P5, 600) + CHECK_UARCH(arch, 0, 5, 0, 4, NS, "P5 MMX", UARCH_P5, UNK) + CHECK_UARCH(arch, 0, 5, 0, 7, NS, "P5 MMX", UARCH_P5, UNK) + CHECK_UARCH(arch, 0, 5, 0, 8, NS, "P5 MMX", UARCH_P5, 250) + CHECK_UARCH(arch, 0, 5, 0, 9, NS, "P5 MMX", UARCH_P5, UNK) + CHECK_UARCH(arch, 0, 6, 0, 0, NS, "P6 Pentium II", UARCH_P6, UNK) + CHECK_UARCH(arch, 0, 6, 0, 1, NS, "P6 Pentium II", UARCH_P6, UNK) // process depends on core + CHECK_UARCH(arch, 0, 6, 0, 2, NS, "P6 Pentium II", UARCH_P6, UNK) + CHECK_UARCH(arch, 0, 6, 0, 3, NS, "P6 Pentium II", UARCH_P6, 350) + CHECK_UARCH(arch, 0, 6, 0, 4, NS, "P6 Pentium II", UARCH_P6, UNK) + CHECK_UARCH(arch, 0, 6, 0, 5, NS, "P6 Pentium II", UARCH_P6, 250) + CHECK_UARCH(arch, 0, 6, 0, 6, NS, "P6 Pentium II", UARCH_P6, UNK) + CHECK_UARCH(arch, 0, 6, 0, 7, NS, "P6 Pentium III", UARCH_P6, 250) + CHECK_UARCH(arch, 0, 6, 0, 8, NS, "P6 Pentium III", UARCH_P6, 180) + CHECK_UARCH(arch, 0, 6, 0, 9, NS, "P6 Pentium M", UARCH_P6, 130) + CHECK_UARCH(arch, 0, 6, 0, 10, NS, "P6 Pentium III", UARCH_P6, 180) + CHECK_UARCH(arch, 0, 6, 0, 11, NS, "P6 Pentium III", UARCH_P6, 130) + CHECK_UARCH(arch, 0, 6, 0, 13, NS, "Dothan", UARCH_DOTHAN, UNK) // process depends on core + CHECK_UARCH(arch, 0, 6, 0, 14, NS, "Yonah", UARCH_YONAH, 65) + CHECK_UARCH(arch, 0, 6, 0, 15, NS, "Merom", UARCH_MEROM, 65) + CHECK_UARCH(arch, 0, 6, 1, 5, NS, "Dothan", UARCH_DOTHAN, 90) + CHECK_UARCH(arch, 0, 6, 1, 6, NS, "Merom", UARCH_MEROM, 65) + CHECK_UARCH(arch, 0, 6, 1, 7, NS, "Penryn", UARCH_PENYR, 45) + CHECK_UARCH(arch, 0, 6, 1, 10, NS, "Nehalem", UARCH_NEHALEM, 45) + CHECK_UARCH(arch, 0, 6, 1, 12, NS, "Bonnell", UARCH_BONNELL, 45) + CHECK_UARCH(arch, 0, 6, 1, 13, NS, "Penryn", UARCH_PENYR, 45) + CHECK_UARCH(arch, 0, 6, 1, 14, NS, "Nehalem", UARCH_NEHALEM, 45) + CHECK_UARCH(arch, 0, 6, 1, 15, NS, "Nehalem", UARCH_NEHALEM, 45) + CHECK_UARCH(arch, 0, 6, 2, 5, NS, "Westmere", UARCH_WESTMERE, 32) + CHECK_UARCH(arch, 0, 6, 2 , 6, NS, "Bonnell", UARCH_BONNELL, 45) + CHECK_UARCH(arch, 0, 6, 2, 7, NS, "Saltwell", UARCH_SALTWELL, 32) + CHECK_UARCH(arch, 0, 6, 2, 10, NS, "Sandy Bridge", UARCH_SANDY_BRIDGE, 32) + CHECK_UARCH(arch, 0, 6, 2, 12, NS, "Westmere", UARCH_WESTMERE, 32) + CHECK_UARCH(arch, 0, 6, 2, 13, NS, "Sandy Bridge", UARCH_SANDY_BRIDGE, 32) + CHECK_UARCH(arch, 0, 6, 2, 14, NS, "Nehalem", UARCH_NEHALEM, 45) + CHECK_UARCH(arch, 0, 6, 2, 15, NS, "Westmere", UARCH_WESTMERE, 32) + CHECK_UARCH(arch, 0, 6, 3, 5, NS, "Saltwell", UARCH_SALTWELL, 14) + CHECK_UARCH(arch, 0, 6, 3, 6, NS, "Saltwell", UARCH_SALTWELL, 32) + CHECK_UARCH(arch, 0, 6, 3, 7, NS, "Silvermont", UARCH_SILVERMONT, 22) + CHECK_UARCH(arch, 0, 6, 3, 10, NS, "Ivy Bridge", UARCH_IVY_BRIDGE, 22) + CHECK_UARCH(arch, 0, 6, 3, 12, NS, "Haswell", UARCH_HASWELL, 22) + CHECK_UARCH(arch, 0, 6, 3, 13, NS, "Broadwell", UARCH_BROADWELL, 14) + CHECK_UARCH(arch, 0, 6, 3, 14, NS, "Ivy Bridge", UARCH_IVY_BRIDGE, 22) + CHECK_UARCH(arch, 0, 6, 3, 15, NS, "Haswell", UARCH_HASWELL, 22) + CHECK_UARCH(arch, 0, 6, 4, 5, NS, "Haswell", UARCH_HASWELL, 22) + CHECK_UARCH(arch, 0, 6, 4, 6, NS, "Haswell", UARCH_HASWELL, 22) + CHECK_UARCH(arch, 0, 6, 4, 7, NS, "Broadwell", UARCH_BROADWELL, 14) + CHECK_UARCH(arch, 0, 6, 4, 10, NS, "Silvermont", UARCH_SILVERMONT, 22) // no docs, but /proc/cpuinfo seen in wild + CHECK_UARCH(arch, 0, 6, 4, 12, NS, "Airmont", UARCH_AIRMONT, 14) + CHECK_UARCH(arch, 0, 6, 4, 13, NS, "Silvermont", UARCH_SILVERMONT, 22) + CHECK_UARCH(arch, 0, 6, 4, 14, 8, "Kaby Lake", UARCH_KABY_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 4, 14, NS, "Skylake", UARCH_SKYLAKE, 14) + CHECK_UARCH(arch, 0, 6, 4, 15, NS, "Broadwell", UARCH_BROADWELL, 14) + CHECK_UARCH(arch, 0, 6, 5, 5, 6, "Cascade Lake", UARCH_CASCADE_LAKE, 14) // no docs, but example from Greg Stewart + CHECK_UARCH(arch, 0, 6, 5, 5, 7, "Cascade Lake", UARCH_CASCADE_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 5, 5, 10, "Cooper Lake", UARCH_COOPER_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 5, 5, NS, "Skylake", UARCH_SKYLAKE, 14) + CHECK_UARCH(arch, 0, 6, 5, 6, NS, "Broadwell", UARCH_BROADWELL, 14) + CHECK_UARCH(arch, 0, 6, 5, 7, NS, "Knights Landing", UARCH_KNIGHTS_LANDING, 14) + CHECK_UARCH(arch, 0, 6, 5, 10, NS, "Silvermont", UARCH_SILVERMONT, 22) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 5, 12, NS, "Goldmont", UARCH_GOLDMONT, 14) + CHECK_UARCH(arch, 0, 6, 5, 13, NS, "Silvermont", UARCH_SILVERMONT, 22) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 5, 14, 8, "Kaby Lake", UARCH_KABY_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 5, 14, NS, "Skylake", UARCH_SKYLAKE, 14) + CHECK_UARCH(arch, 0, 6, 5, 15, NS, "Goldmont", UARCH_GOLDMONT, 14) + CHECK_UARCH(arch, 0, 6, 6, 6, NS, "Palm Cove", UARCH_PALM_COVE, 10) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 6, 10, NS, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 6, 12, NS, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 7, 5, NS, "Airmont", UARCH_AIRMONT, 14) // no spec update; whispers & rumors + CHECK_UARCH(arch, 0, 6, 7, 10, NS, "Goldmont Plus", UARCH_GOLDMONT_PLUS, 14) + CHECK_UARCH(arch, 0, 6, 7, 13, NS, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 7, 14, NS, "Sunny Cove", UARCH_SUNNY_COVE, 10) + CHECK_UARCH(arch, 0, 6, 8, 5, NS, "Knights Mill", UARCH_KNIGHTS_MILL, 14) // no spec update; only MSR_CPUID_table* so far + CHECK_UARCH(arch, 0, 6, 8, 6, NS, "Tremont", UARCH_TREMONT, 10) // LX* + CHECK_UARCH(arch, 0, 6, 8, 10, NS, "Tremont", UARCH_TREMONT, 10) // no spec update; only geekbench.com example + CHECK_UARCH(arch, 0, 6, 8, 12, NS, "Willow Cove", UARCH_WILLOW_COVE, 10) // found only on en.wikichip.org + CHECK_UARCH(arch, 0, 6, 8, 13, NS, "Willow Cove", UARCH_WILLOW_COVE, 10) // LX* + CHECK_UARCH(arch, 0, 6, 8, 14, NS, "Kaby Lake", UARCH_KABY_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 9, 6, NS, "Tremont", UARCH_TREMONT, 10) // LX* + CHECK_UARCH(arch, 0, 6, 9, 12, NS, "Tremont", UARCH_TREMONT, 10) // LX* + CHECK_UARCH(arch, 0, 6, 9, 13, NS, "Sunny Cove", UARCH_SUNNY_COVE, 10) // LX* + CHECK_UARCH(arch, 0, 6, 9, 14, 9, "Kaby Lake", UARCH_KABY_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 9, 14, 10, "Coffee Lake", UARCH_COFFE_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 9, 14, 11, "Coffee Lake", UARCH_COFFE_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 9, 14, 12, "Coffee Lake", UARCH_COFFE_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 9, 14, 13, "Coffee Lake", UARCH_COFFE_LAKE, 14) + CHECK_UARCH(arch, 0, 6, 10, 5, NS, "Kaby Lake", UARCH_KABY_LAKE, 14) // LX* + CHECK_UARCH(arch, 0, 6, 10, 6, NS, "Kaby Lake", UARCH_KABY_LAKE, 14) // no spec update; only instlatx64 example + CHECK_UARCH(arch, 0, 11, 0, 0, NS, "Knights Ferry", UARCH_KNIGHTS_FERRY, 45) // found only on en.wikichip.org + CHECK_UARCH(arch, 0, 11, 0, 1, NS, "Knights Corner", UARCH_KNIGHTS_CORNER, 22) + CHECK_UARCH(arch, 0, 15, 0, 0, NS, "Willamette", UARCH_WILLAMETTE, 180) + CHECK_UARCH(arch, 0, 15, 0, 1, NS, "Willamette", UARCH_WILLAMETTE, 180) + CHECK_UARCH(arch, 0, 15, 0, 2, NS, "Northwood", UARCH_NORTHWOOD, 130) + CHECK_UARCH(arch, 0, 15, 0, 3, NS, "Prescott", UARCH_PRESCOTT, 90) + CHECK_UARCH(arch, 0, 15, 0, 4, NS, "Prescott", UARCH_PRESCOTT, 90) + CHECK_UARCH(arch, 0, 15, 0, 6, NS, "Cedar Mill", UARCH_CEDAR_MILL, 65) + CHECK_UARCH(arch, 1, 15, 0, 0, NS, "Itanium2", UARCH_ITANIUM2, 180) + CHECK_UARCH(arch, 1, 15, 0, 1, NS, "Itanium2", UARCH_ITANIUM2, 130) + CHECK_UARCH(arch, 1, 15, 0, 2, NS, "Itanium2", UARCH_ITANIUM2, 130) + UARCH_END + + // DEBUG + //printf("M=0x%.8X EM=0x%.8X F=0x%.8X EF=0x%.8X S=0x%.8X\n", m, em, f, ef, s); + //printf("Your arch: %s\n", arch->uarch_str); + + return arch; +} diff --git a/src/uarch.h b/src/uarch.h new file mode 100644 index 0000000..c0c10f1 --- /dev/null +++ b/src/uarch.h @@ -0,0 +1,10 @@ +#ifndef __UARCH__ +#define __UARCH__ + +#include + +struct uarch; + +struct uarch* get_uarch_from_cpuid(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s); + +#endif