apei_interp.c revision 1.3 1 /* $NetBSD: apei_interp.c,v 1.3 2024/03/22 18:19:03 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 * XXX Map instruction registers in advance so ERST is safe in nasty
106 * contexts, e.g. to save dmesg?
107 */
108
109 #include <sys/cdefs.h>
110 __KERNEL_RCSID(0, "$NetBSD: apei_interp.c,v 1.3 2024/03/22 18:19:03 riastradh Exp $");
111
112 #include <sys/types.h>
113
114 #include <sys/kmem.h>
115 #include <sys/systm.h>
116
117 #include <dev/acpi/acpivar.h>
118 #include <dev/acpi/apei_interp.h>
119
120 /*
121 * struct apei_actinst
122 *
123 * Sequence of instructions to execute for an action.
124 */
125 struct apei_actinst {
126 uint32_t ninst;
127 uint32_t ip;
128 struct acpi_whea_header **inst;
129 };
130
131 /*
132 * struct apei_interp
133 *
134 * Table of instructions to interpret APEI actions.
135 */
136 struct apei_interp {
137 const char *name;
138 const char *const *actname;
139 unsigned nact;
140 const char *const *instname;
141 unsigned ninst;
142 bool (*instvalid)(ACPI_WHEA_HEADER *, uint32_t,
143 uint32_t);
144 void (*instfunc)(ACPI_WHEA_HEADER *, void *,
145 uint32_t *, uint32_t);
146 struct apei_actinst actinst[];
147 };
148
149 struct apei_interp *
150 apei_interp_create(const char *name,
151 const char *const *actname, unsigned nact,
152 const char *const *instname, unsigned ninst,
153 bool (*instvalid)(ACPI_WHEA_HEADER *, uint32_t, uint32_t),
154 void (*instfunc)(ACPI_WHEA_HEADER *, void *, uint32_t *, uint32_t))
155 {
156 struct apei_interp *I;
157
158 I = kmem_zalloc(offsetof(struct apei_interp, actinst[nact]), KM_SLEEP);
159 I->name = name;
160 I->actname = actname;
161 I->nact = nact;
162 I->instname = instname;
163 I->ninst = ninst;
164 I->instvalid = instvalid;
165 I->instfunc = instfunc;
166
167 return I;
168 }
169
170 void
171 apei_interp_destroy(struct apei_interp *I)
172 {
173 unsigned action, nact = I->nact;
174
175 for (action = 0; action < nact; action++) {
176 struct apei_actinst *const A = &I->actinst[action];
177
178 if (A->ninst == 0 || A->ninst == UINT32_MAX || A->inst == NULL)
179 continue;
180 kmem_free(A->inst, A->ninst * sizeof(A->inst[0]));
181 A->inst = NULL;
182 }
183
184 kmem_free(I, offsetof(struct apei_interp, actinst[nact]));
185 }
186
187 /*
188 * apei_interp_pass1_load(I, i, E)
189 *
190 * Load the ith table entry E into the interpreter I. To be
191 * called for each entry in the table sequentially.
192 *
193 * This first pass counts the number of instructions for each
194 * action, so we can allocate an array of instructions for
195 * indexing each action.
196 */
197 void
198 apei_interp_pass1_load(struct apei_interp *I, uint32_t i,
199 ACPI_WHEA_HEADER *E)
200 {
201
202 /*
203 * If we don't recognize this action, ignore it and move on.
204 */
205 if (E->Action >= I->nact || I->actname[E->Action] == NULL) {
206 aprint_error("%s[%"PRIu32"]: unknown action: 0x%"PRIx8"\n",
207 I->name, i, E->Action);
208 return;
209 }
210 struct apei_actinst *const A = &I->actinst[E->Action];
211
212 /*
213 * If we can't interpret this instruction for this action, or
214 * if we couldn't interpret a previous instruction for this
215 * action, ignore _all_ instructions for this action -- by
216 * marking the action as having UINT32_MAX instructions -- and
217 * move on.
218 */
219 if (E->Instruction >= I->ninst ||
220 I->instname[E->Instruction] == NULL) {
221 aprint_error("%s[%"PRIu32"]: unknown instruction: 0x%02"PRIx8
222 "\n", I->name, i, E->Instruction);
223 A->ninst = UINT32_MAX;
224 return;
225 }
226 if (A->ninst == UINT32_MAX)
227 return;
228
229 /*
230 * Count another instruction. We will make a pointer
231 * to it in a later pass.
232 */
233 A->ninst++;
234
235 /*
236 * If it overflows a reasonable size, bail on this instruction.
237 */
238 if (A->ninst >= 256) {
239 aprint_error("%s[%"PRIu32"]:"
240 " too many instructions for action %"PRIu32" (%s)\n",
241 I->name, i,
242 E->Action, I->actname[E->Action]);
243 A->ninst = UINT32_MAX;
244 return;
245 }
246 }
247
248 /*
249 * apei_interp_pass2_verify(I, i, E)
250 *
251 * Verify the ith entry's instruction, using the caller's
252 * instvalid function, now that all the instructions have been
253 * counted. To be called for each entry in the table
254 * sequentially.
255 *
256 * This second pass checks that GOTO instructions in particular
257 * don't jump out of bounds.
258 */
259 void
260 apei_interp_pass2_verify(struct apei_interp *I, uint32_t i,
261 ACPI_WHEA_HEADER *E)
262 {
263
264 /*
265 * If there's no instruction validation function, skip this
266 * pass.
267 */
268 if (I->instvalid == NULL)
269 return;
270
271 /*
272 * If we skipped it in earlier passes, skip it now.
273 */
274 if (E->Action > I->nact || I->actname[E->Action] == NULL)
275 return;
276
277 /*
278 * If the instruction is invalid, disable the whole action.
279 */
280 struct apei_actinst *const A = &I->actinst[E->Action];
281 if (!(*I->instvalid)(E, A->ninst, i))
282 A->ninst = UINT32_MAX;
283 }
284
285 /*
286 * apei_interp_pass3_alloc(I)
287 *
288 * Allocate an array of instructions for each action that we
289 * didn't decide to bail on, marked with UINT32_MAX.
290 */
291 void
292 apei_interp_pass3_alloc(struct apei_interp *I)
293 {
294 unsigned action;
295
296 for (action = 0; action < I->nact; action++) {
297 struct apei_actinst *const A = &I->actinst[action];
298 if (A->ninst == 0 || A->ninst == UINT32_MAX)
299 continue;
300 A->inst = kmem_zalloc(A->ninst * sizeof(A->inst[0]), KM_SLEEP);
301 }
302 }
303
304 /*
305 * apei_interp_pass4_assemble(I, i, E)
306 *
307 * Put the instruction for the ith entry E into the instruction
308 * array for its action. To be called for each entry in the table
309 * sequentially.
310 */
311 void
312 apei_interp_pass4_assemble(struct apei_interp *I, uint32_t i,
313 ACPI_WHEA_HEADER *E)
314 {
315
316 /*
317 * If we skipped it in earlier passes, skip it now.
318 */
319 if (E->Action >= I->nact || I->actname[E->Action] == NULL)
320 return;
321
322 struct apei_actinst *const A = &I->actinst[E->Action];
323 if (A->ninst == UINT32_MAX)
324 return;
325
326 KASSERT(A->ip < A->ninst);
327 A->inst[A->ip++] = E;
328 }
329
330 /*
331 * apei_interp_pass5_verify(I)
332 *
333 * Paranoia: Verify we got all the instructions for each action,
334 * verify the actions point to their own instructions, and dump
335 * the instructions for each action, collated, with aprint_debug.
336 */
337 void
338 apei_interp_pass5_verify(struct apei_interp *I)
339 {
340 unsigned action;
341
342 for (action = 0; action < I->nact; action++) {
343 struct apei_actinst *const A = &I->actinst[action];
344 unsigned j;
345
346 /*
347 * If the action is disabled, it's all set.
348 */
349 if (A->ninst == UINT32_MAX)
350 continue;
351 KASSERTMSG(A->ip == A->ninst,
352 "action %s ip=%"PRIu32" ninstruction=%"PRIu32,
353 I->actname[action], A->ip, A->ninst);
354
355 /*
356 * XXX Dump the complete instruction table.
357 */
358 for (j = 0; j < A->ninst; j++) {
359 ACPI_WHEA_HEADER *const E = A->inst[j];
360
361 KASSERT(E->Action == action);
362 aprint_debug("%s: %s[%"PRIu32"]: %s\n",
363 I->name, I->actname[action], j,
364 I->instname[E->Instruction]);
365 }
366 }
367 }
368
369 /*
370 * apei_interpret(I, action, cookie)
371 *
372 * Run the instructions associated with the given action by
373 * calling the interpreter's instfunc for each one.
374 *
375 * Halt when the instruction pointer runs past the end of the
376 * array, or after 1000 cycles, whichever comes first.
377 */
378 void
379 apei_interpret(struct apei_interp *I, unsigned action, void *cookie)
380 {
381 unsigned juice = 1000;
382 uint32_t ip = 0;
383
384 if (action > I->nact || I->actname[action] == NULL)
385 return;
386 struct apei_actinst *const A = &I->actinst[action];
387
388 while (ip < A->ninst && juice --> 0) {
389 ACPI_WHEA_HEADER *const E = A->inst[ip++];
390
391 (*I->instfunc)(E, cookie, &ip, A->ninst);
392 }
393 }
394