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_ */