#include #include #include enum { Dmistart = 0x000F0000, Dmiend = 0x000FFFFF, Dmisz = Dmiend+1 - Dmistart, }; typedef struct Enum Enum; typedef struct Item Item; typedef struct Itemv Itemv; typedef struct Smbuf Smbuf; typedef struct Sm Sm; typedef struct Smval Smval; typedef uvlong uintmem; /* wierd */ struct Enum { uint v; char *s; }; struct Smbuf { uchar sig[4]; uchar cksum; uchar len; uchar vers[2]; uchar maxss[2]; /* maximum structure size */ uchar eprev; /* entry point revision */ uchar fma[5]; /* formatted area */ uchar dmi[5]; /* _DMI_ */ uchar dmicksum; uchar stlen[2]; uchar stpa[4]; /* structure table pa */ uchar nstrut[2]; uchar bcdrev; }; struct Smval { int type; int hand; int len; Item *i; Itemv *v; }; struct Sm { Smbuf raw; uintmem stpa; uint stlen; uint n; /* count of structures */ Smval *v; }; struct Item{ char *name; int nbytes; int type; int offset; char *fmt; Enum *tab; }; struct Itemv{ union { char *s; uvlong i; uchar uuid[16]; }; }; enum { Biosinfo = 0, Sysinfo = 1, Module = 2, Chassis = 3, Cpu = 4, Memctlr = 5, /* obs. */ Memstk = 6, /* obs. */ Cache = 7, Conn = 8, Slot = 9, Obddev = 10, /* obs. */ Oemstr = 11, Sysconf = 12, Bioslang = 13, Groupa = 14, Syslog = 15, /* requires extra poking around */ Pmem = 16, Mdev = 17, Merror = 18, Mmap = 19, Mmdev = 20, Pointer = 21, Battery = 22, Wdog = 23, Hwsec = 24, Syspwr = 25, Vprobe = 26, Fan = 27, Tprobe = 28, Cprobe = 29, Bootinfo = 32, Merror64 = 33, Mgmt = 34, Mgmtc = 35, Mgmtdt = 36, Memch = 37, Ipmi = 38, Ps = 39, Obd = 41, Inactive = 126, End = 127, }; Enum tabletab[] = { 0, "biosinfo", 1, "sysinfo", 2, "module", 3, "chassis", 4, "cpu", 5, "memctlr", 6, "memstk", 7, "cache", 8, "conn", 9, "slot", 10, "obddev", 11, "oemstr", 12, "sysconf", 13, "bioslang", 14, "groupa", 15, "syslog", 16, "pmem", 17, "mdev", 18, "merror", 19, "mmap", 20, "mmdev", 21, "pointer", 22, "battery", 23, "wdog", 24, "hwsec", 25, "syspwr", 26, "vprobe", 27, "fan", 28, "tprobe", 29, "cprobe", 31, "bis", 32, "bootinfo", 33, "merror64", 34, "mgmt", 35, "mgmtc", 36, "mgmtdt", 37, "memch", 38, "ipmi", 39, "ps", 41, "obd", 126, "inactive", 127, "end", 0, nil, }; uchar *dmianchor[0x20]; int rfd = -1; int prtype = -1; int prhand = -1; int verbose; Biobuf outsb; Biobuf *out; #define Bvprint(...) do if(verbose) Bprint(__VA_ARGS__); while(0) void realmodefd(void) { if(rfd != -1) return; rfd = open("/dev/realmodemem", OREAD); if(rfd == -1) sysfatal("open: %r"); } void* emalloc(usize sz) { void *v; v = malloc(sz); if(v == nil) sysfatal("malloc: %r"); memset(v, 0, sz); setmalloctag(v, getcallerpc(&sz)); return v; } enum { String, Integer, Uchar, Enumf, Enumbv, }; Item biositems[] = { "vendor", 1, String, -1, "%s", nil, "version", 1, String, -1, "%s", nil, "biosstartseg", 2, Integer, -1, "%#.4llux", nil, "biosdate", 1, String, -1, "%s", nil, "biosromsz", 1, Integer, -1, "%#.4llux", nil, // _+1<<16 "biosflags", 8, Uchar, -1, "%.8H", nil, "extflags0", 1, Integer, -1, "%.2llux", nil, "extflags1", 1, Integer, -1, "%.2llux", nil, "release0", 1, Integer, -1, "%.2llux", nil, "release1", 1, Integer, -1, "%.2llux", nil, "embedrelease0", 1, Integer, -1, "%.2llux", nil, "embedrelease1", 1, Integer, -1, "%.2llux", nil, }; Enum waketype[] = { 0, "reserved", 1, "other", 2, "unknown", 3, "apmtimer", 4, "modem", 5, "lan", 6, "powersw", 7, "pcipme", 8, "powerrestored", 0, nil, }; Item sysitems[] = { "mfg", 1, String, -1, "%s", nil, "product", 1, String, -1, "%s", nil, "version", 1, String, -1, "%s", nil, "serial", 1, String, -1, "%s", nil, "uuid", 16, Uchar, -1, "%.16H", nil, "waketype", 1, Enumf, -1, "%s", waketype, "sku", 1, String, -1, "%s", nil, "family", 1, String, -1, "%s", nil, }; Item moditems[] = { "bbmfg", 1, String, -1, "%s", nil, "product", 1, String, -1, "%s", nil, "bbversion", 1, String, -1, "%s", nil, "bbserial", 1, String, -1, "%s", nil, "assettag", 1, String, -1, "%s", nil, "features", 1, Integer, -1, "%#.2llux", nil, "chassisloc", 1, String, -1, "%s", nil, "chassishand", 2, Integer, -1, "%#.4llux", nil, "bbtype", 1, Integer, -1, "%lld", nil, /* continued object handles; 2 bytes each */ }; Item chassisitems[] = { "chassismfg", 1, String, -1, "%s", nil, "chassistype", 1, Integer, -1, "%lld", nil, "chassisver", 1, String, -1, "%s", nil, "chassisserial", 1, String, -1, "%s", nil, "chassisassettag", 1, String, -1, "%s", nil, "bootstate", 1, Integer, -1, "%lld", nil, "powerst", 1, Integer, -1, "%lld", nil, "thermalst", 1, Integer, -1, "%lld", nil, "securityst", 1, Integer, -1, "%lld", nil, "height", 1, Integer, -1, "%lld", nil, "powercord#", 1, Integer, -1, "%lld", nil, "elementcnt", 1, Integer, -1, "%lld", nil, /* containted elements & sku number */ }; Enum sockettype[] = { 1, "other", 2, "unknown", 3, "daughter board", 4, "zif socket", 5, "replacable piggy back", 6, "none", 7, "lif socket", 8, "slot 1", 9, "slot 2", 0xa, "370-pin socket", 0xb, "slot a", 0xc, "slot m", 0xd, "socket 423", 0xe, "socket a (socket 462)", 0xf, "socket 478", 0x10, "socket 754", 0x11, "socket 940", 0x12, "socket 939", 0x13, "socket mPGA604", 0x14, "socket lga771", 0x15, "socket lga775", 0x16, "socket s1", 0x17, "socket am2", 0x18, "socket f", 0x19, "socket lga1366", 0x1a, "socket g34", 0x1b, "socket am3", 0x1c, "socket c32", 0x1d, "socket lga1156", 0x1d, "socket lga1567", 0x1f, "socket pga988a", 0x20, "socket bg1288", 0x21, "socket rpga988b", 0x22, "socket bga1023", 0x23, "socket bga1224", 0x24, "socket bga1155", 0x25, "socket bga1356", 0x26, "socket lga2011", 0x27, "socket fs1", 0x28, "socket fs2", 0x29, "socket fm1", 0x2a, "socket fm2", 0, nil, }; Item cpuitems[] = { "socket", 1, String, -1, "%s", nil, "cputype", 1, Integer, -1, "%lld", nil, "cpufamily", 1, Integer, -1, "%lld", nil, "cpumfg", 1, String, -1, "%s", nil, "cpuid", 8, Integer, -1, "%llux", nil, "cpuvers", 1, String, -1, "%s", nil, "cpuvolt", 1, Integer, -1, "%lld", nil, "clockmhz", 2, Integer, -1, "%lld", nil, "cpuspeed", 2, Integer, -1, "%lld", nil, "cpuspeed (now)", 2, Integer, -1, "%lld", nil, "cpustatus", 1, Integer, -1, "%lld", nil, "cpuupgrade", 1, Enumf, -1, "%s", sockettype, "cpul1", 2, Integer, -1, "%.2llux", nil, "cpul2", 2, Integer, -1, "%.2llux", nil, "cpul3", 2, Integer, -1, "%.2llux", nil, "cpuserial", 1, String, -1, "%s", nil, "cpuassettag", 1, String, -1, "%s", nil, "cpupart#", 1, String, -1, "%s", nil, "cpucore#", 1, Integer, -1, "%lld", nil, "cpucoreen", 1, Integer, -1, "%lld", nil, "cputhreadcnt", 1, Integer, -1, "%lld", nil, "cpuenum", 2, Integer, -1, "%#.4llux", nil, "cpufamily2", 2, Integer, -1, "%#.4llux", nil, }; Enum ecctypetab[] = { 1, "other", 2, "unknown", 3, "none", 4, "8-bit parity", 5, "32-bit ecc", 6, "32-bit ecc", 7, "32-bit ecc", 8, "crc", 0, nil, }; /* bitfield */ Enum ecccap[] = { 1<<0, "other", 1<<1, "unknown", 1<<2, "none", 1<<3, "single-bit", 1<<4, "double-bit", 1<<5, "error scrubbing", 0, nil, }; Enum interleave[] = { 1, "other", 2, "unknown", 3, "one-way", 4, "two-way", 5, "four-way", 6, "eight-way", 7, "sixteen-way", 0, nil, }; Item memctlritems[] = { "ecctype", 1, Enumf, -1, "%s", ecctypetab, "ecccap", 1, Enumbv, -1, "%s", ecccap, "interleavesupp", 1, Enumf, -1, "%s", interleave, "interleavecurr", 1, Enumf, -1, "%s", interleave, "maxmodsz", 1, Integer, -1, "%ℛ", nil, "speedsupp", 2, Integer, -1, "%#.4llux", nil, "typessupp", 2, Integer, -1, "%#.4llux", nil, "voltages", 1, Integer, -1, "%#.2llux", nil, "memslots", 1, Integer, -1, "%lld", nil, /* "handles" 2*memslots, Integer, -1, "%#.4llux", nil, */ /* "eccenabled" 1, Integer, -1, "%.2llux", nil, */ }; int fmtℛ(Fmt *f) { char *prefix; uint code; prefix = ""; code = va_arg(f->args, uvlong); if(f->flags & FmtSharp){ switch(code){ case 0x7d: return fmtprint(f, "not determinable"); case 0x7e: return fmtprint(f, "installed but disabled"); case 0x7f: return fmtprint(f, "not installed"); } if(code & 0x80) prefix = "dual-port "; code &= ~0x80; } return fmtprint(f, "%s%dMB", prefix, 1<args, uvlong); if(u & 0x8000) return fmtprint(f, "%d kb", u&~0x8000); return fmtprint(f, "%d mb", u); } Item mdevitems[] = { "paryhnd", 2, Integer, -1, "%#.4llux", nil, "errhnd", 2, Integer, -1, "%#.4llux", nil, "twidth", 2, Integer, -1, "%llud", nil, "width", 2, Integer, -1, "%llud", nil, "size", 2, Integer, -1, "%𝒮", nil, "formfactor", 1, Enumf, -1, "%s", formfactor, "deviceset", 1, Integer, -1, "%llud", nil, "locator", 1, String, -1, "%s", nil, "bankloc", 1, String, -1, "%s", nil, "memtype", 1, Enumf, -1, "%s", mdevmemtype, "typedetail", 2, Enumf, -1, "%s", typedetail, "speed", 2, Integer, -1, "%llud Mhz", nil, "mfgr", 1, String, -1, "%s", nil, "serial", 1, String, -1, "%s", nil, "assettag", 1, String, -1, "%s", nil, "part#", 1, String, -1, "%s", nil, "attr", 1, Integer, -1, "%.2llux", nil, // rank or zero "xsize", 4, Integer, -1, "%#.4llud MB", nil, "cfgspeed", 2, Integer, -1, "%llud Mhz", nil, }; Enum errortype[] = { 1, "other", 2, "unknown", 3, "ok", 4, "bad read", 5, "parity error", 6, "single-bit error", 7, "double-bit error", 8, "muti-bit error", 9, "nybble error", 0xa, "cksum error", 0xb, "crc error", 0xc, "corrected single-bit error", 0xd, "corrected error", 0xe, "uncorrectable error", 0, nil, }; Enum errorgran[] = { 1, "other", 2, "unknown", 3, "device", 4, "memory partition", 0, nil, }; Enum memoryop[] = { 1, "other", 2, "unknown", 3, "read", 4, "write", 0, nil, }; Item merroritems[] = { "errortype", 1, Enumf, -1, "%s", errortype, "errorgran", 1, Enumf, -1, "%s", errorgran, "errorop", 1, Enumf, -1, "%s", memoryop, "syndrome", 4, Integer, -1, "%#.8llux", nil, "physaddr", 4, Integer, -1, "%#.8llux", nil, "devaddr", 4, Integer, -1, "%#.8llux", nil, "resolution", 4, Integer, -1, "%#.8llux", nil, }; Item mmapitems[] = { "start", 4, Integer, -1, "%#.8llux kb", nil, "end", 4, Integer, -1, "%#.8llux kb", nil, "ahand", 2, Integer, -1, "%#.4llux", nil, "partwidth", 1, Integer, -1, "%lld", nil, "xstart", 8, Integer, -1, "%#.16llux", nil, "xend", 8, Integer, -1, "%#.16llux", nil, }; /* prec→multiplier, width→prec */ int fmt×(Fmt *f) { uvlong kb, m; kb = va_arg(f->args, uvlong); m = 1024; if(f->flags & FmtPrec){ f->flags &= ~FmtPrec; m = f->prec; } if(f->flags & FmtWidth) return fmtprint(f, "%#.*llux", f->width, kb*m); return fmtprint(f, "%#.8llux", kb*m); } Item mmdevitems[] = { "start", 4, Integer, -1, "%8.1024×", nil, "end", 4, Integer, -1, "%8.1024×", nil, "dhand", 2, Integer, -1, "%#.4llux", nil, "ahand", 2, Integer, -1, "%#.4llux", nil, "row", 1, Integer, -1, "%lld", nil, "interleave", 1, Integer, -1, "%lld", nil, "idepth", 1, Integer, -1, "%lld", nil, "xstart", 8, Integer, -1, "%#.16llux", nil, "xend", 8, Integer, -1, "%#.16llux", nil, }; Item ptritems[] = { "type", 1, Integer, -1, "%lld", nil, "interface", 1, Integer, -1, "%lld", nil, "buttons", 1, Integer, -1, "%lld", nil, }; Enum batterychemistry[] = { 1, "other", 2, "unknown", 3, "lead acid", 4, "nicad", 5, "nimh", 6, "lion", 7, "zincair", 8, "li polymer", 0, nil, }; Item batteryitems[] = { "location", 1, String, -1, "%s", nil, "mfgr", 1, String, -1, "%s", nil, "mfgr date", 1, String, -1, "%s", nil, "serial", 1, String, -1, "%s", nil, "devname", 1, String, -1, "%s", nil, "chemistry", 1, Enumf, -1, "%s", batterychemistry, "capacity", 2, Integer, -1, "%lld mWh", nil, "voltage", 2, Integer, -1, "%lld mV", nil, "sbds vers", 1, Integer, -1, "%lld", nil, "maxerror%", 1, Integer, -1, "%lld", nil, "sbds serial", 2, Integer, -1, "%.4llux", nil, "sbds mfgdate", 2, Integer, -1, "%.4llux", nil, "sbds chem", 1, String, -1, "%s", nil, "capacity ×", 1, Integer, -1, "%lld", nil, "oemword", 2, Integer, -1, "%llux", nil, }; Item wdogitems[] = { "cap", 1, Integer, -1, "%.2llux", nil, "rstcount", 2, Integer, -1, "%lld", nil, "rstlim", 2, Integer, -1, "%lld", nil, "interval", 2, Integer, -1, "%lld min", nil, "timeout", 2, Integer, -1, "%lld min", nil, }; Item hwsecitems[] = { "settings", 1, Integer, -1, "%.2llux", nil, }; Item syspwritems[] = { "month", 1, Integer, -1, "%.2llux", nil, "mday", 1, Integer, -1, "%.2llux", nil, "day", 1, Integer, -1, "%.2llux", nil, "min", 1, Integer, -1, "%.2llux", nil, "osec", 1, Integer, -1, "%.2llux", nil, }; Item vprobeitems[] = { "desc", 1, String, -1, "%s", nil, "locstat", 1, Integer, -1, "%.2llux", nil, "max", 2, Integer, -1, "%.2llud mV", nil, "min", 2, Integer, -1, "%.2llud mV", nil, "res", 2, Integer, -1, "%.2llud mV", nil, "tolerance", 2, Integer, -1, "%.2llud mV", nil, "accuracy", 2, Integer, -1, "%.2llud mV", nil, "oem", 4, Integer, -1, "%.8llux", nil, "nominal", 2, Integer, -1, "%.2llud mV", nil, }; Enum fantypestat[] = { 1<<5, "other", 2<<5, "unknown", 3<<5, "ok", 4<<5, "non-critical", 5<<5, "critical", 6<<5, "non-recoverable", 1, "other", 2, "unknown", 3, "fan", 4, "centrifugal blower", 5, "chip fan", 6, "cabinet fan", 7, "powersupply fan", 8, "heat pipe", 9, "integrated refrig", 0xa, "active cooling", 0xb, "passive cooling", 0, nil, }; Item fanitems[] = { "tprobhnd", 2, Integer, -1, "%.4llux", nil, "typestat", 1, Integer, -1, "%.2llux", nil, "coolgroup", 1, Integer, -1, "%.2llux", nil, "oem", 4, Integer, -1, "%.8llux", nil, "nominalspd", 2, Integer, -1, "%.4lld", nil, "description", 1, String, -1, "%s", nil, }; Item tprobeitems[] = { "desc", 1, String, -1, "%s", nil, "locstat", 1, Integer, -1, "%.2llux", nil, "max", 2, Integer, -1, "%.llud 1/10th °C", nil, "min", 2, Integer, -1, "%.llud 1/10th °C", nil, "res", 2, Integer, -1, "%.llud 1/10th °C", nil, "tolerance", 2, Integer, -1, "%.llud 1/10th °C", nil, "accuracy", 2, Integer, -1, "%.llud 1/10th °C", nil, "oem", 4, Integer, -1, "%.8llux", nil, "nominal", 2, Integer, -1, "%.llud 1/10th °C", nil, }; Item cprobeitems[] = { "desc", 1, String, -1, "%s", nil, "locstat", 1, Integer, -1, "%.2llux", nil, "max", 2, Integer, -1, "%.llud mA", nil, "min", 2, Integer, -1, "%.llud mA", nil, "res", 2, Integer, -1, "%.llud mA", nil, "tolerance", 2, Integer, -1, "%.llud mA", nil, "accuracy", 2, Integer, -1, "%.llud mA", nil, "oem", 4, Integer, -1, "%.8llux", nil, "nominal", 2, Integer, -1, "%.llud mA", nil, }; Item bootinfoitems[] = { "undefined", 6, Integer, -1, "%llux", nil, "status", 10, Uchar, -1, "%.10H", nil, }; Item memerr64items[] = { "type", 1, Integer, -1, "%llud", nil, "gran", 1, Integer, -1, "%llud", nil, "operation", 1, Integer, -1, "%llud", nil, "synrdome", 4, Integer, -1, "%.8llux", nil, "addr", 8, Integer, -1, "%.16llux", nil, "devaddr", 8, Integer, -1, "%.16llux", nil, "resolution", 4, Integer, -1, "%.8llux", nil, }; Enum mgmtaddrtype[] = { 1, "other", 2, "unknown", 3, "i/o port", 4, "memory", 5, "smbus", 0, nil, }; Item mgmtitems[] = { "desc", 1, String, -1, "%s", nil, "type", 1, Integer, -1, "%lld", nil, "addr", 4, Integer, -1, "%#.8llx", nil, "addrtype", 1, Enumf, -1, "%s", mgmtaddrtype, }; Item mgmtcitems[] = { "desc", 1, String, -1, "%s", nil, "devhand", 2, Integer, -1, "%.4llux", nil, "cmphand", 2, Integer, -1, "%.4llux", nil, "thand", 2, Integer, -1, "%.4llux", nil, }; Item mgmtdtitems[] = { "low thresh", 2, Integer, -1, "%.4llud", nil, "hi thresh", 2, Integer, -1, "%.4llud", nil, "low crit thresh", 2, Integer, -1, "%.4llud", nil, "hi crit thresh", 2, Integer, -1, "%.4llud", nil, "low nr thresh", 2, Integer, -1, "%.4llud", nil, "hi nr thresh", 2, Integer, -1, "%.4llud", nil, }; Item memchanitems[] = { "type", 1, Integer, -1, "%llud", nil, "maxload", 1, Integer, -1, "%llud", nil, "devcnt", 1, Integer, -1, "%llud", nil, "load1", 1, Integer, -1, "%llud", nil, "hndl1", 2, Integer, -1, "%.4llux", nil, }; Item ipmiitems[] = { "type", 1, Integer, -1, "%llud", nil, "version", 1, Integer, -1, "%#.2llux", nil, "i²c slaveaddr", 1, Integer, -1, "%#.2llux", nil, "nvstoraddr", 1, Integer, -1, "%#.2llux", nil, "pa", 8, Integer, -1, "%#.16llux", nil, "pa modify", 1, Integer, -1, "%#.2llux", nil, "irq#", 1, Integer, -1, "%#.2llux", nil, }; Item psitems[] = { "pwrgrp", 1, Integer, -1, "%llud", nil, "loc", 1, String, -1, "%s", nil, "name", 1, String, -1, "%s", nil, "mfg", 1, String, -1, "%s", nil, "serial", 1, String, -1, "%s", nil, "assetag", 1, String, -1, "%s", nil, "part#", 1, String, -1, "%s", nil, "rev", 1, String, -1, "%s", nil, "pwrecap", 2, Integer, -1, "%llud mW", nil, "flags", 2, Integer, -1, "%.4llux", nil, "input v hdl", 2, Integer, -1, "%.4llux", nil, "fan hdl", 2, Integer, -1, "%.4llux", nil, "current hdl", 2, Integer, -1, "%.4llux", nil, }; Item obditems[] = { "name", 1, String, -1, "%s", nil, "type", 1, Integer, -1, "%.2llux", nil, "inst", 1, Integer, -1, "%.2llux", nil, "segment", 1, Integer, -1, "%.2llux", nil, "bus", 1, Integer, -1, "%.2llux", nil, "devfn", 1, Integer, -1, "%.2llux", nil, }; typedef struct Itemtab Itemtab; struct Itemtab { Item *tab; int n; }; Itemtab itemtab[] = { [Biosinfo] biositems, nelem(biositems), [Sysinfo] sysitems, nelem(sysitems), [Module] moditems, nelem(moditems), [Chassis] chassisitems, nelem(chassisitems), [Cpu] cpuitems, nelem(cpuitems), [Memctlr] memctlritems, nelem(memctlritems), [Memstk] memstkitems, nelem(memstkitems), [Cache] cacheitems, nelem(cacheitems), [Conn] connitems, nelem(connitems), [Slot] slotitems, nelem(slotitems), [Oemstr] oemitems, nelem(oemitems), [Sysconf] sysconfitems, nelem(sysconfitems), [Bioslang] bioslangitems, nelem(bioslangitems), [Syslog] syslogitems, nelem(syslogitems), [Pmem] pmemitems, nelem(pmemitems), [Mdev] mdevitems, nelem(mdevitems), [Merror] merroritems, nelem(merroritems), [Mmap] mmapitems, nelem(mmapitems), [Mmdev] mmdevitems, nelem(mmdevitems), [Pointer] ptritems, nelem(ptritems), [Battery] batteryitems, nelem(batteryitems), [Wdog] wdogitems, nelem(wdogitems), [Hwsec] hwsecitems, nelem(hwsecitems), [Syspwr] syspwritems, nelem(syspwritems), [Vprobe] vprobeitems, nelem(vprobeitems), [Fan] fanitems, nelem(fanitems), [Tprobe] tprobeitems, nelem(tprobeitems), [Cprobe] cprobeitems, nelem(cprobeitems), [Bootinfo] bootinfoitems, nelem(bootinfoitems), [Merror64] memerr64items, nelem(memerr64items), [Mgmt] mgmtitems, nelem(mgmtitems), [Mgmtc] mgmtcitems, nelem(mgmtcitems), [Mgmtdt] mgmtdtitems, nelem(mgmtdtitems), [Memch] memchanitems, nelem(memchanitems), [Ipmi] ipmiitems, nelem(ipmiitems), [Ps] psitems, nelem(psitems), [Obd] obditems, nelem(obditems), }; void setoffsets(Item *tab, int n) { int i, o; o = 4; for(i = 0; i < n; i++){ tab[i].offset = o; o += tab[i].nbytes; } } void tabinit(void) { int i; for(i = 0; i < nelem(itemtab); i++) setoffsets(itemtab[i].tab, itemtab[i].n); } char* getstring(uchar *p, int i, uchar *e) { uchar *q; if(i == 0) return nil; for(;; i--){ if(i == 1) break; p = memchr(p, 0, e - p - 1); if(p == nil) sysfatal("bad strings"); // return nil; p++; } q = memchr(p, 0, e - p - 1); if(q == nil || q-p == 0) return nil; return strdup((char*)p); } void crack(uchar *p, uchar *e, Item *tabi, Itemv *tabv, int n) { int i, len; Item *t; Itemv *v; len = p[1]; for(i = 0; i < n; i++){ t = tabi + i; v = tabv + i; if(p + t->offset + t->nbytes >= p+len){ /* cheater way to protect against new std. versions */ continue; } switch(t->type){ default: sysfatal("bad type"); case String: v->s = getstring(p + len, p[t->offset], e); break; case Enumf: case Enumbv: case Integer: if(p + t->offset + t->nbytes >= e) sysfatal("range"); v->i = getle(p + t->offset, t->nbytes); break; case Uchar: if(p + t->offset + t->nbytes >= e) sysfatal("range"); memcpy(v->uuid, p + t->offset, t->nbytes); break; } } } void dumpenum(Enum *p) { for(; p->s != nil; p++) Bprint(out, "%s %d\n", p->s, p->v); } char* enumtostr(Enum *p, uvlong i) { for(; p->s != nil; p++) if(i == p->v) return p->s; return nil; } int strtoenum(Enum *p, char *s) { for(; p->s != nil; p++) if(cistrcmp(s, p->s) == 0) return p->v; return -1; } char* enumbvtostr(Enum *p, uint i, char *s0, char *e) { char *s; s = s0; for(; p->s != nil; p++) if(i & p->v){ if(s != s0) s = seprint(s, e, " "); s = seprint(s, e, "%s", p->s); } if(s != s0) return s0; return nil; } void printitems(int type, Item *tabi, Itemv *tabv, int n) { char *s, buf[128]; int i; Item *t; Itemv *v; // Bprint(out, "type %d\n", type); USED(type); for(i = 0; i < n; i++){ t = tabi + i; v = tabv + i; Bprint(out, " %-12s ", t->name); switch(t->type){ default: sysfatal("bad type"); case String: Bprint(out, t->fmt, v->s); break; case Integer: Bprint(out, t->fmt, v->i); break; case Uchar: Bprint(out, t->fmt, v->uuid); break; case Enumf: s = enumtostr(t->tab, v->i); if(s != nil){ Bprint(out, t->fmt, s); Bprint(out, " (%#llux)", v->i); } else Bprint(out, "%lld", v->i); break; case Enumbv: s = enumbvtostr(t->tab, v->i, buf, buf+sizeof buf); if(s != nil){ Bprint(out, t->fmt, s); Bprint(out, " (%#llux)", v->i); } else Bprint(out, "%lld", v->i); break; } Bprint(out, "\n"); } } uchar* next(uchar *p, uchar *e) { int ns; p += p[1]; if(p >= e) sysfatal("structures out-of-bounds"); for(ns = 0;; ns++){ p = memchr(p, 0, e - p - 1); if(p == nil) sysfatal("bad strings"); p++; if(p[0] == 0){ p++; break; } } USED(ns); return p; } Sm* finddmi(void) { uchar *buf, *p, *e; int i, len; Sm *sm; Smval *val; realmodefd(); buf = emalloc(Dmisz); if(pread(rfd, buf, Dmisz, Dmistart) != Dmisz) sysfatal("read: %r"); e = buf + Dmisz; for(p = buf; p < e; p += 16) if(memcmp(p, "_SM_", 4) == 0) goto found; sysfatal("no dmi structure"); found: Bvprint(out, "found at %#lux\n", p-buf+Dmistart); len = p[5]; /* do checksums */ sm = emalloc(len); sm->raw = *(Smbuf*)p; Bvprint(out, "dmi %ud.%ud\n", sm->raw.vers[0], sm->raw.vers[1]); sm->stpa = getle(sm->raw.stpa, 4); sm->stlen = getle(sm->raw.stlen, 2); Bvprint(out, "structure pa %llux len %d count %d\n", sm->stpa, sm->stlen, (uint)getle(sm->raw.nstrut, 2)); sm->n = getle(sm->raw.nstrut, 2); sm->v = emalloc(sm->n*sizeof sm->v[0]); free(buf); buf = emalloc(sm->stlen); if(pread(rfd, buf, sm->stlen, sm->stpa) != sm->stlen) sysfatal("read: %r"); p = buf; e = buf + sm->stlen; for(i = 0; i < sm->n; i++){ val = sm->v + i; val->type = p[0]; val->hand = getle(p+2, 2); val->len = p[1]; if(val->type < nelem(itemtab)){ val->v = emalloc(itemtab[val->type].n*sizeof val->v[0]); val->i = itemtab[val->type].tab; crack(p, e, val->i, val->v, itemtab[val->type].n); } p = next(p, e); } return sm; } void printdmi(Sm *sm) { int i; Smval *val; for(i = 0; i < sm->n; i++){ val = sm->v + i; if(prtype != -1 && val->type != prtype) continue; if(prhand != -1 && val->hand != prhand) continue; Bprint(out, "%d: type %s %ud len %ud handle %ud\n", i, enumtostr(tabletab, val->type), val->type, val->len, val->hand); if(val->type < nelem(itemtab)) printitems(val->type, itemtab[val->type].tab, val->v, itemtab[val->type].n); } } Smval* handtosmval(Sm *sm, int hand) { int i; Smval *val; for(i = 0; i < sm->n; i++){ val = sm->v + i; if(val->hand == hand) return val; } return nil; } Itemv* getval(char *name, Smval *v, int n) { int i; for(i = 0; i < n; i++) if(cistrcmp(name, v->i[i].name) == 0) return v->v + i; return nil; } void memhack(Sm *sm) { int i, cnt; uvlong start, end; Itemv *v; Smval *val, *mem; for(i = 0; i < sm->n; i++){ val = sm->v + i; if(val->type != Mmdev) continue; start = 0; end = 0; cnt = itemtab[val->type].n; v = getval("start", val, cnt); if(v != nil && v->i != 0xffffffff) start = (v->i+0)*1024; else{ v = getval("xstart", val, cnt); if(v != nil) start = v->i; } v = getval("end", val, cnt); if(v != nil && v->i != 0xffffffff){ end = v->i; if((end & 0xffff) == 0xffff) end++; end *= 1024; }else if((v = getval("xend", val, cnt)) != nil){ end = v->i; if((end & 0xffff) == 0xffff) end++; } // if(end == 0) // continue; mem = handtosmval(sm, getval("dhand", val, cnt)->i); if(mem == nil) continue; Bprint(out, "%#.16llux %#.16llux " "%-15s %-20s" "\n", start, end, getval("mfgr", mem, itemtab[Mdev].n)->s, // getval("serial", mem, itemtab[Mdev].n)->s getval("part#", mem, itemtab[Mdev].n)->s ); } } fmtℬ(Fmt *f) { int i; uvlong v, t, c, m; v = va_arg(f->args, uvlong); m = 1; t = 0; for(i = 0; i < 2*sizeof v; i++){ c = v>>4*i & 0xf; t += c*m; m *= 10; } return fmtprint(f, "%lld", t); } /* cmos address i/o ports 0x70/0x71 */ Item type1header[] = { "oem res", 5, Uchar, -1, "%.5H", nil, "mewindow", 1, Integer, -1, "%ℬ", nil, "meincr", 1, Integer, -1, "%lld", nil, "logclearadr", 1, Integer, -1, "%#llux", nil, "logclearbit", 1, Integer, -1, "%#llux", nil, "cmoscksumstart", 1, Integer, -1, "%#llux", nil, "cmoscksumcnt", 1, Integer, -1, "%#llux", nil, "cmoscksumadr", 1, Integer, -1, "%#llux", nil, "reserved", 3, Integer, -1, "%#llux", nil, "headerrev", 1, Integer, -1, "%llud", nil, }; Enum logtype[] = { 0, "reserved", 1, "single-bit ecc error", 2, "multi-bit ecc error", 3, "parity memory error", 4, "bus timeout", 5, "io channel check", 6, "software nmi", 7, "post memory resize", 8, "post error", 9, "pci parity error", 0xa, "pci system error", 0xb, "cpu failure", 0xc, "eisa failsafe timer timeout", 0xd, "correctable memory log disabled", 0xe, "loging disabled (log spam)", 0xf, "reserved (0xf)", 0x10, "system physical limits exceeded", 0x11, "watchdog reset", 0x12, "system configuration info", 0x13, "harddrive info", 0x14, "system reconfigured", 0x15, "uncorrectable cpu-complex error", 0x16, "log cleared", 0x17, "system boot", 0x17, "system boot", }; Enum varliabledatafmt[] = { 0, "none", 1, "handle", /* 2 bytes */ 2, "multiple-event", /* 2 bytes */ 3, "multiple-event handle", /* 4 bytes */ 4, "post results bitmap", /* 8 bytes */ 5, "system mgmt", /* 4 bytes */ 6, "multiple-event sm", /* 8 bytes */ }; Item logdesc[] = { "type", 1, Integer, -1, "%lld", nil, "datafmt", 1, Integer, -1, "%lld", nil, }; Smval* smmatch(Sm *sm, Smval *val, int type) { int i; if(val == nil) i = 0; else i = val - sm->v; for(; i < sm->n; i++){ val = sm->v + i; if(val->type != type) continue; return val; } return nil; } typedef struct Logfn Logfn; typedef struct Log Log; struct Logfn { char *name; int (*open)(Log*); void (*close)(Log*); int (*read)(Log*, void*, int, uvlong); int (*write)(Log*, void*, int, uvlong); }; struct Log { int fd; Logfn *l; int valid; int format; uint len; uvlong hdroffset; uvlong dataoffset; uvlong pa; int access; }; enum { Biosmem0 = 0xff000000, Biosmemsz = 16*1024*1024, }; int mmioopen(Log *l) { if(l->pa >= 1ull<<32 || l->pa < Biosmem0){ werrstr("mmio range: %#llux", l->pa); return -1; } if(l->len > Biosmemsz){ werrstr("mmio size: %#ux", l->len); return -1; } return open("/dev/resmem", OREAD); } void mmioclose(Log *l) { close(l->fd); } int mmioread(Log *l, void *a, int n, uvlong o) { return pread(l->fd, a, n, o+l->pa); } int mmiowrite(Log *l, void *a, int n, uvlong o) { return pwrite(l->fd, a, n, o+l->pa); } Logfn logfntab[] = { [3] {"mmio", mmioopen, mmioclose, mmioread, mmiowrite, }, }; uvlong getv(Smval *val, int cnt, char *s, uvlong dflt) { Itemv *v; v = getval(s, val, cnt); if(v != nil) return v->i; return dflt; } typedef struct Loge Loge; struct Loge { uchar type; uchar len; uchar bcddate[6]; }; void loghack(Sm *sm) { int cnt; Smval *val; Log log; Loge e; uintmem o; val = smmatch(sm, nil, Syslog); if(val == nil) return; cnt = itemtab[val->type].n; memset(&log, 0, sizeof log); log.valid = getv(val, cnt, "status", 0) & 1; log.len = getv(val, cnt, "loglength", 0); log.hdroffset = getv(val, cnt, "hdroffset", 0); log.dataoffset = getv(val, cnt, "dataoffset", 0); log.pa = getv(val, cnt, "pa", 0); log.access = getv(val, cnt, "access", -1); log.format = getv(val, cnt, "format", -1); if(log.valid == 0) sysfatal("log invalid %lld", getv(val, cnt, "status", 0)); if((uint)log.access >= nelem(logfntab) || logfntab[log.access].write == nil) sysfatal("access method %d not supported", log.access); if(log.format != 1) sysfatal("unknown log hdr format %d", log.format); log.l = logfntab + log.access; print("access method %s\n", log.l->name); print("%lld %lld\n", getval("ndesc", val, cnt)->i, getval("desclen", val, cnt)->i); if((log.fd = log.l->open(&log)) == -1) sysfatal("can't open log: %r"); char buf[32]; if(log.l->read(&log, buf, 16, log.hdroffset) != 16) sysfatal("read: %r"); print("%.16H\n", buf); for(o = log.dataoffset;; o += e.len){ memset(&e, 0, sizeof e); log.l->read(&log, buf, 8, o); e.type = buf[0]; if(e.type == 0xff) break; e.len = buf[1] & ~0x80; if(e.len < 8) break; memcpy(e.bcddate, buf+2, 6); print("type %.2ux len %d date %#.6H\n", e.type, e.len, e.bcddate); // log.l->read(&log, buf, e.len, o); // print("data %.*H", e.len-8, buf+8); } log.l->close(&log); } void outinit(void) { if(Binit(&outsb, 1, OWRITE) == -1) sysfatal("Binit: %r"); out = &outsb; } void outterm(void) { Bterm(out); out = nil; } void usage(void) { fprint(2, "usage: dmi [-vmls] [-t type] [-h hand]\n"); exits("usage"); } void main(int argc, char **argv) { char *s, *p; Sm *sm; void (*f)(Sm*); fmtinstall(L'ℛ', fmtℛ); fmtinstall(L'𝒮', fmt𝒮); fmtinstall(L'×', fmt×); fmtinstall(L'ℬ', fmtℬ); /* bcd */ fmtinstall('H', encodefmt); tabinit(); outinit(); f = printdmi; ARGBEGIN{ case 'v': verbose = 1; break; case 't': s = EARGF(usage()); prtype = strtoul(s, &p, 0); if(p == s) prtype = strtoenum(tabletab, s); if(prtype == -1) sysfatal("bad type"); break; case 'h': prhand = strtoul(EARGF(usage()), &p, 0); break; case 'l': dumpenum(tabletab); outterm(); exits(""); case 'm': f = memhack; break; case 's': f = loghack; break; default: usage(); }ARGEND if(argc != 0) usage(); sm = finddmi(); f(sm); outterm(); exits(""); }