/*****************************************************************************\ * * * File name cpuid.c * * * * Description Identify the CPU ID and speed. * * * * Notes References: * * Intel Application Note 485 - The CPUID Instruction * * Intel 64 and IA-32 Architectures Software Developer's Manual * Wikipedia: https://en.wikipedia.org/wiki/CPUID * * * * TO DO: Add support for VMX capabilities detection, like * * Intel's EPT (Extended Page Tables) (= AMD's SLAT (Second * * Level Address Translation)) * * Unfortunately, this is not defined in CPUID, but in MSRs. * * See Intel's IA32 Software Development Manual volume 3 * * chapter 28.2 (EPT) and appendix A (VMX Capability * * Reporting Facility * * * * History * * 1997-06-13 JFL Created this file. * * 1997-09-03 JFL Updated comments. * * 1998-03-18 JFL Added -i option to display processor ID information. * * 1999-02-01 JFL Updated processors IDs and capability flags from the * * latest specs from Intel. * * 2000-03-22 JFL Added Pentium III and some Willamette support. * * 2003-01-22 JFL Added Pentium IV support. * * 2005-04-28 JFL Added Extended Feature Flags support. * * 2005-09-30 JFL Override NODOSLIB's putchar, to output on stdout. * * 2009-08-29 JFL Read the extended model number too. * * Added numerous processor models to the list. * * Added numerous new feature flags definitions. * * 2009-08-31 JFL Added the definition of several AMD extended features. * * 2009-09-01 JFL Added numerous processor code names from wikipedia. * * Added a version time stamp, displayed by -?. * * 2009-10-06 JFL Adapted to WIN32. * * 2012-10-18 JFL Added my name in the help. * * 2013-01-31 JFL Display the number of cores. * * 2013-05-30 JFL Some CPUs pretend to support function 0xB, but do not. * * 2016-04-12 JFL Removed a duplicate prototype, now defined in pmode.h. * * 2017-05-31 JFL Fixed WIN32 warnings. No functional code change. * * 2017-12-18 JFL Fixed DOS warnings. No functional code change. * * 2019-04-19 JFL Use the version strings from the new stversion.h. * * 2019-06-12 JFL Added PROGRAM_DESCRIPTION definition. * * 2019-09-27 JFL Fixed a minor formating error in a debug message. * * 2020-02-23 JFL Decode cpuid(7, 0) output. * * 2020-02-24 JFL Added option -m to experiment with reading MSRs. * * 2020-02-26 JFL Added option -w to experiment with reading WMI props. * * Output a few WMI props, including SLAT, in Windows. * * Skip head spaces in brand string, if any. * * 2020-03-02 JFL Display the CPUID index for every set of feature flags. * * Corrected typos and errors about MTRR registers. * * * * 2022-03-10 ZW Stripped out everything inapplicable to running under * * Simics. Made self-contained. Inline assembly converted * * to GCC style. Aggressively reformatted and linted. * * * * © Copyright 2016 Hewlett Packard Enterprise Development LP * * Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 * \*****************************************************************************/ #define PROGRAM_DESCRIPTION "Identify the processor and its features" #define PROGRAM_NAME "cpuid" #define PROGRAM_VERSION "2022-03-10" #include #include #include #include #include /* Intel processors list */ typedef struct { int iFamily; int iModel; const char *pszCodeName; const char *pszName; } INTEL_PROC; static const INTEL_PROC IntelProcList[] = { // See http://en.wikipedia.org/wiki/List_of_Intel_microprocessors // Family Model CodeName Name Brand name {4, 0, "", "486 DX"}, {4, 1, "", "486 DX"}, {4, 2, "", "486 SX"}, {4, 3, "", "486 DX2"}, {4, 4, "", "486 SL"}, {4, 5, "", "486 SX2"}, {4, 7, "", "486 DX2 enhanced"}, {4, 8, "", "486 DX4"}, {5, 1, "P5", "Pentium"}, // Initial Pentium (60, 66) {5, 2, "P54C", "Pentium"}, // Pentium (75-200) {5, 3, "", "Pentium Overdrive for 486 systems"}, {5, 4, "P55C/Tillamook", "Pentium MMX"}, // Pentium MMX (166-233) {6, 1, "P6", "Pentium Pro"}, // Pentium Pro {6, 3, "Klamath", "Pentium II"}, // Pentium II (233-450) {6, 5, "DesChutes", "Pentium II"}, // Portable P. II {6, 6, "Mendocino", "Celeron"}, {6, 7, "Katmai", "Pentium III"}, {6, 8, "CopperMine", "Pentium III"}, {6, 9, "Banias", "Pentium M model 9 130nm"}, {6, 10, "", "Pentium III Xeon A"}, {6, 11, "Tualatin", "Pentium III model B"}, {6, 13, "Dothan", "Pentium M model D 90nm"}, {6, 14, "Yonah", "Core model E 65nm"}, {6, 15, "Conroe", "Core 2 model F 65nm"}, {6, 21, "Tolapai", "EP80579 Integrated Processor"}, {6, 22, "", "Celeron model 16h"}, {6, 23, "Wolfdale", "Core 2 Extreme 45nm"}, {6, 26, "Bloomfield", "Core i7 45nm"}, {6, 28, "", "Atom 45nm"}, {6, 29, "", "Xeon MP 45nm"}, {15, 0, "Willamette", "Pentium 4 model 0 180nm"}, {15, 1, "", "Pentium 4 model 1 180nm"}, {15, 2, "Northwood", "Pentium 4 model 2 130nm"}, {15, 3, "Prescott", "Pentium 4 model 3 90nm"}, {15, 4, "Prescott-2M", "Pentium 4 model 4 90nm"}, // 64 bits {15, 6, "Cedar Mill", "Pentium 4 model 6 65nm"}, // 64 bits }; #define N_INTEL_PROCS (sizeof(IntelProcList) / sizeof(INTEL_PROC)) /* Forward references */ static void usage(void); static int identify_processor(void); static void DisplayProcInfo(void); static uint32_t _cpuid(uint32_t dwId, uint32_t * pEax, uint32_t * pEbx, uint32_t * pEcx, uint32_t * pEdx); static void _rdmsr(uint32_t dwECX, uint32_t pdwMSR[2]); /* Byte and word extractors */ static inline uint8_t BYTE0(uint32_t n) { return (uint8_t) ((n & 0x000000FFu) >> 0); } static inline uint8_t BYTE1(uint32_t n) { return (uint8_t) ((n & 0x0000FF00u) >> 8); } static inline uint8_t BYTE2(uint32_t n) { return (uint8_t) ((n & 0x00FF0000u) >> 16); } static inline uint16_t WORD0(uint32_t n) { return (uint16_t) ((n & 0x0000FFFFu) >> 0); } static inline uint16_t WORD1(uint32_t n) { return (uint16_t) ((n & 0xFFFF0000u) >> 16); } /*---------------------------------------------------------------------------*\ * * | Function main | | | | Description EXE program main initialization routine | | | | Parameters int argc Number of arguments | | char *argv[] List of arguments | | | | Returns The return code to pass to the BIOS, if run from ROM. | | | | History | | 1996/11/20 JFL Created this routine | * * \*---------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { int iFamily; bool iVerbose = false; /* Process arguments */ for (int i = 1; i < argc; i++) { char *arg = argv[i]; if ((arg[0] == '-') || (arg[0] == '/')) { /* It's a switch */ char *opt = arg + 1; if (!strcmp(opt, "?")) { /* -?: Help */ usage(); /* Display help */ } if (!strcmp(opt, "d")) { /* -d: Debug information */ iVerbose = true; continue; } if (!strcmp(opt, "m")) { /* -m: Read MSR (Experimental) */ unsigned int iMSR; if (((i + 1) < argc) && sscanf(argv[i + 1], "%X", &iMSR)) { uint32_t pdwMSR[2]; i += 1; printf("Reading MSR(0x%X)\n", iMSR); fflush(stdout); _rdmsr(iMSR, pdwMSR); printf("MSR(0x%X) = 0x%08ulX:%08ulX\n", iMSR, pdwMSR[1], pdwMSR[0]); exit(0); } else { fprintf(stderr, "Missing of invalid MSR number\n"); exit(1); } } if (!strcmp(opt, "v")) { /* -v: Verbose information */ iVerbose = true; continue; } if (!strcmp(opt, "V")) { /* -V: Display version information */ printf("%s %s\n", PROGRAM_NAME, PROGRAM_VERSION); return 0; } } } iFamily = identify_processor(); if (iFamily < 5) { printf("\nThe processor is a 80%d\n", (iFamily * 100) + 86); } else { // if (iFamily >= 5) int iModel; int iExtModel; int iExtFamily; uint32_t dwModel; char szBrand[48] = ""; dwModel = _cpuid(1, NULL, NULL, NULL, NULL); /* Compute the extended model number */ iModel = BYTE0(dwModel) >> 4; iExtModel = BYTE2(dwModel) & 0x0F; iModel |= (iExtModel << 4); /* Compute the extended model number */ /* iFamily = BYTE1(dwModel) & 0x0F; */ iExtFamily = (WORD1(dwModel) >> 4) & 0xFF; iFamily |= (iExtFamily << 4); /* On Pentium or better, get the processor brand name from CPUID output */ /* Use the brand string if available */ if (_cpuid(0x80000000, NULL, NULL, NULL, NULL) >= 0x80000004) { uint32_t *pdwBrand = (uint32_t *) szBrand; char *pszBrand; char *pc; // CPUID(0x80000002 - 0x80000004) : Get brand string. _cpuid(0x80000002, pdwBrand + 0, pdwBrand + 1, pdwBrand + 2, pdwBrand + 3); _cpuid(0x80000003, pdwBrand + 4, pdwBrand + 5, pdwBrand + 6, pdwBrand + 7); _cpuid(0x80000004, pdwBrand + 8, pdwBrand + 9, pdwBrand + 10, pdwBrand + 11); // Skip leading spaces for (pszBrand = szBrand; *pszBrand == ' '; pszBrand++) ; // Compress multiple spaces into a single space for (pc = pszBrand; *pc; pc++) { while ((pc[0] == ' ') && (pc[1] == ' ')) { char *pc2; for (pc2 = pc; (pc2[0] = pc2[1]) != '\0'; pc2++) ; } } // Display the readable brand string. printf("\nThe processor is an %s\n", pszBrand); } /* Else compute the processor name from the CPUID family and model numbers */ if ((!szBrand[0]) || iVerbose) { for (size_t i = 0; i < N_INTEL_PROCS; i++) { if ((IntelProcList[i].iFamily == iFamily) && (IntelProcList[i].iModel == iModel)) { printf("\nThe processor is a %s\n", IntelProcList[i].pszName); goto done; } } printf("\nThe processor is a 80%d model %d\n", (iFamily * 100) + 86, iModel); done:; } } if (iVerbose) { DisplayProcInfo(); } return 0; } /*---------------------------------------------------------------------------*\ * * | Function usage | | | | Description Display a brief help for this program | | | | Parameters None | | | | Returns N/A | | | | History | | 1996/10/10 JFL Created this routine | * * \*---------------------------------------------------------------------------*/ static void usage(void) { printf("%s %s - %s\n", PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_DESCRIPTION); puts("\n\ Usage: CPUID [switches]\n\ \n\ Optional switches:\n\ \n\ -v Display detailed processor capabilities information\n\ -V Display this program version and exit\n\ \n\ Author: Jean-Francois Larvoire - jf.larvoire@hpe.com or jf.larvoire@free.fr"); exit(0); } /*---------------------------------------------------------------------------*\ * * | Function DisplayProcInfo | | | | Description Display detailed processor information, from CPUID output.| | | | Parameters None | | | | Returns None | | | | History | | 1998/03/18 JFL Created this routine | | 2009/08/31 JFL Restructured to display both enabled and disabled features| | Added the definitions of numerous AMD extended features. | | 2009/09/01 JFL Renamed from DisplayProcId to DisplayProcInfo. | * * \*---------------------------------------------------------------------------*/ static const char *ppszFeatures[32] = { // Intel Features Flags - EAX=1 -> EDX /* 0x00000001 0 */ "Integrated FPU", /* 0x00000002 1 */ "Enhanced V86 mode", /* 0x00000004 2 */ "I/O breakpoints", /* 0x00000008 3 */ "4 MB pages", /* 0x00000010 4 */ "Time stamp counter", /* 0x00000020 5 */ "Model-specific registers", /* 0x00000040 6 */ "Physical address extensions", /* 0x00000080 7 */ "Machine-check exception", /* 0x00000100 8 */ "CMPXCHG8B instruction", /* 0x00000200 9 */ "Integrated APIC", /* 0x00000400 10 */ "(EDX bit 10 reserved)", /* 0x00000800 11 */ "SYSENTER/SYSEXIT instructions", /* 0x00001000 12 */ "MTRR registers, and the MTRR_CAP register", /* 0x00002000 13 */ "Page Global Enable bit in CR4", /* 0x00004000 14 */ "Machine check architecture", /* 0x00008000 15 */ "CMOV instructions", /* 0x00010000 16 */ "Page Attribute table in MTRRs", /* 0x00020000 17 */ "36-bit page size extensions", /* 0x00040000 18 */ "Processor Serial Number in CPUID#3", /* 0x00080000 19 */ "CLFLUSH instruction", /* 0x00100000 20 */ "(EDX bit 20 reserved)", /* 0x00200000 21 */ "Debug Trace Store & Event Mon.", /* 0x00400000 22 */ "ACPI thermal and clock control registers", /* 0x00800000 23 */ "MMX instructions", /* 0x01000000 24 */ "FXSAVE and FXRSTOR Instructions", /* 0x02000000 25 */ "SSE (Streaming SIMD Extensions)", /* 0x04000000 26 */ "SSE2 (Streaming SIMD Extensions v2)", /* 0x08000000 27 */ "Self-Snoop memory and caches", /* 0x10000000 28 */ "Hyper-threading capable", /* 0x20000000 29 */ "Thermal monitoring circuit", /* 0x40000000 30 */ "IA64 capable", /* 0x80000000 31 */ "Pending Break Enable (PBE# pin) wakeup capability", }; static const char *ppszFeatures2[32] = { // Intel Features Flags - EAX=1 -> ECX /* 0x00000001 0 */ "SSE3 (Streaming SIMD Extensions v3)", /* 0x00000002 1 */ "PCLMULDQ instruction", /* 0x00000004 2 */ "64-Bit Debug Store", /* 0x00000008 3 */ "MONITOR and MWAIT instructions", /* 0x00000010 4 */ "CPL Qualified Debug Store", /* 0x00000020 5 */ "VMX (Virtual Machine Extensions)", /* 0x00000040 6 */ "Safer Mode Extensions (Trusted Execution)", /* 0x00000080 7 */ "Enhanced SpeedStep Technology", /* 0x00000100 8 */ "Thermal Monitor 2 Control Circuit", /* 0x00000200 9 */ "SSSE3 (Suplemental Streaming SIMD Extensions v3)", /* 0x00000400 10 */ "L1 data cache Context ID", /* 0x00000800 11 */ "SDBG (Silicon Debug interface)", /* 0x00001000 12 */ "Fused Multiply Add extensions", /* 0x00002000 13 */ "CMPXCHG16B instruction", /* 0x00004000 14 */ "Send Task Priority Messages update control", /* 0x00008000 15 */ "Perfmon and Debug Capability", /* 0x00010000 16 */ "(ECX bit 16 reserved)", /* 0x00020000 17 */ "Process Context Identifiers (CR4 bit 17)", /* 0x00040000 18 */ "Direct Cache Access for DMA writes", /* 0x00080000 19 */ "SSE4.1 (Streaming SIMD Extensions 4.1)", /* 0x00100000 20 */ "SSE4.2 (Streaming SIMD Extensions 4.2)", /* 0x00200000 21 */ "Extended xAPIC Support", /* 0x00400000 22 */ "MOVBE Instruction", /* 0x00800000 23 */ "POPCNT Instruction", /* 0x01000000 24 */ "Timestamp Counter Deadline", /* 0x02000000 25 */ "AES instruction", /* 0x04000000 26 */ "XSAVE/XRESTOR instructions", /* 0x08000000 27 */ "OS-Enabled SXAVE/XRESTOR Management", /* 0x10000000 28 */ "AVX (Advanced Vector eXtensions)", /* 0x20000000 29 */ "16-bit Floating Point Conversion instructions", /* 0x40000000 30 */ "RDRAND instruction", /* 0x80000000 31 */ "Hypervisor present (always zero on physical CPUs)", }; static const char *ppszFeatures70b[32] = { // Structured Extended Feature Flags - EAX=7, ECX=0 -> EBX /* 0x00000001 0 */ "FSGSBASE instructions (RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE)", /* 0x00000002 1 */ "IA32_TSC_ADJUST MSR is supported", /* 0x00000004 2 */ "SGX (Software Guard Extensions)", /* 0x00000008 3 */ "BMI1 (Bit Manipulation Instruction Set 1)", /* 0x00000010 4 */ "HLE (Hardware Lock Elision)", /* 0x00000020 5 */ "AVX2 (Advanced Vector Extensions 2)", /* 0x00000040 6 */ "x87 FPU Data Pointer updated only on x87 exceptions", /* 0x00000080 7 */ "SMEP (Supervisor-Mode Execution Prevention)", /* 0x00000100 8 */ "BMI2 (Bit Manipulation Instruction Set 2)", /* 0x00000200 9 */ "Enhanced REP MOVSB/STOSB", /* 0x00000400 10 */ "INVPCID instruction", /* 0x00000800 11 */ "RTM (Restricted Transactional Memory) instructions", /* 0x00001000 12 */ "RDT-M (Resource Director Technology Monitoring)", /* 0x00002000 13 */ "FPU CS and DS values deprecated", /* 0x00004000 14 */ "MPX (Memory Protection Extensions)", /* 0x00008000 15 */ "RDT-A (Resource Director Technology Allocation)", /* 0x00010000 16 */ "AVX512F", /* 0x00020000 17 */ "AVX512DQ", /* 0x00040000 18 */ "RDSEED instruction", /* 0x00080000 19 */ "ADX (Multi-Precision Add-Carry Instruction Extensions)", /* 0x00100000 20 */ "SMAP (Supervisor-Mode Access Prevention) instructions", /* 0x00200000 21 */ "AVX512_IFMA", /* 0x00400000 22 */ "PCOMMIT (Persistent Memory Commit) instruction", // Deprecated: https://software.intel.com/en-us/blogs/2016/09/12/deprecate-pcommit-instruction /* 0x00800000 23 */ "CLFLUSHOPT Instruction", /* 0x01000000 24 */ "CLWB (Cache Line Write Back) instruction", /* 0x02000000 25 */ "Intel Processor Trace", /* 0x04000000 26 */ "AVX512PF", /* 0x08000000 27 */ "AVX512ER", /* 0x10000000 28 */ "AVX512CD", /* 0x20000000 29 */ "SHA (Secure Hash Algorithm Extensions)", /* 0x40000000 30 */ "AVX512BW", /* 0x80000000 31 */ "AVX512VL", }; static const char *ppszFeatures70c[32] = { // Structured Extended Feature Flags - EAX=7, ECX=0 -> ECX /* 0x00000001 0 */ "PREFETCHWT1 instruction", /* 0x00000002 1 */ "AVX-512 Vector Bit Manipulation Instructions", /* 0x00000004 2 */ "User-mode Instruction Prevention", /* 0x00000008 3 */ "PKU (Memory Protection Keys for User-mode pages)", /* 0x00000010 4 */ "PKU enabled by OS", /* 0x00000020 5 */ "WAITPKG (UMWAIT instruction)", /* 0x00000040 6 */ "AVX-512 Vector Bit Manipulation Instructions 2", /* 0x00000080 7 */ "SHSTK (Shadow Stack instructions)", /* 0x00000100 8 */ "GFNI (Galois Field instructions)", /* 0x00000200 9 */ "VAES (Vector AES instruction set (VEX-256/EVEX))", /* 0x00000400 10 */ "CLMUL instruction set (VEX-256/EVEX)", /* 0x00000800 11 */ "AVX-512 Vector Neural Network Instructions", /* 0x00001000 12 */ "AVX-512 BITALG instructions", /* 0x00002000 13 */ "(ECX bit 13 reserved)", /* 0x00004000 14 */ "AVX-512 Vector Population Count Double and Quad-word", /* 0x00008000 15 */ "(ECX bit 15 reserved)", /* 0x00010000 16 */ "5-level paging", /* 0x00020000 17 */ "MPX Address-Width Adjust bit 0", /* 0x00040000 18 */ "MPX Address-Width Adjust bit 1", /* 0x00080000 19 */ "MPX Address-Width Adjust bit 2", /* 0x00100000 20 */ "MPX Address-Width Adjust bit 3", /* 0x00200000 21 */ "MPX Address-Width Adjust bit 4", /* 0x00400000 22 */ "RDPID (Read Processor ID) instruction", /* 0x00800000 23 */ "(ECX bit 23 reserved)", /* 0x01000000 24 */ "(ECX bit 24 reserved)", /* 0x02000000 25 */ "CLDEMOTE (Cache Line Demote) instruction", /* 0x04000000 26 */ "(ECX bit 26 reserved)", /* 0x08000000 27 */ "MOVDIR (Direct Store) instructions", /* 0x10000000 28 */ "MOVDIR64B (Direct Store) instructions", /* 0x20000000 29 */ "(ECX bit 29 reserved)", /* 0x40000000 30 */ "SGX (Software Guard Extensions) instructions", /* 0x80000000 31 */ "(ECX bit 31 reserved)", }; static const char *ppszFeatures70d[32] = { // Structured Extended Feature Flags - EAX=7, ECX=0 -> EDX /* 0x00000001 0 */ "", /* 0x00000002 1 */ "", /* 0x00000004 2 */ "AVX-512 4-register Neural Network instructions", /* 0x00000008 3 */ "AVX-512 4-register Multiply Accumulation Single precision", /* 0x00000010 4 */ "FSRM (Fast Short REP MOVSB)", /* 0x00000020 5 */ "", /* 0x00000040 6 */ "", /* 0x00000080 7 */ "", /* 0x00000100 8 */ "", /* 0x00000200 9 */ "", /* 0x00000400 10 */ "", /* 0x00000800 11 */ "", /* 0x00001000 12 */ "", /* 0x00002000 13 */ "", /* 0x00004000 14 */ "", /* 0x00008000 15 */ "", /* 0x00010000 16 */ "", /* 0x00020000 17 */ "", /* 0x00040000 18 */ "PCONFIG Platform Configuration (Memory Encryption)", /* 0x00080000 19 */ "", /* 0x00100000 20 */ "IBT (Indirect-Branch Tracking)", /* 0x00200000 21 */ "", /* 0x00400000 22 */ "", /* 0x00800000 23 */ "", /* 0x01000000 24 */ "", /* 0x02000000 25 */ "", /* 0x04000000 26 */ "IBRS_IBPB (Indirect Branch Restricted Speculation)", /* 0x08000000 27 */ "STIBP (Single Thread Indirect Branch Predictor)", /* 0x10000000 28 */ "", /* 0x20000000 29 */ "Speculative Side Channel Mitigations", /* 0x40000000 30 */ "", /* 0x80000000 31 */ "SSBD (Speculative Store Bypass Disable)", }; static const char *ppszExtFeatures[32] = { // AMD Extended Features Flags - EDX /* Unknown bits, with a "" definition, will not be displayed. */ /* Flags that are just a copy of the corresponding Intel Features Flag are commented-out */ /* 0x00000001 0 */ "", // "Integrated FPU", /* 0x00000002 1 */ "", /* 0x00000004 2 */ "", /* 0x00000008 3 */ "", /* 0x00000010 4 */ "", // "Time stamp counter", /* 0x00000020 5 */ "", /* 0x00000040 6 */ "", /* 0x00000080 7 */ "", /* 0x00000100 8 */ "", // "CMPXCHG8B instruction", /* 0x00000200 9 */ "", /* 0x00000400 10 */ "", /* 0x00000800 11 */ "SYSCALL and SYSRET instructions", /* 0x00001000 12 */ "", /* 0x00002000 13 */ "", /* 0x00004000 14 */ "", /* 0x00008000 15 */ "", // "CMOV instructions", /* 0x00010000 16 */ "", /* 0x00020000 17 */ "", /* 0x00040000 18 */ "", /* 0x00080000 19 */ "", /* 0x00100000 20 */ "Execution disable bit", /* 0x00200000 21 */ "", /* 0x00400000 22 */ "AMD extensions to MMX", /* 0x00800000 23 */ "", // "MMX instructions", /* 0x01000000 24 */ "", // "FXSAVE and FXRSTOR Instructions", /* 0x02000000 25 */ "", // "SSE instructions", /* 0x04000000 26 */ "", /* 0x08000000 27 */ "RDTSCP instruction", /* 0x10000000 28 */ "PDPE1GB Gibibyte pages", /* 0x20000000 29 */ "64 bit instructions (=long mode/EM64T/x86_64)", /* 0x40000000 30 */ "AMD extensions to 3DNow!", /* 0x80000000 31 */ "3DNow! instructions", }; static const char *ppszExtFeatures2[32] = { // AMD Extended Features Flags - ECX /* 0x00000001 0 */ "LAHF and SAHF in 64-bits mode", /* 0x00000002 1 */ "", /* 0x00000004 2 */ "Secure Virtual Machine instructions", /* 0x00000008 3 */ "", /* 0x00000010 4 */ "Use of LOCK prefix to read CR8", /* 0x00000020 5 */ "LZCNT instruction (Count leading Zeros)", /* 0x00000040 6 */ "SSE4A Instructions", /* 0x00000080 7 */ "", /* 0x00000100 8 */ "3DNow! PREFETCH/PREFETCHW instructions", /* 0x00000200 9 */ "", /* 0x00000400 10 */ "", /* 0x00000800 11 */ "", /* 0x00001000 12 */ "DEV support", /* 0x00002000 13 */ "", /* 0x00004000 14 */ "", /* 0x00008000 15 */ "", /* 0x00010000 16 */ "", /* 0x00020000 17 */ "", /* 0x00040000 18 */ "", /* 0x00080000 19 */ "", /* 0x00100000 20 */ "", /* 0x00200000 21 */ "", /* 0x00400000 22 */ "", /* 0x00800000 23 */ "POPCNT instruction", /* 0x01000000 24 */ "", /* 0x02000000 25 */ "", /* 0x04000000 26 */ "", /* 0x08000000 27 */ "", /* 0x10000000 28 */ "", /* 0x20000000 29 */ "", /* 0x40000000 30 */ "", /* 0x80000000 31 */ "", }; static const char *YesNo(unsigned long n) { if (n != 0) return "Yes"; else return "No"; } static void DisplayProcInfo(void) { uint32_t dwMaxValue; uint32_t dwMaxValueX; uint32_t dwModel; uint32_t dwModel2; uint32_t dwFeatures; uint32_t dwFeatures2 = 0; uint32_t dwFeatures3; uint32_t dwFeatures4; char szName[14]; int iFamily; int iModel; int nCores; // CPUID(0) : _cpuid(0, &dwMaxValue, (uint32_t *) (szName + 0), (uint32_t *) (szName + 8), (uint32_t *) (szName + 4)); szName[12] = '\0'; printf("%s", szName); if (dwMaxValue == 0) { putchar('\n'); return; } // CPUID(1) : Request the Family/Model/Step _cpuid(1, &dwModel, &dwModel2, &dwFeatures2, &dwFeatures); iFamily = BYTE1(dwModel) & 0x0F; printf(" Family %d", iFamily); iModel = BYTE0(dwModel) >> 4; printf(" Model %d", iModel); printf(" Stepping %d", BYTE0(dwModel) & 0x0F); for (size_t i = 0; i < N_INTEL_PROCS; i++) { if ((IntelProcList[i].iFamily == iFamily) && (IntelProcList[i].iModel == iModel)) { printf(": %s \"%s\"", IntelProcList[i].pszName, IntelProcList[i].pszCodeName); break; } } printf("\n\n"); // CPUID(0x80000000) : Get max extended function supported. printf("Max base function: 0x%08X\n", dwMaxValue); dwMaxValueX = _cpuid(0x80000000, NULL, NULL, NULL, NULL); if (dwMaxValueX >= 0x80000000) printf("Max extended function: 0x%08X\n", dwMaxValueX); else printf("No extended CPUID functions.\n"); printf("\n"); /* Intel Feature Flags */ printf("CPUID(1): Intel Features Flags: EDX=0x%08X ECX=0x%08X\n", dwFeatures, dwFeatures2); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { printf(" EDX %2u %-3s %s\n", i, YesNo(dwFeatures & dwMask), ppszFeatures[i]); } printf("\n"); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { printf(" ECX %2u %-3s %s\n", i, YesNo(dwFeatures2 & dwMask), ppszFeatures2[i]); } printf("\n"); /* AMD Extended Features Flags */ if (dwMaxValueX >= 0x80000001) { /* Only display those that are documented in recent Intel's manuals */ // CPUID(0x80000001) : Get extended feature flags. dwFeatures4 = 0; _cpuid(0x80000001, NULL, NULL, &dwFeatures4, &dwFeatures3); printf ("CPUID(0x80000001): AMD Extended Features Flags: EDX=0x%08X ECX=0x%0X\n", dwFeatures3, dwFeatures4); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { const char *pszName = ppszExtFeatures[i]; if (pszName[0]) printf(" EDX %2u %-3s %s\n", i, YesNo(dwFeatures3 & dwMask), pszName); } printf("\n"); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { const char *pszName = ppszExtFeatures2[i]; if (pszName[0]) printf(" ECX %2u %-3s %s\n", i, YesNo(dwFeatures4 & dwMask), pszName); } printf("\n"); } /* Structured Extended Feature Flags */ if (dwMaxValue >= 7) { uint32_t dwEAX, dwEBX, dwECX, dwEDX; int nLeaves; dwECX = 0; _cpuid(7, &dwEAX, &dwEBX, &dwECX, &dwEDX); nLeaves = (int)dwEAX; /* Max ECX input value for cpuid(7) */ printf ("CPUID(7): Extended Features Flags: EBX=0x%08X ECX=0x%08X EDX=0x%08X\n", dwEBX, dwECX, dwEDX); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { const char *pszName = ppszFeatures70b[i]; printf(" EBX %2u %-3s %s\n", i, YesNo(dwEBX & dwMask), pszName); } printf("\n"); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { const char *pszName = ppszFeatures70c[i]; printf(" ECX %2u %-3s %s\n", i, YesNo(dwECX & dwMask), pszName); } printf("\n"); for (uint32_t i = 0, dwMask = 1; dwMask; i++, dwMask <<= 1) { const char *pszName = ppszFeatures70d[i]; if (pszName[0]) printf(" EDX %2u %-3s %s\n", i, YesNo(dwEDX & dwMask), pszName); } printf("\n"); if (nLeaves > 0) { printf("ECX=%d => There are more Extended Feature Flags leaves\n\n", nLeaves); } } /* Brand string */ if (dwMaxValueX >= 0x80000004) { char szBrand[48]; uint32_t *pdwBrand = (uint32_t *) szBrand; char *pszBrand = szBrand; // CPUID(0x80000002 - 0x80000004) : Get brand string. _cpuid(0x80000002, pdwBrand + 0, pdwBrand + 1, pdwBrand + 2, pdwBrand + 3); _cpuid(0x80000003, pdwBrand + 4, pdwBrand + 5, pdwBrand + 6, pdwBrand + 7); _cpuid(0x80000004, pdwBrand + 8, pdwBrand + 9, pdwBrand + 10, pdwBrand + 11); while (*pszBrand == ' ') pszBrand++; // Skip head spaces, if any printf("Brand string: \"%s\"\n", pszBrand); printf("\n"); } /* Virtual and Physical address Sizes */ if (dwMaxValueX >= 0x80000008) { uint32_t dwInfo; _cpuid(0x80000008, &dwInfo, NULL, NULL, NULL); printf("Physical Address Size: %d bits\n", BYTE0(dwInfo)); printf("Virtual Address Size: %d bits\n", BYTE1(dwInfo)); printf("\n"); } /* Number of cores and threads */ printf("Cores and threads\n"); nCores = 1; if (dwFeatures & (1L << 28)) nCores = (int)BYTE2(dwModel2); printf(" CPUID(1): Silicon supports %d logical processors\n", nCores); if (dwMaxValue >= 4) { uint32_t dwEAX, dwEBX, dwECX, dwEDX; int nMaxCores, nMaxThreads; dwECX = 0; _cpuid(4, &dwEAX, &dwEBX, &dwECX, &dwEDX); nMaxCores = (int)((dwEAX >> 26) & 0x3F) + 1; nMaxThreads = (int)((dwEAX >> 14) & 0xFFF) + 1; printf(" CPUID(4): Silicon supports %d cores and %d threads/core\n", nMaxCores, nMaxThreads); } if (dwMaxValue >= 11) { uint32_t dwEAX, dwEBX, dwECX, dwEDX; int nMaxCores, nMaxThreads, nMaxLast; uint32_t nLevel; dwECX = 0; _cpuid(11, &dwEAX, &dwEBX, &dwECX, &dwEDX); nMaxThreads = WORD0(dwEBX); if (nMaxThreads) { /* Some CPU models set dwMaxValue >= 11, yet return 0 here, and generate an exception if any further call is made */ dwECX = 1; _cpuid(11, &dwEAX, &dwEBX, &dwECX, &dwEDX); nMaxLast = WORD0(dwEBX); nMaxCores = WORD0(dwEBX) / nMaxThreads; printf(" CPUID(11): Factory enabled %d cores and %d threads/core\n", nMaxCores, nMaxThreads); /* The CPUID spec mentions future procs will have more levels. Loop untested as of January 2013, as no available CPU has any. */ if (nMaxLast) for (nLevel = 2;; nLevel++) { dwECX = nLevel; _cpuid(11, &dwEAX, &dwEBX, &dwECX, &dwEDX); nMaxLast = WORD0(dwEBX); if (!nMaxLast) break; /* No more data. We've reached the last processor set level. */ printf (" CPUID(11): Factory enabled %d level %d core sets\n", nMaxLast, nLevel); } } } printf("\n"); } /*---------------------------------------------------------------------------*\ * * | Function _cpuid | | | | Description Execute a CPUID instruction, and collect results | | | | Parameters uint32_t dwId ID index (input) | | uint32_t *pEax Where to store EAX. Discard EAX if NULL. | | uint32_t *pEbx Where to store EBX. Discard EBX if NULL. | | uint32_t *pEcx Where to store ECX. Discard ECX if NULL. | | uint32_t *pEdx Where to store EDX. Discard EDX if NULL. | | | | Returns DX:AX = EAX | | | | Notes | | | | History | | 2000-03-23 JFL Created this routine | | 2005-04-28 JFL Changed the 1st argument type from int to uint32_t. | | 2013-01-31 JFL Added the ability to pass ECX as an input. | * * \*---------------------------------------------------------------------------*/ static uint32_t _cpuid(uint32_t dwId, uint32_t * pEax, uint32_t * pEbx, uint32_t * pEcx, uint32_t * pEdx) { uint32_t eax, ebx, ecx, edx; // Some advanced CPUID functions use ECX as an input. uint32_t ecxIn = pEcx ? *pEcx : 0; __asm__("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "0" (dwId), "2" (ecxIn)); if (pEax) { *pEax = eax; } if (pEbx) { *pEbx = ebx; } if (pEcx) { *pEcx = ecx; } if (pEdx) { *pEdx = edx; } return eax; } /*---------------------------------------------------------------------------*\ * * | Function _rdmsr | | | | Description Execute a RDMSR instruction, and collect results | | | | Parameters uint32_t dwECX MSR index (input) | | uint32_t pdwMSR[2] Where to store EDX:EAX | | | | Returns Nothing | | | | Notes | | | | History | | 2020-02-24 JFL Created this routine | * * \*---------------------------------------------------------------------------*/ static void _rdmsr(uint32_t dwECX, uint32_t pdwMSR[2]) { uint32_t eax, edx; __asm__("rdmsr" : "=a" (eax), "=d" (edx) : "c" (dwECX)); pdwMSR[0] = eax; pdwMSR[1] = edx; } /*---------------------------------------------------------------------------*\ * * | Function identify_processor | | | | Description Tell which generation of processor we're running on | | | | Parameters None | | | | Returns Processor generation: | | 0 = 8086 | | 1 = 80186 | | 2 = 80286 | | Etc... | | | | Notes Assume that under Win32, the processor is a Pentium | | or better. | | | | History | | 2010-09-06 JFL Created this Win32 version. | * * \*---------------------------------------------------------------------------*/ static int identify_processor(void) { uint32_t dwModel; int iFamily; int iExtFamily; dwModel = _cpuid(1, NULL, NULL, NULL, NULL); /* Compute the extended family number */ iFamily = BYTE1(dwModel) & 0x0F; iExtFamily = (WORD1(dwModel) >> 4) & 0xFF; iFamily |= (iExtFamily << 4); return iFamily; }