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