1/* 2 * Print table of MCA status bit combinations with results in HTML. 3 * Author: Andi Kleen 4 */ 5#define _GNU_SOURCE 1 6#include <stdio.h> 7#include <stdlib.h> 8#include <stddef.h> 9#include <string.h> 10#include <assert.h> 11#include <unistd.h> 12#include <errno.h> 13#define __KERNEL__ 1 14#include <asm/types.h> 15#include <asm/mce.h> 16 17#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x))) 18 19typedef unsigned long long u64; 20 21 22#define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ 23#define MCI_STATUS_AR (1ULL<<55) /* Action required */ 24 25int tolerant = 1; 26int panic_on_oops = 0; 27int mce_ser = 1; 28 29#include "mce-severity.c" 30 31int disable_opt = 0; 32 33struct rname { 34 char *name; 35 unsigned color; 36 char *desc; 37} rnames[] = { 38#define R(x,col,d) [MCE_ ## x ## _SEVERITY] = { #x, col, d } 39 R(NO, 0xc0c0c0, "Ignored"), 40 R(KEEP, 0x800080, "Ignore. Keep for CMC"), 41 R(SOME, 0x808080, "Log & Clear"), 42 R(AO, 0xffff00, "Kill address owner"), 43 R(UC, 0x700000, "Kill or panic"), 44 R(AR, 0x00ff00, "Kill current context"), 45 R(PANIC, 0xff0000, "Shutdown"), 46#undef R 47}; 48 49struct bit { 50 char *name; 51 unsigned offset; 52 u64 bit; 53} bits[] = { 54#define O(x) offsetof(struct mce, x) 55#define S(x) { #x, O(status), MCI_STATUS_ ## x } 56 { "RIPV", O(mcgstatus), MCG_STATUS_RIPV }, 57 { "EIPV", O(mcgstatus), MCG_STATUS_EIPV }, 58 { "MCIP", O(mcgstatus), MCG_STATUS_MCIP }, 59 S(EN), 60 S(VAL), 61 S(UC), 62 S(S), 63 S(AR), 64 S(PCC), 65 S(OVER), 66 { "SCRB-ERR", O(status), 0xc0 }, 67#undef S 68#undef O 69}; 70 71struct mce basem; 72 73#define bit_for_each(i,v) for (i = 0; i < 64; i++) if ((v) & (1ULL << i)) 74 75struct result { 76 int res; 77 unsigned dontcare; 78 char *msg; 79}; 80 81void genstate(struct mce *m, unsigned num) 82{ 83 int i; 84 *m = basem; 85 86 bit_for_each (i, num) 87 *(u64 *)((char *)m + bits[i].offset) |= bits[i].bit; 88} 89 90// find don't care bits 91// brute force version because andi is not clever enough to make the clever 92// version work. luckily the tables are small 93 94#define for_rr(start, i) for (i = start; i < num; i++) if (rr[i].res >= 0) 95#define mask_of(x) ((1U << (x))-1) 96 97static void disable(struct result *rr, int i, int src) 98{ 99 //fprintf(stderr, "disabling %d from %d\n", i, src); 100 rr[i].res = -1; 101} 102 103// handle case: one bit set always the same outcome 104static void one_bit_all(struct result *rr, int num, int mask) 105{ 106 int first, k; 107 if (mask >= num) 108 return; 109 first = mask; 110 for_rr (first, k) { 111 if (!(k & mask)) 112 continue; 113 if (rr[k].res != rr[first].res) 114 return; 115 } 116 rr[first].dontcare = mask_of(ARRAY_SIZE(bits)) & ~mask; 117 for_rr (first + 1, k) { 118 if (k & mask) 119 disable(rr, k, k); 120 } 121} 122 123// check if toggling one bit gives the same outcome 124static void neighbour_same(struct result *rr, int num, int mask) 125{ 126 int k, other; 127 for_rr (mask, k) { 128 if (!(k & mask) || (rr[k].dontcare & mask)) 129 continue; 130 other = k ^ mask; 131 if (other >= num) 132 continue; 133 if (rr[other].res == rr[k].res && rr[other].msg == rr[k].msg) { 134 disable(rr, other, k); 135 rr[k].dontcare |= mask; 136 } 137 } 138} 139 140void optimizer(struct result *rr, int num) 141{ 142 int i; 143 144 for (i = 1; i <= 1 << ARRAY_SIZE(bits); i <<= 1) 145 one_bit_all(rr, num, i); 146 for (i = 1; i <= 1 << ARRAY_SIZE(bits); i <<= 1) 147 neighbour_same(rr, num, i); 148} 149 150int bitcount(u64 v) 151{ 152 int num = 0; 153 while (v) { 154 if (v & 1) 155 num++; 156 v >>= 1; 157 } 158 return num; 159} 160 161void table(char *title) 162{ 163 struct mce m; 164 int i, w, num; 165 166 struct result *rr = calloc(sizeof(struct result), 1U << ARRAY_SIZE(bits)); 167 168 num = 0; 169 for (i = 0; i < 1U << ARRAY_SIZE(bits); i++) { 170 genstate(&m, i); 171 rr[num].res = mce_severity(&m, tolerant, &rr[num].msg); 172 num++; 173 } 174 175 if (!disable_opt) 176 optimizer(rr, num); 177 178 printf("<p><table border=1>\n"); 179 printf("<chaption>%s</chaption>\n", title); 180 181 printf("<tr>\n"); 182 for (i = 0; i < ARRAY_SIZE(bits); i++) { 183 printf("<th>%s</th>", bits[i].name); 184 } 185 printf("<th>Result</th><th>Rule</th><th>Action</th>\n"); 186 printf("</tr>\n"); 187 188 for_rr (0, i) { 189 printf("<tr>"); 190 for (w = 0; w < ARRAY_SIZE(bits); w++) { 191 char *p = "0"; 192 char *col = ""; 193 unsigned mask = 1U << w; 194 195 if (mask & rr[i].dontcare) { 196 p = "x"; 197 col = " bgcolor=\"888888\""; 198 } else if (mask & i) { 199 if (bitcount(bits[w].bit) > 1) 200 asprintf(&p, "%llx", bits[w].bit); 201 else 202 p = "1"; 203 col = " bgcolor=\"ffffff\""; 204 } 205 printf("<td%s>%s</td>", col, p); 206 } 207 struct rname *rname = &rnames[rr[i].res]; 208 if ((unsigned)rr[i].res >= ARRAY_SIZE(rnames)) 209 rname = &((struct rname) { .name = "out of bounds", .color = 0xff00ff }); 210 assert(rname->name != NULL); 211 printf("<td bgcolor=\"%06x\">%s</td>", rname->color, rname->name); 212 assert(rr[i].msg != NULL); 213 printf("<td>%s</td>", rr[i].msg); 214 printf("<td>%s</td>", rname->desc); 215 printf("</tr>\n"); 216 } 217 printf("</table>\n"); 218} 219 220void usage(void) 221{ 222 fprintf(stderr, "ttable [-a]\n" 223 "-a don't print don't care bits, but all states\n"); 224 exit(1); 225} 226 227int main(int ac, char **av) 228{ 229 int opt; 230 while ((opt = getopt(ac, av, "a")) != -1) { 231 switch (opt) { 232 case 'a': 233 disable_opt = 1; 234 break; 235 default: 236 usage(); 237 } 238 } 239 240 printf("<html><body>\n"); 241 printf("<!-- Auto generated. Changes will be overwritten -->\n"); 242 basem.ip = 1; 243 printf("<h1>Linux kernel machine check grading</h1>\n"); 244 printf("Caveats: Only scrubber error AO MCACOD. Only applies to exceptions.\n"); 245 mce_ser = 1; 246 basem.cs = 0; 247 table("With MCA recovery ring 0"); 248 tolerant = 0; 249 table("With MCA recovery ring 0 tolerant = 0"); 250 tolerant = 1; 251 basem.cs = 3; 252 table("With MCA recovery ring 3"); 253 basem.cs = 0; 254 mce_ser = 0; 255 table("Without MCA recovery ring 0"); 256 basem.cs = 3; 257 table("Without MCA recovery ring 3"); 258 printf("</body></html>\n"); 259 return 0; 260} 261