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 */
123struct 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*/
138struct 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
153struct apei_interp *
154apei_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
177void
178apei_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 */
214void
215apei_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 */
277void
278apei_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 */
311void
312apei_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 */
331void
332apei_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 */
360void
361apei_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 */
412void
413apei_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