Add code to detect CPU microarchitecture (Intel only, at the moment)

This commit is contained in:
Dr-Noob
2020-08-31 13:18:25 +02:00
parent d998acdcdf
commit 5148962fa3
5 changed files with 234 additions and 2 deletions

View File

@@ -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 SANITY_FLAGS=-Wfloat-equal -Wshadow -Wpointer-arith -Wstrict-overflow=5 -Wformat=2
SRC_DIR=src/ 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 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 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) ifneq ($(OS),Windows_NT)
SOURCE += $(SRC_DIR)udev.c SOURCE += $(SRC_DIR)udev.c

View File

@@ -15,6 +15,7 @@
#include "cpuid_asm.h" #include "cpuid_asm.h"
#include "global.h" #include "global.h"
#include "apic.h" #include "apic.h"
#include "uarch.h"
#define VENDOR_INTEL_STRING "GenuineIntel" #define VENDOR_INTEL_STRING "GenuineIntel"
#define VENDOR_AMD_STRING "AuthenticAMD" #define VENDOR_AMD_STRING "AuthenticAMD"
@@ -165,6 +166,23 @@ char* get_str_cpu_name_internal() {
return name; 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* get_cpu_info() {
struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo));
init_cpu_info(cpu); init_cpu_info(cpu);
@@ -258,6 +276,8 @@ struct cpuInfo* get_cpu_info() {
sprintf(cpu->cpu_name,"Unknown"); 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); 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; return cpu;
} }

View File

@@ -37,6 +37,8 @@ struct cpuInfo {
uint32_t maxLevels; uint32_t maxLevels;
// Max cpuids extended levels // Max cpuids extended levels
uint32_t maxExtendedLevels; uint32_t maxExtendedLevels;
struct uarch* arch;
}; };
struct cach { struct cach {

200
src/uarch.c Normal file
View File

@@ -0,0 +1,200 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

10
src/uarch.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef __UARCH__
#define __UARCH__
#include <stdint.h>
struct uarch;
struct uarch* get_uarch_from_cpuid(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s);
#endif