xref: /netbsd-src/sys/dev/acpi/apei_einj.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
1 /*	$NetBSD: apei_einj.c,v 1.7 2024/03/28 13:40:08 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 EINJ -- Error Injection Table
31  *
32  * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#error-injection
33  *
34  * XXX Consider a /dev node with ioctls for error injection rather than
35  * the somewhat kooky sysctl interface.  By representing an error
36  * injection request in a structure, we can serialize access to the
37  * platform's EINJ operational context.  However, this also requires
38  * some nontrivial userland support; maybe relying on the user to tread
39  * carefully with error injection is fine -- after all, many types of
40  * error injection will cause a system halt/panic.
41  *
42  * XXX Properly expose SET_ERROR_TYPE_WITH_ADDRESS, which has a more
43  * complicated relationship with its RegisterRegion field.
44  */
45 
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: apei_einj.c,v 1.7 2024/03/28 13:40:08 riastradh Exp $");
48 
49 #include <sys/types.h>
50 
51 #include <sys/device.h>
52 #include <sys/sysctl.h>
53 #include <sys/systm.h>
54 
55 #include <dev/acpi/acpivar.h>
56 #include <dev/acpi/apei_einjvar.h>
57 #include <dev/acpi/apei_interp.h>
58 #include <dev/acpi/apei_mapreg.h>
59 #include <dev/acpi/apei_reg.h>
60 #include <dev/acpi/apeivar.h>
61 
62 #include "ioconf.h"
63 
64 #define	_COMPONENT	ACPI_RESOURCE_COMPONENT
65 ACPI_MODULE_NAME	("apei")
66 
67 static void apei_einj_instfunc(ACPI_WHEA_HEADER *, struct apei_mapreg *,
68     void *, uint32_t *, uint32_t);
69 static uint64_t apei_einj_act(struct apei_softc *, enum AcpiEinjActions,
70     uint64_t);
71 static uint64_t apei_einj_trigger(struct apei_softc *, uint64_t);
72 static int apei_einj_action_sysctl(SYSCTLFN_ARGS);
73 static int apei_einj_trigger_sysctl(SYSCTLFN_ARGS);
74 static int apei_einj_types_sysctl(SYSCTLFN_ARGS);
75 
76 /*
77  * apei_einj_action
78  *
79  *	Symbolic names of the APEI EINJ (Error Injection) logical actions
80  *	are taken (and downcased) from:
81  *
82  *	https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#error-injection-actions
83  */
84 static const char *const apei_einj_action[] = {
85 	[ACPI_EINJ_BEGIN_OPERATION] = "begin_injection_operation",
86 	[ACPI_EINJ_GET_TRIGGER_TABLE] = "get_trigger_error_action_table",
87 	[ACPI_EINJ_SET_ERROR_TYPE] = "set_error_type",
88 	[ACPI_EINJ_GET_ERROR_TYPE] = "get_error_type",
89 	[ACPI_EINJ_END_OPERATION] = "end_operation",
90 	[ACPI_EINJ_EXECUTE_OPERATION] = "execute_operation",
91 	[ACPI_EINJ_CHECK_BUSY_STATUS] = "check_busy_status",
92 	[ACPI_EINJ_GET_COMMAND_STATUS] = "get_command_status",
93 	[ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS] = "set_error_type_with_address",
94 	[ACPI_EINJ_GET_EXECUTE_TIMINGS] = "get_execute_operation_timings",
95 };
96 
97 /*
98  * apei_einj_instruction
99  *
100  *	Symbolic names of the APEI EINJ (Error Injection) instructions to
101  *	implement logical actions are taken (and downcased) from:
102  *
103  *	https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#injection-instructions-table
104  */
105 
106 static const char *const apei_einj_instruction[] = {
107 	[ACPI_EINJ_READ_REGISTER] = "read_register",
108 	[ACPI_EINJ_READ_REGISTER_VALUE] = "read_register",
109 	[ACPI_EINJ_WRITE_REGISTER] = "write_register",
110 	[ACPI_EINJ_WRITE_REGISTER_VALUE] = "write_register_value",
111 	[ACPI_EINJ_NOOP] = "noop",
112 };
113 
114 /*
115  * apei_einj_instreg
116  *
117  *	Table of which instructions use a register operand.
118  *
119  *	Must match apei_einj_instfunc.
120  */
121 static const bool apei_einj_instreg[] = {
122 	[ACPI_EINJ_READ_REGISTER] = true,
123 	[ACPI_EINJ_READ_REGISTER_VALUE] = true,
124 	[ACPI_EINJ_WRITE_REGISTER] = true,
125 	[ACPI_EINJ_WRITE_REGISTER_VALUE] = true,
126 	[ACPI_EINJ_NOOP] = false,
127 };
128 
129 /*
130  * apei_einj_attach(sc)
131  *
132  *	Scan the Error Injection table to ascertain what error
133  *	injection actions the firmware supports and how to perform
134  *	them.  Create sysctl nodes for triggering error injection.
135  */
136 void
137 apei_einj_attach(struct apei_softc *sc)
138 {
139 	ACPI_TABLE_EINJ *einj = sc->sc_tab.einj;
140 	struct apei_einj_softc *jsc = &sc->sc_einj;
141 	ACPI_EINJ_ENTRY *entry;
142 	const struct sysctlnode *sysctl_einj;
143 	const struct sysctlnode *sysctl_einj_action;
144 	uint32_t i, nentries, maxnentries;
145 	unsigned action;
146 	int error;
147 
148 	/*
149 	 * Verify the table length, table header length, and
150 	 * instruction entry count are all sensible.  If the header is
151 	 * truncated, stop here; if the entries are truncated, stop at
152 	 * the largest integral number of full entries that fits.
153 	 */
154 	if (einj->Header.Length < sizeof(*einj)) {
155 		aprint_error_dev(sc->sc_dev, "EINJ: truncated table:"
156 		    " %"PRIu32" < %zu minimum bytes\n",
157 		    einj->Header.Length, sizeof(*einj));
158 		return;
159 	}
160 	if (einj->HeaderLength <
161 	    sizeof(*einj) - offsetof(ACPI_TABLE_EINJ, HeaderLength)) {
162 		aprint_error_dev(sc->sc_dev, "EINJ: truncated header:"
163 		    " %"PRIu32" < %zu bytes\n",
164 		    einj->HeaderLength,
165 		    sizeof(*einj) - offsetof(ACPI_TABLE_EINJ, HeaderLength));
166 		return;
167 	}
168 	nentries = einj->Entries;
169 	maxnentries = (einj->Header.Length - sizeof(*einj))/sizeof(*entry);
170 	if (nentries > maxnentries) {
171 		aprint_error_dev(sc->sc_dev, "EINJ: excessive entries:"
172 		    " %"PRIu32", truncating to %"PRIu32"\n",
173 		    nentries, maxnentries);
174 		nentries = maxnentries;
175 	}
176 	if (nentries*sizeof(*entry) < einj->Header.Length - sizeof(*einj)) {
177 		aprint_error_dev(sc->sc_dev, "EINJ:"
178 		    " %zu bytes of trailing garbage after last entry\n",
179 		    einj->Header.Length - nentries*sizeof(*entry));
180 	}
181 
182 	/*
183 	 * Create sysctl hw.acpi.apei.einj for all EINJ-related knobs.
184 	 */
185 	error = sysctl_createv(&sc->sc_sysctllog, 0,
186 	    &sc->sc_sysctlroot, &sysctl_einj, 0,
187 	    CTLTYPE_NODE, "einj",
188 	    SYSCTL_DESCR("Error injection"),
189 	    NULL, 0, NULL, 0,
190 	    CTL_CREATE, CTL_EOL);
191 	if (error) {
192 		aprint_error_dev(sc->sc_dev, "failed to create"
193 		    " hw.acpi.apei.einj: %d\n", error);
194 		sysctl_einj = NULL;
195 	}
196 
197 	/*
198 	 * Create an interpreter for EINJ actions.
199 	 */
200 	jsc->jsc_interp = apei_interp_create("EINJ",
201 	    apei_einj_action, __arraycount(apei_einj_action),
202 	    apei_einj_instruction, __arraycount(apei_einj_instruction),
203 	    apei_einj_instreg, /*instvalid*/NULL, apei_einj_instfunc);
204 
205 	/*
206 	 * Compile the interpreter from the EINJ action instruction
207 	 * table.
208 	 */
209 	entry = (ACPI_EINJ_ENTRY *)(einj + 1);
210 	for (i = 0; i < nentries; i++, entry++)
211 		apei_interp_pass1_load(jsc->jsc_interp, i, &entry->WheaHeader);
212 	entry = (ACPI_EINJ_ENTRY *)(einj + 1);
213 	for (i = 0; i < nentries; i++, entry++) {
214 		apei_interp_pass2_verify(jsc->jsc_interp, i,
215 		    &entry->WheaHeader);
216 	}
217 	apei_interp_pass3_alloc(jsc->jsc_interp);
218 	entry = (ACPI_EINJ_ENTRY *)(einj + 1);
219 	for (i = 0; i < nentries; i++, entry++) {
220 		apei_interp_pass4_assemble(jsc->jsc_interp, i,
221 		    &entry->WheaHeader);
222 	}
223 	apei_interp_pass5_verify(jsc->jsc_interp);
224 
225 	/*
226 	 * Create sysctl hw.acpi.apei.einj.action for individual actions.
227 	 */
228 	error = sysctl_einj == NULL ? ENOENT :
229 	    sysctl_createv(&sc->sc_sysctllog, 0,
230 		&sysctl_einj, &sysctl_einj_action, 0,
231 		CTLTYPE_NODE, "action",
232 		SYSCTL_DESCR("EINJ actions"),
233 		NULL, 0, NULL, 0,
234 		CTL_CREATE, CTL_EOL);
235 	if (error) {
236 		aprint_error_dev(sc->sc_dev, "failed to create"
237 		    " hw.acpi.apei.einj.action: %d\n", error);
238 		sysctl_einj_action = NULL;
239 	}
240 
241 	/*
242 	 * Create sysctl nodes for each action we know about.
243 	 */
244 	for (action = 0; action < __arraycount(apei_einj_action); action++) {
245 		if (apei_einj_action[action] == NULL)
246 			continue;
247 
248 		/*
249 		 * Check to see if there are any instructions for this
250 		 * action.
251 		 *
252 		 * XXX Maybe add this to the apei_interp.h abstraction.
253 		 */
254 		entry = (ACPI_EINJ_ENTRY *)(einj + 1);
255 		for (i = 0; i < nentries; i++, entry++) {
256 			ACPI_WHEA_HEADER *const header = &entry->WheaHeader;
257 
258 			if (action == header->Action)
259 				break;
260 		}
261 		if (i == nentries) {
262 			/*
263 			 * No instructions for this action, so assume
264 			 * it's not supported.
265 			 */
266 			continue;
267 		}
268 
269 		/*
270 		 * Create a sysctl knob to perform the action.
271 		 */
272 		error = sysctl_einj_action == NULL ? ENOENT :
273 		    sysctl_createv(&sc->sc_sysctllog, 0,
274 			&sysctl_einj_action, NULL, CTLFLAG_READWRITE,
275 			CTLTYPE_QUAD, apei_einj_action[action],
276 			NULL,	/* description */
277 			&apei_einj_action_sysctl, 0, NULL, 0,
278 			action, CTL_EOL);
279 		if (error) {
280 			aprint_error_dev(sc->sc_dev, "failed to create"
281 			    " sysctl hw.acpi.apei.einj.action.%s: %d\n",
282 			    apei_einj_action[action], error);
283 			continue;
284 		}
285 	}
286 
287 	/*
288 	 * Create a sysctl knob to trigger error.
289 	 */
290 	error = sysctl_einj == NULL ? ENOENT :
291 	    sysctl_createv(&sc->sc_sysctllog, 0,
292 		&sysctl_einj, NULL, CTLFLAG_READWRITE,
293 		CTLTYPE_QUAD, "trigger",
294 		NULL,	/* description */
295 		&apei_einj_trigger_sysctl, 0, NULL, 0,
296 		CTL_CREATE, CTL_EOL);
297 	if (error) {
298 		aprint_error_dev(sc->sc_dev, "failed to create"
299 		    " sysctl hw.acpi.apei.einj.trigger: %d\n",
300 		    error);
301 	}
302 
303 	/*
304 	 * Query the available types of error to inject and print it to
305 	 * dmesg.
306 	 *
307 	 * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#error-types
308 	 */
309 	uint64_t types = apei_einj_act(sc, ACPI_EINJ_GET_ERROR_TYPE, 0);
310 	char typesbuf[1024], *typesp;
311 	/* XXX define this format somewhere */
312 	snprintb_m(typesbuf, sizeof(typesbuf), "\177\020"
313 	    "b\000"	"PROC_CORRECTABLE\0"
314 	    "b\001"	"PROC_UNCORRECTABLE\0"
315 	    "b\002"	"PROC_FATAL\0"
316 	    "b\003"	"MEM_CORRECTABLE\0"
317 	    "b\004"	"MEM_UNCORRECTABLE\0"
318 	    "b\005"	"MEM_FATAL\0"
319 	    "b\006"	"PCIE_CORRECTABLE\0"
320 	    "b\007"	"PCIE_UNCORRECTABLE\0"
321 	    "b\010"	"PCIE_FATAL\0"
322 	    "b\011"	"PLAT_CORRECTABLE\0"
323 	    "b\012"	"PLAT_UNCORRECTABLE\0"
324 	    "b\013"	"PLAT_FATAL\0"
325 	    "b\014"	"CXLCACHE_CORRECTABLE\0"
326 	    "b\015"	"CXLCACHE_UNCORRECTABLE\0"
327 	    "b\016"	"CXLCACHE_FATAL\0"
328 	    "b\017"	"CXLMEM_CORRECTABLE\0"
329 	    "b\020"	"CXLMEM_UNCORRECTABLE\0"
330 	    "b\021"	"CXLMEM_FATAL\0"
331 //	    "f\022\014"	"reserved\0"
332 	    "b\036"	"EINJv2\0"
333 	    "b\037"	"VENDOR\0"
334 	    "\0", types, 36);
335 	for (typesp = typesbuf; strlen(typesp); typesp += strlen(typesp) + 1) {
336 		aprint_normal_dev(sc->sc_dev, "EINJ: can inject:"
337 		    " %s\n", typesp);
338 	}
339 
340 	/*
341 	 * Create a sysctl knob to query the available types of error
342 	 * to inject.  In principle this could change dynamically, so
343 	 * we'll make it dynamic.
344 	 */
345 	error = sysctl_einj == NULL ? ENOENT :
346 	    sysctl_createv(&sc->sc_sysctllog, 0,
347 		&sysctl_einj, NULL, 0,
348 		CTLTYPE_QUAD, "types",
349 		SYSCTL_DESCR("Types of errors that can be injected"),
350 		&apei_einj_types_sysctl, 0, NULL, 0,
351 		CTL_CREATE, CTL_EOL);
352 	if (error) {
353 		aprint_error_dev(sc->sc_dev, "failed to create"
354 		    " sysctl hw.acpi.apei.einj.types: %d\n",
355 		    error);
356 	}
357 }
358 
359 /*
360  * apei_einj_detach(sc)
361  *
362  *	Free any software resources associated with the Error Injection
363  *	table.
364  */
365 void
366 apei_einj_detach(struct apei_softc *sc)
367 {
368 	struct apei_einj_softc *jsc = &sc->sc_einj;
369 
370 	if (jsc->jsc_interp) {
371 		apei_interp_destroy(jsc->jsc_interp);
372 		jsc->jsc_interp = NULL;
373 	}
374 }
375 
376 /*
377  * struct apei_einj_machine
378  *
379  *	Machine state for executing EINJ instructions.
380  */
381 struct apei_einj_machine {
382 	struct apei_softc	*sc;
383 	uint64_t		x;	/* in */
384 	uint64_t		y;	/* out */
385 };
386 
387 /*
388  * apei_einj_instfunc(header, cookie, &ip, maxip)
389  *
390  *	Run a single instruction in the service of performing an EINJ
391  *	action.  Updates the EINJ machine at cookie in place.
392  *
393  *	This doesn't read or write ip.  The TRIGGER_ERROR logic relies
394  *	on this; if you change the fact, you must update that logic
395  *	too.
396  */
397 static void
398 apei_einj_instfunc(ACPI_WHEA_HEADER *header, struct apei_mapreg *map,
399     void *cookie, uint32_t *ipp, uint32_t maxip)
400 {
401 	struct apei_einj_machine *M = cookie;
402 
403 	/*
404 	 * Abbreviate some of the intermediate quantities to make the
405 	 * instruction logic conciser and more legible.
406 	 */
407 	const uint8_t BitOffset = header->RegisterRegion.BitOffset;
408 	const uint64_t Mask = header->Mask;
409 	const uint64_t Value = header->Value;
410 	ACPI_GENERIC_ADDRESS *const reg = &header->RegisterRegion;
411 	const bool preserve_register = header->Flags & ACPI_EINJ_PRESERVE;
412 
413 	aprint_debug_dev(M->sc->sc_dev, "%s: instr=0x%02"PRIx8
414 	    " (%s)"
415 	    " Address=0x%"PRIx64
416 	    " BitOffset=%"PRIu8" Mask=0x%"PRIx64" Value=0x%"PRIx64
417 	    " Flags=0x%"PRIx8"\n",
418 	    __func__, header->Instruction,
419 	    (header->Instruction < __arraycount(apei_einj_instruction)
420 		? apei_einj_instruction[header->Instruction]
421 		: "unknown"),
422 	    reg->Address,
423 	    BitOffset, Mask, Value,
424 	    header->Flags);
425 
426 	/*
427 	 * Zero-initialize the output by default.
428 	 */
429 	M->y = 0;
430 
431 	/*
432 	 * Dispatch the instruction.
433 	 */
434 	switch (header->Instruction) {
435 	case ACPI_EINJ_READ_REGISTER:
436 		M->y = apei_read_register(reg, map, Mask);
437 		break;
438 	case ACPI_EINJ_READ_REGISTER_VALUE: {
439 		uint64_t v;
440 
441 		v = apei_read_register(reg, map, Mask);
442 		M->y = (v == Value ? 1 : 0);
443 		break;
444 	}
445 	case ACPI_EINJ_WRITE_REGISTER:
446 		apei_write_register(reg, map, Mask, preserve_register, M->x);
447 		break;
448 	case ACPI_EINJ_WRITE_REGISTER_VALUE:
449 		apei_write_register(reg, map, Mask, preserve_register, Value);
450 		break;
451 	case ACPI_EINJ_NOOP:
452 		break;
453 	default:		/* XXX unreachable */
454 		break;
455 	}
456 }
457 
458 /*
459  * apei_einj_act(sc, action, x)
460  *
461  *	Perform the named EINJ action with input x, by executing the
462  *	instruction defined for the action by the EINJ, and return the
463  *	output.
464  */
465 static uint64_t
466 apei_einj_act(struct apei_softc *sc, enum AcpiEinjActions action,
467     uint64_t x)
468 {
469 	struct apei_einj_softc *const jsc = &sc->sc_einj;
470 	struct apei_einj_machine einj_machine, *const M = &einj_machine;
471 
472 	aprint_debug_dev(sc->sc_dev, "%s: action=%d (%s) input=0x%"PRIx64"\n",
473 	    __func__,
474 	    action,
475 	    (action < __arraycount(apei_einj_action)
476 		? apei_einj_action[action]
477 		: "unknown"),
478 	    x);
479 
480 	/*
481 	 * Initialize the machine to execute the action's instructions.
482 	 */
483 	memset(M, 0, sizeof(*M));
484 	M->sc = sc;
485 	M->x = x;		/* input */
486 	M->y = 0;		/* output */
487 
488 	/*
489 	 * Run the interpreter.
490 	 */
491 	apei_interpret(jsc->jsc_interp, action, M);
492 
493 	/*
494 	 * Return the result.
495 	 */
496 	aprint_debug_dev(sc->sc_dev, "%s: output=0x%"PRIx64"\n", __func__,
497 	    M->y);
498 	return M->y;
499 }
500 
501 /*
502  * apei_einj_trigger(sc, x)
503  *
504  *	Obtain the TRIGGER_ERROR action table and, if there is anything
505  *	to be done with it, execute it with input x and return the
506  *	output.  If nothing is to be done, return 0.
507  */
508 static uint64_t
509 apei_einj_trigger(struct apei_softc *sc, uint64_t x)
510 {
511 	uint64_t teatab_pa;
512 	ACPI_EINJ_TRIGGER *teatab = NULL;
513 	size_t mapsize = 0, tabsize, bodysize;
514 	ACPI_EINJ_ENTRY *entry;
515 	struct apei_einj_machine einj_machine, *const M = &einj_machine;
516 	uint32_t i, nentries;
517 
518 	/*
519 	 * Initialize the machine to execute the TRIGGER_ERROR action's
520 	 * instructions.  Do this early to keep the error branches
521 	 * simpler.
522 	 */
523 	memset(M, 0, sizeof(*M));
524 	M->sc = sc;
525 	M->x = x;		/* input */
526 	M->y = 0;		/* output */
527 
528 	/*
529 	 * Get the TRIGGER_ERROR action table's physical address.
530 	 */
531 	teatab_pa = apei_einj_act(sc, ACPI_EINJ_GET_TRIGGER_TABLE, 0);
532 
533 	/*
534 	 * Map just the header.  We don't know how large the table is
535 	 * because we get that from the header.
536 	 */
537 	mapsize = sizeof(*teatab);
538 	teatab = AcpiOsMapMemory(teatab_pa, mapsize);
539 
540 	/*
541 	 * If there's no entries, stop here -- nothing to do separately
542 	 * to trigger an error report.
543 	 */
544 	nentries = teatab->EntryCount;
545 	if (nentries == 0)
546 		goto out;
547 
548 	/*
549 	 * If the header size or the table size is nonsense, bail.
550 	 */
551 	if (teatab->HeaderSize < sizeof(*teatab) ||
552 	    teatab->TableSize < teatab->HeaderSize) {
553 		device_printf(sc->sc_dev, "TRIGGER_ERROR action table:"
554 		    " invalid sizes:"
555 		    " HeaderSize=%"PRIu32" TableSize=%"PRIu32"\n",
556 		    teatab->HeaderSize, teatab->TableSize);
557 	}
558 
559 	/*
560 	 * If the revision is nonzero, we don't know what to do.  I've
561 	 * only seen revision zero so far, and the spec doesn't say
562 	 * anything about revisions that I've found.
563 	 */
564 	if (teatab->Revision != 0) {
565 		device_printf(sc->sc_dev, "TRIGGER_ERROR action table:"
566 		    " unknown revision: %"PRIx32"\n", teatab->Revision);
567 		goto out;
568 	}
569 
570 	/*
571 	 * Truncate the table to the number of entries requested and
572 	 * ignore trailing garbage if the table is long, or round the
573 	 * number of entries down to what fits in the table if the
574 	 * table is short.
575 	 */
576 	tabsize = teatab->TableSize;
577 	bodysize = tabsize - teatab->HeaderSize;
578 	if (nentries < howmany(bodysize, sizeof(ACPI_EINJ_ENTRY))) {
579 		device_printf(sc->sc_dev, "TRIGGER_ERROR action table:"
580 		    " %zu bytes of trailing garbage\n",
581 		    tabsize - nentries*sizeof(ACPI_EINJ_ENTRY));
582 		bodysize = nentries*sizeof(ACPI_EINJ_ENTRY);
583 		tabsize = teatab->HeaderSize + bodysize;
584 	} else if (nentries > howmany(bodysize, sizeof(ACPI_EINJ_ENTRY))) {
585 		device_printf(sc->sc_dev, "TRIGGER_ERROR action table:"
586 		    " truncated to %zu entries\n",
587 		    nentries*sizeof(ACPI_EINJ_ENTRY));
588 		nentries = howmany(bodysize, sizeof(ACPI_EINJ_ENTRY));
589 		bodysize = nentries*sizeof(ACPI_EINJ_ENTRY);
590 		tabsize = teatab->HeaderSize + bodysize;
591 	}
592 
593 	/*
594 	 * Unmap the header and map the whole table instead.
595 	 */
596 	AcpiOsUnmapMemory(teatab, mapsize);
597 	mapsize = tabsize;
598 	teatab = AcpiOsMapMemory(teatab_pa, mapsize);
599 
600 	/*
601 	 * Now iterate over the EINJ-type entries and execute the
602 	 * trigger error action instructions -- but skip if they're not
603 	 * for the TRIGGER_ERROR action, and stop if they're truncated.
604 	 *
605 	 * Entries are fixed-size, so we can just index them.
606 	 */
607 	entry = (ACPI_EINJ_ENTRY *)((char *)teatab + teatab->HeaderSize);
608 	for (i = 0; i < nentries; i++) {
609 		ACPI_WHEA_HEADER *const header = &entry[i].WheaHeader;
610 
611 		/*
612 		 * Verify the action is TRIGGER_ERROR.  If not, skip.
613 		 */
614 		if (header->Action != ACPI_EINJ_TRIGGER_ERROR) {
615 			device_printf(sc->sc_dev, "TRIGGER_ERROR action table:"
616 			    " other action: %"PRIu32" (%s)\n",
617 			    header->Action,
618 			    (header->Action < __arraycount(apei_einj_action)
619 				? apei_einj_action[header->Action]
620 				: "unknown"));
621 			continue;
622 		}
623 
624 		/*
625 		 * Verify the instruction.
626 		 */
627 		if (header->Instruction >= __arraycount(apei_einj_instreg)) {
628 			device_printf(sc->sc_dev, "TRIGGER_ERROR action table:"
629 			    " unknown instruction: %"PRIu32"\n",
630 			    header->Instruction);
631 			continue;
632 		}
633 
634 		/*
635 		 * Map the register if needed.
636 		 */
637 		struct apei_mapreg *map = NULL;
638 		if (apei_einj_instreg[header->Instruction]) {
639 			map = apei_mapreg_map(&header->RegisterRegion);
640 			if (map == NULL) {
641 				device_printf(sc->sc_dev, "TRIGGER_ERROR"
642 				    " action table: failed to map register\n");
643 				continue;
644 			}
645 		}
646 
647 		/*
648 		 * Execute the instruction.  Since there's only one
649 		 * action, we don't bother with the apei_interp
650 		 * machinery to collate instruction tables for each
651 		 * action.  EINJ instructions don't change ip.
652 		 */
653 		uint32_t ip = i + 1;
654 		apei_einj_instfunc(header, map, M, &ip, nentries);
655 		KASSERT(ip == i + 1);
656 
657 		/*
658 		 * Unmap the register if mapped.
659 		 */
660 		if (map != NULL)
661 			apei_mapreg_unmap(&header->RegisterRegion, map);
662 	}
663 
664 out:	if (teatab) {
665 		AcpiOsUnmapMemory(teatab, mapsize);
666 		teatab = NULL;
667 		mapsize = 0;
668 	}
669 	return M->y;
670 }
671 
672 /*
673  * apei_einj_action_sysctl:
674  *
675  *	Handle sysctl queries under hw.acpi.apei.einj.action.*.
676  */
677 static int
678 apei_einj_action_sysctl(SYSCTLFN_ARGS)
679 {
680 	device_t apei0 = NULL;
681 	struct apei_softc *sc;
682 	enum AcpiEinjActions action;
683 	struct sysctlnode node = *rnode;
684 	uint64_t v;
685 	int error;
686 
687 	/*
688 	 * As a defence against mistakes, require the user to specify a
689 	 * write.
690 	 */
691 	if (newp == NULL) {
692 		error = ENOENT;
693 		goto out;
694 	}
695 
696 	/*
697 	 * Take a reference to the apei0 device so it doesn't go away
698 	 * while we're working, and get the softc.
699 	 */
700 	if ((apei0 = device_lookup_acquire(&apei_cd, 0)) == NULL) {
701 		error = ENXIO;
702 		goto out;
703 	}
704 	sc = device_private(apei0);
705 
706 	/*
707 	 * Fail if there's no EINJ.
708 	 */
709 	if (sc->sc_tab.einj == NULL) {
710 		error = ENODEV;
711 		goto out;
712 	}
713 
714 	/*
715 	 * Identify the requested action.  If we don't recognize it,
716 	 * fail with EINVAL.
717 	 */
718 	switch (node.sysctl_num) {
719 	case ACPI_EINJ_BEGIN_OPERATION:
720 	case ACPI_EINJ_GET_TRIGGER_TABLE:
721 	case ACPI_EINJ_SET_ERROR_TYPE:
722 	case ACPI_EINJ_GET_ERROR_TYPE:
723 	case ACPI_EINJ_END_OPERATION:
724 	case ACPI_EINJ_EXECUTE_OPERATION:
725 	case ACPI_EINJ_CHECK_BUSY_STATUS:
726 	case ACPI_EINJ_GET_COMMAND_STATUS:
727 	case ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS:
728 	case ACPI_EINJ_GET_EXECUTE_TIMINGS:
729 		action = node.sysctl_num;
730 		break;
731 	default:
732 		error = ENOENT;
733 		goto out;
734 	}
735 
736 	/*
737 	 * Kludge: Copy the `new value' for the sysctl in as an input
738 	 * to the injection action.
739 	 */
740 	error = sysctl_copyin(curlwp, newp, &v, sizeof(v));
741 	if (error)
742 		goto out;
743 
744 	/*
745 	 * Perform the EINJ action by following the table's
746 	 * instructions.
747 	 */
748 	v = apei_einj_act(sc, action, v);
749 
750 	/*
751 	 * Return the output of the operation as the `old value' of the
752 	 * sysctl.  This also updates v with what was written to the
753 	 * sysctl was written, but we don't care because we already
754 	 * read that in and acted on it.
755 	 */
756 	node.sysctl_data = &v;
757 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
758 
759 out:	if (apei0) {
760 		device_release(apei0);
761 		apei0 = NULL;
762 	}
763 	return error;
764 }
765 
766 /*
767  * apei_einj_trigger_sysctl
768  *
769  *	Handle sysctl hw.acpi.apei.einj.trigger.
770  */
771 static int
772 apei_einj_trigger_sysctl(SYSCTLFN_ARGS)
773 {
774 	device_t apei0 = NULL;
775 	struct apei_softc *sc;
776 	struct sysctlnode node = *rnode;
777 	uint64_t v;
778 	int error;
779 
780 	/*
781 	 * As a defence against mistakes, require the user to specify a
782 	 * write.
783 	 */
784 	if (newp == NULL) {
785 		error = ENOENT;
786 		goto out;
787 	}
788 
789 	/*
790 	 * Take a reference to the apei0 device so it doesn't go away
791 	 * while we're working, and get the softc.
792 	 */
793 	if ((apei0 = device_lookup_acquire(&apei_cd, 0)) == NULL) {
794 		error = ENXIO;
795 		goto out;
796 	}
797 	sc = device_private(apei0);
798 
799 	/*
800 	 * Fail if there's no EINJ.
801 	 */
802 	if (sc->sc_tab.einj == NULL) {
803 		error = ENODEV;
804 		goto out;
805 	}
806 
807 	/*
808 	 * Kludge: Copy the `new value' for the sysctl in as an input
809 	 * to the trigger action.
810 	 */
811 	error = sysctl_copyin(curlwp, newp, &v, sizeof(v));
812 	if (error)
813 		goto out;
814 
815 	/*
816 	 * Perform the TRIGGER_ERROR action.
817 	 */
818 	v = apei_einj_trigger(sc, v);
819 
820 	/*
821 	 * Return the output of the operation as the `old value' of the
822 	 * sysctl.  This also updates v with what was written to the
823 	 * sysctl was written, but we don't care because we already
824 	 * read that in and acted on it.
825 	 */
826 	node.sysctl_data = &v;
827 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
828 
829 out:	if (apei0) {
830 		device_release(apei0);
831 		apei0 = NULL;
832 	}
833 	return error;
834 }
835 
836 /*
837  * apei_einj_types_sysctl
838  *
839  *	Handle sysctl hw.acpi.apei.einj.types.
840  */
841 static int
842 apei_einj_types_sysctl(SYSCTLFN_ARGS)
843 {
844 	device_t apei0 = NULL;
845 	struct apei_softc *sc;
846 	struct sysctlnode node = *rnode;
847 	uint64_t types;
848 	int error;
849 
850 	/*
851 	 * Take a reference to the apei0 device so it doesn't go away
852 	 * while we're working, and get the softc.
853 	 *
854 	 * XXX Is this necessary?  Shouldn't sysctl_teardown take care
855 	 * of preventing new sysctl calls and waiting until all pending
856 	 * sysctl calls are done?
857 	 */
858 	if ((apei0 = device_lookup_acquire(&apei_cd, 0)) == NULL) {
859 		error = ENXIO;
860 		goto out;
861 	}
862 	sc = device_private(apei0);
863 
864 	/*
865 	 * Fail if there's no EINJ.
866 	 */
867 	if (sc->sc_tab.einj == NULL) {
868 		error = ENODEV;
869 		goto out;
870 	}
871 
872 	/*
873 	 * Perform the GET_ERROR_TYPE action and return the value to
874 	 * sysctl.
875 	 *
876 	 * XXX Should this do it between BEGIN_INJECTION_OPERATION and
877 	 * END_OPERATION?
878 	 */
879 	types = apei_einj_act(sc, ACPI_EINJ_GET_ERROR_TYPE, 0);
880 	node.sysctl_data = &types;
881 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
882 
883 out:	if (apei0) {
884 		device_release(apei0);
885 		apei0 = NULL;
886 	}
887 	return error;
888 }
889