Module Name: src Committed By: riastradh Date: Fri Mar 22 20:48:05 UTC 2024
Modified Files: src/sys/dev/acpi: apei_einj.c apei_erst.c apei_interp.c apei_interp.h apei_reg.c apei_reg.h Log Message: apei(4): Pre-map registers when compiling interpreter. This way we don't have to worry about mapping them in nasty contexts where access to uvm_km_alloc may not be allowed. Paves the way to use ERST for saving dmesg on crash. Exception: ACPI_ERST_MOVE_DATA still needs to do AcpiOsMapMemory. We'll need to reserve a couple pages to avoid that. PR kern/58046 To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/dev/acpi/apei_einj.c \ src/sys/dev/acpi/apei_interp.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/acpi/apei_erst.c \ src/sys/dev/acpi/apei_interp.h src/sys/dev/acpi/apei_reg.c \ src/sys/dev/acpi/apei_reg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/acpi/apei_einj.c diff -u src/sys/dev/acpi/apei_einj.c:1.3 src/sys/dev/acpi/apei_einj.c:1.4 --- src/sys/dev/acpi/apei_einj.c:1.3 Thu Mar 21 02:35:09 2024 +++ src/sys/dev/acpi/apei_einj.c Fri Mar 22 20:48:05 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: apei_einj.c,v 1.3 2024/03/21 02:35:09 riastradh Exp $ */ +/* $NetBSD: apei_einj.c,v 1.4 2024/03/22 20:48:05 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -44,7 +44,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: apei_einj.c,v 1.3 2024/03/21 02:35:09 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: apei_einj.c,v 1.4 2024/03/22 20:48:05 riastradh Exp $"); #include <sys/types.h> @@ -55,6 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: apei_einj.c, #include <dev/acpi/acpivar.h> #include <dev/acpi/apei_einjvar.h> #include <dev/acpi/apei_interp.h> +#include <dev/acpi/apei_mapreg.h> #include <dev/acpi/apei_reg.h> #include <dev/acpi/apeivar.h> @@ -63,8 +64,8 @@ __KERNEL_RCSID(0, "$NetBSD: apei_einj.c, #define _COMPONENT ACPI_RESOURCE_COMPONENT ACPI_MODULE_NAME ("apei") -static void apei_einj_instfunc(ACPI_WHEA_HEADER *, void *, uint32_t *, - uint32_t); +static void apei_einj_instfunc(ACPI_WHEA_HEADER *, struct apei_mapreg *, + void *, uint32_t *, uint32_t); static uint64_t apei_einj_act(struct apei_softc *, enum AcpiEinjActions, uint64_t); static uint64_t apei_einj_trigger(struct apei_softc *, uint64_t); @@ -111,6 +112,21 @@ static const char *const apei_einj_instr }; /* + * apei_einj_instreg + * + * Table of which isntructions use a register operand. + * + * Must match apei_einj_instfunc. + */ +static const bool apei_einj_instreg[] = { + [ACPI_EINJ_READ_REGISTER] = true, + [ACPI_EINJ_READ_REGISTER_VALUE] = true, + [ACPI_EINJ_WRITE_REGISTER] = true, + [ACPI_EINJ_WRITE_REGISTER_VALUE] = true, + [ACPI_EINJ_NOOP] = false, +}; + +/* * apei_einj_attach(sc) * * Scan the Error Injection table to ascertain what error @@ -184,7 +200,7 @@ apei_einj_attach(struct apei_softc *sc) jsc->jsc_interp = apei_interp_create("EINJ", apei_einj_action, __arraycount(apei_einj_action), apei_einj_instruction, __arraycount(apei_einj_instruction), - /*instvalid*/NULL, apei_einj_instfunc); + apei_einj_instreg, /*instvalid*/NULL, apei_einj_instfunc); /* * Compile the interpreter from the EINJ action instruction @@ -379,8 +395,8 @@ struct apei_einj_machine { * too. */ static void -apei_einj_instfunc(ACPI_WHEA_HEADER *header, void *cookie, uint32_t *ipp, - uint32_t maxip) +apei_einj_instfunc(ACPI_WHEA_HEADER *header, struct apei_mapreg *map, + void *cookie, uint32_t *ipp, uint32_t maxip) { struct apei_einj_machine *M = cookie; ACPI_STATUS rv = AE_OK; @@ -418,24 +434,26 @@ apei_einj_instfunc(ACPI_WHEA_HEADER *hea */ switch (header->Instruction) { case ACPI_EINJ_READ_REGISTER: - rv = apei_read_register(reg, Mask, &M->y); + rv = apei_read_register(reg, map, Mask, &M->y); if (ACPI_FAILURE(rv)) break; break; case ACPI_EINJ_READ_REGISTER_VALUE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; M->y = (v == Value ? 1 : 0); break; } case ACPI_EINJ_WRITE_REGISTER: - rv = apei_write_register(reg, Mask, preserve_register, M->x); + rv = apei_write_register(reg, map, Mask, preserve_register, + M->x); break; case ACPI_EINJ_WRITE_REGISTER_VALUE: - rv = apei_write_register(reg, Mask, preserve_register, Value); + rv = apei_write_register(reg, map, Mask, preserve_register, + Value); break; case ACPI_EINJ_NOOP: break; @@ -621,14 +639,43 @@ apei_einj_trigger(struct apei_softc *sc, } /* + * Verify the instruction. + */ + if (header->Instruction >= __arraycount(apei_einj_instreg)) { + device_printf(sc->sc_dev, "TRIGGER_ERROR action table:" + " unknown instruction: %"PRIu32"\n", + header->Instruction); + continue; + } + + /* + * Map the register if needed. + */ + struct apei_mapreg *map = NULL; + if (apei_einj_instreg[header->Instruction]) { + map = apei_mapreg_map(&header->RegisterRegion); + if (map == NULL) { + device_printf(sc->sc_dev, "TRIGGER_ERROR" + " action table: failed to map register\n"); + continue; + } + } + + /* * Execute the instruction. Since there's only one * action, we don't bother with the apei_interp * machinery to collate instruction tables for each * action. EINJ instructions don't change ip. */ uint32_t ip = i + 1; - apei_einj_instfunc(header, M, &ip, nentries); + apei_einj_instfunc(header, map, M, &ip, nentries); KASSERT(ip == i + 1); + + /* + * Unmap the register if mapped. + */ + if (map != NULL) + apei_mapreg_unmap(&header->RegisterRegion, map); } out: if (teatab) { Index: src/sys/dev/acpi/apei_interp.c diff -u src/sys/dev/acpi/apei_interp.c:1.3 src/sys/dev/acpi/apei_interp.c:1.4 --- src/sys/dev/acpi/apei_interp.c:1.3 Fri Mar 22 18:19:03 2024 +++ src/sys/dev/acpi/apei_interp.c Fri Mar 22 20:48:05 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: apei_interp.c,v 1.3 2024/03/22 18:19:03 riastradh Exp $ */ +/* $NetBSD: apei_interp.c,v 1.4 2024/03/22 20:48:05 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -101,13 +101,10 @@ * a convenience for catching mistakes in firmware, not a security * measure, since the OS is absolutely vulnerable to malicious firmware * anyway. - * - * XXX Map instruction registers in advance so ERST is safe in nasty - * contexts, e.g. to save dmesg? */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: apei_interp.c,v 1.3 2024/03/22 18:19:03 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: apei_interp.c,v 1.4 2024/03/22 20:48:05 riastradh Exp $"); #include <sys/types.h> @@ -116,6 +113,7 @@ __KERNEL_RCSID(0, "$NetBSD: apei_interp. #include <dev/acpi/acpivar.h> #include <dev/acpi/apei_interp.h> +#include <dev/acpi/apei_mapreg.h> /* * struct apei_actinst @@ -125,7 +123,11 @@ __KERNEL_RCSID(0, "$NetBSD: apei_interp. struct apei_actinst { uint32_t ninst; uint32_t ip; - struct acpi_whea_header **inst; + struct { + struct acpi_whea_header *header; + struct apei_mapreg *map; + } *inst; + bool disable; }; /* @@ -139,10 +141,12 @@ struct apei_interp { unsigned nact; const char *const *instname; unsigned ninst; + const bool *instreg; bool (*instvalid)(ACPI_WHEA_HEADER *, uint32_t, uint32_t); - void (*instfunc)(ACPI_WHEA_HEADER *, void *, - uint32_t *, uint32_t); + void (*instfunc)(ACPI_WHEA_HEADER *, + struct apei_mapreg *, void *, uint32_t *, + uint32_t); struct apei_actinst actinst[]; }; @@ -150,8 +154,10 @@ struct apei_interp * apei_interp_create(const char *name, const char *const *actname, unsigned nact, const char *const *instname, unsigned ninst, + const bool *instreg, bool (*instvalid)(ACPI_WHEA_HEADER *, uint32_t, uint32_t), - void (*instfunc)(ACPI_WHEA_HEADER *, void *, uint32_t *, uint32_t)) + void (*instfunc)(ACPI_WHEA_HEADER *, struct apei_mapreg *, void *, + uint32_t *, uint32_t)) { struct apei_interp *I; @@ -161,6 +167,7 @@ apei_interp_create(const char *name, I->nact = nact; I->instname = instname; I->ninst = ninst; + I->instreg = instreg; I->instvalid = instvalid; I->instfunc = instfunc; @@ -174,9 +181,19 @@ apei_interp_destroy(struct apei_interp * for (action = 0; action < nact; action++) { struct apei_actinst *const A = &I->actinst[action]; + unsigned j; - if (A->ninst == 0 || A->ninst == UINT32_MAX || A->inst == NULL) + if (A->ninst == 0 || A->inst == NULL) continue; + + for (j = 0; j < A->ninst; j++) { + ACPI_WHEA_HEADER *const E = A->inst[j].header; + struct apei_mapreg *const map = A->inst[j].map; + + if (map != NULL) + apei_mapreg_unmap(&E->RegisterRegion, map); + } + kmem_free(A->inst, A->ninst * sizeof(A->inst[0])); A->inst = NULL; } @@ -212,18 +229,17 @@ apei_interp_pass1_load(struct apei_inter /* * If we can't interpret this instruction for this action, or * if we couldn't interpret a previous instruction for this - * action, ignore _all_ instructions for this action -- by - * marking the action as having UINT32_MAX instructions -- and - * move on. + * action, disable this action and move on. */ if (E->Instruction >= I->ninst || I->instname[E->Instruction] == NULL) { aprint_error("%s[%"PRIu32"]: unknown instruction: 0x%02"PRIx8 "\n", I->name, i, E->Instruction); - A->ninst = UINT32_MAX; + A->ninst = 0; + A->disable = true; return; } - if (A->ninst == UINT32_MAX) + if (A->disable) return; /* @@ -233,14 +249,16 @@ apei_interp_pass1_load(struct apei_inter A->ninst++; /* - * If it overflows a reasonable size, bail on this instruction. + * If it overflows a reasonable size, disable the action + * altogether. */ if (A->ninst >= 256) { aprint_error("%s[%"PRIu32"]:" " too many instructions for action %"PRIu32" (%s)\n", I->name, i, E->Action, I->actname[E->Action]); - A->ninst = UINT32_MAX; + A->ninst = 0; + A->disable = true; return; } } @@ -278,15 +296,17 @@ apei_interp_pass2_verify(struct apei_int * If the instruction is invalid, disable the whole action. */ struct apei_actinst *const A = &I->actinst[E->Action]; - if (!(*I->instvalid)(E, A->ninst, i)) - A->ninst = UINT32_MAX; + if (!(*I->instvalid)(E, A->ninst, i)) { + A->ninst = 0; + A->disable = true; + } } /* * apei_interp_pass3_alloc(I) * * Allocate an array of instructions for each action that we - * didn't decide to bail on, marked with UINT32_MAX. + * didn't disable. */ void apei_interp_pass3_alloc(struct apei_interp *I) @@ -295,7 +315,7 @@ apei_interp_pass3_alloc(struct apei_inte for (action = 0; action < I->nact; action++) { struct apei_actinst *const A = &I->actinst[action]; - if (A->ninst == 0 || A->ninst == UINT32_MAX) + if (A->ninst == 0 || A->disable) continue; A->inst = kmem_zalloc(A->ninst * sizeof(A->inst[0]), KM_SLEEP); } @@ -320,11 +340,14 @@ apei_interp_pass4_assemble(struct apei_i return; struct apei_actinst *const A = &I->actinst[E->Action]; - if (A->ninst == UINT32_MAX) + if (A->disable) return; KASSERT(A->ip < A->ninst); - A->inst[A->ip++] = E; + const uint32_t ip = A->ip++; + A->inst[ip].header = E; + A->inst[ip].map = I->instreg[E->Instruction] ? + apei_mapreg_map(&E->RegisterRegion) : NULL; } /* @@ -346,7 +369,7 @@ apei_interp_pass5_verify(struct apei_int /* * If the action is disabled, it's all set. */ - if (A->ninst == UINT32_MAX) + if (A->disable) continue; KASSERTMSG(A->ip == A->ninst, "action %s ip=%"PRIu32" ninstruction=%"PRIu32, @@ -356,9 +379,20 @@ apei_interp_pass5_verify(struct apei_int * XXX Dump the complete instruction table. */ for (j = 0; j < A->ninst; j++) { - ACPI_WHEA_HEADER *const E = A->inst[j]; + ACPI_WHEA_HEADER *const E = A->inst[j].header; KASSERT(E->Action == action); + + /* + * If we need the register and weren't able to + * map it, disable the action. + */ + if (I->instreg[E->Instruction] && + A->inst[j].map == NULL) { + A->disable = true; + continue; + } + aprint_debug("%s: %s[%"PRIu32"]: %s\n", I->name, I->actname[action], j, I->instname[E->Instruction]); @@ -384,10 +418,14 @@ apei_interpret(struct apei_interp *I, un if (action > I->nact || I->actname[action] == NULL) return; struct apei_actinst *const A = &I->actinst[action]; + if (A->disable) + return; while (ip < A->ninst && juice --> 0) { - ACPI_WHEA_HEADER *const E = A->inst[ip++]; + ACPI_WHEA_HEADER *const E = A->inst[ip].header; + struct apei_mapreg *const map = A->inst[ip].map; - (*I->instfunc)(E, cookie, &ip, A->ninst); + ip++; + (*I->instfunc)(E, map, cookie, &ip, A->ninst); } } Index: src/sys/dev/acpi/apei_erst.c diff -u src/sys/dev/acpi/apei_erst.c:1.1 src/sys/dev/acpi/apei_erst.c:1.2 --- src/sys/dev/acpi/apei_erst.c:1.1 Wed Mar 20 17:11:43 2024 +++ src/sys/dev/acpi/apei_erst.c Fri Mar 22 20:48:05 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: apei_erst.c,v 1.1 2024/03/20 17:11:43 riastradh Exp $ */ +/* $NetBSD: apei_erst.c,v 1.2 2024/03/22 20:48:05 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: apei_erst.c,v 1.1 2024/03/20 17:11:43 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: apei_erst.c,v 1.2 2024/03/22 20:48:05 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -53,8 +53,8 @@ __KERNEL_RCSID(0, "$NetBSD: apei_erst.c, ACPI_MODULE_NAME ("apei") static bool apei_erst_instvalid(ACPI_WHEA_HEADER *, uint32_t, uint32_t); -static void apei_erst_instfunc(ACPI_WHEA_HEADER *, void *, uint32_t *, - uint32_t); +static void apei_erst_instfunc(ACPI_WHEA_HEADER *, struct apei_mapreg *, + void *, uint32_t *, uint32_t); static uint64_t apei_erst_act(struct apei_softc *, enum AcpiErstActions, uint64_t); @@ -119,6 +119,35 @@ static const char *apei_erst_instruction }; /* + * apei_erst_instreg + * + * Table of which isntructions use a register operand. + * + * Must match apei_erst_instfunc. + */ +static const bool apei_erst_instreg[] = { + [ACPI_ERST_READ_REGISTER] = true, + [ACPI_ERST_READ_REGISTER_VALUE] = true, + [ACPI_ERST_WRITE_REGISTER] = true, + [ACPI_ERST_WRITE_REGISTER_VALUE] = true, + [ACPI_ERST_NOOP] = false, + [ACPI_ERST_LOAD_VAR1] = true, + [ACPI_ERST_LOAD_VAR2] = true, + [ACPI_ERST_STORE_VAR1] = true, + [ACPI_ERST_ADD] = false, + [ACPI_ERST_SUBTRACT] = false, + [ACPI_ERST_ADD_VALUE] = true, + [ACPI_ERST_SUBTRACT_VALUE] = true, + [ACPI_ERST_STALL] = false, + [ACPI_ERST_STALL_WHILE_TRUE] = true, + [ACPI_ERST_SKIP_NEXT_IF_TRUE] = true, + [ACPI_ERST_GOTO] = false, + [ACPI_ERST_SET_SRC_ADDRESS_BASE] = true, + [ACPI_ERST_SET_DST_ADDRESS_BASE] = true, + [ACPI_ERST_MOVE_DATA] = true, +}; + +/* * XXX dtrace and kernhist */ static void @@ -228,7 +257,7 @@ apei_erst_attach(struct apei_softc *sc) ssc->ssc_interp = apei_interp_create("ERST", apei_erst_action, __arraycount(apei_erst_action), apei_erst_instruction, __arraycount(apei_erst_instruction), - apei_erst_instvalid, apei_erst_instfunc); + apei_erst_instreg, apei_erst_instvalid, apei_erst_instfunc); /* * Compile the interpreter from the ERST action instruction @@ -332,7 +361,7 @@ struct apei_erst_machine { }; /* - * apei_erst_instfunc(header, cookie, &ip, maxip) + * apei_erst_instfunc(header, map, cookie, &ip, maxip) * * Run a single instruction in the service of performing an ERST * action. Updates the ERST machine at cookie, and the ip if @@ -343,8 +372,8 @@ struct apei_erst_machine { * execute. */ static void -apei_erst_instfunc(ACPI_WHEA_HEADER *header, void *cookie, uint32_t *ipp, - uint32_t maxip) +apei_erst_instfunc(ACPI_WHEA_HEADER *header, struct apei_mapreg *map, + void *cookie, uint32_t *ipp, uint32_t maxip) { struct apei_erst_machine *const M = cookie; ACPI_STATUS rv = AE_OK; @@ -382,33 +411,35 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea */ switch (header->Instruction) { case ACPI_ERST_READ_REGISTER: - rv = apei_read_register(reg, Mask, &M->y); + rv = apei_read_register(reg, map, Mask, &M->y); break; case ACPI_ERST_READ_REGISTER_VALUE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; M->y = (v == Value ? 1 : 0); break; } case ACPI_ERST_WRITE_REGISTER: - rv = apei_write_register(reg, Mask, preserve_register, M->x); + rv = apei_write_register(reg, map, Mask, preserve_register, + M->x); break; case ACPI_ERST_WRITE_REGISTER_VALUE: - rv = apei_write_register(reg, Mask, preserve_register, Value); + rv = apei_write_register(reg, map, Mask, preserve_register, + Value); break; case ACPI_ERST_NOOP: break; case ACPI_ERST_LOAD_VAR1: - rv = apei_read_register(reg, Mask, &M->var1); + rv = apei_read_register(reg, map, Mask, &M->var1); break; case ACPI_ERST_LOAD_VAR2: - rv = apei_read_register(reg, Mask, &M->var2); + rv = apei_read_register(reg, map, Mask, &M->var2); break; case ACPI_ERST_STORE_VAR1: - rv = apei_write_register(reg, Mask, preserve_register, + rv = apei_write_register(reg, map, Mask, preserve_register, M->var1); break; case ACPI_ERST_ADD: @@ -433,25 +464,25 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea case ACPI_ERST_ADD_VALUE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; v += Value; - rv = apei_write_register(reg, Mask, preserve_register, v); + rv = apei_write_register(reg, map, Mask, preserve_register, v); break; } case ACPI_ERST_SUBTRACT_VALUE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; v -= Value; - rv = apei_write_register(reg, Mask, preserve_register, v); + rv = apei_write_register(reg, map, Mask, preserve_register, v); break; } case ACPI_ERST_STALL: @@ -461,7 +492,7 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea for (;;) { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; if (v != Value) @@ -472,7 +503,7 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea case ACPI_ERST_SKIP_NEXT_IF_TRUE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; @@ -496,7 +527,7 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea case ACPI_ERST_SET_SRC_ADDRESS_BASE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; M->src_base = v; @@ -505,7 +536,7 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea case ACPI_ERST_SET_DST_ADDRESS_BASE: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; M->src_base = v; @@ -514,9 +545,13 @@ apei_erst_instfunc(ACPI_WHEA_HEADER *hea case ACPI_ERST_MOVE_DATA: { uint64_t v; - rv = apei_read_register(reg, Mask, &v); + rv = apei_read_register(reg, map, Mask, &v); if (ACPI_FAILURE(rv)) break; + /* + * XXX This might not work in nasty contexts unless we + * pre-allocate a virtual page for the mapping. + */ apei_pmemmove(M->dst_base + v, M->src_base + v, M->var2); break; } Index: src/sys/dev/acpi/apei_interp.h diff -u src/sys/dev/acpi/apei_interp.h:1.1 src/sys/dev/acpi/apei_interp.h:1.2 --- src/sys/dev/acpi/apei_interp.h:1.1 Wed Mar 20 17:11:43 2024 +++ src/sys/dev/acpi/apei_interp.h Fri Mar 22 20:48:05 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: apei_interp.h,v 1.1 2024/03/20 17:11:43 riastradh Exp $ */ +/* $NetBSD: apei_interp.h,v 1.2 2024/03/22 20:48:05 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -33,12 +33,15 @@ struct acpi_whea_header; struct apei_interp; +struct apei_mapreg; struct apei_interp *apei_interp_create(const char *, const char *const *, unsigned, const char *const *, unsigned, + const bool *, bool (*)(struct acpi_whea_header *, uint32_t, uint32_t), - void (*)(struct acpi_whea_header *, void *, uint32_t *, uint32_t)); + void (*)(struct acpi_whea_header *, struct apei_mapreg *, void *, + uint32_t *, uint32_t)); void apei_interp_destroy(struct apei_interp *); void apei_interp_pass1_load(struct apei_interp *, uint32_t, Index: src/sys/dev/acpi/apei_reg.c diff -u src/sys/dev/acpi/apei_reg.c:1.1 src/sys/dev/acpi/apei_reg.c:1.2 --- src/sys/dev/acpi/apei_reg.c:1.1 Wed Mar 20 17:11:44 2024 +++ src/sys/dev/acpi/apei_reg.c Fri Mar 22 20:48:05 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: apei_reg.c,v 1.1 2024/03/20 17:11:44 riastradh Exp $ */ +/* $NetBSD: apei_reg.c,v 1.2 2024/03/22 20:48:05 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -31,18 +31,19 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: apei_reg.c,v 1.1 2024/03/20 17:11:44 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: apei_reg.c,v 1.2 2024/03/22 20:48:05 riastradh Exp $"); #include <sys/types.h> #include <dev/acpi/acpivar.h> +#include <dev/acpi/apei_mapreg.h> #include <dev/acpi/apei_reg.h> /* - * apei_read_register(Register, Mask, &X) + * apei_read_register(Register, map, Mask, &X) * - * Read from Register, shifted out of position and then masked - * with Mask, and store the result in X. + * Read from Register mapped at map, shifted out of position and + * then masked with Mask, and store the result in X. * * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#read-register * @@ -50,17 +51,13 @@ __KERNEL_RCSID(0, "$NetBSD: apei_reg.c,v * that section is under the ERST part.) */ ACPI_STATUS -apei_read_register(ACPI_GENERIC_ADDRESS *Register, uint64_t Mask, uint64_t *p) +apei_read_register(ACPI_GENERIC_ADDRESS *Register, struct apei_mapreg *map, + uint64_t Mask, uint64_t *p) { const uint8_t BitOffset = Register->BitOffset; uint64_t X; - ACPI_STATUS rv; - rv = AcpiRead(&X, Register); - if (ACPI_FAILURE(rv)) { - *p = 0; /* XXX */ - return rv; - } + X = apei_mapreg_read(Register, map); X >>= BitOffset; X &= Mask; @@ -69,10 +66,11 @@ apei_read_register(ACPI_GENERIC_ADDRESS } /* - * apei_write_register(Register, Mask, preserve_register, X) + * apei_write_register(Register, map, Mask, preserve_register, X) * * Write X, masked with Mask and shifted into position, to - * Register, preserving other bits if preserve_register is true. + * Register, mapped at map, preserving other bits if + * preserve_register is true. * * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#write-register * @@ -82,22 +80,20 @@ apei_read_register(ACPI_GENERIC_ADDRESS * which has been lost in more recent versions of the spec. */ ACPI_STATUS -apei_write_register(ACPI_GENERIC_ADDRESS *Register, uint64_t Mask, - bool preserve_register, uint64_t X) +apei_write_register(ACPI_GENERIC_ADDRESS *Register, struct apei_mapreg *map, + uint64_t Mask, bool preserve_register, uint64_t X) { const uint8_t BitOffset = Register->BitOffset; - ACPI_STATUS rv; X &= Mask; X <<= BitOffset; if (preserve_register) { uint64_t Y; - rv = AcpiRead(&Y, Register); - if (ACPI_FAILURE(rv)) - return rv; + Y = apei_mapreg_read(Register, map); Y &= ~(Mask << BitOffset); X |= Y; } - return AcpiWrite(X, Register); + apei_mapreg_write(Register, map, X); + return AE_OK; } Index: src/sys/dev/acpi/apei_reg.h diff -u src/sys/dev/acpi/apei_reg.h:1.1 src/sys/dev/acpi/apei_reg.h:1.2 --- src/sys/dev/acpi/apei_reg.h:1.1 Wed Mar 20 17:11:44 2024 +++ src/sys/dev/acpi/apei_reg.h Fri Mar 22 20:48:05 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: apei_reg.h,v 1.1 2024/03/20 17:11:44 riastradh Exp $ */ +/* $NetBSD: apei_reg.h,v 1.2 2024/03/22 20:48:05 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -33,8 +33,11 @@ #include <dev/acpi/acpivar.h> -ACPI_STATUS apei_read_register(ACPI_GENERIC_ADDRESS *, uint64_t, uint64_t *); -ACPI_STATUS apei_write_register(ACPI_GENERIC_ADDRESS *, uint64_t, bool, - uint64_t); +struct apei_mapreg; + +ACPI_STATUS apei_read_register(ACPI_GENERIC_ADDRESS *, struct apei_mapreg *, + uint64_t, uint64_t *); +ACPI_STATUS apei_write_register(ACPI_GENERIC_ADDRESS *, struct apei_mapreg *, + uint64_t, bool, uint64_t); #endif /* _SYS_DEV_ACPI_APEI_REG_H_ */