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
19 typedef 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
25 int tolerant = 1;
26 int panic_on_oops = 0;
27 int mce_ser = 1;
28
29 #include "mce-severity.c"
30
31 int disable_opt = 0;
32
33 struct 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
49 struct 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
71 struct mce basem;
72
73 #define bit_for_each(i,v) for (i = 0; i < 64; i++) if ((v) & (1ULL << i))
74
75 struct result {
76 int res;
77 unsigned dontcare;
78 char *msg;
79 };
80
genstate(struct mce * m,unsigned num)81 void 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
disable(struct result * rr,int i,int src)97 static 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
one_bit_all(struct result * rr,int num,int mask)104 static 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
neighbour_same(struct result * rr,int num,int mask)124 static 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
optimizer(struct result * rr,int num)140 void 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
bitcount(u64 v)150 int 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
table(char * title)161 void 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
usage(void)220 void 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
main(int ac,char ** av)227 int 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