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