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