#define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include struct cpuid { uint32_t eax, ebx, ecx, edx; }; static int cpuid(int cpu, uint32_t leaf, uint32_t subleaf, struct cpuid *data) { static int fd = -1; static int last_cpu; off_t offset = leaf + ((off_t)subleaf << 32); if (fd < 0 || last_cpu != cpu) { char devstr[64]; if (fd >= 0) close(fd); snprintf(devstr, sizeof devstr, "/dev/cpu/%d/cpuid", cpu); fd = open(devstr, O_RDONLY); last_cpu = cpu; } return pread(fd, data, sizeof(*data), offset) == sizeof(*data) ? 0 : -1; } static char *make_string(uint32_t val) { static char string[5] = "xxxx"; int i, ch; for ( i = 0 ; i < 4 ; i++ ) { ch = val & 0xff; string[i] = isprint(ch) ? ch : '.'; val >>= 8; } return string; } static void print_cpuid_level(uint32_t leaf, uint32_t subleaf, struct cpuid *lvl) { printf("%08x %08x: ", leaf, subleaf); printf("%08x %s ", lvl->eax, make_string(lvl->eax)); printf("%08x %s ", lvl->ebx, make_string(lvl->ebx)); printf("%08x %s ", lvl->ecx, make_string(lvl->ecx)); printf("%08x %s\n", lvl->edx, make_string(lvl->edx)); } static void dump_cpuid_leaf(int cpu, uint32_t leaf) { struct cpuid lvl, lastlvl, lvl0; uint32_t subleaf; cpuid(cpu, leaf, 0, &lvl0); print_cpuid_level(leaf, 0, &lvl0); /* * There is no standard mechanism for enumerating the number of * subleaves, this is a heuristic... */ lastlvl = lvl0; for (subleaf = 1; subleaf != 0; subleaf++) { if (cpuid(cpu, leaf, subleaf, &lvl)) return; switch (leaf) { case 4: if ((lvl.eax & 0x1f) == 0 || !memcmp(&lvl, &lastlvl, sizeof lvl)) return; break; case 7: if (subleaf >= lvl0.eax) return; break; case 0xb: if ((lvl.ecx & ~0xff) == 0) return; case 0xd: if ((lvl.eax | lvl.ebx | lvl.ecx | lvl.edx) == 0) return; default: /* Generic, anticipatory rules */ /* Exclude ecx here for levels which return the initial ecx value */ if ((lvl.eax | lvl.ebx | lvl.ecx | lvl.edx) == 0) return; if (!memcmp(&lvl, &lvl0, sizeof lvl)) return; break; } print_cpuid_level(leaf, subleaf, &lvl); lastlvl = lvl; } } static void dump_levels(int cpu, uint32_t region) { static struct cpuid invalid_leaf; struct cpuid max; uint32_t n; if (cpuid(cpu, region, 0, &max)) return; /* * Intel processors may return the last group 0 CPUID leaf instead * all zero for a not-present level */ if (region == 0) { cpuid(cpu, max.eax+1, 0, &invalid_leaf); } else { if (!memcmp(&max, &invalid_leaf, sizeof(struct cpuid))) return; } if ( (max.eax & 0xffff0000) == region ) { for ( n = region ; n <= max.eax ; n++ ) { dump_cpuid_leaf(cpu, n); } } } int main(int argc, char *argv[]) { int cpu; uint32_t n; cpu = (argc > 1) ? atoi(argv[1]) : 0; printf("Leaf Subleaf EAX EBX ECX EDX \n"); for ( n = 0 ; n <= 0xffff ; n++ ) { dump_levels(cpu, n << 16); } return 0; }