--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "cpuid.h"
+
+static const char *cpuname(struct cpuid_info *cpu);
+static const char *cpuvendor(struct cpuid_info *cpu);
+
+struct cpuid_info cpuid;
+
+void print_cpuid(struct cpuid_info *cpu)
+{
+ int i, col, len;
+ char buf[64];
+ static const char *featstr[32] = {
+ "fpu", "vme", "dbgext", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", "?", "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "psn", "clf", "?", "dtes", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", "htt", "tm1", "ia64", "pbe"};
+ static const char *feat2str[32] = {
+ "sse3", "pclmul", "dtes64", "monitor", "ds-cpl", "vmx", "smx", "est",
+ "tm2", "ssse3", "cid", "sdbg", "fma", "cx16", "etprd", "pdcm",
+ "?", "pcid", "dca", "sse41", "sse42", "x2apic", "movbe", "popcnt",
+ "?", "aes", "xsave", "osxsave", "avx", "f16c", "rdrand", "?"};
+
+ printf("CPU: %s - %s\n", cpuvendor(cpu), cpuname(cpu));
+ printf("features:\n ");
+ col = 3;
+ for(i=0; i<32; i++) {
+ if(cpu->feat & (1 << i)) {
+ len = strlen(featstr[i]) + 1;
+ if(col + len >= 80) {
+ fputs("\n ", stdout);
+ col = 3;
+ }
+ col += printf(" %s", featstr[i]);
+ }
+ }
+ for(i=0; i<32; i++) {
+ if(cpu->feat2 & (1 << i)) {
+ len = strlen(feat2str[i]) + 1;
+ if(col + len >= 80) {
+ fputs("\n ", stdout);
+ col = 3;
+ }
+ col += printf(" %s", feat2str[i]);
+ }
+ }
+ putchar('\n');
+}
+
+static const char *fam4_models[16] = {
+ "486 DX 25/33", "486 DX 50", "486 SX", "486 DX/2", "486 SL", "486 SX/2",
+ 0, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB"
+};
+static const char *fam5_models[16] = {
+ "Pentium 60/66", "Pentium 60/66", "Pentium 75-200", "OverDrive", "Pentium MMX",
+ 0, 0, "Mobile Pentium 75-200", "Mobile Pentium MMX", "Quark"
+};
+static const char *fam6_models[16] = {
+ "Pentium Pro", "Pentium Pro", 0, "Pentium 2", "Pentium 2", "Pentium 2",
+ "Mobile Pentium 2", "Pentium 3", "Pentium 3", 0, "Pentium 3", "Pentium 3"
+};
+
+
+static const char *cpuname(struct cpuid_info *cpu)
+{
+ int model, family;
+ char *rd, *wr;
+
+ if(cpu->brandstr) {
+ /* unwank the string */
+ rd = wr = cpu->brandstr;
+ while(*rd) {
+ if(rd[0] == '(' && rd[1] == 'T' && rd[2] == 'M' && rd[3] == ')')
+ rd += 4;
+ else if(rd[0] == '(' && rd[1] == 'R' && rd[2] == ')')
+ rd += 3;
+ if(rd != wr) *wr = *rd;
+ wr++;
+ rd++;
+ }
+ return cpu->brandstr;
+ }
+
+ if(CPUID_EXTMODEL(cpu->id)) {
+ /* processors new enough to have an extended model, should also provide
+ * a brand string. If we end up here, we don't know what it is
+ */
+ return "unknown";
+ }
+
+ model = CPUID_MODEL(cpu->id);
+ family = CPUID_FAMILY(cpu->id) | (CPUID_EXTFAMILY(cpu->id) << 4);
+
+ switch(family) {
+ case 3: return "386";
+ case 4: return fam4_models[model] ? fam4_models[model] : "486";
+ case 5: return fam5_models[model] ? fam5_models[model] : "Pentium";
+ case 6: return fam6_models[model] ? fam6_models[model] : "unknown";
+ case 15: return "Pentium 4";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+static const char *cpuvendor(struct cpuid_info *cpu)
+{
+ static char other[16];
+ static const struct { const char *wank, *vendor; } unwanktab[] = {
+ {"GenuineIntel", "intel"},
+ {"AuthenticAMD", "AMD"},
+ {"AMDisbetter!", "AMD"},
+ {"CentaurHauls", "IDT"},
+ {"CyrixInstead", "Cyrix"},
+ {"TransmetaCPU", "Transmeta"},
+ {"GenuineTMx86", "Transmeta"},
+ {"Geode by NSC", "NatSemi"},
+ {"NexGenDriven", "NexGen"},
+ {"RiseRiseRise", "Rise"},
+ {"SiS SiS SiS ", "SiS"},
+ {"UMC UMC UMC ", "UMC"},
+ {"VIA VIA VIA ", "VIA"},
+ {"Vortex86 SoC", "DM&P"},
+ {" Shanghai ", "Zhaoxin"},
+ {"HygonGenuine", "Hygon"},
+ {"E2K MACHINE", "MCST Elbrus"},
+ {"MiSTer A0486", "ao486"},
+ {"bhyve bhyve ", "bhyve"},
+ {" KVMKVMKVM ", "KVM"},
+ {"TCGTCGTCGTCG", "qemu"},
+ {"Microsoft Hv", "MS Hyper-V"},
+ {" lrpepyh vr", "Parallels"},
+ {"VMwareVMware", "VMware"},
+ {"XenVMMXenVMM", "Xen"},
+ {"ACRNACRNACRN", "ACRN"},
+ {" QNXQVMBSQG ", "QNX Hypervisor"},
+ {0, 0}
+ };
+
+ int i;
+ for(i=0; unwanktab[i].wank; i++) {
+ if(memcmp(cpu->vendor, unwanktab[i].wank, 12) == 0) {
+ return unwanktab[i].vendor;
+ }
+ }
+
+ memcpy(other, cpu->vendor, 12);
+ other[12] = 0;
+ return other;
+}
--- /dev/null
+#ifndef CPUID_H_
+#define CPUID_H_
+
+#include "inttypes.h"
+
+struct cpuid_info {
+ uint32_t maxidx; /* 0: eax */
+ char vendor[12]; /* 0: ebx, edx, ecx */
+ uint32_t id; /* 1: eax */
+ uint32_t rsvd0; /* 1: ebx */
+ uint32_t feat; /* 1: edx */
+ uint32_t feat2; /* 1: ecx */
+
+ char brandstr[48]; /* 80000002h-80000004h */
+};
+
+extern struct cpuid_info cpuid;
+
+#define CPU_HAVE_MMX (cpuid.feat & CPUID_FEAT_MMX)
+#define CPU_HAVE_MTRR (cpuid.feat & CPUID_FEAT_MTRR)
+
+#define CPUID_STEPPING(id) ((id) & 0xf)
+#define CPUID_MODEL(id) (((id) >> 4) & 0xf)
+#define CPUID_FAMILY(id) (((id) >> 8) & 0xf)
+#define CPUID_EXTMODEL(id) (((id) >> 16) & 0xf)
+#define CPUID_EXTFAMILY(id) (((id) >> 20) & 0xff)
+
+#define CPUID_FEAT_FPU 0x00000001
+#define CPUID_FEAT_VME 0x00000002
+#define CPUID_FEAT_DBGEXT 0x00000004
+#define CPUID_FEAT_PSE 0x00000008
+#define CPUID_FEAT_TSC 0x00000010
+#define CPUID_FEAT_MSR 0x00000020
+#define CPUID_FEAT_PAE 0x00000040
+#define CPUID_FEAT_MCE 0x00000080
+#define CPUID_FEAT_CX8 0x00000100
+#define CPUID_FEAT_APIC 0x00000200
+
+#define CPUID_FEAT_SEP 0x00000800
+#define CPUID_FEAT_MTRR 0x00001000
+#define CPUID_FEAT_PGE 0x00002000
+#define CPUID_FEAT_MCA 0x00004000
+#define CPUID_FEAT_CMOV 0x00008000
+#define CPUID_FEAT_PAT 0x00010000
+#define CPUID_FEAT_PSE36 0x00020000
+#define CPUID_FEAT_PSN 0x00040000
+#define CPUID_FEAT_CLF 0x00080000
+
+#define CPUID_FEAT_DTES 0x00200000
+#define CPUID_FEAT_ACPI 0x00400000
+#define CPUID_FEAT_MMX 0x00800000
+#define CPUID_FEAT_FXSR 0x01000000
+#define CPUID_FEAT_SSE 0x02000000
+#define CPUID_FEAT_SSE2 0x04000000
+#define CPUID_FEAT_SS 0x08000000
+#define CPUID_FEAT_HTT 0x10000000
+#define CPUID_FEAT_TM1 0x20000000
+#define CPUID_FEAT_IA64 0x40000000
+#define CPUID_FEAT_PBE 0x80000000
+
+#define CPUID_FEAT2_SSE3 0x00000001
+#define CPUID_FEAT2_PCLMUL 0x00000002
+#define CPUID_FEAT2_DTES64 0x00000004
+#define CPUID_FEAT2_MONITOR 0x00000008
+#define CPUID_FEAT2_DS_CPL 0x00000010
+#define CPUID_FEAT2_VMX 0x00000020
+#define CPUID_FEAT2_SMX 0x00000040
+#define CPUID_FEAT2_EST 0x00000080
+#define CPUID_FEAT2_TM2 0x00000100
+#define CPUID_FEAT2_SSSE3 0x00000200
+#define CPUID_FEAT2_CID 0x00000400
+#define CPUID_FEAT2_SDBG 0x00000800
+#define CPUID_FEAT2_FMA 0x00001000
+#define CPUID_FEAT2_CX16 0x00002000
+#define CPUID_FEAT2_ETPRD 0x00004000
+#define CPUID_FEAT2_PDCM 0x00008000
+
+#define CPUID_FEAT2_PCID 0x00020000
+#define CPUID_FEAT2_DCA 0x00040000
+#define CPUID_FEAT2_SSE41 0x00080000
+#define CPUID_FEAT2_SSE42 0x00100000
+#define CPUID_FEAT2_X2APIC 0x00200000
+#define CPUID_FEAT2_MOVBE 0x00400000
+#define CPUID_FEAT2_POPCNT 0x00800000
+
+#define CPUID_FEAT2_AES 0x02000000
+#define CPUID_FEAT2_XSAVE 0x04000000
+#define CPUID_FEAT2_OSXSAVE 0x08000000
+#define CPUID_FEAT2_AVX 0x10000000
+#define CPUID_FEAT2_F16C 0x20000000
+#define CPUID_FEAT2_RDRAND 0x40000000
+
+int read_cpuid(struct cpuid_info *info);
+void print_cpuid(struct cpuid_info *info);
+
+#endif /* CPUID_H_ */