/* * Print table of MCA status bit combinations with results in HTML. * Author: Andi Kleen */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #define __KERNEL__ 1 #include #include #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x))) typedef unsigned long long u64; #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ #define MCI_STATUS_AR (1ULL<<55) /* Action required */ int tolerant = 1; int panic_on_oops = 0; int mce_ser = 1; #include "mce-severity.c" int disable_opt = 0; struct rname { char *name; unsigned color; char *desc; } rnames[] = { #define R(x,col,d) [MCE_ ## x ## _SEVERITY] = { #x, col, d } R(NO, 0xc0c0c0, "Ignored"), R(KEEP, 0x800080, "Ignore. Keep for CMC"), R(SOME, 0x808080, "Log & Clear"), R(AO, 0xffff00, "Kill address owner"), R(UC, 0x700000, "Kill or panic"), R(AR, 0x00ff00, "Kill current context"), R(PANIC, 0xff0000, "Shutdown"), #undef R }; struct bit { char *name; unsigned offset; u64 bit; } bits[] = { #define O(x) offsetof(struct mce, x) #define S(x) { #x, O(status), MCI_STATUS_ ## x } { "RIPV", O(mcgstatus), MCG_STATUS_RIPV }, { "EIPV", O(mcgstatus), MCG_STATUS_EIPV }, { "MCIP", O(mcgstatus), MCG_STATUS_MCIP }, S(EN), S(VAL), S(UC), S(S), S(AR), S(PCC), S(OVER), { "SCRB-ERR", O(status), 0xc0 }, #undef S #undef O }; struct mce basem; #define bit_for_each(i,v) for (i = 0; i < 64; i++) if ((v) & (1ULL << i)) struct result { int res; unsigned dontcare; char *msg; }; void genstate(struct mce *m, unsigned num) { int i; *m = basem; bit_for_each (i, num) *(u64 *)((char *)m + bits[i].offset) |= bits[i].bit; } // find don't care bits // brute force version because andi is not clever enough to make the clever // version work. luckily the tables are small #define for_rr(start, i) for (i = start; i < num; i++) if (rr[i].res >= 0) #define mask_of(x) ((1U << (x))-1) static void disable(struct result *rr, int i, int src) { //fprintf(stderr, "disabling %d from %d\n", i, src); rr[i].res = -1; } // handle case: one bit set always the same outcome static void one_bit_all(struct result *rr, int num, int mask) { int first, k; if (mask >= num) return; first = mask; for_rr (first, k) { if (!(k & mask)) continue; if (rr[k].res != rr[first].res) return; } rr[first].dontcare = mask_of(ARRAY_SIZE(bits)) & ~mask; for_rr (first + 1, k) { if (k & mask) disable(rr, k, k); } } // check if toggling one bit gives the same outcome static void neighbour_same(struct result *rr, int num, int mask) { int k, other; for_rr (mask, k) { if (!(k & mask) || (rr[k].dontcare & mask)) continue; other = k ^ mask; if (other >= num) continue; if (rr[other].res == rr[k].res && rr[other].msg == rr[k].msg) { disable(rr, other, k); rr[k].dontcare |= mask; } } } void optimizer(struct result *rr, int num) { int i; for (i = 1; i <= 1 << ARRAY_SIZE(bits); i <<= 1) one_bit_all(rr, num, i); for (i = 1; i <= 1 << ARRAY_SIZE(bits); i <<= 1) neighbour_same(rr, num, i); } int bitcount(u64 v) { int num = 0; while (v) { if (v & 1) num++; v >>= 1; } return num; } void table(char *title) { struct mce m; int i, w, num; struct result *rr = calloc(sizeof(struct result), 1U << ARRAY_SIZE(bits)); num = 0; for (i = 0; i < 1U << ARRAY_SIZE(bits); i++) { genstate(&m, i); rr[num].res = mce_severity(&m, tolerant, &rr[num].msg); num++; } if (!disable_opt) optimizer(rr, num); printf("

\n"); printf("%s\n", title); printf("\n"); for (i = 0; i < ARRAY_SIZE(bits); i++) { printf("", bits[i].name); } printf("\n"); printf("\n"); for_rr (0, i) { printf(""); for (w = 0; w < ARRAY_SIZE(bits); w++) { char *p = "0"; char *col = ""; unsigned mask = 1U << w; if (mask & rr[i].dontcare) { p = "x"; col = " bgcolor=\"888888\""; } else if (mask & i) { if (bitcount(bits[w].bit) > 1) asprintf(&p, "%llx", bits[w].bit); else p = "1"; col = " bgcolor=\"ffffff\""; } printf("%s", col, p); } struct rname *rname = &rnames[rr[i].res]; if ((unsigned)rr[i].res >= ARRAY_SIZE(rnames)) rname = &((struct rname) { .name = "out of bounds", .color = 0xff00ff }); assert(rname->name != NULL); printf("", rname->color, rname->name); assert(rr[i].msg != NULL); printf("", rr[i].msg); printf("", rname->desc); printf("\n"); } printf("
%sResultRuleAction
%s%s%s
\n"); } void usage(void) { fprintf(stderr, "ttable [-a]\n" "-a don't print don't care bits, but all states\n"); exit(1); } int main(int ac, char **av) { int opt; while ((opt = getopt(ac, av, "a")) != -1) { switch (opt) { case 'a': disable_opt = 1; break; default: usage(); } } printf("\n"); printf("\n"); basem.ip = 1; printf("

Linux kernel machine check grading

\n"); printf("Caveats: Only scrubber error AO MCACOD. Only applies to exceptions.\n"); mce_ser = 1; basem.cs = 0; table("With MCA recovery ring 0"); tolerant = 0; table("With MCA recovery ring 0 tolerant = 0"); tolerant = 1; basem.cs = 3; table("With MCA recovery ring 3"); basem.cs = 0; mce_ser = 0; table("Without MCA recovery ring 0"); basem.cs = 3; table("Without MCA recovery ring 3"); printf("\n"); return 0; }