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>
