xref: /freebsd/sys/dev/coreboot/coreboot.c (revision 5f74217c05a99f38a31a6e4950220964595d4ac8)
1*5f74217cSAbdelkader Boudih /*
2*5f74217cSAbdelkader Boudih  * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
3*5f74217cSAbdelkader Boudih  *
4*5f74217cSAbdelkader Boudih  * SPDX-License-Identifier: BSD-2-Clause
5*5f74217cSAbdelkader Boudih  */
6*5f74217cSAbdelkader Boudih 
7*5f74217cSAbdelkader Boudih /*
8*5f74217cSAbdelkader Boudih  * coreboot(4) - FreeBSD driver for coreboot firmware tables
9*5f74217cSAbdelkader Boudih  *
10*5f74217cSAbdelkader Boudih  * Discovers the coreboot table by scanning low memory for the "LBIO"
11*5f74217cSAbdelkader Boudih  * signature, follows CB_TAG_FORWARD to the high-memory table, and
12*5f74217cSAbdelkader Boudih  * exposes firmware information through sysctl(9) and character devices.
13*5f74217cSAbdelkader Boudih  */
14*5f74217cSAbdelkader Boudih 
15*5f74217cSAbdelkader Boudih #include <sys/systm.h>
16*5f74217cSAbdelkader Boudih #include <sys/bus.h>
17*5f74217cSAbdelkader Boudih #include <sys/kernel.h>
18*5f74217cSAbdelkader Boudih #include <sys/malloc.h>
19*5f74217cSAbdelkader Boudih #include <sys/module.h>
20*5f74217cSAbdelkader Boudih #include <sys/rman.h>
21*5f74217cSAbdelkader Boudih #include <sys/sysctl.h>
22*5f74217cSAbdelkader Boudih 
23*5f74217cSAbdelkader Boudih #include <vm/vm.h>
24*5f74217cSAbdelkader Boudih #include <vm/vm_param.h>
25*5f74217cSAbdelkader Boudih #include <vm/pmap.h>
26*5f74217cSAbdelkader Boudih 
27*5f74217cSAbdelkader Boudih #include <machine/bus.h>
28*5f74217cSAbdelkader Boudih #include <machine/resource.h>
29*5f74217cSAbdelkader Boudih 
30*5f74217cSAbdelkader Boudih #include <dev/coreboot/coreboot.h>
31*5f74217cSAbdelkader Boudih 
32*5f74217cSAbdelkader Boudih static struct coreboot_softc *coreboot_sc;
33*5f74217cSAbdelkader Boudih 
34*5f74217cSAbdelkader Boudih /*
35*5f74217cSAbdelkader Boudih  * Debug verbosity control, non-zero enables extra output.
36*5f74217cSAbdelkader Boudih  * Tunable via loader.conf: hw.coreboot.debug=1
37*5f74217cSAbdelkader Boudih  * Runtime: sysctl hw.coreboot.debug=1
38*5f74217cSAbdelkader Boudih  * Registered dynamically under hw.coreboot in
39*5f74217cSAbdelkader Boudih  * coreboot_register_sysctls().
40*5f74217cSAbdelkader Boudih  */
41*5f74217cSAbdelkader Boudih static int coreboot_debug = 0;
42*5f74217cSAbdelkader Boudih TUNABLE_INT("hw.coreboot.debug", &coreboot_debug);
43*5f74217cSAbdelkader Boudih 
44*5f74217cSAbdelkader Boudih struct coreboot_softc *
coreboot_get_softc(void)45*5f74217cSAbdelkader Boudih coreboot_get_softc(void)
46*5f74217cSAbdelkader Boudih {
47*5f74217cSAbdelkader Boudih 	return (coreboot_sc);
48*5f74217cSAbdelkader Boudih }
49*5f74217cSAbdelkader Boudih 
50*5f74217cSAbdelkader Boudih static void	coreboot_identify(driver_t *, device_t);
51*5f74217cSAbdelkader Boudih static int	coreboot_probe(device_t);
52*5f74217cSAbdelkader Boudih static int	coreboot_attach(device_t);
53*5f74217cSAbdelkader Boudih static int	coreboot_detach(device_t);
54*5f74217cSAbdelkader Boudih static int	coreboot_modevent(module_t, int, void *);
55*5f74217cSAbdelkader Boudih 
56*5f74217cSAbdelkader Boudih /*
57*5f74217cSAbdelkader Boudih  * Scan a physical memory region for the "LBIO" signature.
58*5f74217cSAbdelkader Boudih  * Returns the physical address of the header, or 0 if not found.
59*5f74217cSAbdelkader Boudih  */
60*5f74217cSAbdelkader Boudih static vm_paddr_t
coreboot_scan_region(vm_paddr_t start,vm_paddr_t end)61*5f74217cSAbdelkader Boudih coreboot_scan_region(vm_paddr_t start, vm_paddr_t end)
62*5f74217cSAbdelkader Boudih {
63*5f74217cSAbdelkader Boudih 	vm_paddr_t addr;
64*5f74217cSAbdelkader Boudih 	void *va;
65*5f74217cSAbdelkader Boudih 	struct cb_header *hdr;
66*5f74217cSAbdelkader Boudih 
67*5f74217cSAbdelkader Boudih 	for (addr = (start == 0 ? CB_SCAN_LOW_STEP : start); addr < end;
68*5f74217cSAbdelkader Boudih 	    addr += CB_SCAN_LOW_STEP) {
69*5f74217cSAbdelkader Boudih 		va = pmap_mapbios(addr, sizeof(struct cb_header));
70*5f74217cSAbdelkader Boudih 		if (va == NULL)
71*5f74217cSAbdelkader Boudih 			continue;
72*5f74217cSAbdelkader Boudih 
73*5f74217cSAbdelkader Boudih 		hdr = (struct cb_header *)va;
74*5f74217cSAbdelkader Boudih 		if (memcmp(hdr->signature, CB_HEADER_SIGNATURE,
75*5f74217cSAbdelkader Boudih 		    CB_HEADER_SIG_LEN) == 0) {
76*5f74217cSAbdelkader Boudih 			pmap_unmapbios(va, sizeof(struct cb_header));
77*5f74217cSAbdelkader Boudih 			return (addr);
78*5f74217cSAbdelkader Boudih 		}
79*5f74217cSAbdelkader Boudih 		pmap_unmapbios(va, sizeof(struct cb_header));
80*5f74217cSAbdelkader Boudih 	}
81*5f74217cSAbdelkader Boudih 	return (0);
82*5f74217cSAbdelkader Boudih }
83*5f74217cSAbdelkader Boudih 
84*5f74217cSAbdelkader Boudih /*
85*5f74217cSAbdelkader Boudih  * Validate length fields in the header before using them for mappings
86*5f74217cSAbdelkader Boudih  * and pointer arithmetic.
87*5f74217cSAbdelkader Boudih  */
88*5f74217cSAbdelkader Boudih static int
coreboot_sanitize_header(const struct cb_header * hdr,vm_size_t * map_size)89*5f74217cSAbdelkader Boudih coreboot_sanitize_header(const struct cb_header *hdr, vm_size_t *map_size)
90*5f74217cSAbdelkader Boudih {
91*5f74217cSAbdelkader Boudih 	uint64_t total;
92*5f74217cSAbdelkader Boudih 
93*5f74217cSAbdelkader Boudih 	if (hdr->header_bytes < sizeof(*hdr) ||
94*5f74217cSAbdelkader Boudih 	    hdr->header_bytes > CB_MAX_HEADER_BYTES)
95*5f74217cSAbdelkader Boudih 		return (EINVAL);
96*5f74217cSAbdelkader Boudih 	if ((hdr->header_bytes % CB_TABLE_ALIGN) != 0)
97*5f74217cSAbdelkader Boudih 		return (EINVAL);
98*5f74217cSAbdelkader Boudih 	if (hdr->table_bytes > CB_MAX_TABLE_BYTES)
99*5f74217cSAbdelkader Boudih 		return (EINVAL);
100*5f74217cSAbdelkader Boudih 	if ((hdr->table_bytes % CB_TABLE_ALIGN) != 0)
101*5f74217cSAbdelkader Boudih 		return (EINVAL);
102*5f74217cSAbdelkader Boudih 
103*5f74217cSAbdelkader Boudih 	total = (uint64_t)hdr->header_bytes + (uint64_t)hdr->table_bytes;
104*5f74217cSAbdelkader Boudih 	if (total > CB_MAX_TABLE_MAP_BYTES)
105*5f74217cSAbdelkader Boudih 		return (EINVAL);
106*5f74217cSAbdelkader Boudih 
107*5f74217cSAbdelkader Boudih 	*map_size = (vm_size_t)total;
108*5f74217cSAbdelkader Boudih 	return (0);
109*5f74217cSAbdelkader Boudih }
110*5f74217cSAbdelkader Boudih 
111*5f74217cSAbdelkader Boudih /*
112*5f74217cSAbdelkader Boudih  * Validate the coreboot header checksum.
113*5f74217cSAbdelkader Boudih  * Returns 0 on success, non-zero on failure.
114*5f74217cSAbdelkader Boudih  */
115*5f74217cSAbdelkader Boudih static int
coreboot_validate_header(struct cb_header * hdr,vm_size_t mapped_len)116*5f74217cSAbdelkader Boudih coreboot_validate_header(struct cb_header *hdr, vm_size_t mapped_len)
117*5f74217cSAbdelkader Boudih {
118*5f74217cSAbdelkader Boudih 	uint16_t cksum;
119*5f74217cSAbdelkader Boudih 
120*5f74217cSAbdelkader Boudih 	if (hdr->header_bytes > mapped_len)
121*5f74217cSAbdelkader Boudih 		return (EINVAL);
122*5f74217cSAbdelkader Boudih 
123*5f74217cSAbdelkader Boudih 	cksum = cb_checksum(hdr, hdr->header_bytes);
124*5f74217cSAbdelkader Boudih 	if (cksum != 0)
125*5f74217cSAbdelkader Boudih 		return (EINVAL);
126*5f74217cSAbdelkader Boudih 
127*5f74217cSAbdelkader Boudih 	return (0);
128*5f74217cSAbdelkader Boudih }
129*5f74217cSAbdelkader Boudih 
130*5f74217cSAbdelkader Boudih /*
131*5f74217cSAbdelkader Boudih  * Validate checksum for the table payload.
132*5f74217cSAbdelkader Boudih  */
133*5f74217cSAbdelkader Boudih static int
coreboot_validate_table(struct cb_header * hdr,vm_size_t mapped_len)134*5f74217cSAbdelkader Boudih coreboot_validate_table(struct cb_header *hdr, vm_size_t mapped_len)
135*5f74217cSAbdelkader Boudih {
136*5f74217cSAbdelkader Boudih 	const uint8_t *table;
137*5f74217cSAbdelkader Boudih 	uint16_t cksum;
138*5f74217cSAbdelkader Boudih 
139*5f74217cSAbdelkader Boudih 	if (hdr->table_bytes == 0)
140*5f74217cSAbdelkader Boudih 		return (0);
141*5f74217cSAbdelkader Boudih 
142*5f74217cSAbdelkader Boudih 	if ((uint64_t)hdr->header_bytes + (uint64_t)hdr->table_bytes >
143*5f74217cSAbdelkader Boudih 	    mapped_len)
144*5f74217cSAbdelkader Boudih 		return (EINVAL);
145*5f74217cSAbdelkader Boudih 	if (hdr->table_checksum > UINT16_MAX)
146*5f74217cSAbdelkader Boudih 		return (EINVAL);
147*5f74217cSAbdelkader Boudih 
148*5f74217cSAbdelkader Boudih 	table = (const uint8_t *)hdr + hdr->header_bytes;
149*5f74217cSAbdelkader Boudih 	cksum = cb_checksum(table, hdr->table_bytes);
150*5f74217cSAbdelkader Boudih 	if (cksum != (uint16_t)hdr->table_checksum)
151*5f74217cSAbdelkader Boudih 		return (EINVAL);
152*5f74217cSAbdelkader Boudih 
153*5f74217cSAbdelkader Boudih 	return (0);
154*5f74217cSAbdelkader Boudih }
155*5f74217cSAbdelkader Boudih 
156*5f74217cSAbdelkader Boudih static void
coreboot_copy_bounded_string(const char * src,size_t maxlen,char * dst,size_t dstlen)157*5f74217cSAbdelkader Boudih coreboot_copy_bounded_string(const char *src, size_t maxlen, char *dst,
158*5f74217cSAbdelkader Boudih     size_t dstlen)
159*5f74217cSAbdelkader Boudih {
160*5f74217cSAbdelkader Boudih 	size_t slen;
161*5f74217cSAbdelkader Boudih 
162*5f74217cSAbdelkader Boudih 	if (dstlen == 0)
163*5f74217cSAbdelkader Boudih 		return;
164*5f74217cSAbdelkader Boudih 
165*5f74217cSAbdelkader Boudih 	slen = strnlen(src, maxlen);
166*5f74217cSAbdelkader Boudih 	if (slen >= dstlen)
167*5f74217cSAbdelkader Boudih 		slen = dstlen - 1;
168*5f74217cSAbdelkader Boudih 	memcpy(dst, src, slen);
169*5f74217cSAbdelkader Boudih 	dst[slen] = '\0';
170*5f74217cSAbdelkader Boudih }
171*5f74217cSAbdelkader Boudih 
172*5f74217cSAbdelkader Boudih /*
173*5f74217cSAbdelkader Boudih  * Copy a coreboot string record into a destination buffer.
174*5f74217cSAbdelkader Boudih  */
175*5f74217cSAbdelkader Boudih static void
coreboot_copy_string(const struct cb_string * rec,char * dst,size_t dstlen)176*5f74217cSAbdelkader Boudih coreboot_copy_string(const struct cb_string *rec, char *dst, size_t dstlen)
177*5f74217cSAbdelkader Boudih {
178*5f74217cSAbdelkader Boudih 	size_t slen;
179*5f74217cSAbdelkader Boudih 
180*5f74217cSAbdelkader Boudih 	slen = rec->size - sizeof(struct cb_record);
181*5f74217cSAbdelkader Boudih 	if (slen >= dstlen)
182*5f74217cSAbdelkader Boudih 		slen = dstlen - 1;
183*5f74217cSAbdelkader Boudih 	memcpy(dst, rec->string, slen);
184*5f74217cSAbdelkader Boudih 	dst[slen] = '\0';
185*5f74217cSAbdelkader Boudih 
186*5f74217cSAbdelkader Boudih 	/* Strip trailing whitespace/nulls */
187*5f74217cSAbdelkader Boudih 	while (slen > 0 && (dst[slen - 1] == '\0' || dst[slen - 1] == ' ' ||
188*5f74217cSAbdelkader Boudih 	    dst[slen - 1] == '\n'))
189*5f74217cSAbdelkader Boudih 		dst[--slen] = '\0';
190*5f74217cSAbdelkader Boudih }
191*5f74217cSAbdelkader Boudih 
192*5f74217cSAbdelkader Boudih /*
193*5f74217cSAbdelkader Boudih  * Extract mainboard vendor and part number from the strings field.
194*5f74217cSAbdelkader Boudih  */
195*5f74217cSAbdelkader Boudih static void
coreboot_parse_mainboard(struct coreboot_softc * sc,const struct cb_mainboard * mb)196*5f74217cSAbdelkader Boudih coreboot_parse_mainboard(struct coreboot_softc *sc,
197*5f74217cSAbdelkader Boudih     const struct cb_mainboard *mb)
198*5f74217cSAbdelkader Boudih {
199*5f74217cSAbdelkader Boudih 	const char *strings = (const char *)mb->strings;
200*5f74217cSAbdelkader Boudih 	size_t total = mb->size - offsetof(struct cb_mainboard, strings);
201*5f74217cSAbdelkader Boudih 	uint8_t vendor_off, part_off;
202*5f74217cSAbdelkader Boudih 
203*5f74217cSAbdelkader Boudih 	vendor_off = mb->vendor_idx;
204*5f74217cSAbdelkader Boudih 	part_off = mb->part_idx;
205*5f74217cSAbdelkader Boudih 
206*5f74217cSAbdelkader Boudih 	if (vendor_off < total)
207*5f74217cSAbdelkader Boudih 		coreboot_copy_bounded_string(strings + vendor_off,
208*5f74217cSAbdelkader Boudih 		    total - vendor_off, sc->mb_vendor, sizeof(sc->mb_vendor));
209*5f74217cSAbdelkader Boudih 	if (part_off < total)
210*5f74217cSAbdelkader Boudih 		coreboot_copy_bounded_string(strings + part_off,
211*5f74217cSAbdelkader Boudih 		    total - part_off, sc->mb_part, sizeof(sc->mb_part));
212*5f74217cSAbdelkader Boudih }
213*5f74217cSAbdelkader Boudih 
214*5f74217cSAbdelkader Boudih /*
215*5f74217cSAbdelkader Boudih  * Parse all records in the coreboot table and populate softc.
216*5f74217cSAbdelkader Boudih  */
217*5f74217cSAbdelkader Boudih static void
coreboot_parse_table(struct coreboot_softc * sc,struct cb_header * hdr)218*5f74217cSAbdelkader Boudih coreboot_parse_table(struct coreboot_softc *sc, struct cb_header *hdr)
219*5f74217cSAbdelkader Boudih {
220*5f74217cSAbdelkader Boudih 	uint8_t *entry;
221*5f74217cSAbdelkader Boudih 	uint8_t *table_end;
222*5f74217cSAbdelkader Boudih 	struct cb_record *rec;
223*5f74217cSAbdelkader Boudih 
224*5f74217cSAbdelkader Boudih 	entry = (uint8_t *)hdr + hdr->header_bytes;
225*5f74217cSAbdelkader Boudih 	table_end = entry + hdr->table_bytes;
226*5f74217cSAbdelkader Boudih 
227*5f74217cSAbdelkader Boudih 	while ((size_t)(table_end - entry) >= sizeof(struct cb_record)) {
228*5f74217cSAbdelkader Boudih 		size_t rec_size;
229*5f74217cSAbdelkader Boudih 
230*5f74217cSAbdelkader Boudih 		rec = (struct cb_record *)entry;
231*5f74217cSAbdelkader Boudih 		rec_size = rec->size;
232*5f74217cSAbdelkader Boudih 
233*5f74217cSAbdelkader Boudih 		if (rec_size < sizeof(struct cb_record))
234*5f74217cSAbdelkader Boudih 			break;
235*5f74217cSAbdelkader Boudih 		if (rec_size > (size_t)(table_end - entry))
236*5f74217cSAbdelkader Boudih 			break;
237*5f74217cSAbdelkader Boudih 
238*5f74217cSAbdelkader Boudih 		switch (rec->tag) {
239*5f74217cSAbdelkader Boudih 		case CB_TAG_VERSION:
240*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
241*5f74217cSAbdelkader Boudih 			    sc->version, sizeof(sc->version));
242*5f74217cSAbdelkader Boudih 			break;
243*5f74217cSAbdelkader Boudih 
244*5f74217cSAbdelkader Boudih 		case CB_TAG_EXTRA_VERSION:
245*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
246*5f74217cSAbdelkader Boudih 			    sc->extra_version, sizeof(sc->extra_version));
247*5f74217cSAbdelkader Boudih 			break;
248*5f74217cSAbdelkader Boudih 
249*5f74217cSAbdelkader Boudih 		case CB_TAG_BUILD:
250*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
251*5f74217cSAbdelkader Boudih 			    sc->build, sizeof(sc->build));
252*5f74217cSAbdelkader Boudih 			break;
253*5f74217cSAbdelkader Boudih 
254*5f74217cSAbdelkader Boudih 		case CB_TAG_COMPILE_TIME:
255*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
256*5f74217cSAbdelkader Boudih 			    sc->compile_time, sizeof(sc->compile_time));
257*5f74217cSAbdelkader Boudih 			break;
258*5f74217cSAbdelkader Boudih 
259*5f74217cSAbdelkader Boudih 		case CB_TAG_COMPILER:
260*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
261*5f74217cSAbdelkader Boudih 			    sc->compiler, sizeof(sc->compiler));
262*5f74217cSAbdelkader Boudih 			break;
263*5f74217cSAbdelkader Boudih 
264*5f74217cSAbdelkader Boudih 		case CB_TAG_PLATFORM_BLOB_VERSION:
265*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
266*5f74217cSAbdelkader Boudih 			    sc->platform_blob_version,
267*5f74217cSAbdelkader Boudih 			    sizeof(sc->platform_blob_version));
268*5f74217cSAbdelkader Boudih 			break;
269*5f74217cSAbdelkader Boudih 
270*5f74217cSAbdelkader Boudih 		case CB_TAG_SERIALNO:
271*5f74217cSAbdelkader Boudih 			coreboot_copy_string((struct cb_string *)rec,
272*5f74217cSAbdelkader Boudih 			    sc->serialno, sizeof(sc->serialno));
273*5f74217cSAbdelkader Boudih 			break;
274*5f74217cSAbdelkader Boudih 
275*5f74217cSAbdelkader Boudih 		case CB_TAG_VERSION_TIMESTAMP: {
276*5f74217cSAbdelkader Boudih 			struct cb_version_timestamp *ts =
277*5f74217cSAbdelkader Boudih 			    (struct cb_version_timestamp *)rec;
278*5f74217cSAbdelkader Boudih 
279*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ts))
280*5f74217cSAbdelkader Boudih 				break;
281*5f74217cSAbdelkader Boudih 			sc->version_timestamp = ts->timestamp;
282*5f74217cSAbdelkader Boudih 			sc->has_version_timestamp = 1;
283*5f74217cSAbdelkader Boudih 			break;
284*5f74217cSAbdelkader Boudih 		}
285*5f74217cSAbdelkader Boudih 
286*5f74217cSAbdelkader Boudih 		case CB_TAG_MAINBOARD:
287*5f74217cSAbdelkader Boudih 			if (rec_size < offsetof(struct cb_mainboard, strings))
288*5f74217cSAbdelkader Boudih 				break;
289*5f74217cSAbdelkader Boudih 			coreboot_parse_mainboard(sc,
290*5f74217cSAbdelkader Boudih 			    (struct cb_mainboard *)rec);
291*5f74217cSAbdelkader Boudih 			break;
292*5f74217cSAbdelkader Boudih 
293*5f74217cSAbdelkader Boudih 		case CB_TAG_SERIAL: {
294*5f74217cSAbdelkader Boudih 			struct cb_serial *ser = (struct cb_serial *)rec;
295*5f74217cSAbdelkader Boudih 
296*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ser))
297*5f74217cSAbdelkader Boudih 				break;
298*5f74217cSAbdelkader Boudih 			sc->serial_baseaddr = ser->baseaddr;
299*5f74217cSAbdelkader Boudih 			sc->serial_baud = ser->baud;
300*5f74217cSAbdelkader Boudih 			sc->serial_regwidth = ser->regwidth;
301*5f74217cSAbdelkader Boudih 			sc->has_serial = 1;
302*5f74217cSAbdelkader Boudih 			break;
303*5f74217cSAbdelkader Boudih 		}
304*5f74217cSAbdelkader Boudih 
305*5f74217cSAbdelkader Boudih 		case CB_TAG_TSC_INFO: {
306*5f74217cSAbdelkader Boudih 			struct cb_tsc_info *tsc = (struct cb_tsc_info *)rec;
307*5f74217cSAbdelkader Boudih 
308*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*tsc))
309*5f74217cSAbdelkader Boudih 				break;
310*5f74217cSAbdelkader Boudih 			sc->tsc_freq_khz = tsc->freq_khz;
311*5f74217cSAbdelkader Boudih 			sc->has_tsc_info = 1;
312*5f74217cSAbdelkader Boudih 			break;
313*5f74217cSAbdelkader Boudih 		}
314*5f74217cSAbdelkader Boudih 
315*5f74217cSAbdelkader Boudih 		case CB_TAG_PCIE: {
316*5f74217cSAbdelkader Boudih 			struct cb_pcie *pcie = (struct cb_pcie *)rec;
317*5f74217cSAbdelkader Boudih 
318*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*pcie))
319*5f74217cSAbdelkader Boudih 				break;
320*5f74217cSAbdelkader Boudih 			sc->pcie_ctrl_base = pcie->ctrl_base;
321*5f74217cSAbdelkader Boudih 			sc->has_pcie = 1;
322*5f74217cSAbdelkader Boudih 			break;
323*5f74217cSAbdelkader Boudih 		}
324*5f74217cSAbdelkader Boudih 
325*5f74217cSAbdelkader Boudih 		case CB_TAG_BOOT_MEDIA_PARAMS: {
326*5f74217cSAbdelkader Boudih 			struct cb_boot_media_params *bmp =
327*5f74217cSAbdelkader Boudih 			    (struct cb_boot_media_params *)rec;
328*5f74217cSAbdelkader Boudih 
329*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*bmp))
330*5f74217cSAbdelkader Boudih 				break;
331*5f74217cSAbdelkader Boudih 			sc->fmap_offset = bmp->fmap_offset;
332*5f74217cSAbdelkader Boudih 			sc->cbfs_offset = bmp->cbfs_offset;
333*5f74217cSAbdelkader Boudih 			sc->cbfs_size = bmp->cbfs_size;
334*5f74217cSAbdelkader Boudih 			sc->boot_media_size = bmp->boot_media_size;
335*5f74217cSAbdelkader Boudih 			sc->has_boot_media = 1;
336*5f74217cSAbdelkader Boudih 			break;
337*5f74217cSAbdelkader Boudih 		}
338*5f74217cSAbdelkader Boudih 
339*5f74217cSAbdelkader Boudih 		case CB_TAG_MMC_INFO: {
340*5f74217cSAbdelkader Boudih 			struct cb_mmc_info *mmc = (struct cb_mmc_info *)rec;
341*5f74217cSAbdelkader Boudih 
342*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*mmc))
343*5f74217cSAbdelkader Boudih 				break;
344*5f74217cSAbdelkader Boudih 			sc->mmc_early_cmd1_status = mmc->early_cmd1_status;
345*5f74217cSAbdelkader Boudih 			sc->has_mmc_info = 1;
346*5f74217cSAbdelkader Boudih 			break;
347*5f74217cSAbdelkader Boudih 		}
348*5f74217cSAbdelkader Boudih 
349*5f74217cSAbdelkader Boudih 		case CB_TAG_CBMEM_CONSOLE: {
350*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
351*5f74217cSAbdelkader Boudih 
352*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
353*5f74217cSAbdelkader Boudih 				break;
354*5f74217cSAbdelkader Boudih 			sc->console_paddr = (vm_paddr_t)ref->cbmem_addr;
355*5f74217cSAbdelkader Boudih 			sc->has_console = 1;
356*5f74217cSAbdelkader Boudih 			break;
357*5f74217cSAbdelkader Boudih 		}
358*5f74217cSAbdelkader Boudih 
359*5f74217cSAbdelkader Boudih 		case CB_TAG_CBMEM_ENTRY: {
360*5f74217cSAbdelkader Boudih 			struct cb_cbmem_entry *ent =
361*5f74217cSAbdelkader Boudih 			    (struct cb_cbmem_entry *)rec;
362*5f74217cSAbdelkader Boudih 
363*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ent))
364*5f74217cSAbdelkader Boudih 				break;
365*5f74217cSAbdelkader Boudih 			if (sc->cbmem_count < CB_MAX_CBMEM_ENTRIES) {
366*5f74217cSAbdelkader Boudih 				struct cbmem_entry_info *info =
367*5f74217cSAbdelkader Boudih 				    &sc->cbmem_entries[sc->cbmem_count];
368*5f74217cSAbdelkader Boudih 				info->id = ent->id;
369*5f74217cSAbdelkader Boudih 				info->address = ent->address;
370*5f74217cSAbdelkader Boudih 				info->size = ent->entry_size;
371*5f74217cSAbdelkader Boudih 				strlcpy(info->name, cbmem_id_to_name(ent->id),
372*5f74217cSAbdelkader Boudih 				    sizeof(info->name));
373*5f74217cSAbdelkader Boudih 				sc->cbmem_count++;
374*5f74217cSAbdelkader Boudih 			}
375*5f74217cSAbdelkader Boudih 			break;
376*5f74217cSAbdelkader Boudih 		}
377*5f74217cSAbdelkader Boudih 
378*5f74217cSAbdelkader Boudih 		case CB_TAG_BOARD_CONFIG: {
379*5f74217cSAbdelkader Boudih 			struct cb_board_config *bc =
380*5f74217cSAbdelkader Boudih 			    (struct cb_board_config *)rec;
381*5f74217cSAbdelkader Boudih 
382*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*bc))
383*5f74217cSAbdelkader Boudih 				break;
384*5f74217cSAbdelkader Boudih 			sc->fw_config = bc->fw_config;
385*5f74217cSAbdelkader Boudih 			sc->board_id = bc->board_id;
386*5f74217cSAbdelkader Boudih 			sc->ram_code = bc->ram_code;
387*5f74217cSAbdelkader Boudih 			sc->sku_id = bc->sku_id;
388*5f74217cSAbdelkader Boudih 			sc->has_board_config = 1;
389*5f74217cSAbdelkader Boudih 			break;
390*5f74217cSAbdelkader Boudih 		}
391*5f74217cSAbdelkader Boudih 
392*5f74217cSAbdelkader Boudih 		case CB_TAG_MAC_ADDRS: {
393*5f74217cSAbdelkader Boudih 			struct cb_macs *macs = (struct cb_macs *)rec;
394*5f74217cSAbdelkader Boudih 			uint32_t i, count;
395*5f74217cSAbdelkader Boudih 
396*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*macs))
397*5f74217cSAbdelkader Boudih 				break;
398*5f74217cSAbdelkader Boudih 			count = macs->count;
399*5f74217cSAbdelkader Boudih 			if (count > CB_MAX_MAC_ADDRS)
400*5f74217cSAbdelkader Boudih 				count = CB_MAX_MAC_ADDRS;
401*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*macs) +
402*5f74217cSAbdelkader Boudih 			    count * sizeof(struct cb_mac_address))
403*5f74217cSAbdelkader Boudih 				break;
404*5f74217cSAbdelkader Boudih 			for (i = 0; i < count; i++)
405*5f74217cSAbdelkader Boudih 				sc->macs[i] = macs->entries[i];
406*5f74217cSAbdelkader Boudih 			sc->mac_count = count;
407*5f74217cSAbdelkader Boudih 			break;
408*5f74217cSAbdelkader Boudih 		}
409*5f74217cSAbdelkader Boudih 
410*5f74217cSAbdelkader Boudih 		case CB_TAG_ACPI_RSDP: {
411*5f74217cSAbdelkader Boudih 			struct cb_acpi_rsdp *rsdp =
412*5f74217cSAbdelkader Boudih 			    (struct cb_acpi_rsdp *)rec;
413*5f74217cSAbdelkader Boudih 
414*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*rsdp))
415*5f74217cSAbdelkader Boudih 				break;
416*5f74217cSAbdelkader Boudih 			sc->acpi_rsdp = rsdp->rsdp_pointer;
417*5f74217cSAbdelkader Boudih 			sc->has_acpi_rsdp = 1;
418*5f74217cSAbdelkader Boudih 			break;
419*5f74217cSAbdelkader Boudih 		}
420*5f74217cSAbdelkader Boudih 
421*5f74217cSAbdelkader Boudih 		case CB_TAG_SPI_FLASH: {
422*5f74217cSAbdelkader Boudih 			struct cb_spi_flash *spi =
423*5f74217cSAbdelkader Boudih 			    (struct cb_spi_flash *)rec;
424*5f74217cSAbdelkader Boudih 
425*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*spi))
426*5f74217cSAbdelkader Boudih 				break;
427*5f74217cSAbdelkader Boudih 			sc->spi_flash_size = spi->flash_size;
428*5f74217cSAbdelkader Boudih 			sc->spi_sector_size = spi->sector_size;
429*5f74217cSAbdelkader Boudih 			sc->spi_erase_cmd = spi->erase_cmd;
430*5f74217cSAbdelkader Boudih 			sc->spi_flags = spi->flags;
431*5f74217cSAbdelkader Boudih 			sc->has_spi_flash = 1;
432*5f74217cSAbdelkader Boudih 			break;
433*5f74217cSAbdelkader Boudih 		}
434*5f74217cSAbdelkader Boudih 
435*5f74217cSAbdelkader Boudih 		case CB_TAG_CONSOLE: {
436*5f74217cSAbdelkader Boudih 			struct cb_console *con = (struct cb_console *)rec;
437*5f74217cSAbdelkader Boudih 
438*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*con))
439*5f74217cSAbdelkader Boudih 				break;
440*5f74217cSAbdelkader Boudih 			sc->console_type = con->type;
441*5f74217cSAbdelkader Boudih 			sc->has_console_type = 1;
442*5f74217cSAbdelkader Boudih 			break;
443*5f74217cSAbdelkader Boudih 		}
444*5f74217cSAbdelkader Boudih 
445*5f74217cSAbdelkader Boudih 		case CB_TAG_FRAMEBUFFER: {
446*5f74217cSAbdelkader Boudih 			struct cb_framebuffer *fb =
447*5f74217cSAbdelkader Boudih 			    (struct cb_framebuffer *)rec;
448*5f74217cSAbdelkader Boudih 
449*5f74217cSAbdelkader Boudih 			if (rec_size < CB_FRAMEBUFFER_MIN_SIZE)
450*5f74217cSAbdelkader Boudih 				break;
451*5f74217cSAbdelkader Boudih 			sc->fb_addr = fb->physical_address;
452*5f74217cSAbdelkader Boudih 			sc->fb_x_res = fb->x_resolution;
453*5f74217cSAbdelkader Boudih 			sc->fb_y_res = fb->y_resolution;
454*5f74217cSAbdelkader Boudih 			sc->fb_stride = fb->bytes_per_line;
455*5f74217cSAbdelkader Boudih 			sc->fb_bpp = fb->bits_per_pixel;
456*5f74217cSAbdelkader Boudih 			sc->has_framebuffer = 1;
457*5f74217cSAbdelkader Boudih 			break;
458*5f74217cSAbdelkader Boudih 		}
459*5f74217cSAbdelkader Boudih 
460*5f74217cSAbdelkader Boudih 		case CB_TAG_GPIO: {
461*5f74217cSAbdelkader Boudih 			struct cb_gpios *gpios = (struct cb_gpios *)rec;
462*5f74217cSAbdelkader Boudih 			uint32_t i, count;
463*5f74217cSAbdelkader Boudih 
464*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*gpios))
465*5f74217cSAbdelkader Boudih 				break;
466*5f74217cSAbdelkader Boudih 			count = gpios->count;
467*5f74217cSAbdelkader Boudih 			if (count > CB_MAX_GPIOS)
468*5f74217cSAbdelkader Boudih 				count = CB_MAX_GPIOS;
469*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*gpios) +
470*5f74217cSAbdelkader Boudih 			    count * sizeof(struct cb_gpio))
471*5f74217cSAbdelkader Boudih 				break;
472*5f74217cSAbdelkader Boudih 			for (i = 0; i < count; i++)
473*5f74217cSAbdelkader Boudih 				sc->gpios[i] = gpios->entries[i];
474*5f74217cSAbdelkader Boudih 			sc->gpio_count = count;
475*5f74217cSAbdelkader Boudih 			break;
476*5f74217cSAbdelkader Boudih 		}
477*5f74217cSAbdelkader Boudih 
478*5f74217cSAbdelkader Boudih 		case CB_TAG_TPM_PPI_HANDOFF: {
479*5f74217cSAbdelkader Boudih 			struct cb_tpm_ppi *tpm = (struct cb_tpm_ppi *)rec;
480*5f74217cSAbdelkader Boudih 
481*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*tpm))
482*5f74217cSAbdelkader Boudih 				break;
483*5f74217cSAbdelkader Boudih 			sc->tpm_ppi_addr = tpm->ppi_address;
484*5f74217cSAbdelkader Boudih 			sc->tpm_version = tpm->tpm_version;
485*5f74217cSAbdelkader Boudih 			sc->has_tpm = 1;
486*5f74217cSAbdelkader Boudih 			break;
487*5f74217cSAbdelkader Boudih 		}
488*5f74217cSAbdelkader Boudih 
489*5f74217cSAbdelkader Boudih 		case CB_TAG_TIMESTAMPS: {
490*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
491*5f74217cSAbdelkader Boudih 
492*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
493*5f74217cSAbdelkader Boudih 				break;
494*5f74217cSAbdelkader Boudih 			sc->timestamps_paddr = (vm_paddr_t)ref->cbmem_addr;
495*5f74217cSAbdelkader Boudih 			sc->has_timestamps = 1;
496*5f74217cSAbdelkader Boudih 			break;
497*5f74217cSAbdelkader Boudih 		}
498*5f74217cSAbdelkader Boudih 
499*5f74217cSAbdelkader Boudih 		case CB_TAG_ACPI_GNVS: {
500*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
501*5f74217cSAbdelkader Boudih 
502*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
503*5f74217cSAbdelkader Boudih 				break;
504*5f74217cSAbdelkader Boudih 			sc->acpi_gnvs_paddr = (vm_paddr_t)ref->cbmem_addr;
505*5f74217cSAbdelkader Boudih 			sc->has_acpi_gnvs = 1;
506*5f74217cSAbdelkader Boudih 			break;
507*5f74217cSAbdelkader Boudih 		}
508*5f74217cSAbdelkader Boudih 
509*5f74217cSAbdelkader Boudih 		case CB_TAG_ACPI_CNVS: {
510*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
511*5f74217cSAbdelkader Boudih 
512*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
513*5f74217cSAbdelkader Boudih 				break;
514*5f74217cSAbdelkader Boudih 			sc->acpi_cnvs_paddr = (vm_paddr_t)ref->cbmem_addr;
515*5f74217cSAbdelkader Boudih 			sc->has_acpi_cnvs = 1;
516*5f74217cSAbdelkader Boudih 			break;
517*5f74217cSAbdelkader Boudih 		}
518*5f74217cSAbdelkader Boudih 
519*5f74217cSAbdelkader Boudih 		case CB_TAG_VPD: {
520*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
521*5f74217cSAbdelkader Boudih 
522*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
523*5f74217cSAbdelkader Boudih 				break;
524*5f74217cSAbdelkader Boudih 			sc->vpd_paddr = (vm_paddr_t)ref->cbmem_addr;
525*5f74217cSAbdelkader Boudih 			sc->has_vpd = 1;
526*5f74217cSAbdelkader Boudih 			break;
527*5f74217cSAbdelkader Boudih 		}
528*5f74217cSAbdelkader Boudih 
529*5f74217cSAbdelkader Boudih 		case CB_TAG_WIFI_CALIBRATION: {
530*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
531*5f74217cSAbdelkader Boudih 
532*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
533*5f74217cSAbdelkader Boudih 				break;
534*5f74217cSAbdelkader Boudih 			sc->wifi_cal_paddr = (vm_paddr_t)ref->cbmem_addr;
535*5f74217cSAbdelkader Boudih 			sc->has_wifi_cal = 1;
536*5f74217cSAbdelkader Boudih 			break;
537*5f74217cSAbdelkader Boudih 		}
538*5f74217cSAbdelkader Boudih 
539*5f74217cSAbdelkader Boudih 		case CB_TAG_FMAP: {
540*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
541*5f74217cSAbdelkader Boudih 
542*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
543*5f74217cSAbdelkader Boudih 				break;
544*5f74217cSAbdelkader Boudih 			sc->fmap_paddr = (vm_paddr_t)ref->cbmem_addr;
545*5f74217cSAbdelkader Boudih 			sc->has_fmap = 1;
546*5f74217cSAbdelkader Boudih 			break;
547*5f74217cSAbdelkader Boudih 		}
548*5f74217cSAbdelkader Boudih 
549*5f74217cSAbdelkader Boudih 		case CB_TAG_VBOOT_WORKBUF: {
550*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
551*5f74217cSAbdelkader Boudih 
552*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
553*5f74217cSAbdelkader Boudih 				break;
554*5f74217cSAbdelkader Boudih 			sc->vboot_workbuf_paddr = (vm_paddr_t)ref->cbmem_addr;
555*5f74217cSAbdelkader Boudih 			sc->has_vboot_workbuf = 1;
556*5f74217cSAbdelkader Boudih 			break;
557*5f74217cSAbdelkader Boudih 		}
558*5f74217cSAbdelkader Boudih 
559*5f74217cSAbdelkader Boudih 		case CB_TAG_TYPE_C_INFO: {
560*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
561*5f74217cSAbdelkader Boudih 
562*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
563*5f74217cSAbdelkader Boudih 				break;
564*5f74217cSAbdelkader Boudih 			sc->type_c_info_paddr = (vm_paddr_t)ref->cbmem_addr;
565*5f74217cSAbdelkader Boudih 			sc->has_type_c_info = 1;
566*5f74217cSAbdelkader Boudih 			break;
567*5f74217cSAbdelkader Boudih 		}
568*5f74217cSAbdelkader Boudih 
569*5f74217cSAbdelkader Boudih 		case CB_TAG_ROOT_BRIDGE_INFO: {
570*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
571*5f74217cSAbdelkader Boudih 
572*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
573*5f74217cSAbdelkader Boudih 				break;
574*5f74217cSAbdelkader Boudih 			sc->root_bridge_info_paddr =
575*5f74217cSAbdelkader Boudih 			    (vm_paddr_t)ref->cbmem_addr;
576*5f74217cSAbdelkader Boudih 			sc->has_root_bridge_info = 1;
577*5f74217cSAbdelkader Boudih 			break;
578*5f74217cSAbdelkader Boudih 		}
579*5f74217cSAbdelkader Boudih 
580*5f74217cSAbdelkader Boudih 		case CB_TAG_TPM_CB_LOG: {
581*5f74217cSAbdelkader Boudih 			struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
582*5f74217cSAbdelkader Boudih 
583*5f74217cSAbdelkader Boudih 			if (rec_size < sizeof(*ref))
584*5f74217cSAbdelkader Boudih 				break;
585*5f74217cSAbdelkader Boudih 			sc->tpm_log_paddr = (vm_paddr_t)ref->cbmem_addr;
586*5f74217cSAbdelkader Boudih 			sc->has_tpm_log = 1;
587*5f74217cSAbdelkader Boudih 			break;
588*5f74217cSAbdelkader Boudih 		}
589*5f74217cSAbdelkader Boudih 
590*5f74217cSAbdelkader Boudih 		case CB_TAG_SMMSTOREV2: {
591*5f74217cSAbdelkader Boudih 			struct cb_smmstorev2 *smm =
592*5f74217cSAbdelkader Boudih 			    (struct cb_smmstorev2 *)rec;
593*5f74217cSAbdelkader Boudih 
594*5f74217cSAbdelkader Boudih 			if (rec_size < CB_SMMSTOREV2_BASE_SIZE)
595*5f74217cSAbdelkader Boudih 				break;
596*5f74217cSAbdelkader Boudih 			sc->smmstore_num_blocks = smm->num_blocks;
597*5f74217cSAbdelkader Boudih 			sc->smmstore_block_size = smm->block_size;
598*5f74217cSAbdelkader Boudih 			sc->smmstore_com_buffer = smm->com_buffer;
599*5f74217cSAbdelkader Boudih 			sc->smmstore_apm_cmd = smm->apm_cmd;
600*5f74217cSAbdelkader Boudih 			/* 64-bit mmap_addr only present in newer coreboot */
601*5f74217cSAbdelkader Boudih 			if (rec_size >= sizeof(*smm))
602*5f74217cSAbdelkader Boudih 				sc->smmstore_mmap_addr = smm->mmap_addr;
603*5f74217cSAbdelkader Boudih 			else
604*5f74217cSAbdelkader Boudih 				sc->smmstore_mmap_addr =
605*5f74217cSAbdelkader Boudih 				    (uint64_t)smm->mmap_addr_lo;
606*5f74217cSAbdelkader Boudih 			sc->has_smmstore = 1;
607*5f74217cSAbdelkader Boudih 			break;
608*5f74217cSAbdelkader Boudih 		}
609*5f74217cSAbdelkader Boudih 
610*5f74217cSAbdelkader Boudih 		default:
611*5f74217cSAbdelkader Boudih 			break;
612*5f74217cSAbdelkader Boudih 		}
613*5f74217cSAbdelkader Boudih 
614*5f74217cSAbdelkader Boudih 		entry += rec_size;
615*5f74217cSAbdelkader Boudih 	}
616*5f74217cSAbdelkader Boudih }
617*5f74217cSAbdelkader Boudih 
618*5f74217cSAbdelkader Boudih /*
619*5f74217cSAbdelkader Boudih  * Table-driven sysctl registration.
620*5f74217cSAbdelkader Boudih  *
621*5f74217cSAbdelkader Boudih  * Each leaf descriptor specifies the parent node, name, type, data offset
622*5f74217cSAbdelkader Boudih  * into softc, a guard flag offset (or -1 for unconditional), and flags.
623*5f74217cSAbdelkader Boudih  * Nodes that group related leaves are indexed by cb_sysctl_node.
624*5f74217cSAbdelkader Boudih  */
625*5f74217cSAbdelkader Boudih 
626*5f74217cSAbdelkader Boudih /* Node indices for parent selection */
627*5f74217cSAbdelkader Boudih enum cb_sysctl_node {
628*5f74217cSAbdelkader Boudih 	CB_NODE_ROOT = 0,
629*5f74217cSAbdelkader Boudih 	CB_NODE_MAINBOARD,
630*5f74217cSAbdelkader Boudih 	CB_NODE_SERIAL,
631*5f74217cSAbdelkader Boudih 	CB_NODE_BOARD,
632*5f74217cSAbdelkader Boudih 	CB_NODE_BOOT_MEDIA,
633*5f74217cSAbdelkader Boudih 	CB_NODE_SPI_FLASH,
634*5f74217cSAbdelkader Boudih 	CB_NODE_FRAMEBUFFER,
635*5f74217cSAbdelkader Boudih 	CB_NODE_TPM,
636*5f74217cSAbdelkader Boudih 	CB_NODE_SMMSTORE,
637*5f74217cSAbdelkader Boudih 	CB_NODE_CBMEM_REFS,
638*5f74217cSAbdelkader Boudih 	CB_NODE_COUNT
639*5f74217cSAbdelkader Boudih };
640*5f74217cSAbdelkader Boudih 
641*5f74217cSAbdelkader Boudih /* Sysctl value type discriminator */
642*5f74217cSAbdelkader Boudih enum cb_sysctl_type {
643*5f74217cSAbdelkader Boudih 	CB_SYSCTL_U8,
644*5f74217cSAbdelkader Boudih 	CB_SYSCTL_U16,
645*5f74217cSAbdelkader Boudih 	CB_SYSCTL_U32,
646*5f74217cSAbdelkader Boudih 	CB_SYSCTL_S32,
647*5f74217cSAbdelkader Boudih 	CB_SYSCTL_U64,
648*5f74217cSAbdelkader Boudih 	CB_SYSCTL_ULONG,
649*5f74217cSAbdelkader Boudih 	CB_SYSCTL_STRING,
650*5f74217cSAbdelkader Boudih };
651*5f74217cSAbdelkader Boudih 
652*5f74217cSAbdelkader Boudih /*
653*5f74217cSAbdelkader Boudih  * Guard mode: how to decide whether a leaf should be registered.
654*5f74217cSAbdelkader Boudih  *   STR_NONEMPTY: check that the char[] at guard_off is non-empty
655*5f74217cSAbdelkader Boudih  *   FLAG_SET:     check that the int at guard_off is non-zero
656*5f74217cSAbdelkader Boudih  *   ALWAYS:       unconditional (guard_off ignored)
657*5f74217cSAbdelkader Boudih  */
658*5f74217cSAbdelkader Boudih enum cb_sysctl_guard {
659*5f74217cSAbdelkader Boudih 	CB_GUARD_ALWAYS,
660*5f74217cSAbdelkader Boudih 	CB_GUARD_FLAG_SET,
661*5f74217cSAbdelkader Boudih 	CB_GUARD_STR_NONEMPTY,
662*5f74217cSAbdelkader Boudih };
663*5f74217cSAbdelkader Boudih 
664*5f74217cSAbdelkader Boudih struct cb_sysctl_node_desc {
665*5f74217cSAbdelkader Boudih 	enum cb_sysctl_node	id;
666*5f74217cSAbdelkader Boudih 	enum cb_sysctl_node	parent;
667*5f74217cSAbdelkader Boudih 	const char		*name;
668*5f74217cSAbdelkader Boudih 	const char		*desc;
669*5f74217cSAbdelkader Boudih };
670*5f74217cSAbdelkader Boudih 
671*5f74217cSAbdelkader Boudih struct cb_sysctl_leaf {
672*5f74217cSAbdelkader Boudih 	enum cb_sysctl_node	parent;
673*5f74217cSAbdelkader Boudih 	const char		*name;
674*5f74217cSAbdelkader Boudih 	enum cb_sysctl_type	type;
675*5f74217cSAbdelkader Boudih 	size_t			data_off;
676*5f74217cSAbdelkader Boudih 	enum cb_sysctl_guard	guard;
677*5f74217cSAbdelkader Boudih 	size_t			guard_off;
678*5f74217cSAbdelkader Boudih 	int			flags;
679*5f74217cSAbdelkader Boudih 	const char		*desc;
680*5f74217cSAbdelkader Boudih };
681*5f74217cSAbdelkader Boudih 
682*5f74217cSAbdelkader Boudih /* Helper macros for field offset within coreboot_softc */
683*5f74217cSAbdelkader Boudih #define SC_OFF(field)	offsetof(struct coreboot_softc, field)
684*5f74217cSAbdelkader Boudih 
685*5f74217cSAbdelkader Boudih static const struct cb_sysctl_node_desc cb_nodes[] = {
686*5f74217cSAbdelkader Boudih 	{ CB_NODE_MAINBOARD,	CB_NODE_ROOT,	"mainboard",
687*5f74217cSAbdelkader Boudih 	    "Mainboard information" },
688*5f74217cSAbdelkader Boudih 	{ CB_NODE_SERIAL,	CB_NODE_ROOT,	"serial",
689*5f74217cSAbdelkader Boudih 	    "Serial port" },
690*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOARD,	CB_NODE_ROOT,	"board",
691*5f74217cSAbdelkader Boudih 	    "Board identification" },
692*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOOT_MEDIA,	CB_NODE_ROOT,	"boot_media",
693*5f74217cSAbdelkader Boudih 	    "Boot media parameters" },
694*5f74217cSAbdelkader Boudih 	{ CB_NODE_SPI_FLASH,	CB_NODE_ROOT,	"spi_flash",
695*5f74217cSAbdelkader Boudih 	    "SPI flash parameters" },
696*5f74217cSAbdelkader Boudih 	{ CB_NODE_FRAMEBUFFER,	CB_NODE_ROOT,	"framebuffer",
697*5f74217cSAbdelkader Boudih 	    "Framebuffer information" },
698*5f74217cSAbdelkader Boudih 	{ CB_NODE_TPM,		CB_NODE_ROOT,	"tpm",
699*5f74217cSAbdelkader Boudih 	    "TPM information" },
700*5f74217cSAbdelkader Boudih 	{ CB_NODE_SMMSTORE,	CB_NODE_ROOT,	"smmstore",
701*5f74217cSAbdelkader Boudih 	    "SMMSTORE v2 configuration" },
702*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS,	CB_NODE_ROOT,	"cbmem_refs",
703*5f74217cSAbdelkader Boudih 	    "Additional CBMEM reference addresses" },
704*5f74217cSAbdelkader Boudih };
705*5f74217cSAbdelkader Boudih 
706*5f74217cSAbdelkader Boudih static const struct cb_sysctl_leaf cb_leaves[] = {
707*5f74217cSAbdelkader Boudih 	/* Root-level strings (guarded by non-empty string) */
708*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "version", CB_SYSCTL_STRING,
709*5f74217cSAbdelkader Boudih 	    SC_OFF(version), CB_GUARD_STR_NONEMPTY, SC_OFF(version),
710*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Firmware version" },
711*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "build", CB_SYSCTL_STRING,
712*5f74217cSAbdelkader Boudih 	    SC_OFF(build), CB_GUARD_STR_NONEMPTY, SC_OFF(build),
713*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Build date" },
714*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "compile_time", CB_SYSCTL_STRING,
715*5f74217cSAbdelkader Boudih 	    SC_OFF(compile_time), CB_GUARD_STR_NONEMPTY, SC_OFF(compile_time),
716*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Firmware compile time" },
717*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "compiler", CB_SYSCTL_STRING,
718*5f74217cSAbdelkader Boudih 	    SC_OFF(compiler), CB_GUARD_STR_NONEMPTY, SC_OFF(compiler),
719*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Compiler info" },
720*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "extra_version", CB_SYSCTL_STRING,
721*5f74217cSAbdelkader Boudih 	    SC_OFF(extra_version), CB_GUARD_STR_NONEMPTY, SC_OFF(extra_version),
722*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Extra version info" },
723*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "serialno", CB_SYSCTL_STRING,
724*5f74217cSAbdelkader Boudih 	    SC_OFF(serialno), CB_GUARD_STR_NONEMPTY, SC_OFF(serialno),
725*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Serial number" },
726*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "platform_blob_version", CB_SYSCTL_STRING,
727*5f74217cSAbdelkader Boudih 	    SC_OFF(platform_blob_version), CB_GUARD_STR_NONEMPTY,
728*5f74217cSAbdelkader Boudih 	    SC_OFF(platform_blob_version),
729*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Platform blob version" },
730*5f74217cSAbdelkader Boudih 
731*5f74217cSAbdelkader Boudih 	/* Root-level scalars */
732*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "version_timestamp", CB_SYSCTL_U32,
733*5f74217cSAbdelkader Boudih 	    SC_OFF(version_timestamp), CB_GUARD_FLAG_SET,
734*5f74217cSAbdelkader Boudih 	    SC_OFF(has_version_timestamp),
735*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Firmware version timestamp" },
736*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "table_addr", CB_SYSCTL_U64,
737*5f74217cSAbdelkader Boudih 	    SC_OFF(table_paddr), CB_GUARD_ALWAYS, 0,
738*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Physical address of coreboot table" },
739*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "table_size", CB_SYSCTL_ULONG,
740*5f74217cSAbdelkader Boudih 	    SC_OFF(table_size), CB_GUARD_ALWAYS, 0,
741*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Total coreboot table size" },
742*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "tsc_freq_khz", CB_SYSCTL_U32,
743*5f74217cSAbdelkader Boudih 	    SC_OFF(tsc_freq_khz), CB_GUARD_FLAG_SET, SC_OFF(has_tsc_info),
744*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "TSC frequency in kHz" },
745*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "pcie_ctrl_base", CB_SYSCTL_U64,
746*5f74217cSAbdelkader Boudih 	    SC_OFF(pcie_ctrl_base), CB_GUARD_FLAG_SET, SC_OFF(has_pcie),
747*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "PCIe controller base address" },
748*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "acpi_rsdp", CB_SYSCTL_U64,
749*5f74217cSAbdelkader Boudih 	    SC_OFF(acpi_rsdp), CB_GUARD_FLAG_SET, SC_OFF(has_acpi_rsdp),
750*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "ACPI RSDP physical address" },
751*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "mmc_early_cmd1_status", CB_SYSCTL_S32,
752*5f74217cSAbdelkader Boudih 	    SC_OFF(mmc_early_cmd1_status), CB_GUARD_FLAG_SET,
753*5f74217cSAbdelkader Boudih 	    SC_OFF(has_mmc_info),
754*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Early eMMC CMD1 status" },
755*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "console_type", CB_SYSCTL_U16,
756*5f74217cSAbdelkader Boudih 	    SC_OFF(console_type), CB_GUARD_FLAG_SET, SC_OFF(has_console_type),
757*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Firmware console type" },
758*5f74217cSAbdelkader Boudih 	{ CB_NODE_ROOT, "timestamps_addr", CB_SYSCTL_U64,
759*5f74217cSAbdelkader Boudih 	    SC_OFF(timestamps_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_timestamps),
760*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Timestamps CBMEM physical address" },
761*5f74217cSAbdelkader Boudih 
762*5f74217cSAbdelkader Boudih 	/* Mainboard children */
763*5f74217cSAbdelkader Boudih 	{ CB_NODE_MAINBOARD, "vendor", CB_SYSCTL_STRING,
764*5f74217cSAbdelkader Boudih 	    SC_OFF(mb_vendor), CB_GUARD_STR_NONEMPTY, SC_OFF(mb_vendor),
765*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Board vendor" },
766*5f74217cSAbdelkader Boudih 	{ CB_NODE_MAINBOARD, "part", CB_SYSCTL_STRING,
767*5f74217cSAbdelkader Boudih 	    SC_OFF(mb_part), CB_GUARD_STR_NONEMPTY, SC_OFF(mb_part),
768*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Board part number" },
769*5f74217cSAbdelkader Boudih 
770*5f74217cSAbdelkader Boudih 	/* Serial children */
771*5f74217cSAbdelkader Boudih 	{ CB_NODE_SERIAL, "baseaddr", CB_SYSCTL_U32,
772*5f74217cSAbdelkader Boudih 	    SC_OFF(serial_baseaddr), CB_GUARD_FLAG_SET, SC_OFF(has_serial),
773*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Base address" },
774*5f74217cSAbdelkader Boudih 	{ CB_NODE_SERIAL, "baud", CB_SYSCTL_U32,
775*5f74217cSAbdelkader Boudih 	    SC_OFF(serial_baud), CB_GUARD_FLAG_SET, SC_OFF(has_serial),
776*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Baud rate" },
777*5f74217cSAbdelkader Boudih 	{ CB_NODE_SERIAL, "regwidth", CB_SYSCTL_U32,
778*5f74217cSAbdelkader Boudih 	    SC_OFF(serial_regwidth), CB_GUARD_FLAG_SET, SC_OFF(has_serial),
779*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Register width" },
780*5f74217cSAbdelkader Boudih 
781*5f74217cSAbdelkader Boudih 	/* Board config children */
782*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOARD, "fw_config", CB_SYSCTL_U64,
783*5f74217cSAbdelkader Boudih 	    SC_OFF(fw_config), CB_GUARD_FLAG_SET, SC_OFF(has_board_config),
784*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Firmware configuration bitmask" },
785*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOARD, "board_id", CB_SYSCTL_U32,
786*5f74217cSAbdelkader Boudih 	    SC_OFF(board_id), CB_GUARD_FLAG_SET, SC_OFF(has_board_config),
787*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Board ID" },
788*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOARD, "ram_code", CB_SYSCTL_U32,
789*5f74217cSAbdelkader Boudih 	    SC_OFF(ram_code), CB_GUARD_FLAG_SET, SC_OFF(has_board_config),
790*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "RAM code" },
791*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOARD, "sku_id", CB_SYSCTL_U32,
792*5f74217cSAbdelkader Boudih 	    SC_OFF(sku_id), CB_GUARD_FLAG_SET, SC_OFF(has_board_config),
793*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "SKU ID" },
794*5f74217cSAbdelkader Boudih 
795*5f74217cSAbdelkader Boudih 	/* Boot media children */
796*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOOT_MEDIA, "fmap_offset", CB_SYSCTL_U64,
797*5f74217cSAbdelkader Boudih 	    SC_OFF(fmap_offset), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media),
798*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "FMAP offset from boot media start" },
799*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOOT_MEDIA, "cbfs_offset", CB_SYSCTL_U64,
800*5f74217cSAbdelkader Boudih 	    SC_OFF(cbfs_offset), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media),
801*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "CBFS offset from boot media start" },
802*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOOT_MEDIA, "cbfs_size", CB_SYSCTL_U64,
803*5f74217cSAbdelkader Boudih 	    SC_OFF(cbfs_size), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media),
804*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "CBFS size in bytes" },
805*5f74217cSAbdelkader Boudih 	{ CB_NODE_BOOT_MEDIA, "size", CB_SYSCTL_U64,
806*5f74217cSAbdelkader Boudih 	    SC_OFF(boot_media_size), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media),
807*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Boot media size in bytes" },
808*5f74217cSAbdelkader Boudih 
809*5f74217cSAbdelkader Boudih 	/* SPI flash children */
810*5f74217cSAbdelkader Boudih 	{ CB_NODE_SPI_FLASH, "size", CB_SYSCTL_U32,
811*5f74217cSAbdelkader Boudih 	    SC_OFF(spi_flash_size), CB_GUARD_FLAG_SET, SC_OFF(has_spi_flash),
812*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Flash size in bytes" },
813*5f74217cSAbdelkader Boudih 	{ CB_NODE_SPI_FLASH, "sector_size", CB_SYSCTL_U32,
814*5f74217cSAbdelkader Boudih 	    SC_OFF(spi_sector_size), CB_GUARD_FLAG_SET, SC_OFF(has_spi_flash),
815*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Sector size in bytes" },
816*5f74217cSAbdelkader Boudih 	{ CB_NODE_SPI_FLASH, "erase_cmd", CB_SYSCTL_U8,
817*5f74217cSAbdelkader Boudih 	    SC_OFF(spi_erase_cmd), CB_GUARD_FLAG_SET, SC_OFF(has_spi_flash),
818*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Erase command byte" },
819*5f74217cSAbdelkader Boudih 
820*5f74217cSAbdelkader Boudih 	/* Framebuffer children */
821*5f74217cSAbdelkader Boudih 	{ CB_NODE_FRAMEBUFFER, "addr", CB_SYSCTL_U64,
822*5f74217cSAbdelkader Boudih 	    SC_OFF(fb_addr), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer),
823*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Physical address" },
824*5f74217cSAbdelkader Boudih 	{ CB_NODE_FRAMEBUFFER, "x_res", CB_SYSCTL_U32,
825*5f74217cSAbdelkader Boudih 	    SC_OFF(fb_x_res), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer),
826*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Horizontal resolution" },
827*5f74217cSAbdelkader Boudih 	{ CB_NODE_FRAMEBUFFER, "y_res", CB_SYSCTL_U32,
828*5f74217cSAbdelkader Boudih 	    SC_OFF(fb_y_res), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer),
829*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Vertical resolution" },
830*5f74217cSAbdelkader Boudih 	{ CB_NODE_FRAMEBUFFER, "bpp", CB_SYSCTL_U8,
831*5f74217cSAbdelkader Boudih 	    SC_OFF(fb_bpp), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer),
832*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Bits per pixel" },
833*5f74217cSAbdelkader Boudih 
834*5f74217cSAbdelkader Boudih 	/* TPM children */
835*5f74217cSAbdelkader Boudih 	{ CB_NODE_TPM, "version", CB_SYSCTL_U8,
836*5f74217cSAbdelkader Boudih 	    SC_OFF(tpm_version), CB_GUARD_FLAG_SET, SC_OFF(has_tpm),
837*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "TPM version (1=1.2, 2=2.0)" },
838*5f74217cSAbdelkader Boudih 	{ CB_NODE_TPM, "ppi_addr", CB_SYSCTL_U32,
839*5f74217cSAbdelkader Boudih 	    SC_OFF(tpm_ppi_addr), CB_GUARD_FLAG_SET, SC_OFF(has_tpm),
840*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "PPI address" },
841*5f74217cSAbdelkader Boudih 	{ CB_NODE_TPM, "cblog_addr", CB_SYSCTL_U64,
842*5f74217cSAbdelkader Boudih 	    SC_OFF(tpm_log_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_tpm_log),
843*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "TPM event log physical address" },
844*5f74217cSAbdelkader Boudih 
845*5f74217cSAbdelkader Boudih 	/* SMMSTORE children */
846*5f74217cSAbdelkader Boudih 	{ CB_NODE_SMMSTORE, "num_blocks", CB_SYSCTL_U32,
847*5f74217cSAbdelkader Boudih 	    SC_OFF(smmstore_num_blocks), CB_GUARD_FLAG_SET,
848*5f74217cSAbdelkader Boudih 	    SC_OFF(has_smmstore),
849*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Number of blocks" },
850*5f74217cSAbdelkader Boudih 	{ CB_NODE_SMMSTORE, "block_size", CB_SYSCTL_U32,
851*5f74217cSAbdelkader Boudih 	    SC_OFF(smmstore_block_size), CB_GUARD_FLAG_SET,
852*5f74217cSAbdelkader Boudih 	    SC_OFF(has_smmstore),
853*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Block size in bytes" },
854*5f74217cSAbdelkader Boudih 	{ CB_NODE_SMMSTORE, "mmap_addr", CB_SYSCTL_U64,
855*5f74217cSAbdelkader Boudih 	    SC_OFF(smmstore_mmap_addr), CB_GUARD_FLAG_SET,
856*5f74217cSAbdelkader Boudih 	    SC_OFF(has_smmstore),
857*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Memory-mapped address" },
858*5f74217cSAbdelkader Boudih 	{ CB_NODE_SMMSTORE, "com_buffer", CB_SYSCTL_U32,
859*5f74217cSAbdelkader Boudih 	    SC_OFF(smmstore_com_buffer), CB_GUARD_FLAG_SET,
860*5f74217cSAbdelkader Boudih 	    SC_OFF(has_smmstore),
861*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Communication buffer address" },
862*5f74217cSAbdelkader Boudih 	{ CB_NODE_SMMSTORE, "apm_cmd", CB_SYSCTL_U8,
863*5f74217cSAbdelkader Boudih 	    SC_OFF(smmstore_apm_cmd), CB_GUARD_FLAG_SET,
864*5f74217cSAbdelkader Boudih 	    SC_OFF(has_smmstore),
865*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "APM command byte" },
866*5f74217cSAbdelkader Boudih 
867*5f74217cSAbdelkader Boudih 	/* CBMEM reference addresses */
868*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "acpi_gnvs", CB_SYSCTL_U64,
869*5f74217cSAbdelkader Boudih 	    SC_OFF(acpi_gnvs_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_acpi_gnvs),
870*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "ACPI GNVS CBMEM physical address" },
871*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "acpi_cnvs", CB_SYSCTL_U64,
872*5f74217cSAbdelkader Boudih 	    SC_OFF(acpi_cnvs_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_acpi_cnvs),
873*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "ACPI CNVS CBMEM physical address" },
874*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "vpd", CB_SYSCTL_U64,
875*5f74217cSAbdelkader Boudih 	    SC_OFF(vpd_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_vpd),
876*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "VPD CBMEM physical address" },
877*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "wifi_calibration", CB_SYSCTL_U64,
878*5f74217cSAbdelkader Boudih 	    SC_OFF(wifi_cal_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_wifi_cal),
879*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "WiFi calibration CBMEM physical address" },
880*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "fmap", CB_SYSCTL_U64,
881*5f74217cSAbdelkader Boudih 	    SC_OFF(fmap_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_fmap),
882*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "FMAP CBMEM physical address" },
883*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "vboot_workbuf", CB_SYSCTL_U64,
884*5f74217cSAbdelkader Boudih 	    SC_OFF(vboot_workbuf_paddr), CB_GUARD_FLAG_SET,
885*5f74217cSAbdelkader Boudih 	    SC_OFF(has_vboot_workbuf),
886*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Vboot work buffer CBMEM physical address" },
887*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "type_c_info", CB_SYSCTL_U64,
888*5f74217cSAbdelkader Boudih 	    SC_OFF(type_c_info_paddr), CB_GUARD_FLAG_SET,
889*5f74217cSAbdelkader Boudih 	    SC_OFF(has_type_c_info),
890*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Type-C info CBMEM physical address" },
891*5f74217cSAbdelkader Boudih 	{ CB_NODE_CBMEM_REFS, "root_bridge_info", CB_SYSCTL_U64,
892*5f74217cSAbdelkader Boudih 	    SC_OFF(root_bridge_info_paddr), CB_GUARD_FLAG_SET,
893*5f74217cSAbdelkader Boudih 	    SC_OFF(has_root_bridge_info),
894*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD, "Root bridge info CBMEM physical address" },
895*5f74217cSAbdelkader Boudih };
896*5f74217cSAbdelkader Boudih 
897*5f74217cSAbdelkader Boudih /*
898*5f74217cSAbdelkader Boudih  * Check whether a leaf's guard condition is satisfied.
899*5f74217cSAbdelkader Boudih  */
900*5f74217cSAbdelkader Boudih static int
cb_sysctl_guard_check(const struct cb_sysctl_leaf * leaf,const struct coreboot_softc * sc)901*5f74217cSAbdelkader Boudih cb_sysctl_guard_check(const struct cb_sysctl_leaf *leaf,
902*5f74217cSAbdelkader Boudih     const struct coreboot_softc *sc)
903*5f74217cSAbdelkader Boudih {
904*5f74217cSAbdelkader Boudih 	const char *base;
905*5f74217cSAbdelkader Boudih 
906*5f74217cSAbdelkader Boudih 	base = (const char *)sc;
907*5f74217cSAbdelkader Boudih 	switch (leaf->guard) {
908*5f74217cSAbdelkader Boudih 	case CB_GUARD_ALWAYS:
909*5f74217cSAbdelkader Boudih 		return (1);
910*5f74217cSAbdelkader Boudih 	case CB_GUARD_FLAG_SET:
911*5f74217cSAbdelkader Boudih 		return (*(const int *)(base + leaf->guard_off) != 0);
912*5f74217cSAbdelkader Boudih 	case CB_GUARD_STR_NONEMPTY:
913*5f74217cSAbdelkader Boudih 		return (*(base + leaf->guard_off) != '\0');
914*5f74217cSAbdelkader Boudih 	}
915*5f74217cSAbdelkader Boudih 	return (0);
916*5f74217cSAbdelkader Boudih }
917*5f74217cSAbdelkader Boudih 
918*5f74217cSAbdelkader Boudih /*
919*5f74217cSAbdelkader Boudih  * Type-to-handler mapping for sysctl_add_oid().
920*5f74217cSAbdelkader Boudih  * Mirrors the SYSCTL_ADD_* macros but avoids their CTASSERT on flags.
921*5f74217cSAbdelkader Boudih  */
922*5f74217cSAbdelkader Boudih static const struct {
923*5f74217cSAbdelkader Boudih 	int		ctltype;
924*5f74217cSAbdelkader Boudih 	int		(*handler)(SYSCTL_HANDLER_ARGS);
925*5f74217cSAbdelkader Boudih 	const char	*fmt;
926*5f74217cSAbdelkader Boudih } cb_sysctl_types[] = {
927*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_U8]     = { CTLTYPE_U8,	sysctl_handle_8,	"CU" },
928*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_U16]    = { CTLTYPE_U16,	sysctl_handle_16,	"SU" },
929*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_U32]    = { CTLTYPE_U32,	sysctl_handle_32,	"IU" },
930*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_S32]    = { CTLTYPE_S32,	sysctl_handle_32,	"I" },
931*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_U64]    = { CTLTYPE_U64,	sysctl_handle_64,	"QU" },
932*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_ULONG]  = { CTLTYPE_ULONG,	sysctl_handle_long,	"LU" },
933*5f74217cSAbdelkader Boudih 	[CB_SYSCTL_STRING] = { CTLTYPE_STRING,	sysctl_handle_string,	"A" },
934*5f74217cSAbdelkader Boudih };
935*5f74217cSAbdelkader Boudih 
936*5f74217cSAbdelkader Boudih /*
937*5f74217cSAbdelkader Boudih  * Add a single sysctl leaf under the given parent OID.
938*5f74217cSAbdelkader Boudih  */
939*5f74217cSAbdelkader Boudih static void
cb_sysctl_add_leaf(struct sysctl_ctx_list * ctx,struct sysctl_oid * parent,const struct cb_sysctl_leaf * leaf,struct coreboot_softc * sc)940*5f74217cSAbdelkader Boudih cb_sysctl_add_leaf(struct sysctl_ctx_list *ctx, struct sysctl_oid *parent,
941*5f74217cSAbdelkader Boudih     const struct cb_sysctl_leaf *leaf, struct coreboot_softc *sc)
942*5f74217cSAbdelkader Boudih {
943*5f74217cSAbdelkader Boudih 	void *ptr;
944*5f74217cSAbdelkader Boudih 
945*5f74217cSAbdelkader Boudih 	ptr = (char *)sc + leaf->data_off;
946*5f74217cSAbdelkader Boudih 
947*5f74217cSAbdelkader Boudih 	sysctl_add_oid(ctx, SYSCTL_CHILDREN(parent), OID_AUTO,
948*5f74217cSAbdelkader Boudih 	    leaf->name,
949*5f74217cSAbdelkader Boudih 	    cb_sysctl_types[leaf->type].ctltype | CTLFLAG_MPSAFE | leaf->flags,
950*5f74217cSAbdelkader Boudih 	    ptr, 0,
951*5f74217cSAbdelkader Boudih 	    cb_sysctl_types[leaf->type].handler,
952*5f74217cSAbdelkader Boudih 	    cb_sysctl_types[leaf->type].fmt,
953*5f74217cSAbdelkader Boudih 	    __DESCR(leaf->desc), NULL);
954*5f74217cSAbdelkader Boudih }
955*5f74217cSAbdelkader Boudih 
956*5f74217cSAbdelkader Boudih /*
957*5f74217cSAbdelkader Boudih  * Register the sysctl tree under hw.coreboot.*
958*5f74217cSAbdelkader Boudih  *
959*5f74217cSAbdelkader Boudih  * Static leaves and nodes are driven by the cb_leaves[] and cb_nodes[]
960*5f74217cSAbdelkader Boudih  * tables.  Dynamic entries (CBMEM, MAC, GPIO) that require loops over
961*5f74217cSAbdelkader Boudih  * runtime-determined counts are handled explicitly below the table loop.
962*5f74217cSAbdelkader Boudih  */
963*5f74217cSAbdelkader Boudih static void
coreboot_register_sysctls(struct coreboot_softc * sc)964*5f74217cSAbdelkader Boudih coreboot_register_sysctls(struct coreboot_softc *sc)
965*5f74217cSAbdelkader Boudih {
966*5f74217cSAbdelkader Boudih 	struct sysctl_oid *nodes[CB_NODE_COUNT];
967*5f74217cSAbdelkader Boudih 	struct sysctl_oid *oid_cbmem, *oid_entry;
968*5f74217cSAbdelkader Boudih 	struct sysctl_oid *oid_mac, *oid_gpio, *oid_pin;
969*5f74217cSAbdelkader Boudih 	char numstr[8];
970*5f74217cSAbdelkader Boudih 	uint32_t i;
971*5f74217cSAbdelkader Boudih 	int any_cbref;
972*5f74217cSAbdelkader Boudih 
973*5f74217cSAbdelkader Boudih 	sysctl_ctx_init(&sc->sysctl_ctx);
974*5f74217cSAbdelkader Boudih 	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
975*5f74217cSAbdelkader Boudih 	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "coreboot",
976*5f74217cSAbdelkader Boudih 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "coreboot firmware information");
977*5f74217cSAbdelkader Boudih 
978*5f74217cSAbdelkader Boudih 	if (sc->sysctl_tree == NULL)
979*5f74217cSAbdelkader Boudih 		return;
980*5f74217cSAbdelkader Boudih 
981*5f74217cSAbdelkader Boudih 	memset(nodes, 0, sizeof(nodes));
982*5f74217cSAbdelkader Boudih 	nodes[CB_NODE_ROOT] = sc->sysctl_tree;
983*5f74217cSAbdelkader Boudih 
984*5f74217cSAbdelkader Boudih 	SYSCTL_ADD_INT(&sc->sysctl_ctx,
985*5f74217cSAbdelkader Boudih 	    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "debug",
986*5f74217cSAbdelkader Boudih 	    CTLFLAG_RW, &coreboot_debug, 0,
987*5f74217cSAbdelkader Boudih 	    "Enable verbose coreboot diagnostics");
988*5f74217cSAbdelkader Boudih 
989*5f74217cSAbdelkader Boudih 	/*
990*5f74217cSAbdelkader Boudih 	 * Create intermediate nodes on demand.
991*5f74217cSAbdelkader Boudih 	 *
992*5f74217cSAbdelkader Boudih 	 * The mainboard node is special: it appears when either vendor or
993*5f74217cSAbdelkader Boudih 	 * part is present.  The TPM node appears when has_tpm or has_tpm_log
994*5f74217cSAbdelkader Boudih 	 * is set.  The cbmem_refs node appears when any of its children
995*5f74217cSAbdelkader Boudih 	 * would be registered.  All other nodes are gated by the guard
996*5f74217cSAbdelkader Boudih 	 * flags on their children (a node is created the first time a child
997*5f74217cSAbdelkader Boudih 	 * needs it).
998*5f74217cSAbdelkader Boudih 	 */
999*5f74217cSAbdelkader Boudih 
1000*5f74217cSAbdelkader Boudih 	/* Pre-create mainboard node if either string is populated */
1001*5f74217cSAbdelkader Boudih 	if (sc->mb_vendor[0] != '\0' || sc->mb_part[0] != '\0')
1002*5f74217cSAbdelkader Boudih 		nodes[CB_NODE_MAINBOARD] = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1003*5f74217cSAbdelkader Boudih 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "mainboard",
1004*5f74217cSAbdelkader Boudih 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Mainboard information");
1005*5f74217cSAbdelkader Boudih 
1006*5f74217cSAbdelkader Boudih 	/* TPM node appears for has_tpm OR has_tpm_log */
1007*5f74217cSAbdelkader Boudih 	if (sc->has_tpm || sc->has_tpm_log)
1008*5f74217cSAbdelkader Boudih 		nodes[CB_NODE_TPM] = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1009*5f74217cSAbdelkader Boudih 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "tpm",
1010*5f74217cSAbdelkader Boudih 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "TPM information");
1011*5f74217cSAbdelkader Boudih 
1012*5f74217cSAbdelkader Boudih 	/* cbmem_refs node: created if any ref address is present */
1013*5f74217cSAbdelkader Boudih 	any_cbref = sc->has_acpi_gnvs || sc->has_acpi_cnvs || sc->has_vpd ||
1014*5f74217cSAbdelkader Boudih 	    sc->has_wifi_cal || sc->has_fmap || sc->has_vboot_workbuf ||
1015*5f74217cSAbdelkader Boudih 	    sc->has_type_c_info || sc->has_root_bridge_info;
1016*5f74217cSAbdelkader Boudih 	if (any_cbref)
1017*5f74217cSAbdelkader Boudih 		nodes[CB_NODE_CBMEM_REFS] = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1018*5f74217cSAbdelkader Boudih 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "cbmem_refs",
1019*5f74217cSAbdelkader Boudih 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1020*5f74217cSAbdelkader Boudih 		    "Additional CBMEM reference addresses");
1021*5f74217cSAbdelkader Boudih 
1022*5f74217cSAbdelkader Boudih 	/* Walk the leaf table and register matching entries */
1023*5f74217cSAbdelkader Boudih 	for (i = 0; i < nitems(cb_leaves); i++) {
1024*5f74217cSAbdelkader Boudih 		const struct cb_sysctl_leaf *leaf = &cb_leaves[i];
1025*5f74217cSAbdelkader Boudih 		enum cb_sysctl_node nid = leaf->parent;
1026*5f74217cSAbdelkader Boudih 
1027*5f74217cSAbdelkader Boudih 		if (!cb_sysctl_guard_check(leaf, sc))
1028*5f74217cSAbdelkader Boudih 			continue;
1029*5f74217cSAbdelkader Boudih 
1030*5f74217cSAbdelkader Boudih 		/* Lazily create the parent node if not yet instantiated */
1031*5f74217cSAbdelkader Boudih 		if (nodes[nid] == NULL) {
1032*5f74217cSAbdelkader Boudih 			const struct cb_sysctl_node_desc *nd;
1033*5f74217cSAbdelkader Boudih 			uint32_t j;
1034*5f74217cSAbdelkader Boudih 
1035*5f74217cSAbdelkader Boudih 			for (j = 0; j < nitems(cb_nodes); j++) {
1036*5f74217cSAbdelkader Boudih 				if (cb_nodes[j].id == nid)
1037*5f74217cSAbdelkader Boudih 					break;
1038*5f74217cSAbdelkader Boudih 			}
1039*5f74217cSAbdelkader Boudih 			if (j >= nitems(cb_nodes))
1040*5f74217cSAbdelkader Boudih 				continue;
1041*5f74217cSAbdelkader Boudih 			nd = &cb_nodes[j];
1042*5f74217cSAbdelkader Boudih 			nodes[nid] = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1043*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(nodes[nd->parent]), OID_AUTO,
1044*5f74217cSAbdelkader Boudih 			    nd->name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1045*5f74217cSAbdelkader Boudih 			    nd->desc);
1046*5f74217cSAbdelkader Boudih 			if (nodes[nid] == NULL)
1047*5f74217cSAbdelkader Boudih 				continue;
1048*5f74217cSAbdelkader Boudih 		}
1049*5f74217cSAbdelkader Boudih 
1050*5f74217cSAbdelkader Boudih 		cb_sysctl_add_leaf(&sc->sysctl_ctx, nodes[nid], leaf, sc);
1051*5f74217cSAbdelkader Boudih 	}
1052*5f74217cSAbdelkader Boudih 
1053*5f74217cSAbdelkader Boudih 	/* --- Dynamic entries that don't fit the static table --- */
1054*5f74217cSAbdelkader Boudih 
1055*5f74217cSAbdelkader Boudih 	/* CBMEM entry enumeration */
1056*5f74217cSAbdelkader Boudih 	if (sc->cbmem_count > 0) {
1057*5f74217cSAbdelkader Boudih 		oid_cbmem = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1058*5f74217cSAbdelkader Boudih 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "cbmem",
1059*5f74217cSAbdelkader Boudih 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "CBMEM entries");
1060*5f74217cSAbdelkader Boudih 
1061*5f74217cSAbdelkader Boudih 		for (i = 0; i < sc->cbmem_count; i++) {
1062*5f74217cSAbdelkader Boudih 			struct cbmem_entry_info *info = &sc->cbmem_entries[i];
1063*5f74217cSAbdelkader Boudih 
1064*5f74217cSAbdelkader Boudih 			snprintf(numstr, sizeof(numstr), "%u", i);
1065*5f74217cSAbdelkader Boudih 			oid_entry = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1066*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_cbmem), OID_AUTO, numstr,
1067*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1068*5f74217cSAbdelkader Boudih 			    "CBMEM entry");
1069*5f74217cSAbdelkader Boudih 
1070*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_STRING(&sc->sysctl_ctx,
1071*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_entry), OID_AUTO, "name",
1072*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, info->name, 0, "Entry name");
1073*5f74217cSAbdelkader Boudih 
1074*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_U32(&sc->sysctl_ctx,
1075*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_entry), OID_AUTO, "id",
1076*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, &info->id, 0, "Entry ID (hex)");
1077*5f74217cSAbdelkader Boudih 
1078*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_U64(&sc->sysctl_ctx,
1079*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_entry), OID_AUTO, "address",
1080*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, (uint64_t *)&info->address, 0,
1081*5f74217cSAbdelkader Boudih 			    "Physical address");
1082*5f74217cSAbdelkader Boudih 
1083*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_U32(&sc->sysctl_ctx,
1084*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_entry), OID_AUTO, "size",
1085*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, &info->size, 0, "Entry size");
1086*5f74217cSAbdelkader Boudih 		}
1087*5f74217cSAbdelkader Boudih 	}
1088*5f74217cSAbdelkader Boudih 
1089*5f74217cSAbdelkader Boudih 	/* Factory MAC addresses */
1090*5f74217cSAbdelkader Boudih 	if (sc->mac_count > 0) {
1091*5f74217cSAbdelkader Boudih 		oid_mac = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1092*5f74217cSAbdelkader Boudih 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "mac",
1093*5f74217cSAbdelkader Boudih 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1094*5f74217cSAbdelkader Boudih 		    "Factory MAC addresses");
1095*5f74217cSAbdelkader Boudih 
1096*5f74217cSAbdelkader Boudih 		for (i = 0; i < sc->mac_count; i++) {
1097*5f74217cSAbdelkader Boudih 			uint8_t *m = sc->macs[i].mac_addr;
1098*5f74217cSAbdelkader Boudih 
1099*5f74217cSAbdelkader Boudih 			snprintf(numstr, sizeof(numstr), "%u", i);
1100*5f74217cSAbdelkader Boudih 			snprintf(sc->mac_strs[i], sizeof(sc->mac_strs[i]),
1101*5f74217cSAbdelkader Boudih 			    "%02x:%02x:%02x:%02x:%02x:%02x",
1102*5f74217cSAbdelkader Boudih 			    m[0], m[1], m[2], m[3], m[4], m[5]);
1103*5f74217cSAbdelkader Boudih 
1104*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_STRING(&sc->sysctl_ctx,
1105*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_mac), OID_AUTO, numstr,
1106*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, sc->mac_strs[i], 0,
1107*5f74217cSAbdelkader Boudih 			    "MAC address");
1108*5f74217cSAbdelkader Boudih 		}
1109*5f74217cSAbdelkader Boudih 	}
1110*5f74217cSAbdelkader Boudih 
1111*5f74217cSAbdelkader Boudih 	/* GPIO pins */
1112*5f74217cSAbdelkader Boudih 	if (sc->gpio_count > 0) {
1113*5f74217cSAbdelkader Boudih 		oid_gpio = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1114*5f74217cSAbdelkader Boudih 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "gpio",
1115*5f74217cSAbdelkader Boudih 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1116*5f74217cSAbdelkader Boudih 		    "GPIO pin states");
1117*5f74217cSAbdelkader Boudih 
1118*5f74217cSAbdelkader Boudih 		for (i = 0; i < sc->gpio_count; i++) {
1119*5f74217cSAbdelkader Boudih 			struct cb_gpio *g = &sc->gpios[i];
1120*5f74217cSAbdelkader Boudih 
1121*5f74217cSAbdelkader Boudih 			snprintf(numstr, sizeof(numstr), "%u", i);
1122*5f74217cSAbdelkader Boudih 			oid_pin = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1123*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_gpio), OID_AUTO, numstr,
1124*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1125*5f74217cSAbdelkader Boudih 			    "GPIO pin");
1126*5f74217cSAbdelkader Boudih 
1127*5f74217cSAbdelkader Boudih 			/* Ensure name is NUL-terminated */
1128*5f74217cSAbdelkader Boudih 			g->name[sizeof(g->name) - 1] = '\0';
1129*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_STRING(&sc->sysctl_ctx,
1130*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_pin), OID_AUTO, "name",
1131*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, g->name, 0, "Pin name");
1132*5f74217cSAbdelkader Boudih 
1133*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_U32(&sc->sysctl_ctx,
1134*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_pin), OID_AUTO, "port",
1135*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, &g->port, 0, "Port number");
1136*5f74217cSAbdelkader Boudih 
1137*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_U32(&sc->sysctl_ctx,
1138*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_pin), OID_AUTO, "value",
1139*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, &g->value, 0, "Pin value");
1140*5f74217cSAbdelkader Boudih 
1141*5f74217cSAbdelkader Boudih 			SYSCTL_ADD_U32(&sc->sysctl_ctx,
1142*5f74217cSAbdelkader Boudih 			    SYSCTL_CHILDREN(oid_pin), OID_AUTO, "polarity",
1143*5f74217cSAbdelkader Boudih 			    CTLFLAG_RD, &g->polarity, 0, "Pin polarity");
1144*5f74217cSAbdelkader Boudih 		}
1145*5f74217cSAbdelkader Boudih 	}
1146*5f74217cSAbdelkader Boudih 
1147*5f74217cSAbdelkader Boudih 	/* Timestamp PROC sysctl */
1148*5f74217cSAbdelkader Boudih 	if (sc->has_timestamps)
1149*5f74217cSAbdelkader Boudih 		coreboot_timestamps_register(sc, sc->sysctl_tree);
1150*5f74217cSAbdelkader Boudih }
1151*5f74217cSAbdelkader Boudih 
1152*5f74217cSAbdelkader Boudih /*
1153*5f74217cSAbdelkader Boudih  * Map and validate a coreboot table at physical address pa.
1154*5f74217cSAbdelkader Boudih  * On success, *vap points to the mapped table and *sizep is the total size.
1155*5f74217cSAbdelkader Boudih  * The caller must pmap_unmapbios(*vap, *sizep) when done.
1156*5f74217cSAbdelkader Boudih  */
1157*5f74217cSAbdelkader Boudih static int
coreboot_map_table(vm_paddr_t pa,void ** vap,vm_size_t * sizep)1158*5f74217cSAbdelkader Boudih coreboot_map_table(vm_paddr_t pa, void **vap, vm_size_t *sizep)
1159*5f74217cSAbdelkader Boudih {
1160*5f74217cSAbdelkader Boudih 	struct cb_header *hdr;
1161*5f74217cSAbdelkader Boudih 	void *va;
1162*5f74217cSAbdelkader Boudih 	vm_size_t map_size;
1163*5f74217cSAbdelkader Boudih 	int error;
1164*5f74217cSAbdelkader Boudih 
1165*5f74217cSAbdelkader Boudih 	va = pmap_mapbios(pa, sizeof(struct cb_header));
1166*5f74217cSAbdelkader Boudih 	if (va == NULL)
1167*5f74217cSAbdelkader Boudih 		return (ENOMEM);
1168*5f74217cSAbdelkader Boudih 
1169*5f74217cSAbdelkader Boudih 	hdr = (struct cb_header *)va;
1170*5f74217cSAbdelkader Boudih 	if (memcmp(hdr->signature, CB_HEADER_SIGNATURE,
1171*5f74217cSAbdelkader Boudih 	    CB_HEADER_SIG_LEN) != 0) {
1172*5f74217cSAbdelkader Boudih 		pmap_unmapbios(va, sizeof(struct cb_header));
1173*5f74217cSAbdelkader Boudih 		return (ENXIO);
1174*5f74217cSAbdelkader Boudih 	}
1175*5f74217cSAbdelkader Boudih 
1176*5f74217cSAbdelkader Boudih 	error = coreboot_sanitize_header(hdr, &map_size);
1177*5f74217cSAbdelkader Boudih 	pmap_unmapbios(va, sizeof(struct cb_header));
1178*5f74217cSAbdelkader Boudih 	if (error != 0)
1179*5f74217cSAbdelkader Boudih 		return (ENXIO);
1180*5f74217cSAbdelkader Boudih 
1181*5f74217cSAbdelkader Boudih 	va = pmap_mapbios(pa, map_size);
1182*5f74217cSAbdelkader Boudih 	if (va == NULL)
1183*5f74217cSAbdelkader Boudih 		return (ENOMEM);
1184*5f74217cSAbdelkader Boudih 
1185*5f74217cSAbdelkader Boudih 	hdr = (struct cb_header *)va;
1186*5f74217cSAbdelkader Boudih 	if (coreboot_validate_header(hdr, map_size) != 0 ||
1187*5f74217cSAbdelkader Boudih 	    coreboot_validate_table(hdr, map_size) != 0) {
1188*5f74217cSAbdelkader Boudih 		pmap_unmapbios(va, map_size);
1189*5f74217cSAbdelkader Boudih 		return (ENXIO);
1190*5f74217cSAbdelkader Boudih 	}
1191*5f74217cSAbdelkader Boudih 
1192*5f74217cSAbdelkader Boudih 	*vap = va;
1193*5f74217cSAbdelkader Boudih 	*sizep = map_size;
1194*5f74217cSAbdelkader Boudih 	return (0);
1195*5f74217cSAbdelkader Boudih }
1196*5f74217cSAbdelkader Boudih 
1197*5f74217cSAbdelkader Boudih /*
1198*5f74217cSAbdelkader Boudih  * Identify: scan low memory for "LBIO" signature and register a child
1199*5f74217cSAbdelkader Boudih  */
1200*5f74217cSAbdelkader Boudih static void
coreboot_identify(driver_t * driver,device_t parent)1201*5f74217cSAbdelkader Boudih coreboot_identify(driver_t *driver, device_t parent)
1202*5f74217cSAbdelkader Boudih {
1203*5f74217cSAbdelkader Boudih 	vm_paddr_t low_addr, real_addr;
1204*5f74217cSAbdelkader Boudih 	struct cb_header *hdr;
1205*5f74217cSAbdelkader Boudih 	uint8_t *entry, *table_end;
1206*5f74217cSAbdelkader Boudih 	struct cb_record *rec;
1207*5f74217cSAbdelkader Boudih 	device_t child;
1208*5f74217cSAbdelkader Boudih 	void *va;
1209*5f74217cSAbdelkader Boudih 	vm_size_t map_size;
1210*5f74217cSAbdelkader Boudih 	int error;
1211*5f74217cSAbdelkader Boudih 
1212*5f74217cSAbdelkader Boudih 	if (!device_is_alive(parent))
1213*5f74217cSAbdelkader Boudih 		return;
1214*5f74217cSAbdelkader Boudih 
1215*5f74217cSAbdelkader Boudih 	if (device_find_child(parent, "coreboot", -1) != NULL)
1216*5f74217cSAbdelkader Boudih 		return;
1217*5f74217cSAbdelkader Boudih 
1218*5f74217cSAbdelkader Boudih 	low_addr = coreboot_scan_region(CB_SCAN_LOW_START, CB_SCAN_LOW_END);
1219*5f74217cSAbdelkader Boudih 	if (low_addr == 0)
1220*5f74217cSAbdelkader Boudih 		return;
1221*5f74217cSAbdelkader Boudih 
1222*5f74217cSAbdelkader Boudih 	va = pmap_mapbios(low_addr, sizeof(struct cb_header));
1223*5f74217cSAbdelkader Boudih 	if (va == NULL)
1224*5f74217cSAbdelkader Boudih 		return;
1225*5f74217cSAbdelkader Boudih 
1226*5f74217cSAbdelkader Boudih 	/* Scan already verified the signature; re-read to get sizes. */
1227*5f74217cSAbdelkader Boudih 	hdr = (struct cb_header *)va;
1228*5f74217cSAbdelkader Boudih 	error = coreboot_sanitize_header(hdr, &map_size);
1229*5f74217cSAbdelkader Boudih 	pmap_unmapbios(va, sizeof(struct cb_header));
1230*5f74217cSAbdelkader Boudih 	if (error != 0)
1231*5f74217cSAbdelkader Boudih 		return;
1232*5f74217cSAbdelkader Boudih 
1233*5f74217cSAbdelkader Boudih 	va = pmap_mapbios(low_addr, map_size);
1234*5f74217cSAbdelkader Boudih 	if (va == NULL)
1235*5f74217cSAbdelkader Boudih 		return;
1236*5f74217cSAbdelkader Boudih 
1237*5f74217cSAbdelkader Boudih 	hdr = (struct cb_header *)va;
1238*5f74217cSAbdelkader Boudih 	if (coreboot_validate_header(hdr, map_size) != 0 ||
1239*5f74217cSAbdelkader Boudih 	    coreboot_validate_table(hdr, map_size) != 0) {
1240*5f74217cSAbdelkader Boudih 		pmap_unmapbios(va, map_size);
1241*5f74217cSAbdelkader Boudih 		return;
1242*5f74217cSAbdelkader Boudih 	}
1243*5f74217cSAbdelkader Boudih 
1244*5f74217cSAbdelkader Boudih 	/* Look for CB_TAG_FORWARD to find the real table in high memory */
1245*5f74217cSAbdelkader Boudih 	real_addr = low_addr;
1246*5f74217cSAbdelkader Boudih 	entry = (uint8_t *)hdr + hdr->header_bytes;
1247*5f74217cSAbdelkader Boudih 	table_end = entry + hdr->table_bytes;
1248*5f74217cSAbdelkader Boudih 	while ((size_t)(table_end - entry) >= sizeof(struct cb_record)) {
1249*5f74217cSAbdelkader Boudih 		size_t rec_size;
1250*5f74217cSAbdelkader Boudih 
1251*5f74217cSAbdelkader Boudih 		rec = (struct cb_record *)entry;
1252*5f74217cSAbdelkader Boudih 		rec_size = rec->size;
1253*5f74217cSAbdelkader Boudih 		if (rec_size < sizeof(struct cb_record))
1254*5f74217cSAbdelkader Boudih 			break;
1255*5f74217cSAbdelkader Boudih 		if (rec_size > (size_t)(table_end - entry))
1256*5f74217cSAbdelkader Boudih 			break;
1257*5f74217cSAbdelkader Boudih 		if (rec->tag == CB_TAG_FORWARD) {
1258*5f74217cSAbdelkader Boudih 			if (rec_size >= sizeof(struct cb_forward)) {
1259*5f74217cSAbdelkader Boudih 				struct cb_forward *fwd;
1260*5f74217cSAbdelkader Boudih 
1261*5f74217cSAbdelkader Boudih 				fwd = (struct cb_forward *)entry;
1262*5f74217cSAbdelkader Boudih 				real_addr = (vm_paddr_t)fwd->forward;
1263*5f74217cSAbdelkader Boudih 			}
1264*5f74217cSAbdelkader Boudih 			break;
1265*5f74217cSAbdelkader Boudih 		}
1266*5f74217cSAbdelkader Boudih 		entry += rec_size;
1267*5f74217cSAbdelkader Boudih 	}
1268*5f74217cSAbdelkader Boudih 	pmap_unmapbios(va, map_size);
1269*5f74217cSAbdelkader Boudih 
1270*5f74217cSAbdelkader Boudih 	child = BUS_ADD_CHILD(parent, 5, "coreboot", DEVICE_UNIT_ANY);
1271*5f74217cSAbdelkader Boudih 	if (child == NULL)
1272*5f74217cSAbdelkader Boudih 		return;
1273*5f74217cSAbdelkader Boudih 	device_set_driver(child, driver);
1274*5f74217cSAbdelkader Boudih 
1275*5f74217cSAbdelkader Boudih 	bus_set_resource(child, SYS_RES_MEMORY, 0, real_addr, PAGE_SIZE);
1276*5f74217cSAbdelkader Boudih 	device_set_desc(child, "coreboot firmware table");
1277*5f74217cSAbdelkader Boudih }
1278*5f74217cSAbdelkader Boudih 
1279*5f74217cSAbdelkader Boudih /*
1280*5f74217cSAbdelkader Boudih  * Probe: validate the coreboot header at the discovered address
1281*5f74217cSAbdelkader Boudih  */
1282*5f74217cSAbdelkader Boudih static int
coreboot_probe(device_t dev)1283*5f74217cSAbdelkader Boudih coreboot_probe(device_t dev)
1284*5f74217cSAbdelkader Boudih {
1285*5f74217cSAbdelkader Boudih 	vm_paddr_t pa;
1286*5f74217cSAbdelkader Boudih 	void *va;
1287*5f74217cSAbdelkader Boudih 	vm_size_t map_size;
1288*5f74217cSAbdelkader Boudih 	int error;
1289*5f74217cSAbdelkader Boudih 
1290*5f74217cSAbdelkader Boudih 	pa = bus_get_resource_start(dev, SYS_RES_MEMORY, 0);
1291*5f74217cSAbdelkader Boudih 	if (pa == 0)
1292*5f74217cSAbdelkader Boudih 		return (ENXIO);
1293*5f74217cSAbdelkader Boudih 
1294*5f74217cSAbdelkader Boudih 	error = coreboot_map_table(pa, &va, &map_size);
1295*5f74217cSAbdelkader Boudih 	if (error != 0)
1296*5f74217cSAbdelkader Boudih 		return (error);
1297*5f74217cSAbdelkader Boudih 
1298*5f74217cSAbdelkader Boudih 	pmap_unmapbios(va, map_size);
1299*5f74217cSAbdelkader Boudih 	return (BUS_PROBE_SPECIFIC);
1300*5f74217cSAbdelkader Boudih }
1301*5f74217cSAbdelkader Boudih 
1302*5f74217cSAbdelkader Boudih /*
1303*5f74217cSAbdelkader Boudih  * Attach: map the full table, parse records, register sysctls and cdevs
1304*5f74217cSAbdelkader Boudih  */
1305*5f74217cSAbdelkader Boudih static int
coreboot_attach(device_t dev)1306*5f74217cSAbdelkader Boudih coreboot_attach(device_t dev)
1307*5f74217cSAbdelkader Boudih {
1308*5f74217cSAbdelkader Boudih 	struct coreboot_softc *sc;
1309*5f74217cSAbdelkader Boudih 	struct cb_header *hdr;
1310*5f74217cSAbdelkader Boudih 	vm_paddr_t pa;
1311*5f74217cSAbdelkader Boudih 	void *va;
1312*5f74217cSAbdelkader Boudih 	vm_size_t map_size;
1313*5f74217cSAbdelkader Boudih 	int error;
1314*5f74217cSAbdelkader Boudih 
1315*5f74217cSAbdelkader Boudih 	sc = device_get_softc(dev);
1316*5f74217cSAbdelkader Boudih 	sc->dev = dev;
1317*5f74217cSAbdelkader Boudih 
1318*5f74217cSAbdelkader Boudih 	pa = bus_get_resource_start(dev, SYS_RES_MEMORY, 0);
1319*5f74217cSAbdelkader Boudih 
1320*5f74217cSAbdelkader Boudih 	error = coreboot_map_table(pa, &va, &map_size);
1321*5f74217cSAbdelkader Boudih 	if (error != 0) {
1322*5f74217cSAbdelkader Boudih 		device_printf(dev, "coreboot table validation failed at %#jx\n",
1323*5f74217cSAbdelkader Boudih 		    (uintmax_t)pa);
1324*5f74217cSAbdelkader Boudih 		return (error);
1325*5f74217cSAbdelkader Boudih 	}
1326*5f74217cSAbdelkader Boudih 
1327*5f74217cSAbdelkader Boudih 	sc->table_paddr = pa;
1328*5f74217cSAbdelkader Boudih 	sc->table_size = map_size;
1329*5f74217cSAbdelkader Boudih 	sc->table_vaddr = va;
1330*5f74217cSAbdelkader Boudih 
1331*5f74217cSAbdelkader Boudih 	hdr = (struct cb_header *)va;
1332*5f74217cSAbdelkader Boudih 	device_printf(dev, "coreboot table at %#jx (%u entries, %u bytes)\n",
1333*5f74217cSAbdelkader Boudih 	    (uintmax_t)pa, hdr->table_entries, hdr->table_bytes);
1334*5f74217cSAbdelkader Boudih 
1335*5f74217cSAbdelkader Boudih 	coreboot_parse_table(sc, hdr);
1336*5f74217cSAbdelkader Boudih 
1337*5f74217cSAbdelkader Boudih 	if (sc->version[0] != '\0')
1338*5f74217cSAbdelkader Boudih 		device_printf(dev, "firmware: %s\n", sc->version);
1339*5f74217cSAbdelkader Boudih 	if (sc->mb_vendor[0] != '\0')
1340*5f74217cSAbdelkader Boudih 		device_printf(dev, "mainboard: %s %s\n", sc->mb_vendor,
1341*5f74217cSAbdelkader Boudih 		    sc->mb_part);
1342*5f74217cSAbdelkader Boudih 	if (sc->has_console)
1343*5f74217cSAbdelkader Boudih 		device_printf(dev, "CBMEM console at %#jx\n",
1344*5f74217cSAbdelkader Boudih 		    (uintmax_t)sc->console_paddr);
1345*5f74217cSAbdelkader Boudih 	device_printf(dev, "CBMEM entries: %u\n", sc->cbmem_count);
1346*5f74217cSAbdelkader Boudih 	if (sc->has_board_config)
1347*5f74217cSAbdelkader Boudih 		device_printf(dev,
1348*5f74217cSAbdelkader Boudih 		    "board: id=%u sku=%u fw_config=%#jx\n",
1349*5f74217cSAbdelkader Boudih 		    sc->board_id, sc->sku_id,
1350*5f74217cSAbdelkader Boudih 		    (uintmax_t)sc->fw_config);
1351*5f74217cSAbdelkader Boudih 	if (sc->mac_count > 0)
1352*5f74217cSAbdelkader Boudih 		device_printf(dev, "factory MAC addresses: %u\n",
1353*5f74217cSAbdelkader Boudih 		    sc->mac_count);
1354*5f74217cSAbdelkader Boudih 	if (sc->has_acpi_rsdp)
1355*5f74217cSAbdelkader Boudih 		device_printf(dev, "ACPI RSDP at %#jx\n",
1356*5f74217cSAbdelkader Boudih 		    (uintmax_t)sc->acpi_rsdp);
1357*5f74217cSAbdelkader Boudih 	if (sc->has_pcie)
1358*5f74217cSAbdelkader Boudih 		device_printf(dev, "PCIe controller at %#jx\n",
1359*5f74217cSAbdelkader Boudih 		    (uintmax_t)sc->pcie_ctrl_base);
1360*5f74217cSAbdelkader Boudih 	if (sc->has_boot_media)
1361*5f74217cSAbdelkader Boudih 		device_printf(dev, "boot media: %#jx bytes, CBFS %#jx+%#jx\n",
1362*5f74217cSAbdelkader Boudih 		    (uintmax_t)sc->boot_media_size,
1363*5f74217cSAbdelkader Boudih 		    (uintmax_t)sc->cbfs_offset, (uintmax_t)sc->cbfs_size);
1364*5f74217cSAbdelkader Boudih 	if (sc->has_mmc_info)
1365*5f74217cSAbdelkader Boudih 		device_printf(dev, "MMC early CMD1 status: %d\n",
1366*5f74217cSAbdelkader Boudih 		    sc->mmc_early_cmd1_status);
1367*5f74217cSAbdelkader Boudih 
1368*5f74217cSAbdelkader Boudih 	if (bootverbose) {
1369*5f74217cSAbdelkader Boudih 		if (sc->has_spi_flash)
1370*5f74217cSAbdelkader Boudih 			device_printf(dev,
1371*5f74217cSAbdelkader Boudih 			    "SPI flash: %u bytes, sector %u, erase %#x\n",
1372*5f74217cSAbdelkader Boudih 			    sc->spi_flash_size, sc->spi_sector_size,
1373*5f74217cSAbdelkader Boudih 			    sc->spi_erase_cmd);
1374*5f74217cSAbdelkader Boudih 		if (sc->has_console_type)
1375*5f74217cSAbdelkader Boudih 			device_printf(dev, "console type: %u\n",
1376*5f74217cSAbdelkader Boudih 			    sc->console_type);
1377*5f74217cSAbdelkader Boudih 		if (sc->has_framebuffer)
1378*5f74217cSAbdelkader Boudih 			device_printf(dev,
1379*5f74217cSAbdelkader Boudih 			    "framebuffer: %ux%u@%ubpp at %#jx\n",
1380*5f74217cSAbdelkader Boudih 			    sc->fb_x_res, sc->fb_y_res, sc->fb_bpp,
1381*5f74217cSAbdelkader Boudih 			    (uintmax_t)sc->fb_addr);
1382*5f74217cSAbdelkader Boudih 		if (sc->gpio_count > 0)
1383*5f74217cSAbdelkader Boudih 			device_printf(dev, "GPIO pins: %u\n",
1384*5f74217cSAbdelkader Boudih 			    sc->gpio_count);
1385*5f74217cSAbdelkader Boudih 		if (sc->has_tpm)
1386*5f74217cSAbdelkader Boudih 			device_printf(dev, "TPM %u.%u PPI at %#x\n",
1387*5f74217cSAbdelkader Boudih 			    sc->tpm_version == 2 ? 2 : 1,
1388*5f74217cSAbdelkader Boudih 			    sc->tpm_version == 2 ? 0 : 2,
1389*5f74217cSAbdelkader Boudih 			    sc->tpm_ppi_addr);
1390*5f74217cSAbdelkader Boudih 	}
1391*5f74217cSAbdelkader Boudih 
1392*5f74217cSAbdelkader Boudih 	if (coreboot_debug) {
1393*5f74217cSAbdelkader Boudih 		if (sc->has_smmstore)
1394*5f74217cSAbdelkader Boudih 			device_printf(dev,
1395*5f74217cSAbdelkader Boudih 			    "SMMSTORE v2: %u blocks x %u bytes, "
1396*5f74217cSAbdelkader Boudih 			    "apm_cmd=%#x\n",
1397*5f74217cSAbdelkader Boudih 			    sc->smmstore_num_blocks,
1398*5f74217cSAbdelkader Boudih 			    sc->smmstore_block_size,
1399*5f74217cSAbdelkader Boudih 			    sc->smmstore_apm_cmd);
1400*5f74217cSAbdelkader Boudih 		if (sc->has_timestamps)
1401*5f74217cSAbdelkader Boudih 			device_printf(dev, "timestamps at %#jx\n",
1402*5f74217cSAbdelkader Boudih 			    (uintmax_t)sc->timestamps_paddr);
1403*5f74217cSAbdelkader Boudih 		if (sc->has_tpm_log)
1404*5f74217cSAbdelkader Boudih 			device_printf(dev, "TPM CB log at %#jx\n",
1405*5f74217cSAbdelkader Boudih 			    (uintmax_t)sc->tpm_log_paddr);
1406*5f74217cSAbdelkader Boudih 		if (sc->has_fmap)
1407*5f74217cSAbdelkader Boudih 			device_printf(dev, "FMAP at %#jx\n",
1408*5f74217cSAbdelkader Boudih 			    (uintmax_t)sc->fmap_paddr);
1409*5f74217cSAbdelkader Boudih 	}
1410*5f74217cSAbdelkader Boudih 
1411*5f74217cSAbdelkader Boudih 	coreboot_register_sysctls(sc);
1412*5f74217cSAbdelkader Boudih 
1413*5f74217cSAbdelkader Boudih 	coreboot_sc = sc;
1414*5f74217cSAbdelkader Boudih 
1415*5f74217cSAbdelkader Boudih 	if (sc->has_console) {
1416*5f74217cSAbdelkader Boudih 		error = coreboot_console_create(sc);
1417*5f74217cSAbdelkader Boudih 		if (error != 0)
1418*5f74217cSAbdelkader Boudih 			device_printf(dev,
1419*5f74217cSAbdelkader Boudih 			    "failed to create /dev/coreboot_console (%d)\n",
1420*5f74217cSAbdelkader Boudih 			    error);
1421*5f74217cSAbdelkader Boudih 	}
1422*5f74217cSAbdelkader Boudih 	if (sc->cbmem_count > 0) {
1423*5f74217cSAbdelkader Boudih 		error = coreboot_cbmem_create(sc);
1424*5f74217cSAbdelkader Boudih 		if (error != 0)
1425*5f74217cSAbdelkader Boudih 			device_printf(dev, "failed to create /dev/cbmem (%d)\n",
1426*5f74217cSAbdelkader Boudih 			    error);
1427*5f74217cSAbdelkader Boudih 	}
1428*5f74217cSAbdelkader Boudih 
1429*5f74217cSAbdelkader Boudih 	return (0);
1430*5f74217cSAbdelkader Boudih }
1431*5f74217cSAbdelkader Boudih 
1432*5f74217cSAbdelkader Boudih /*
1433*5f74217cSAbdelkader Boudih  * Detach: unmap table, destroy cdevs and sysctls
1434*5f74217cSAbdelkader Boudih  */
1435*5f74217cSAbdelkader Boudih static int
coreboot_detach(device_t dev)1436*5f74217cSAbdelkader Boudih coreboot_detach(device_t dev)
1437*5f74217cSAbdelkader Boudih {
1438*5f74217cSAbdelkader Boudih 	struct coreboot_softc *sc;
1439*5f74217cSAbdelkader Boudih 
1440*5f74217cSAbdelkader Boudih 	sc = device_get_softc(dev);
1441*5f74217cSAbdelkader Boudih 
1442*5f74217cSAbdelkader Boudih 	coreboot_cbmem_destroy(sc);
1443*5f74217cSAbdelkader Boudih 	coreboot_console_destroy(sc);
1444*5f74217cSAbdelkader Boudih 
1445*5f74217cSAbdelkader Boudih 	coreboot_sc = NULL;
1446*5f74217cSAbdelkader Boudih 
1447*5f74217cSAbdelkader Boudih 	sysctl_ctx_free(&sc->sysctl_ctx);
1448*5f74217cSAbdelkader Boudih 
1449*5f74217cSAbdelkader Boudih 	if (sc->table_vaddr != NULL) {
1450*5f74217cSAbdelkader Boudih 		pmap_unmapbios(sc->table_vaddr, sc->table_size);
1451*5f74217cSAbdelkader Boudih 		sc->table_vaddr = NULL;
1452*5f74217cSAbdelkader Boudih 	}
1453*5f74217cSAbdelkader Boudih 
1454*5f74217cSAbdelkader Boudih 	if (sc->console_vaddr != NULL) {
1455*5f74217cSAbdelkader Boudih 		pmap_unmapbios(sc->console_vaddr, sc->console_size);
1456*5f74217cSAbdelkader Boudih 		sc->console_vaddr = NULL;
1457*5f74217cSAbdelkader Boudih 		sc->console_size = 0;
1458*5f74217cSAbdelkader Boudih 		sc->console_data_size = 0;
1459*5f74217cSAbdelkader Boudih 	}
1460*5f74217cSAbdelkader Boudih 
1461*5f74217cSAbdelkader Boudih 	return (0);
1462*5f74217cSAbdelkader Boudih }
1463*5f74217cSAbdelkader Boudih 
1464*5f74217cSAbdelkader Boudih static int
coreboot_modevent(module_t mod,int what,void * arg)1465*5f74217cSAbdelkader Boudih coreboot_modevent(module_t mod, int what, void *arg)
1466*5f74217cSAbdelkader Boudih {
1467*5f74217cSAbdelkader Boudih 	device_t *devs;
1468*5f74217cSAbdelkader Boudih 	int count, i;
1469*5f74217cSAbdelkader Boudih 
1470*5f74217cSAbdelkader Boudih 	switch (what) {
1471*5f74217cSAbdelkader Boudih 	case MOD_LOAD:
1472*5f74217cSAbdelkader Boudih 		break;
1473*5f74217cSAbdelkader Boudih 	case MOD_UNLOAD:
1474*5f74217cSAbdelkader Boudih 		devclass_get_devices(devclass_find("coreboot"), &devs, &count);
1475*5f74217cSAbdelkader Boudih 		for (i = 0; i < count; i++)
1476*5f74217cSAbdelkader Boudih 			device_delete_child(device_get_parent(devs[i]),
1477*5f74217cSAbdelkader Boudih 			    devs[i]);
1478*5f74217cSAbdelkader Boudih 		free(devs, M_TEMP);
1479*5f74217cSAbdelkader Boudih 		break;
1480*5f74217cSAbdelkader Boudih 	default:
1481*5f74217cSAbdelkader Boudih 		break;
1482*5f74217cSAbdelkader Boudih 	}
1483*5f74217cSAbdelkader Boudih 
1484*5f74217cSAbdelkader Boudih 	return (0);
1485*5f74217cSAbdelkader Boudih }
1486*5f74217cSAbdelkader Boudih 
1487*5f74217cSAbdelkader Boudih static device_method_t coreboot_methods[] = {
1488*5f74217cSAbdelkader Boudih 	DEVMETHOD(device_identify,	coreboot_identify),
1489*5f74217cSAbdelkader Boudih 	DEVMETHOD(device_probe,		coreboot_probe),
1490*5f74217cSAbdelkader Boudih 	DEVMETHOD(device_attach,	coreboot_attach),
1491*5f74217cSAbdelkader Boudih 	DEVMETHOD(device_detach,	coreboot_detach),
1492*5f74217cSAbdelkader Boudih 	DEVMETHOD_END
1493*5f74217cSAbdelkader Boudih };
1494*5f74217cSAbdelkader Boudih 
1495*5f74217cSAbdelkader Boudih static driver_t coreboot_driver = {
1496*5f74217cSAbdelkader Boudih 	"coreboot",
1497*5f74217cSAbdelkader Boudih 	coreboot_methods,
1498*5f74217cSAbdelkader Boudih 	sizeof(struct coreboot_softc),
1499*5f74217cSAbdelkader Boudih };
1500*5f74217cSAbdelkader Boudih 
1501*5f74217cSAbdelkader Boudih DRIVER_MODULE(coreboot, nexus, coreboot_driver, coreboot_modevent, NULL);
1502*5f74217cSAbdelkader Boudih MODULE_VERSION(coreboot, 1);
1503