Home | History | Annotate | Line # | Download | only in acpi
      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 *
    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
    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
    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
    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
    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
    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
    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
    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