xref: /netbsd-src/sys/dev/acpi/apei_interp.c (revision 4f770de5f66563383ee89b6def85e56e2bda7731)
1 /*	$NetBSD: apei_interp.c,v 1.4 2024/03/22 20:48:05 riastradh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2024 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * APEI action interpreter.
31  *
32  * APEI provides a generalized abstraction to implement the actions an
33  * OS must take to inject an error, or save state in a persistent error
34  * record for the next boot, since there are many different hardware
35  * register interfaces for, e.g., injecting errors.
36  *
37  * You might think that APEI, being part of ACPI, would use the usual
38  * ACPI interpreter to run ACPI methods for these actions.  You would
39  * be wrong.  Alas.
40  *
41  * Instead, there is an entirely different little language of actions
42  * that an OS must write programs in to inject errors, and an entirely
43  * different little language of instructions that the interpreter for
44  * the actions uses to interpret the OS's error injection program.  Got
45  * it?
46  *
47  * The EINJ and ERST tables provide a series entries that look like:
48  *
49  *	+-----------------------------------------------+
50  *	| Action=SET_ERROR_TYPE				|
51  *	| Instruction=SKIP_NEXT_INSTRUCTION_IF_TRUE	|
52  *	| Register=0x7fabcd10 [memory]			|
53  *	| Value=0xdeadbeef				|
54  *	+-----------------------------------------------+
55  *	| Action=SET_ERROR_TYPE				|
56  *	| Instruction=WRITE_REGISTER_VALUE		|
57  *	| Register=0x7fabcd14 [memory]			|
58  *	| Value=1					|
59  *	+-----------------------------------------------+
60  *	| Action=SET_ERROR_TYPE				|
61  *	| Instruction=READ_REGISTER			|
62  *	| Register=0x7fabcd1c [memory]			|
63  *	+-----------------------------------------------+
64  *	| Action=SET_ERROR_TYPE				|
65  *	| Instruction=WRITE_REGISTER			|
66  *	| Register=0x7fabcd20 [memory]			|
67  *	+-----------------------------------------------+
68  *	| Action=EXECUTE_OPERATION			|
69  *	| Instruction=LOAD_VAR1				|
70  *	| Register=0x7fabcf00 [memory]			|
71  *	+-----------------------------------------------+
72  *	| Action=SET_ERROR_TYPE				|
73  *	| Instruction=WRITE_REGISTER_VALUE		|
74  *	| Register=0x7fabcd24 [memory]			|
75  *	| Value=42					|
76  *	+-----------------------------------------------+
77  *	| ...						|
78  *	+-----------------------------------------------+
79  *
80  * The entries tell the OS, for each action the OS might want to
81  * perform like BEGIN_INJECTION_OPERATION or SET_ERROR_TYPE or
82  * EXECUTE_OPERATION, what instructions must be executed and in what
83  * order.
84  *
85  * The instructions run in one of two little state machines -- there's
86  * a different instruction set for EINJ and ERST -- and vary from noops
87  * to reading and writing registers to arithmetic on registers to
88  * conditional and unconditional branches.
89  *
90  * Yes, that means this little language -- the ERST language, anyway,
91  * not the EINJ language -- is Turing-complete.
92  *
93  * This APEI interpreter first compiles the table into a contiguous
94  * sequence of instructions for each action, to make execution easier,
95  * since there's no requirement that the instructions for an action be
96  * contiguous in the table, and the GOTO instruction relies on
97  * contiguous indexing of the instructions for an action.
98  *
99  * This interpreter also does a little validation so the firmware
100  * doesn't, e.g., GOTO somewhere in oblivion.  The validation is mainly
101  * a convenience for catching mistakes in firmware, not a security
102  * measure, since the OS is absolutely vulnerable to malicious firmware
103  * anyway.
104  */
105 
106 #include <sys/cdefs.h>
107 __KERNEL_RCSID(0, "$NetBSD: apei_interp.c,v 1.4 2024/03/22 20:48:05 riastradh Exp $");
108 
109 #include <sys/types.h>
110 
111 #include <sys/kmem.h>
112 #include <sys/systm.h>
113 
114 #include <dev/acpi/acpivar.h>
115 #include <dev/acpi/apei_interp.h>
116 #include <dev/acpi/apei_mapreg.h>
117 
118 /*
119  * struct apei_actinst
120  *
121  *	Sequence of instructions to execute for an action.
122  */
123 struct apei_actinst {
124 	uint32_t		ninst;
125 	uint32_t		ip;
126 	struct {
127 		struct acpi_whea_header	*header;
128 		struct apei_mapreg	*map;
129 	}			*inst;
130 	bool			disable;
131 };
132 
133 /*
134  * struct apei_interp
135  *
136  *	Table of instructions to interpret APEI actions.
137 */
138 struct apei_interp {
139 	const char		*name;
140 	const char		*const *actname;
141 	unsigned		nact;
142 	const char		*const *instname;
143 	unsigned		ninst;
144 	const bool		*instreg;
145 	bool			(*instvalid)(ACPI_WHEA_HEADER *, uint32_t,
146 				    uint32_t);
147 	void			(*instfunc)(ACPI_WHEA_HEADER *,
148 				    struct apei_mapreg *, void *, uint32_t *,
149 				    uint32_t);
150 	struct apei_actinst	actinst[];
151 };
152 
153 struct apei_interp *
apei_interp_create(const char * name,const char * const * actname,unsigned nact,const char * const * instname,unsigned ninst,const bool * instreg,bool (* instvalid)(ACPI_WHEA_HEADER *,uint32_t,uint32_t),void (* instfunc)(ACPI_WHEA_HEADER *,struct apei_mapreg *,void *,uint32_t *,uint32_t))154 apei_interp_create(const char *name,
155     const char *const *actname, unsigned nact,
156     const char *const *instname, unsigned ninst,
157     const bool *instreg,
158     bool (*instvalid)(ACPI_WHEA_HEADER *, uint32_t, uint32_t),
159     void (*instfunc)(ACPI_WHEA_HEADER *, struct apei_mapreg *, void *,
160 	uint32_t *, uint32_t))
161 {
162 	struct apei_interp *I;
163 
164 	I = kmem_zalloc(offsetof(struct apei_interp, actinst[nact]), KM_SLEEP);
165 	I->name = name;
166 	I->actname = actname;
167 	I->nact = nact;
168 	I->instname = instname;
169 	I->ninst = ninst;
170 	I->instreg = instreg;
171 	I->instvalid = instvalid;
172 	I->instfunc = instfunc;
173 
174 	return I;
175 }
176 
177 void
apei_interp_destroy(struct apei_interp * I)178 apei_interp_destroy(struct apei_interp *I)
179 {
180 	unsigned action, nact = I->nact;
181 
182 	for (action = 0; action < nact; action++) {
183 		struct apei_actinst *const A = &I->actinst[action];
184 		unsigned j;
185 
186 		if (A->ninst == 0 || A->inst == NULL)
187 			continue;
188 
189 		for (j = 0; j < A->ninst; j++) {
190 			ACPI_WHEA_HEADER *const E = A->inst[j].header;
191 			struct apei_mapreg *const map = A->inst[j].map;
192 
193 			if (map != NULL)
194 				apei_mapreg_unmap(&E->RegisterRegion, map);
195 		}
196 
197 		kmem_free(A->inst, A->ninst * sizeof(A->inst[0]));
198 		A->inst = NULL;
199 	}
200 
201 	kmem_free(I, offsetof(struct apei_interp, actinst[nact]));
202 }
203 
204 /*
205  * apei_interp_pass1_load(I, i, E)
206  *
207  *	Load the ith table entry E into the interpreter I.  To be
208  *	called for each entry in the table sequentially.
209  *
210  *	This first pass counts the number of instructions for each
211  *	action, so we can allocate an array of instructions for
212  *	indexing each action.
213  */
214 void
apei_interp_pass1_load(struct apei_interp * I,uint32_t i,ACPI_WHEA_HEADER * E)215 apei_interp_pass1_load(struct apei_interp *I, uint32_t i,
216     ACPI_WHEA_HEADER *E)
217 {
218 
219 	/*
220 	 * If we don't recognize this action, ignore it and move on.
221 	 */
222 	if (E->Action >= I->nact || I->actname[E->Action] == NULL) {
223 		aprint_error("%s[%"PRIu32"]: unknown action: 0x%"PRIx8"\n",
224 		    I->name, i, E->Action);
225 		return;
226 	}
227 	struct apei_actinst *const A = &I->actinst[E->Action];
228 
229 	/*
230 	 * If we can't interpret this instruction for this action, or
231 	 * if we couldn't interpret a previous instruction for this
232 	 * action, disable this action and move on.
233 	 */
234 	if (E->Instruction >= I->ninst ||
235 	    I->instname[E->Instruction] == NULL) {
236 		aprint_error("%s[%"PRIu32"]: unknown instruction: 0x%02"PRIx8
237 		    "\n", I->name, i, E->Instruction);
238 		A->ninst = 0;
239 		A->disable = true;
240 		return;
241 	}
242 	if (A->disable)
243 		return;
244 
245 	/*
246 	 * Count another instruction.  We will make a pointer
247 	 * to it in a later pass.
248 	 */
249 	A->ninst++;
250 
251 	/*
252 	 * If it overflows a reasonable size, disable the action
253 	 * altogether.
254 	 */
255 	if (A->ninst >= 256) {
256 		aprint_error("%s[%"PRIu32"]:"
257 		    " too many instructions for action %"PRIu32" (%s)\n",
258 		    I->name, i,
259 		    E->Action, I->actname[E->Action]);
260 		A->ninst = 0;
261 		A->disable = true;
262 		return;
263 	}
264 }
265 
266 /*
267  * apei_interp_pass2_verify(I, i, E)
268  *
269  *	Verify the ith entry's instruction, using the caller's
270  *	instvalid function, now that all the instructions have been
271  *	counted.  To be called for each entry in the table
272  *	sequentially.
273  *
274  *	This second pass checks that GOTO instructions in particular
275  *	don't jump out of bounds.
276  */
277 void
apei_interp_pass2_verify(struct apei_interp * I,uint32_t i,ACPI_WHEA_HEADER * E)278 apei_interp_pass2_verify(struct apei_interp *I, uint32_t i,
279     ACPI_WHEA_HEADER *E)
280 {
281 
282 	/*
283 	 * If there's no instruction validation function, skip this
284 	 * pass.
285 	 */
286 	if (I->instvalid == NULL)
287 		return;
288 
289 	/*
290 	 * If we skipped it in earlier passes, skip it now.
291 	 */
292 	if (E->Action > I->nact || I->actname[E->Action] == NULL)
293 		return;
294 
295 	/*
296 	 * If the instruction is invalid, disable the whole action.
297 	 */
298 	struct apei_actinst *const A = &I->actinst[E->Action];
299 	if (!(*I->instvalid)(E, A->ninst, i)) {
300 		A->ninst = 0;
301 		A->disable = true;
302 	}
303 }
304 
305 /*
306  * apei_interp_pass3_alloc(I)
307  *
308  *	Allocate an array of instructions for each action that we
309  *	didn't disable.
310  */
311 void
apei_interp_pass3_alloc(struct apei_interp * I)312 apei_interp_pass3_alloc(struct apei_interp *I)
313 {
314 	unsigned action;
315 
316 	for (action = 0; action < I->nact; action++) {
317 		struct apei_actinst *const A = &I->actinst[action];
318 		if (A->ninst == 0 || A->disable)
319 			continue;
320 		A->inst = kmem_zalloc(A->ninst * sizeof(A->inst[0]), KM_SLEEP);
321 	}
322 }
323 
324 /*
325  * apei_interp_pass4_assemble(I, i, E)
326  *
327  *	Put the instruction for the ith entry E into the instruction
328  *	array for its action.  To be called for each entry in the table
329  *	sequentially.
330  */
331 void
apei_interp_pass4_assemble(struct apei_interp * I,uint32_t i,ACPI_WHEA_HEADER * E)332 apei_interp_pass4_assemble(struct apei_interp *I, uint32_t i,
333     ACPI_WHEA_HEADER *E)
334 {
335 
336 	/*
337 	 * If we skipped it in earlier passes, skip it now.
338 	 */
339 	if (E->Action >= I->nact || I->actname[E->Action] == NULL)
340 		return;
341 
342 	struct apei_actinst *const A = &I->actinst[E->Action];
343 	if (A->disable)
344 		return;
345 
346 	KASSERT(A->ip < A->ninst);
347 	const uint32_t ip = A->ip++;
348 	A->inst[ip].header = E;
349 	A->inst[ip].map = I->instreg[E->Instruction] ?
350 	    apei_mapreg_map(&E->RegisterRegion) : NULL;
351 }
352 
353 /*
354  * apei_interp_pass5_verify(I)
355  *
356  *	Paranoia: Verify we got all the instructions for each action,
357  *	verify the actions point to their own instructions, and dump
358  *	the instructions for each action, collated, with aprint_debug.
359  */
360 void
apei_interp_pass5_verify(struct apei_interp * I)361 apei_interp_pass5_verify(struct apei_interp *I)
362 {
363 	unsigned action;
364 
365 	for (action = 0; action < I->nact; action++) {
366 		struct apei_actinst *const A = &I->actinst[action];
367 		unsigned j;
368 
369 		/*
370 		 * If the action is disabled, it's all set.
371 		 */
372 		if (A->disable)
373 			continue;
374 		KASSERTMSG(A->ip == A->ninst,
375 		    "action %s ip=%"PRIu32" ninstruction=%"PRIu32,
376 		    I->actname[action], A->ip, A->ninst);
377 
378 		/*
379 		 * XXX Dump the complete instruction table.
380 		 */
381 		for (j = 0; j < A->ninst; j++) {
382 			ACPI_WHEA_HEADER *const E = A->inst[j].header;
383 
384 			KASSERT(E->Action == action);
385 
386 			/*
387 			 * If we need the register and weren't able to
388 			 * map it, disable the action.
389 			 */
390 			if (I->instreg[E->Instruction] &&
391 			    A->inst[j].map == NULL) {
392 				A->disable = true;
393 				continue;
394 			}
395 
396 			aprint_debug("%s: %s[%"PRIu32"]: %s\n",
397 			    I->name, I->actname[action], j,
398 			    I->instname[E->Instruction]);
399 		}
400 	}
401 }
402 
403 /*
404  * apei_interpret(I, action, cookie)
405  *
406  *	Run the instructions associated with the given action by
407  *	calling the interpreter's instfunc for each one.
408  *
409  *	Halt when the instruction pointer runs past the end of the
410  *	array, or after 1000 cycles, whichever comes first.
411  */
412 void
apei_interpret(struct apei_interp * I,unsigned action,void * cookie)413 apei_interpret(struct apei_interp *I, unsigned action, void *cookie)
414 {
415 	unsigned juice = 1000;
416 	uint32_t ip = 0;
417 
418 	if (action > I->nact || I->actname[action] == NULL)
419 		return;
420 	struct apei_actinst *const A = &I->actinst[action];
421 	if (A->disable)
422 		return;
423 
424 	while (ip < A->ninst && juice --> 0) {
425 		ACPI_WHEA_HEADER *const E = A->inst[ip].header;
426 		struct apei_mapreg *const map = A->inst[ip].map;
427 
428 		ip++;
429 		(*I->instfunc)(E, map, cookie, &ip, A->ninst);
430 	}
431 }
432