Home | History | Annotate | Line # | Download | only in acpi
apei_interp.c revision 1.1
      1  1.1  riastrad /*	$NetBSD: apei_interp.c,v 1.1 2024/03/20 17:11:43 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.1  riastrad  *	| Value=0xdeadbeef				|
     53  1.1  riastrad  *	+-----------------------------------------------+
     54  1.1  riastrad  *	| Action=SET_ERROR_TYPE				|
     55  1.1  riastrad  *	| Instruction=WRITE_REGISTER_VALUE		|
     56  1.1  riastrad  *	| Register=0x7fabcd14 [memory]			|
     57  1.1  riastrad  *	+-----------------------------------------------+
     58  1.1  riastrad  *	| Action=SET_ERROR_TYPE				|
     59  1.1  riastrad  *	| Instruction=READ_REGISTER			|
     60  1.1  riastrad  *	| Register=0x7fabcd1c [memory]			|
     61  1.1  riastrad  *	+-----------------------------------------------+
     62  1.1  riastrad  *	| Action=SET_ERROR_TYPE				|
     63  1.1  riastrad  *	| Instruction=WRITE_REGISTER			|
     64  1.1  riastrad  *	| Register=0x7fabcd20 [memory]			|
     65  1.1  riastrad  *	+-----------------------------------------------+
     66  1.1  riastrad  *	| Action=EXECUTE_OPERATION			|
     67  1.1  riastrad  *	| Instruction=LOAD_VAR1				|
     68  1.1  riastrad  *	| Register=0x7fabcf00 [memory]			|
     69  1.1  riastrad  *	+-----------------------------------------------+
     70  1.1  riastrad  *	| Action=SET_ERROR_TYPE				|
     71  1.1  riastrad  *	| Instruction=WRITE_REGISTER_VALUE		|
     72  1.1  riastrad  *	| Register=0x7fabcd24 [memory]			|
     73  1.1  riastrad  *	| Value=42					|
     74  1.1  riastrad  *	+-----------------------------------------------+
     75  1.1  riastrad  *	| ...						|
     76  1.1  riastrad  *	+-----------------------------------------------+
     77  1.1  riastrad  *
     78  1.1  riastrad  * The entries tell the OS, for each action the OS might want to
     79  1.1  riastrad  * perform like BEGIN_INJECTION_OPERATION or SET_ERROR_TYPE or
     80  1.1  riastrad  * EXECUTE_OPERATION, what instructions must be executed and in what
     81  1.1  riastrad  * order.
     82  1.1  riastrad  *
     83  1.1  riastrad  * The instructions run in one of two little state machines -- there's
     84  1.1  riastrad  * a different instruction set for EINJ and ERST -- and vary from noops
     85  1.1  riastrad  * to reading and writing registers to arithmetic on registers to
     86  1.1  riastrad  * conditional and unconditional branches.
     87  1.1  riastrad  *
     88  1.1  riastrad  * Yes, that means this little language -- the ERST language, anyway,
     89  1.1  riastrad  * not the EINJ language -- is Turing-complete.
     90  1.1  riastrad  *
     91  1.1  riastrad  * This APEI interpreter first compiles the table into a contiguous
     92  1.1  riastrad  * sequence of instructions for each action, to make execution easier,
     93  1.1  riastrad  * since there's no requirement that the actions be in order, and the
     94  1.1  riastrad  * GOTO instruction relies on contiguous indexing of the instructions
     95  1.1  riastrad  * for an action.
     96  1.1  riastrad  *
     97  1.1  riastrad  * This interpreter also does a little validation so the firmware
     98  1.1  riastrad  * doesn't, e.g., GOTO somewhere in oblivion.  The validation is mainly
     99  1.1  riastrad  * a convenience for catching mistakes in firmware, not a security
    100  1.1  riastrad  * measure, since the OS is absolutely vulnerable to malicious firmware
    101  1.1  riastrad  * anyway.
    102  1.1  riastrad  *
    103  1.1  riastrad  * XXX Map instruction registers in advance so ERST is safe in nasty
    104  1.1  riastrad  * contexts, e.g. to save dmesg?
    105  1.1  riastrad  */
    106  1.1  riastrad 
    107  1.1  riastrad #include <sys/cdefs.h>
    108  1.1  riastrad __KERNEL_RCSID(0, "$NetBSD: apei_interp.c,v 1.1 2024/03/20 17:11:43 riastradh Exp $");
    109  1.1  riastrad 
    110  1.1  riastrad #include <sys/types.h>
    111  1.1  riastrad 
    112  1.1  riastrad #include <sys/kmem.h>
    113  1.1  riastrad #include <sys/systm.h>
    114  1.1  riastrad 
    115  1.1  riastrad #include <dev/acpi/acpivar.h>
    116  1.1  riastrad #include <dev/acpi/apei_interp.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.1  riastrad 	struct acpi_whea_header	**inst;
    127  1.1  riastrad };
    128  1.1  riastrad 
    129  1.1  riastrad /*
    130  1.1  riastrad  * struct apei_interp
    131  1.1  riastrad  *
    132  1.1  riastrad  *	Table of instructions to interpret APEI actions.
    133  1.1  riastrad */
    134  1.1  riastrad struct apei_interp {
    135  1.1  riastrad 	const char		*name;
    136  1.1  riastrad 	const char		*const *actname;
    137  1.1  riastrad 	unsigned		nact;
    138  1.1  riastrad 	const char		*const *instname;
    139  1.1  riastrad 	unsigned		ninst;
    140  1.1  riastrad 	bool			(*instvalid)(ACPI_WHEA_HEADER *, uint32_t,
    141  1.1  riastrad 				    uint32_t);
    142  1.1  riastrad 	void			(*instfunc)(ACPI_WHEA_HEADER *, void *,
    143  1.1  riastrad 				    uint32_t *, uint32_t);
    144  1.1  riastrad 	struct apei_actinst	actinst[];
    145  1.1  riastrad };
    146  1.1  riastrad 
    147  1.1  riastrad struct apei_interp *
    148  1.1  riastrad apei_interp_create(const char *name,
    149  1.1  riastrad     const char *const *actname, unsigned nact,
    150  1.1  riastrad     const char *const *instname, unsigned ninst,
    151  1.1  riastrad     bool (*instvalid)(ACPI_WHEA_HEADER *, uint32_t, uint32_t),
    152  1.1  riastrad     void (*instfunc)(ACPI_WHEA_HEADER *, void *, uint32_t *, uint32_t))
    153  1.1  riastrad {
    154  1.1  riastrad 	struct apei_interp *I;
    155  1.1  riastrad 
    156  1.1  riastrad 	I = kmem_zalloc(offsetof(struct apei_interp, actinst[nact]), KM_SLEEP);
    157  1.1  riastrad 	I->name = name;
    158  1.1  riastrad 	I->actname = actname;
    159  1.1  riastrad 	I->nact = nact;
    160  1.1  riastrad 	I->instname = instname;
    161  1.1  riastrad 	I->ninst = ninst;
    162  1.1  riastrad 	I->instvalid = instvalid;
    163  1.1  riastrad 	I->instfunc = instfunc;
    164  1.1  riastrad 
    165  1.1  riastrad 	return I;
    166  1.1  riastrad }
    167  1.1  riastrad 
    168  1.1  riastrad void
    169  1.1  riastrad apei_interp_destroy(struct apei_interp *I)
    170  1.1  riastrad {
    171  1.1  riastrad 	unsigned nact = I->nact;
    172  1.1  riastrad 
    173  1.1  riastrad 	kmem_free(I, offsetof(struct apei_interp, actinst[nact]));
    174  1.1  riastrad }
    175  1.1  riastrad 
    176  1.1  riastrad /*
    177  1.1  riastrad  * apei_interp_pass1_load(I, i, E)
    178  1.1  riastrad  *
    179  1.1  riastrad  *	Load the ith table entry E into the interpreter I.  To be
    180  1.1  riastrad  *	called for each entry in the table sequentially.
    181  1.1  riastrad  *
    182  1.1  riastrad  *	This first pass counts the number of instructions for each
    183  1.1  riastrad  *	action, so we can allocate an array of instructions for
    184  1.1  riastrad  *	indexing each action.
    185  1.1  riastrad  */
    186  1.1  riastrad void
    187  1.1  riastrad apei_interp_pass1_load(struct apei_interp *I, uint32_t i,
    188  1.1  riastrad     ACPI_WHEA_HEADER *E)
    189  1.1  riastrad {
    190  1.1  riastrad 
    191  1.1  riastrad 	/*
    192  1.1  riastrad 	 * If we don't recognize this action, ignore it and move on.
    193  1.1  riastrad 	 */
    194  1.1  riastrad 	if (E->Action >= I->nact || I->actname[E->Action] == NULL) {
    195  1.1  riastrad 		aprint_error("%s[%"PRIu32"]: unknown action: 0x%"PRIx8"\n",
    196  1.1  riastrad 		    I->name, i, E->Action);
    197  1.1  riastrad 		return;
    198  1.1  riastrad 	}
    199  1.1  riastrad 	struct apei_actinst *const A = &I->actinst[E->Action];
    200  1.1  riastrad 
    201  1.1  riastrad 	/*
    202  1.1  riastrad 	 * If we can't interpret this instruction for this action, or
    203  1.1  riastrad 	 * if we couldn't interpret a previous instruction for this
    204  1.1  riastrad 	 * action, ignore _all_ instructions for this action -- by
    205  1.1  riastrad 	 * marking the action as having UINT32_MAX instructions -- and
    206  1.1  riastrad 	 * move on.
    207  1.1  riastrad 	 */
    208  1.1  riastrad 	if (E->Instruction >= I->ninst ||
    209  1.1  riastrad 	    I->instname[E->Instruction] == NULL) {
    210  1.1  riastrad 		aprint_error("%s[%"PRIu32"]: unknown instruction: 0x%02"PRIx8
    211  1.1  riastrad 		    "\n", I->name, i, E->Instruction);
    212  1.1  riastrad 		A->ninst = UINT32_MAX;
    213  1.1  riastrad 		return;
    214  1.1  riastrad 	}
    215  1.1  riastrad 	if (A->ninst == UINT32_MAX)
    216  1.1  riastrad 		return;
    217  1.1  riastrad 
    218  1.1  riastrad 	/*
    219  1.1  riastrad 	 * Count another instruction.  We will make a pointer
    220  1.1  riastrad 	 * to it in a later pass.
    221  1.1  riastrad 	 */
    222  1.1  riastrad 	A->ninst++;
    223  1.1  riastrad 
    224  1.1  riastrad 	/*
    225  1.1  riastrad 	 * If it overflows a reasonable size, bail on this instruction.
    226  1.1  riastrad 	 */
    227  1.1  riastrad 	if (A->ninst >= 256) {
    228  1.1  riastrad 		aprint_error("%s[%"PRIu32"]:"
    229  1.1  riastrad 		    " too many instructions for action %"PRIu32" (%s)\n",
    230  1.1  riastrad 		    I->name, i,
    231  1.1  riastrad 		    E->Action, I->actname[E->Action]);
    232  1.1  riastrad 		A->ninst = UINT32_MAX;
    233  1.1  riastrad 		return;
    234  1.1  riastrad 	}
    235  1.1  riastrad }
    236  1.1  riastrad 
    237  1.1  riastrad /*
    238  1.1  riastrad  * apei_interp_pass2_verify(I, i, E)
    239  1.1  riastrad  *
    240  1.1  riastrad  *	Verify the ith entry's instruction, using the caller's
    241  1.1  riastrad  *	instvalid function, now that all the instructions have been
    242  1.1  riastrad  *	counted.  To be called for each entry in the table
    243  1.1  riastrad  *	sequentially.
    244  1.1  riastrad  *
    245  1.1  riastrad  *	This second pass checks that GOTO instructions in particular
    246  1.1  riastrad  *	don't jump out of bounds.
    247  1.1  riastrad  */
    248  1.1  riastrad void
    249  1.1  riastrad apei_interp_pass2_verify(struct apei_interp *I, uint32_t i,
    250  1.1  riastrad     ACPI_WHEA_HEADER *E)
    251  1.1  riastrad {
    252  1.1  riastrad 
    253  1.1  riastrad 	/*
    254  1.1  riastrad 	 * If there's no instruction validation function, skip this
    255  1.1  riastrad 	 * pass.
    256  1.1  riastrad 	 */
    257  1.1  riastrad 	if (I->instvalid == NULL)
    258  1.1  riastrad 		return;
    259  1.1  riastrad 
    260  1.1  riastrad 	/*
    261  1.1  riastrad 	 * If we skipped it in earlier passes, skip it now.
    262  1.1  riastrad 	 */
    263  1.1  riastrad 	if (E->Action > I->nact || I->actname[E->Action] == NULL)
    264  1.1  riastrad 		return;
    265  1.1  riastrad 
    266  1.1  riastrad 	/*
    267  1.1  riastrad 	 * If the instruction is invalid, disable the whole action.
    268  1.1  riastrad 	 */
    269  1.1  riastrad 	struct apei_actinst *const A = &I->actinst[E->Action];
    270  1.1  riastrad 	if (!(*I->instvalid)(E, A->ninst, i))
    271  1.1  riastrad 		A->ninst = UINT32_MAX;
    272  1.1  riastrad }
    273  1.1  riastrad 
    274  1.1  riastrad /*
    275  1.1  riastrad  * apei_interp_pass3_alloc(I)
    276  1.1  riastrad  *
    277  1.1  riastrad  *	Allocate an array of instructions for each action that we
    278  1.1  riastrad  *	didn't decide to bail on, marked with UINT32_MAX.
    279  1.1  riastrad  */
    280  1.1  riastrad void
    281  1.1  riastrad apei_interp_pass3_alloc(struct apei_interp *I)
    282  1.1  riastrad {
    283  1.1  riastrad 	unsigned action;
    284  1.1  riastrad 
    285  1.1  riastrad 	for (action = 0; action < I->nact; action++) {
    286  1.1  riastrad 		struct apei_actinst *const A = &I->actinst[action];
    287  1.1  riastrad 		if (A->ninst == 0 || A->ninst == UINT32_MAX)
    288  1.1  riastrad 			continue;
    289  1.1  riastrad 		A->inst = kmem_zalloc(A->ninst * sizeof(A->inst[0]), KM_SLEEP);
    290  1.1  riastrad 	}
    291  1.1  riastrad }
    292  1.1  riastrad 
    293  1.1  riastrad /*
    294  1.1  riastrad  * apei_interp_pass4_assemble(I, i, E)
    295  1.1  riastrad  *
    296  1.1  riastrad  *	Put the instruction for the ith entry E into the instruction
    297  1.1  riastrad  *	array for its action.  To be called for each entry in the table
    298  1.1  riastrad  *	sequentially.
    299  1.1  riastrad  */
    300  1.1  riastrad void
    301  1.1  riastrad apei_interp_pass4_assemble(struct apei_interp *I, uint32_t i,
    302  1.1  riastrad     ACPI_WHEA_HEADER *E)
    303  1.1  riastrad {
    304  1.1  riastrad 
    305  1.1  riastrad 	/*
    306  1.1  riastrad 	 * If we skipped it in earlier passes, skip it now.
    307  1.1  riastrad 	 */
    308  1.1  riastrad 	if (E->Action >= I->nact || I->actname[E->Action] == NULL)
    309  1.1  riastrad 		return;
    310  1.1  riastrad 
    311  1.1  riastrad 	struct apei_actinst *const A = &I->actinst[E->Action];
    312  1.1  riastrad 	if (A->ninst == UINT32_MAX)
    313  1.1  riastrad 		return;
    314  1.1  riastrad 
    315  1.1  riastrad 	KASSERT(A->ip < A->ninst);
    316  1.1  riastrad 	A->inst[A->ip++] = E;
    317  1.1  riastrad }
    318  1.1  riastrad 
    319  1.1  riastrad /*
    320  1.1  riastrad  * apei_interp_pass5_verify(I)
    321  1.1  riastrad  *
    322  1.1  riastrad  *	Paranoia: Verify we got all the instructions for each action,
    323  1.1  riastrad  *	verify the actions point to their own instructions, and dump
    324  1.1  riastrad  *	the instructions for each action, collated, with aprint_debug.
    325  1.1  riastrad  */
    326  1.1  riastrad void
    327  1.1  riastrad apei_interp_pass5_verify(struct apei_interp *I)
    328  1.1  riastrad {
    329  1.1  riastrad 	unsigned action;
    330  1.1  riastrad 
    331  1.1  riastrad 	for (action = 0; action < I->nact; action++) {
    332  1.1  riastrad 		struct apei_actinst *const A = &I->actinst[action];
    333  1.1  riastrad 		unsigned j;
    334  1.1  riastrad 
    335  1.1  riastrad 		/*
    336  1.1  riastrad 		 * If the action is disabled, it's all set.
    337  1.1  riastrad 		 */
    338  1.1  riastrad 		if (A->ninst == UINT32_MAX)
    339  1.1  riastrad 			continue;
    340  1.1  riastrad 		KASSERTMSG(A->ip == A->ninst,
    341  1.1  riastrad 		    "action %s ip=%"PRIu32" ninstruction=%"PRIu32,
    342  1.1  riastrad 		    I->actname[action], A->ip, A->ninst);
    343  1.1  riastrad 
    344  1.1  riastrad 		/*
    345  1.1  riastrad 		 * XXX Dump the complete instruction table.
    346  1.1  riastrad 		 */
    347  1.1  riastrad 		for (j = 0; j < A->ninst; j++) {
    348  1.1  riastrad 			ACPI_WHEA_HEADER *const E = A->inst[j];
    349  1.1  riastrad 
    350  1.1  riastrad 			KASSERT(E->Action == action);
    351  1.1  riastrad 			aprint_debug("%s: %s[%"PRIu32"]: %s\n",
    352  1.1  riastrad 			    I->name, I->actname[action], j,
    353  1.1  riastrad 			    I->instname[E->Instruction]);
    354  1.1  riastrad 		}
    355  1.1  riastrad 	}
    356  1.1  riastrad }
    357  1.1  riastrad 
    358  1.1  riastrad /*
    359  1.1  riastrad  * apei_interpret(I, action, cookie)
    360  1.1  riastrad  *
    361  1.1  riastrad  *	Run the instructions associated with the given action by
    362  1.1  riastrad  *	calling the interpreter's instfunc for each one.
    363  1.1  riastrad  *
    364  1.1  riastrad  *	Halt when the instruction pointer runs past the end of the
    365  1.1  riastrad  *	array, or after 1000 cycles, whichever comes first.
    366  1.1  riastrad  */
    367  1.1  riastrad void
    368  1.1  riastrad apei_interpret(struct apei_interp *I, unsigned action, void *cookie)
    369  1.1  riastrad {
    370  1.1  riastrad 	unsigned juice = 1000;
    371  1.1  riastrad 	uint32_t ip = 0;
    372  1.1  riastrad 
    373  1.1  riastrad 	if (action > I->nact || I->actname[action] == NULL)
    374  1.1  riastrad 		return;
    375  1.1  riastrad 	struct apei_actinst *const A = &I->actinst[action];
    376  1.1  riastrad 
    377  1.1  riastrad 	while (ip < A->ninst && juice --> 0) {
    378  1.1  riastrad 		ACPI_WHEA_HEADER *const E = A->inst[ip++];
    379  1.1  riastrad 
    380  1.1  riastrad 		(*I->instfunc)(E, cookie, &ip, A->ninst);
    381  1.1  riastrad 	}
    382  1.1  riastrad }
    383