The branch main has been updated by adrian:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5f74217c05a99f38a31a6e4950220964595d4ac8

commit 5f74217c05a99f38a31a6e4950220964595d4ac8
Author:     Abdelkader Boudih <[email protected]>
AuthorDate: 2026-07-29 19:11:55 +0000
Commit:     Adrian Chadd <[email protected]>
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 <[email protected]>
+.\"
+.\" 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 [email protected] .
+.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 <[email protected]>
+ *
+ * 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 ***

Reply via email to