xref: /netbsd-src/sys/dev/acpi/apei_bert.c (revision 4b159fe528de68c639f4f9cd4d8b3ef59df8a58d)
1*4b159fe5Sriastradh /*	$NetBSD: apei_bert.c,v 1.1 2024/03/20 17:11:43 riastradh Exp $	*/
2*4b159fe5Sriastradh 
3*4b159fe5Sriastradh /*-
4*4b159fe5Sriastradh  * Copyright (c) 2024 The NetBSD Foundation, Inc.
5*4b159fe5Sriastradh  * All rights reserved.
6*4b159fe5Sriastradh  *
7*4b159fe5Sriastradh  * Redistribution and use in source and binary forms, with or without
8*4b159fe5Sriastradh  * modification, are permitted provided that the following conditions
9*4b159fe5Sriastradh  * are met:
10*4b159fe5Sriastradh  * 1. Redistributions of source code must retain the above copyright
11*4b159fe5Sriastradh  *    notice, this list of conditions and the following disclaimer.
12*4b159fe5Sriastradh  * 2. Redistributions in binary form must reproduce the above copyright
13*4b159fe5Sriastradh  *    notice, this list of conditions and the following disclaimer in the
14*4b159fe5Sriastradh  *    documentation and/or other materials provided with the distribution.
15*4b159fe5Sriastradh  *
16*4b159fe5Sriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17*4b159fe5Sriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18*4b159fe5Sriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19*4b159fe5Sriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20*4b159fe5Sriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4b159fe5Sriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4b159fe5Sriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4b159fe5Sriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4b159fe5Sriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4b159fe5Sriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4b159fe5Sriastradh  * POSSIBILITY OF SUCH DAMAGE.
27*4b159fe5Sriastradh  */
28*4b159fe5Sriastradh 
29*4b159fe5Sriastradh /*
30*4b159fe5Sriastradh  * APEI BERT -- Boot Error Record Table
31*4b159fe5Sriastradh  *
32*4b159fe5Sriastradh  * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#boot-error-source
33*4b159fe5Sriastradh  */
34*4b159fe5Sriastradh 
35*4b159fe5Sriastradh #include <sys/cdefs.h>
36*4b159fe5Sriastradh __KERNEL_RCSID(0, "$NetBSD: apei_bert.c,v 1.1 2024/03/20 17:11:43 riastradh Exp $");
37*4b159fe5Sriastradh 
38*4b159fe5Sriastradh #include <sys/types.h>
39*4b159fe5Sriastradh 
40*4b159fe5Sriastradh #include <sys/systm.h>
41*4b159fe5Sriastradh 
42*4b159fe5Sriastradh #include <dev/acpi/acpivar.h>
43*4b159fe5Sriastradh #include <dev/acpi/apeivar.h>
44*4b159fe5Sriastradh #include <dev/acpi/apei_bertvar.h>
45*4b159fe5Sriastradh 
46*4b159fe5Sriastradh #define	_COMPONENT	ACPI_RESOURCE_COMPONENT
47*4b159fe5Sriastradh ACPI_MODULE_NAME	("apei")
48*4b159fe5Sriastradh 
49*4b159fe5Sriastradh /*
50*4b159fe5Sriastradh  * apei_bert_attach(sc)
51*4b159fe5Sriastradh  *
52*4b159fe5Sriastradh  *	Scan the Boot Error Record Table for hardware errors that
53*4b159fe5Sriastradh  *	happened early at boot or on the previous boot.
54*4b159fe5Sriastradh  */
55*4b159fe5Sriastradh void
apei_bert_attach(struct apei_softc * sc)56*4b159fe5Sriastradh apei_bert_attach(struct apei_softc *sc)
57*4b159fe5Sriastradh {
58*4b159fe5Sriastradh 	const ACPI_TABLE_BERT *bert = sc->sc_tab.bert;
59*4b159fe5Sriastradh 	struct apei_bert_softc *bsc = &sc->sc_bert;
60*4b159fe5Sriastradh 	bool fatal = false;
61*4b159fe5Sriastradh 
62*4b159fe5Sriastradh 	/*
63*4b159fe5Sriastradh 	 * Verify the table is large enough.
64*4b159fe5Sriastradh 	 */
65*4b159fe5Sriastradh 	if (bert->Header.Length < sizeof(*bert)) {
66*4b159fe5Sriastradh 		aprint_error_dev(sc->sc_dev, "BERT: truncated table:"
67*4b159fe5Sriastradh 		    " %"PRIu32" < %zu bytes\n",
68*4b159fe5Sriastradh 		    bert->Header.Length, sizeof(*bert));
69*4b159fe5Sriastradh 		return;
70*4b159fe5Sriastradh 	}
71*4b159fe5Sriastradh 
72*4b159fe5Sriastradh 	/*
73*4b159fe5Sriastradh 	 * In verbose boots, print the BERT physical address and
74*4b159fe5Sriastradh 	 * length.  The operator might find this handy for dd'ing it
75*4b159fe5Sriastradh 	 * from /dev/mem, if allowed.
76*4b159fe5Sriastradh 	 */
77*4b159fe5Sriastradh 	aprint_verbose_dev(sc->sc_dev, "BERT: 0x%x bytes at 0x%"PRIx64"\n",
78*4b159fe5Sriastradh 	    bert->RegionLength, bert->Address);
79*4b159fe5Sriastradh 
80*4b159fe5Sriastradh 	/*
81*4b159fe5Sriastradh 	 * Verify the length is enough for a Generic Error Status Block
82*4b159fe5Sriastradh 	 * header, at least.
83*4b159fe5Sriastradh 	 */
84*4b159fe5Sriastradh 	if (bert->RegionLength < sizeof(*bsc->bsc_gesb)) {
85*4b159fe5Sriastradh 		aprint_error_dev(sc->sc_dev,
86*4b159fe5Sriastradh 		    "BERT: truncated boot error region, %"PRIu32" < %zu bytes",
87*4b159fe5Sriastradh 		    bert->RegionLength, sizeof(*bsc->bsc_gesb));
88*4b159fe5Sriastradh 		return;
89*4b159fe5Sriastradh 	}
90*4b159fe5Sriastradh 
91*4b159fe5Sriastradh 	/*
92*4b159fe5Sriastradh 	 * Map the GESB and process it, but don't acknowledge it --
93*4b159fe5Sriastradh 	 * this is a one-time polled source; it won't (or at least,
94*4b159fe5Sriastradh 	 * shouldn't) change after boot.
95*4b159fe5Sriastradh 	 */
96*4b159fe5Sriastradh 	bsc->bsc_gesb = AcpiOsMapMemory(bert->Address, bert->RegionLength);
97*4b159fe5Sriastradh 	const uint32_t status = apei_gesb_report(sc, bsc->bsc_gesb,
98*4b159fe5Sriastradh 	    bert->RegionLength, "boot error record", &fatal);
99*4b159fe5Sriastradh 	if (status == 0) {
100*4b159fe5Sriastradh 		/*
101*4b159fe5Sriastradh 		 * If there were no boot errors, leave a note in dmesg
102*4b159fe5Sriastradh 		 * to this effect without cluttering up the console
103*4b159fe5Sriastradh 		 * unless you asked for it by `boot -v'.
104*4b159fe5Sriastradh 		 */
105*4b159fe5Sriastradh 		aprint_verbose_dev(sc->sc_dev,
106*4b159fe5Sriastradh 		    "BERT: no boot errors recorded\n");
107*4b159fe5Sriastradh 	}
108*4b159fe5Sriastradh 
109*4b159fe5Sriastradh 	/*
110*4b159fe5Sriastradh 	 * If the error was fatal, print a warning to the console.
111*4b159fe5Sriastradh 	 * Probably not actually fatal now since it is usually related
112*4b159fe5Sriastradh 	 * to early or previous boot.
113*4b159fe5Sriastradh 	 */
114*4b159fe5Sriastradh 	if (fatal) {
115*4b159fe5Sriastradh 		aprint_error_dev(sc->sc_dev, "BERT:"
116*4b159fe5Sriastradh 		    " fatal pre-boot error recorded\n");
117*4b159fe5Sriastradh 	}
118*4b159fe5Sriastradh 
119*4b159fe5Sriastradh 	/* XXX expose content via sysctl? */
120*4b159fe5Sriastradh }
121*4b159fe5Sriastradh 
122*4b159fe5Sriastradh /*
123*4b159fe5Sriastradh  * apei_bert_detach(sc)
124*4b159fe5Sriastradh  *
125*4b159fe5Sriastradh  *	Free any software resources associated with the Boot Error
126*4b159fe5Sriastradh  *	Record Table.
127*4b159fe5Sriastradh  */
128*4b159fe5Sriastradh void
apei_bert_detach(struct apei_softc * sc)129*4b159fe5Sriastradh apei_bert_detach(struct apei_softc *sc)
130*4b159fe5Sriastradh {
131*4b159fe5Sriastradh 	const ACPI_TABLE_BERT *bert = sc->sc_tab.bert;
132*4b159fe5Sriastradh 	struct apei_bert_softc *bsc = &sc->sc_bert;
133*4b159fe5Sriastradh 
134*4b159fe5Sriastradh 	if (bsc->bsc_gesb) {
135*4b159fe5Sriastradh 		AcpiOsUnmapMemory(bsc->bsc_gesb, bert->RegionLength);
136*4b159fe5Sriastradh 		bsc->bsc_gesb = NULL;
137*4b159fe5Sriastradh 	}
138*4b159fe5Sriastradh }
139