• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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