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