Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jul 2026 19:25:23 +0000
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Abdelkader Boudih <freebsd@seuros.com>
Subject:   git: 5f74217c05a9 - main - coreboot: Add coreboot firmware table driver
Message-ID:  <6a6a53a3.45234.2b3d1ac2@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a6a53a3.45234.2b3d1ac2>