git: 5f74217c05a9 - main - coreboot: Add coreboot firmware table driver
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 29 Jul 2026 19:25:23 UTC
The branch main has been updated by adrian:
URL: https://cgit.FreeBSD.org/src/commit/?id=5f74217c05a99f38a31a6e4950220964595d4ac8
commit 5f74217c05a99f38a31a6e4950220964595d4ac8
Author: Abdelkader Boudih <freebsd@seuros.com>
AuthorDate: 2026-07-29 19:11:55 +0000
Commit: Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-07-29 19:12:41 +0000
coreboot: Add coreboot firmware table driver
Nexus-attached driver that discovers and parses coreboot's LBIO tables
from physical memory. Exposes firmware metadata (version, build info,
mainboard, serial config, TSC frequency, CBMEM entries) via sysctl
hw.coreboot.*, the firmware console ring buffer via /dev/coreboot_console,
and structured CBMEM entry access via /dev/cbmem ioctl interface.
Tested on:
- Qotom Q535G6 (Kabylake)
- Intel NUC D54250WYK (Haswell)
- Intel NUC D33217GKE (Ivy Bridge)
- Dell 3100 2-in-1 (Gabbiter)
- Dell 3100 (Fleex)
- Lenovo IdeaPad 320s
- Lenovo ThinkPad T480
- HP Chromebook 11 G4
- HP Chromebook 11 G5
- HP Chromebook 11 G6 EE
- HP Chromebook 14 G4
- HP Chromebook 14 G5
- HP Chromebook x360 11 G1 EE
- HP Chromebook x360 11 G2 EE
- HP Chromebook x360 14 G1
- Acer C720
- Acer Chromebook 11
- Lenovo N22
Reviewed by: ngie, kib, adrian
Differential Revision: https://reviews.freebsd.org/D55649
---
etc/mtree/BSD.include.dist | 2 +
include/Makefile | 11 +-
share/man/man4/Makefile | 1 +
share/man/man4/coreboot.4 | 355 ++++++++
sys/conf/files | 4 +
sys/conf/files.x86 | 4 +
sys/dev/coreboot/coreboot.c | 1502 ++++++++++++++++++++++++++++++++
sys/dev/coreboot/coreboot.h | 632 ++++++++++++++
sys/dev/coreboot/coreboot_cbmem.c | 151 ++++
sys/dev/coreboot/coreboot_console.c | 192 ++++
sys/dev/coreboot/coreboot_timestamps.c | 214 +++++
sys/dev/coreboot/corebootio.h | 123 +++
sys/modules/Makefile | 2 +
sys/modules/coreboot/Makefile | 7 +
14 files changed, 3198 insertions(+), 2 deletions(-)
diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist
index 81ea0842035c..05e739bcf5dd 100644
--- a/etc/mtree/BSD.include.dist
+++ b/etc/mtree/BSD.include.dist
@@ -207,6 +207,8 @@
..
ciss
..
+ coreboot
+ ..
evdev
..
filemon
diff --git a/include/Makefile b/include/Makefile
index 3d83556f5238..60c2ca5819dc 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -151,6 +151,10 @@ CAMSCSI= scsi_all.h \
smp_all.h
CAMSCSIDIR= ${INCLUDEDIR}/cam/scsi
+.PATH: ${SRCTOP}/sys/dev/coreboot
+COREBOOT= corebootio.h
+COREBOOTDIR= ${INCLUDEDIR}/dev/coreboot
+
.PATH: ${SRCTOP}/sys/fs/cd9660
FS9660= cd9660_mount.h \
cd9660_node.h \
@@ -254,6 +258,7 @@ INCSGROUPS= INCS \
CAMMMC \
CAMNVME \
CAMSCSI \
+ COREBOOT \
CRYPTO \
EVDEV \
FS9660 \
@@ -381,7 +386,7 @@ copies: .PHONY .META
cd ${SDESTDIR}${INCLUDEDIR}; find ${LDIRS} ${LSUBDIRS} ${LSUBSUBDIRS} crypto \
machine machine/pc ${_MARCHS} -maxdepth 1 -mindepth 1 -type l \
-name "*.h" -print -delete || true
-.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/evdev:Ndev/hid:Ndev/hyperv:Ndev/pci:Ndev/veriexec:Ndev/wg} ${LSUBSUBDIRS}
+.for i in ${LDIRS} ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/coreboot:Ndev/evdev:Ndev/hid:Ndev/hyperv:Ndev/pci:Ndev/veriexec:Ndev/wg} ${LSUBSUBDIRS}
cd ${SRCTOP}/sys; \
${INSTALL} -C ${TAG_ARGS:D${TAG_ARGS},dev} -o ${BINOWN} -g ${BINGRP} -m 444 $i/*.h \
${SDESTDIR}${INCLUDEDIR}/$i
@@ -417,7 +422,7 @@ symlinks: .PHONY .META
cd ${SRCTOP}; ${INSTALL_SYMLINK} ${TAG_ARGS:D${TAG_ARGS},dev} \
$$(printf '../../../%s ' sys/$i/*.h) ${SDESTDIR}${INCLUDEDIR}/$i
.endfor
-.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/evdev:Ndev/hid:Ndev/hyperv:Ndev/pci:Ndev/veriexec:Ndev/wg}
+.for i in ${LSUBDIRS:Ndev/agp:Ndev/acpica:Ndev/coreboot:Ndev/evdev:Ndev/hid:Ndev/hyperv:Ndev/pci:Ndev/veriexec:Ndev/wg}
cd ${SRCTOP}; ${INSTALL_SYMLINK} ${TAG_ARGS:D${TAG_ARGS},dev} \
$$(printf '../../../../%s ' sys/$i/*.h) ${SDESTDIR}${INCLUDEDIR}/$i
.endfor
@@ -438,6 +443,8 @@ symlinks: .PHONY .META
${SDESTDIR}${INCLUDEDIR}/dev/hyperv; \
${INSTALL_SYMLINK} ${TAG_ARGS:D${TAG_ARGS},dev} ../../../../sys/dev/pci/pcireg.h \
${SDESTDIR}${INCLUDEDIR}/dev/pci; \
+ ${INSTALL_SYMLINK} ${TAG_ARGS:D${TAG_ARGS},dev} ../../../../sys/dev/coreboot/corebootio.h \
+ ${SDESTDIR}${INCLUDEDIR}/dev/coreboot; \
${INSTALL_SYMLINK} ${TAG_ARGS:D${TAG_ARGS},dev} ../../../../sys/dev/veriexec/veriexec_ioctl.h \
${SDESTDIR}${INCLUDEDIR}/dev/veriexec;
.for i in ${LSUBSUBDIRS}
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 80b9ac16ce87..cd7a16c58923 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -126,6 +126,7 @@ MAN= aac.4 \
chromebook_platform.4 \
${_chvgpio.4} \
ciss.4 \
+ coreboot.4 \
${_coretemp.4} \
cp2112.4 \
${_cpuctl.4} \
diff --git a/share/man/man4/coreboot.4 b/share/man/man4/coreboot.4
new file mode 100644
index 000000000000..315a466cee8c
--- /dev/null
+++ b/share/man/man4/coreboot.4
@@ -0,0 +1,355 @@
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd March 2, 2026
+.Dt COREBOOT 4
+.Os
+.Sh NAME
+.Nm coreboot
+.Nd coreboot firmware table driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device coreboot"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+coreboot_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides access to firmware tables created by the coreboot
+open-source firmware project.
+It discovers the coreboot table by scanning low memory for the
+.Dq LBIO
+signature, follows any forward pointer to the real table in high memory,
+and validates the IP-style checksums.
+.Pp
+The driver exposes firmware information through three interfaces:
+.Bl -tag -width "/dev/coreboot_console"
+.It Sy sysctl
+A
+.Xr sysctl 8
+tree under
+.Va hw.coreboot
+provides access to:
+.Bl -bullet -compact
+.It
+firmware version, build date, and compiler information
+.It
+mainboard identification and board configuration
+.It
+MAC addresses, framebuffer, GPIO, and SPI flash details
+.It
+TPM information and SMMSTORE configuration
+.It
+ACPI RSDP address, PCIe controller base, and TSC frequency
+.It
+boot timestamps and CBMEM entry enumeration
+.El
+.It Pa /dev/coreboot_console
+A character device providing read-only access to the CBMEM firmware console
+ring buffer.
+This contains coreboot's own boot log, analogous to
+.Xr dmesg 8
+but for the firmware stage before the OS kernel starts.
+The ring buffer uses bit 31 of its cursor as an overflow indicator;
+when set, the buffer has wrapped and data is read starting from the
+cursor position.
+.It Pa /dev/cbmem
+A character device providing
+.Xr ioctl 2
+access to individual CBMEM entries.
+CBMEM is coreboot's mechanism for passing data between firmware stages
+and to the operating system.
+.El
+.Ss Verbose Output
+By default, the driver prints a single attach summary line showing table
+location and size.
+.Pp
+When
+.Va bootverbose
+is set
+.Pq e.g., Dq Li boot -v ,
+the driver additionally prints firmware identity and parsed hardware details
+such as mainboard, board config, MAC count, ACPI RSDP, SPI flash, framebuffer,
+GPIO, and TPM summary.
+.Pp
+When
+.Va hw.coreboot.debug
+is non-zero, the driver prints extra internal diagnostics such as SMMSTORE,
+timestamp, TPM CB log, and FMAP addresses.
+.Pp
+All sysctl nodes are registered regardless of verbosity settings.
+.Ss sysctl Variables
+The following
+.Xr sysctl 8
+variables are available when the driver is loaded
+(variables only appear if the corresponding table record exists):
+.Bl -tag -width "hw.coreboot.smmstore.com_buffer"
+.It Va hw.coreboot.debug
+Enable verbose coreboot diagnostics (read-write, default 0).
+Tunable via
+.Xr loader.conf 5
+as
+.Va hw.coreboot.debug .
+.It Va hw.coreboot.version
+Firmware version string.
+.It Va hw.coreboot.build
+Build date and time.
+.It Va hw.coreboot.compile_time
+Firmware compile time string.
+.It Va hw.coreboot.compiler
+Compiler identification string.
+.It Va hw.coreboot.extra_version
+Extra version information.
+.It Va hw.coreboot.platform_blob_version
+Platform blob version string.
+.It Va hw.coreboot.serialno
+Board serial number.
+.It Va hw.coreboot.version_timestamp
+Firmware version timestamp.
+.It Va hw.coreboot.table_addr
+Physical address of the coreboot table.
+.It Va hw.coreboot.table_size
+Total size of the coreboot table in bytes.
+.It Va hw.coreboot.mainboard.vendor
+Mainboard vendor name.
+.It Va hw.coreboot.mainboard.part
+Mainboard part number.
+.It Va hw.coreboot.serial.baseaddr
+Serial port base address.
+.It Va hw.coreboot.serial.baud
+Serial port baud rate.
+.It Va hw.coreboot.serial.regwidth
+Serial port register width.
+.It Va hw.coreboot.tsc_freq_khz
+TSC frequency in kilohertz as reported by firmware.
+.It Va hw.coreboot.pcie_ctrl_base
+PCIe controller base address.
+.It Va hw.coreboot.acpi_rsdp
+ACPI RSDP physical address.
+.It Va hw.coreboot.board.fw_config
+Firmware configuration bitmask.
+.It Va hw.coreboot.board.board_id
+Board ID.
+.It Va hw.coreboot.board.ram_code
+RAM code.
+.It Va hw.coreboot.board.sku_id
+SKU ID.
+.It Va hw.coreboot.mac.N
+Factory MAC address N (formatted as xx:xx:xx:xx:xx:xx).
+.It Va hw.coreboot.boot_media.fmap_offset
+FMAP offset from boot media start.
+.It Va hw.coreboot.boot_media.cbfs_offset
+CBFS offset from boot media start.
+.It Va hw.coreboot.boot_media.cbfs_size
+CBFS size in bytes.
+.It Va hw.coreboot.boot_media.size
+Boot media size in bytes.
+.It Va hw.coreboot.mmc_early_cmd1_status
+Early eMMC/MMC CMD1 status value.
+.It Va hw.coreboot.spi_flash.size
+SPI flash size in bytes.
+.It Va hw.coreboot.spi_flash.sector_size
+SPI flash sector size in bytes.
+.It Va hw.coreboot.spi_flash.erase_cmd
+SPI flash erase command byte.
+.It Va hw.coreboot.console_type
+Firmware console type (0=serial8250, 1=VGA, 2=BTEXT, 3=LOGBUF, 4=SROM,
+5=EHCI, 6=serial8250mem).
+.It Va hw.coreboot.framebuffer.addr
+Framebuffer physical address.
+.It Va hw.coreboot.framebuffer.x_res
+Framebuffer horizontal resolution.
+.It Va hw.coreboot.framebuffer.y_res
+Framebuffer vertical resolution.
+.It Va hw.coreboot.framebuffer.bpp
+Framebuffer bits per pixel.
+.It Va hw.coreboot.gpio.N.name
+GPIO pin N name.
+.It Va hw.coreboot.gpio.N.port
+GPIO pin N port number.
+.It Va hw.coreboot.gpio.N.value
+GPIO pin N value.
+.It Va hw.coreboot.gpio.N.polarity
+GPIO pin N polarity.
+.It Va hw.coreboot.tpm.version
+TPM version (1=TPM 1.2, 2=TPM 2.0).
+.It Va hw.coreboot.tpm.ppi_addr
+TPM Physical Presence Interface address.
+.It Va hw.coreboot.tpm.cblog_addr
+TPM event log physical address.
+.It Va hw.coreboot.smmstore.num_blocks
+SMMSTORE v2 number of blocks.
+.It Va hw.coreboot.smmstore.block_size
+SMMSTORE v2 block size in bytes.
+.It Va hw.coreboot.smmstore.mmap_addr
+SMMSTORE v2 memory-mapped address.
+.It Va hw.coreboot.smmstore.com_buffer
+SMMSTORE v2 communication buffer address.
+.It Va hw.coreboot.smmstore.apm_cmd
+SMMSTORE v2 APM command byte.
+.It Va hw.coreboot.cbmem_refs.acpi_gnvs
+ACPI GNVS CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.acpi_cnvs
+ACPI CNVS CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.vpd
+VPD CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.wifi_calibration
+WiFi calibration CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.fmap
+FMAP CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.vboot_workbuf
+Vboot work buffer CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.type_c_info
+Type-C info CBMEM physical address.
+.It Va hw.coreboot.cbmem_refs.root_bridge_info
+Root bridge info CBMEM physical address.
+.It Va hw.coreboot.timestamps_addr
+Timestamps CBMEM physical address.
+.It Va hw.coreboot.timestamps
+Formatted boot stage timing table (read-only).
+Each line shows the timestamp ID, stage name, absolute time in
+microseconds, and delta from the previous stage.
+.It Va hw.coreboot.cbmem.N.id
+CBMEM entry ID.
+.It Va hw.coreboot.cbmem.N.name
+Human-readable CBMEM entry name.
+.It Va hw.coreboot.cbmem.N.address
+Physical address of the CBMEM entry.
+.It Va hw.coreboot.cbmem.N.size
+Size of the CBMEM entry in bytes.
+.El
+.Ss ioctl Interface
+The
+.Pa /dev/cbmem
+device supports the following
+.Xr ioctl 2
+commands, defined in
+.In dev/coreboot/corebootio.h :
+.Bl -tag -width CBMEM_IOC_LIST
+.It Dv CBMEM_IOC_LIST
+Returns a
+.Vt struct cbmem_list
+containing the count and metadata of all discovered CBMEM entries.
+.It Dv CBMEM_IOC_READ
+Reads data from a CBMEM entry identified by its ID.
+Takes a
+.Vt struct cbmem_read_req
+specifying the entry ID, offset, size, and a userspace buffer.
+.El
+.Sh FILES
+.Bl -tag -width "/dev/coreboot_console"
+.It Pa /dev/coreboot_console
+Firmware console ring buffer (read-only).
+.It Pa /dev/cbmem
+CBMEM entry access device.
+.El
+.Sh EXAMPLES
+Display the coreboot firmware version:
+.Pp
+.Dl "sysctl hw.coreboot.version"
+.Pp
+Read the firmware boot log:
+.Pp
+.Dl "cat /dev/coreboot_console"
+.Pp
+List all CBMEM entries:
+.Pp
+.Dl "sysctl hw.coreboot.cbmem"
+.Pp
+Show board identification:
+.Pp
+.Dl "sysctl hw.coreboot.board"
+.Pp
+Show factory MAC addresses:
+.Pp
+.Dl "sysctl hw.coreboot.mac"
+.Pp
+Display boot stage timestamps:
+.Pp
+.Dl "sysctl hw.coreboot.timestamps"
+.Pp
+Enable debug output and reload the module (the sysctl value resets on
+unload, so it must be set again or persisted via
+.Xr loader.conf 5 ) :
+.Bd -literal -offset indent
+kldunload coreboot
+kldload coreboot
+sysctl hw.coreboot.debug=1
+dmesg | grep coreboot
+.Ed
+.Pp
+To persist debug across reboots, add to
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.coreboot.debug=1
+.Ed
+.Sh COMPATIBILITY
+The
+.Nm
+driver works with any x86 system running coreboot firmware.
+The coreboot table format uses a stable ABI with forward-compatible
+tagged records; unknown tags are safely skipped.
+.Pp
+Linux provides similar functionality through a custom bus type with
+separate modules for each table record type, exposed via sysfs.
+The
+.Fx
+driver uses a single module with native
+.Xr sysctl 8
+and
+.Xr ioctl 2
+interfaces instead.
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr smbios 4 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 16.0 .
+.Sh AUTHORS
+.An Abdelkader Boudih Aq Mt freebsd@seuros.com .
+.Sh CAVEATS
+The driver discovers the coreboot table by scanning physical memory
+addresses 0x0 through 0x1000 for the
+.Dq LBIO
+signature.
+On systems without coreboot firmware, the driver will silently
+not attach.
+.Pp
+The
+.Pa /dev/coreboot_console
+content is static after boot; coreboot does not write to the
+console buffer after handing off control to the payload.
diff --git a/sys/conf/files b/sys/conf/files
index 567e024259b0..57da06f27883 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1358,6 +1358,10 @@ dev/cfi/cfi_core.c optional cfi
dev/cfi/cfi_dev.c optional cfi
dev/cfi/cfi_disk.c optional cfid
dev/chromebook_platform/chromebook_platform.c optional chromebook_platform
+dev/coreboot/coreboot.c optional coreboot
+dev/coreboot/coreboot_cbmem.c optional coreboot
+dev/coreboot/coreboot_console.c optional coreboot
+dev/coreboot/coreboot_timestamps.c optional coreboot
dev/ciss/ciss.c optional ciss
dev/clk/clk.c optional clk
dev/clk/clkdev_if.m optional clk
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index d700041e01d0..8c02edbb6a35 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -83,6 +83,10 @@ dev/bxe/bxe_elink.c optional bxe pci
dev/bxe/57710_init_values.c optional bxe pci
dev/bxe/57711_init_values.c optional bxe pci
dev/bxe/57712_init_values.c optional bxe pci
+dev/coreboot/coreboot.c optional coreboot
+dev/coreboot/coreboot_console.c optional coreboot
+dev/coreboot/coreboot_cbmem.c optional coreboot
+dev/coreboot/coreboot_timestamps.c optional coreboot
dev/coretemp/coretemp.c optional coretemp
dev/cpuctl/cpuctl.c optional cpuctl
dev/dpms/dpms.c optional dpms
diff --git a/sys/dev/coreboot/coreboot.c b/sys/dev/coreboot/coreboot.c
new file mode 100644
index 000000000000..66b49209e3af
--- /dev/null
+++ b/sys/dev/coreboot/coreboot.c
@@ -0,0 +1,1502 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * coreboot(4) - FreeBSD driver for coreboot firmware tables
+ *
+ * Discovers the coreboot table by scanning low memory for the "LBIO"
+ * signature, follows CB_TAG_FORWARD to the high-memory table, and
+ * exposes firmware information through sysctl(9) and character devices.
+ */
+
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/coreboot/coreboot.h>
+
+static struct coreboot_softc *coreboot_sc;
+
+/*
+ * Debug verbosity control, non-zero enables extra output.
+ * Tunable via loader.conf: hw.coreboot.debug=1
+ * Runtime: sysctl hw.coreboot.debug=1
+ * Registered dynamically under hw.coreboot in
+ * coreboot_register_sysctls().
+ */
+static int coreboot_debug = 0;
+TUNABLE_INT("hw.coreboot.debug", &coreboot_debug);
+
+struct coreboot_softc *
+coreboot_get_softc(void)
+{
+ return (coreboot_sc);
+}
+
+static void coreboot_identify(driver_t *, device_t);
+static int coreboot_probe(device_t);
+static int coreboot_attach(device_t);
+static int coreboot_detach(device_t);
+static int coreboot_modevent(module_t, int, void *);
+
+/*
+ * Scan a physical memory region for the "LBIO" signature.
+ * Returns the physical address of the header, or 0 if not found.
+ */
+static vm_paddr_t
+coreboot_scan_region(vm_paddr_t start, vm_paddr_t end)
+{
+ vm_paddr_t addr;
+ void *va;
+ struct cb_header *hdr;
+
+ for (addr = (start == 0 ? CB_SCAN_LOW_STEP : start); addr < end;
+ addr += CB_SCAN_LOW_STEP) {
+ va = pmap_mapbios(addr, sizeof(struct cb_header));
+ if (va == NULL)
+ continue;
+
+ hdr = (struct cb_header *)va;
+ if (memcmp(hdr->signature, CB_HEADER_SIGNATURE,
+ CB_HEADER_SIG_LEN) == 0) {
+ pmap_unmapbios(va, sizeof(struct cb_header));
+ return (addr);
+ }
+ pmap_unmapbios(va, sizeof(struct cb_header));
+ }
+ return (0);
+}
+
+/*
+ * Validate length fields in the header before using them for mappings
+ * and pointer arithmetic.
+ */
+static int
+coreboot_sanitize_header(const struct cb_header *hdr, vm_size_t *map_size)
+{
+ uint64_t total;
+
+ if (hdr->header_bytes < sizeof(*hdr) ||
+ hdr->header_bytes > CB_MAX_HEADER_BYTES)
+ return (EINVAL);
+ if ((hdr->header_bytes % CB_TABLE_ALIGN) != 0)
+ return (EINVAL);
+ if (hdr->table_bytes > CB_MAX_TABLE_BYTES)
+ return (EINVAL);
+ if ((hdr->table_bytes % CB_TABLE_ALIGN) != 0)
+ return (EINVAL);
+
+ total = (uint64_t)hdr->header_bytes + (uint64_t)hdr->table_bytes;
+ if (total > CB_MAX_TABLE_MAP_BYTES)
+ return (EINVAL);
+
+ *map_size = (vm_size_t)total;
+ return (0);
+}
+
+/*
+ * Validate the coreboot header checksum.
+ * Returns 0 on success, non-zero on failure.
+ */
+static int
+coreboot_validate_header(struct cb_header *hdr, vm_size_t mapped_len)
+{
+ uint16_t cksum;
+
+ if (hdr->header_bytes > mapped_len)
+ return (EINVAL);
+
+ cksum = cb_checksum(hdr, hdr->header_bytes);
+ if (cksum != 0)
+ return (EINVAL);
+
+ return (0);
+}
+
+/*
+ * Validate checksum for the table payload.
+ */
+static int
+coreboot_validate_table(struct cb_header *hdr, vm_size_t mapped_len)
+{
+ const uint8_t *table;
+ uint16_t cksum;
+
+ if (hdr->table_bytes == 0)
+ return (0);
+
+ if ((uint64_t)hdr->header_bytes + (uint64_t)hdr->table_bytes >
+ mapped_len)
+ return (EINVAL);
+ if (hdr->table_checksum > UINT16_MAX)
+ return (EINVAL);
+
+ table = (const uint8_t *)hdr + hdr->header_bytes;
+ cksum = cb_checksum(table, hdr->table_bytes);
+ if (cksum != (uint16_t)hdr->table_checksum)
+ return (EINVAL);
+
+ return (0);
+}
+
+static void
+coreboot_copy_bounded_string(const char *src, size_t maxlen, char *dst,
+ size_t dstlen)
+{
+ size_t slen;
+
+ if (dstlen == 0)
+ return;
+
+ slen = strnlen(src, maxlen);
+ if (slen >= dstlen)
+ slen = dstlen - 1;
+ memcpy(dst, src, slen);
+ dst[slen] = '\0';
+}
+
+/*
+ * Copy a coreboot string record into a destination buffer.
+ */
+static void
+coreboot_copy_string(const struct cb_string *rec, char *dst, size_t dstlen)
+{
+ size_t slen;
+
+ slen = rec->size - sizeof(struct cb_record);
+ if (slen >= dstlen)
+ slen = dstlen - 1;
+ memcpy(dst, rec->string, slen);
+ dst[slen] = '\0';
+
+ /* Strip trailing whitespace/nulls */
+ while (slen > 0 && (dst[slen - 1] == '\0' || dst[slen - 1] == ' ' ||
+ dst[slen - 1] == '\n'))
+ dst[--slen] = '\0';
+}
+
+/*
+ * Extract mainboard vendor and part number from the strings field.
+ */
+static void
+coreboot_parse_mainboard(struct coreboot_softc *sc,
+ const struct cb_mainboard *mb)
+{
+ const char *strings = (const char *)mb->strings;
+ size_t total = mb->size - offsetof(struct cb_mainboard, strings);
+ uint8_t vendor_off, part_off;
+
+ vendor_off = mb->vendor_idx;
+ part_off = mb->part_idx;
+
+ if (vendor_off < total)
+ coreboot_copy_bounded_string(strings + vendor_off,
+ total - vendor_off, sc->mb_vendor, sizeof(sc->mb_vendor));
+ if (part_off < total)
+ coreboot_copy_bounded_string(strings + part_off,
+ total - part_off, sc->mb_part, sizeof(sc->mb_part));
+}
+
+/*
+ * Parse all records in the coreboot table and populate softc.
+ */
+static void
+coreboot_parse_table(struct coreboot_softc *sc, struct cb_header *hdr)
+{
+ uint8_t *entry;
+ uint8_t *table_end;
+ struct cb_record *rec;
+
+ entry = (uint8_t *)hdr + hdr->header_bytes;
+ table_end = entry + hdr->table_bytes;
+
+ while ((size_t)(table_end - entry) >= sizeof(struct cb_record)) {
+ size_t rec_size;
+
+ rec = (struct cb_record *)entry;
+ rec_size = rec->size;
+
+ if (rec_size < sizeof(struct cb_record))
+ break;
+ if (rec_size > (size_t)(table_end - entry))
+ break;
+
+ switch (rec->tag) {
+ case CB_TAG_VERSION:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->version, sizeof(sc->version));
+ break;
+
+ case CB_TAG_EXTRA_VERSION:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->extra_version, sizeof(sc->extra_version));
+ break;
+
+ case CB_TAG_BUILD:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->build, sizeof(sc->build));
+ break;
+
+ case CB_TAG_COMPILE_TIME:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->compile_time, sizeof(sc->compile_time));
+ break;
+
+ case CB_TAG_COMPILER:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->compiler, sizeof(sc->compiler));
+ break;
+
+ case CB_TAG_PLATFORM_BLOB_VERSION:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->platform_blob_version,
+ sizeof(sc->platform_blob_version));
+ break;
+
+ case CB_TAG_SERIALNO:
+ coreboot_copy_string((struct cb_string *)rec,
+ sc->serialno, sizeof(sc->serialno));
+ break;
+
+ case CB_TAG_VERSION_TIMESTAMP: {
+ struct cb_version_timestamp *ts =
+ (struct cb_version_timestamp *)rec;
+
+ if (rec_size < sizeof(*ts))
+ break;
+ sc->version_timestamp = ts->timestamp;
+ sc->has_version_timestamp = 1;
+ break;
+ }
+
+ case CB_TAG_MAINBOARD:
+ if (rec_size < offsetof(struct cb_mainboard, strings))
+ break;
+ coreboot_parse_mainboard(sc,
+ (struct cb_mainboard *)rec);
+ break;
+
+ case CB_TAG_SERIAL: {
+ struct cb_serial *ser = (struct cb_serial *)rec;
+
+ if (rec_size < sizeof(*ser))
+ break;
+ sc->serial_baseaddr = ser->baseaddr;
+ sc->serial_baud = ser->baud;
+ sc->serial_regwidth = ser->regwidth;
+ sc->has_serial = 1;
+ break;
+ }
+
+ case CB_TAG_TSC_INFO: {
+ struct cb_tsc_info *tsc = (struct cb_tsc_info *)rec;
+
+ if (rec_size < sizeof(*tsc))
+ break;
+ sc->tsc_freq_khz = tsc->freq_khz;
+ sc->has_tsc_info = 1;
+ break;
+ }
+
+ case CB_TAG_PCIE: {
+ struct cb_pcie *pcie = (struct cb_pcie *)rec;
+
+ if (rec_size < sizeof(*pcie))
+ break;
+ sc->pcie_ctrl_base = pcie->ctrl_base;
+ sc->has_pcie = 1;
+ break;
+ }
+
+ case CB_TAG_BOOT_MEDIA_PARAMS: {
+ struct cb_boot_media_params *bmp =
+ (struct cb_boot_media_params *)rec;
+
+ if (rec_size < sizeof(*bmp))
+ break;
+ sc->fmap_offset = bmp->fmap_offset;
+ sc->cbfs_offset = bmp->cbfs_offset;
+ sc->cbfs_size = bmp->cbfs_size;
+ sc->boot_media_size = bmp->boot_media_size;
+ sc->has_boot_media = 1;
+ break;
+ }
+
+ case CB_TAG_MMC_INFO: {
+ struct cb_mmc_info *mmc = (struct cb_mmc_info *)rec;
+
+ if (rec_size < sizeof(*mmc))
+ break;
+ sc->mmc_early_cmd1_status = mmc->early_cmd1_status;
+ sc->has_mmc_info = 1;
+ break;
+ }
+
+ case CB_TAG_CBMEM_CONSOLE: {
+ struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec;
+
+ if (rec_size < sizeof(*ref))
+ break;
+ sc->console_paddr = (vm_paddr_t)ref->cbmem_addr;
+ sc->has_console = 1;
+ break;
+ }
+
+ case CB_TAG_CBMEM_ENTRY: {
+ struct cb_cbmem_entry *ent =
+ (struct cb_cbmem_entry *)rec;
+
+ if (rec_size < sizeof(*ent))
+ break;
+ if (sc->cbmem_count < CB_MAX_CBMEM_ENTRIES) {
+ struct cbmem_entry_info *info =
+ &sc->cbmem_entries[sc->cbmem_count];
+ info->id = ent->id;
+ info->address = ent->address;
+ info->size = ent->entry_size;
+ strlcpy(info->name, cbmem_id_to_name(ent->id),
+ sizeof(info->name));
+ sc->cbmem_count++;
+ }
+ break;
+ }
+
+ case CB_TAG_BOARD_CONFIG: {
+ struct cb_board_config *bc =
+ (struct cb_board_config *)rec;
+
+ if (rec_size < sizeof(*bc))
+ break;
+ sc->fw_config = bc->fw_config;
+ sc->board_id = bc->board_id;
+ sc->ram_code = bc->ram_code;
+ sc->sku_id = bc->sku_id;
+ sc->has_board_config = 1;
+ break;
+ }
+
+ case CB_TAG_MAC_ADDRS: {
+ struct cb_macs *macs = (struct cb_macs *)rec;
+ uint32_t i, count;
+
+ if (rec_size < sizeof(*macs))
+ break;
+ count = macs->count;
+ if (count > CB_MAX_MAC_ADDRS)
+ count = CB_MAX_MAC_ADDRS;
+ if (rec_size < sizeof(*macs) +
+ count * sizeof(struct cb_mac_address))
+ break;
+ for (i = 0; i < count; i++)
+ sc->macs[i] = macs->entries[i];
+ sc->mac_count = count;
+ break;
+ }
+
+ case CB_TAG_ACPI_RSDP: {
+ struct cb_acpi_rsdp *rsdp =
+ (struct cb_acpi_rsdp *)rec;
+
+ if (rec_size < sizeof(*rsdp))
+ break;
+ sc->acpi_rsdp = rsdp->rsdp_pointer;
+ sc->has_acpi_rsdp = 1;
+ break;
+ }
+
+ case CB_TAG_SPI_FLASH: {
+ struct cb_spi_flash *spi =
+ (struct cb_spi_flash *)rec;
+
+ if (rec_size < sizeof(*spi))
+ break;
+ sc->spi_flash_size = spi->flash_size;
+ sc->spi_sector_size = spi->sector_size;
+ sc->spi_erase_cmd = spi->erase_cmd;
+ sc->spi_flags = spi->flags;
+ sc->has_spi_flash = 1;
+ break;
+ }
+
+ case CB_TAG_CONSOLE: {
+ struct cb_console *con = (struct cb_console *)rec;
+
+ if (rec_size < sizeof(*con))
+ break;
+ sc->console_type = con->type;
+ sc->has_console_type = 1;
+ break;
+ }
+
+ case CB_TAG_FRAMEBUFFER: {
+ struct cb_framebuffer *fb =
+ (struct cb_framebuffer *)rec;
+
+ if (rec_size < CB_FRAMEBUFFER_MIN_SIZE)
+ break;
+ sc->fb_addr = fb->physical_address;
+ sc->fb_x_res = fb->x_resolution;
+ sc->fb_y_res = fb->y_resolution;
+ sc->fb_stride = fb->bytes_per_line;
+ sc->fb_bpp = fb->bits_per_pixel;
+ sc->has_framebuffer = 1;
+ break;
*** 2420 LINES SKIPPED ***