#include #include #include #define CUT(x, a, b) (((x)&((1<<((b)+1))-1))>>(a)) typedef struct Res { ulong ax, bx, cx, dx; } Res; Biobuf *out; uchar _cpuid[] = { 0x5E, /* POP SI (PC) */ 0x5D, /* POP BP (Res&) */ 0x58, /* POP AX */ 0x59, /* POP CX */ 0x51, /* PUSH CX */ 0x50, /* PUSH AX */ 0x55, /* PUSH BP */ 0x56, /* PUSH SI */ 0x31, 0xDB, /* XOR BX, BX */ 0x31, 0xD2, /* XOR DX, DX */ 0x0F, 0xA2, /* CPUID */ 0x89, 0x45, 0x00, /* MOV AX, 0(BP) */ 0x89, 0x5d, 0x04, /* MOV BX, 4(BP) */ 0x89, 0x4d, 0x08, /* MOV CX, 8(BP) */ 0x89, 0x55, 0x0C, /* MOV DX, 12(BP) */ 0xC3, /* RET */ }; Res (*cpuid)(ulong ax, ulong cx) = (Res(*)(ulong, ulong)) _cpuid; void func0(ulong) { Res r; char buf[13]; r = cpuid(0, 0); ((ulong *) buf)[0] = r.bx; ((ulong *) buf)[1] = r.dx; ((ulong *) buf)[2] = r.cx; buf[12] = 0; Bprint(out, "vendor %s\n", buf); } void printbits(char *id, ulong x, char **s) { int i, j; for(i = 0, j = 0; i < 32; i++) if((x & (1<> 8 & 0xf; model = r.ax >> 8 & 0xf; if(family == 15) family += r.ax >> 20 & 0xff; if(family == 6 || family == 15) model += r.ax >> 12 & 0xf0; Bprint(out, "typefammod %.1x %.2x %.3x %.1x\n", (int)(r.ax >> 12 & 3), family, model, (int)(r.ax & 0xf)); printbits("features", r.dx, bitsdx); printbits("features", r.cx, bitscx); } void func7(ulong) { Res r; static char *bitebx[32] = { [0] "fsgsbase", nil, "sgx", "bmi1", [4] "hle", "avx2", nil, "smep", [8] "bmi2", "erms", "invpcid", "rtm", [12] "pqm", nil, "mpx", "pqe", [16] "avx512", "avx512dq", "rdseed", "adx", [20] "smap", "avx512ifma", "pcommit", "clflushopt", [24] "clwb", "intelpt", "avx512pf", "avx512er", [28] "avx512cd", "sha", "avx512bw", "avx512vl", }; static char *bitecx[32] = { [0] "prefetchwt1", "avx512vbmi", "umip", "pku", [4] "ospke", "waitpkg", "avx512vbmi2", "cetss", [8] "gfni", "vaes", "vpclmulqdq", "avx512vnni", [12] "avx512bitalg", nil, "avx512vpopcntdq", nil, [16] nil, nil, nil, nil, [20] nil, nil, "rdpid", nil, [24] nil, "cldemote", nil, "movdiri", [28] "movdir64b", "enqcmd", "sgxlc", "pks", }; static char *bitedx[32] = { [0] nil, nil, "avx512vnniw4", "avx512fmaps4", [4] "fsrm", nil, nil, nil, [8] "avx512vp2i", nil, nil, nil, }; static char *biteax[32] = { [0] nil, nil, nil, nil, [4] nil, "avx512bf16", nil, nil, }; r = cpuid(7, 0); printbits("features", r.bx, bitebx); printbits("features", r.cx, bitecx); printbits("features", r.dx, bitedx); r = cpuid(7, 1); printbits("features", r.ax, biteax); } void func13(ulong) { Res r; static char *bitsax[32] = { [0] "xsaveopt", "xsavec", "xgetbv1", "xsaves", }; r = cpuid(13, 1); printbits("features", r.ax, bitsax); } void extfunc1(ulong ax) { Res r; static char *bitsdx[32] = { [0] "fpu", "vme", "de", "pse", [4] "tsc", "msr", "pae", "mce", [8] "cx8", "apic", nil, "syscall", [12] "mtrr", "pge", "mca", "cmov", [16] "pat", "pse36", nil, "mp", [20] "nx", nil, "mmx+", "mmx", [24] "fxsr", "ffxsr", "pg1g", "tscp", [28] nil, "lm", "3dnow!+", "3dnow!", }; static char *bitscx[32] = { [0] "ahf64", "cmp", "svm", "eas", [4] "cr8d", "lzcnt", "sse4a", "msse", [8] "3dnow!p", "osvw", "ibs", "xop", [12] "skinit", "wdt", nil, "lwp", [16] "fma4", "tce", nil, "nodeid", [20] nil, "tbm", "topx", "pcx_core", [24] "pcx_nb", nil, nil, nil, [28] nil, nil, nil, nil, }; r = cpuid(ax, 0); Bprint(out, "extmodel %.8ulx / %.8ulx\n", r.ax, r.bx); printbits("extfeatures", r.dx, bitsdx); printbits("extfeatures", r.cx, bitscx); } void extfunc2(ulong ax) { char buf[49]; int i; Res r; char *p; if(ax != 0x80000004) return; buf[48] = 0; for(i = 0; i < 3; i++){ r = cpuid(0x80000002 + i, 0); ((ulong *) buf)[4 * i + 0] = r.ax; ((ulong *) buf)[4 * i + 1] = r.bx; ((ulong *) buf)[4 * i + 2] = r.cx; ((ulong *) buf)[4 * i + 3] = r.dx; } p = buf; while(*p == ' ') p++; Bprint(out, "procname %s\n", p); } void extfunc8(ulong ax) { Res r; r = cpuid(ax, 0); Bprint(out, "physbits %uld\n", CUT(r.ax, 0, 7)); Bprint(out, "virtbits %uld\n", CUT(r.ax, 8, 15)); if(CUT(r.ax, 16, 23) != 0) Bprint(out, "guestbits %uld\n", CUT(r.ax, 16, 23)); } void (*funcs[])(ulong) = { [0] func0, [1] func1, [7] func7, [13] func13, }; void (*extfuncs[])(ulong) = { [1] extfunc1, [2] extfunc2, [3] extfunc2, [4] extfunc2, [8] extfunc8, }; void stdfunc(ulong ax) { Res r; r = cpuid(ax, 0); Bprint(out, "%.8ulx %.8ulx %.8ulx %.8ulx %.8ulx\n", ax, r.ax, r.bx, r.cx, r.dx); } char Egreg[] = "this information is classified"; void notehand(void *, char *s) { if(strncmp(s, "sys:", 4) == 0) sysfatal(Egreg); noted(NDFLT); } void main(int argc, char **argv) { Res r; int i, rflag, aflag; ulong w; static Biobuf buf; rflag = aflag = 0; ARGBEGIN { case 'r': rflag++; break; case 'a': aflag++; break; } ARGEND; notify(notehand); /* first long in a.out header */ w = *(ulong *)(((uintptr)main)&~0xfff); notify(nil); switch(w){ default: sysfatal(Egreg); case 0x978a0000: /* amd64 */ /* patch out POP BP -> POP AX */ _cpuid[1] = 0x58; case 0xeb010000: /* 386 */ break; } segflush(_cpuid, sizeof(_cpuid)); Binit(&buf, 1, OWRITE); out = &buf; r = cpuid(0, 0); for(i = 0; i <= r.ax; i++) if(i >= nelem(funcs) || funcs[i] == nil || rflag){ if(rflag || aflag) stdfunc(i); }else funcs[i](i); r = cpuid(0x80000000, 0); if(r.ax < 0x80000000) exits(nil); r.ax -= 0x80000000; for(i = 0; i <= r.ax; i++) if(i >= nelem(extfuncs) || extfuncs[i] == nil || rflag){ if(rflag || aflag) stdfunc(0x80000000 | i); }else extfuncs[i](0x80000000 | i); exits(nil); }