/* * Copyright (c) 2026 Abdelkader Boudih * * SPDX-License-Identifier: BSD-2-Clause */ /* * coreboot(4) driver for FreeBSD * * Structures and constants derived from the coreboot table specification. */ #ifndef _DEV_COREBOOT_COREBOOT_H_ #define _DEV_COREBOOT_COREBOOT_H_ #include #include #include #include #include #define CB_HEADER_SIGNATURE "LBIO" #define CB_HEADER_SIG_LEN 4 /* * Memory scan range for coreboot table discovery. * Low memory (0x0–0x1000) contains a forward pointer to the real table. */ #define CB_SCAN_LOW_START 0x00000000 #define CB_SCAN_LOW_END 0x00001000 #define CB_SCAN_LOW_STEP 16 /* * Defensive limits for parsing untrusted firmware-provided lengths. */ #define CB_TABLE_ALIGN 4 #define CB_MAX_HEADER_BYTES 4096 #define CB_MAX_TABLE_BYTES (1024 * 1024) #define CB_MAX_TABLE_MAP_BYTES (CB_MAX_HEADER_BYTES + CB_MAX_TABLE_BYTES) #define CB_MAX_CONSOLE_BYTES (1024 * 1024) /* * Coreboot table record tags - only tags we actually parse. * Full enum preserved for forward compatibility (unknown tags are skipped). */ enum cb_tag { CB_TAG_UNUSED = 0x0000, CB_TAG_MAINBOARD = 0x0003, CB_TAG_VERSION = 0x0004, CB_TAG_EXTRA_VERSION = 0x0005, CB_TAG_BUILD = 0x0006, CB_TAG_COMPILE_TIME = 0x0007, CB_TAG_COMPILER = 0x000b, CB_TAG_SERIAL = 0x000f, CB_TAG_CONSOLE = 0x0010, CB_TAG_FORWARD = 0x0011, CB_TAG_FRAMEBUFFER = 0x0012, CB_TAG_GPIO = 0x0013, CB_TAG_TIMESTAMPS = 0x0016, CB_TAG_CBMEM_CONSOLE = 0x0017, CB_TAG_ACPI_GNVS = 0x0024, CB_TAG_VERSION_TIMESTAMP = 0x0026, CB_TAG_WIFI_CALIBRATION = 0x0027, CB_TAG_SPI_FLASH = 0x0029, CB_TAG_SERIALNO = 0x002a, CB_TAG_VPD = 0x002c, CB_TAG_BOOT_MEDIA_PARAMS = 0x0030, CB_TAG_CBMEM_ENTRY = 0x0031, CB_TAG_TSC_INFO = 0x0032, CB_TAG_MAC_ADDRS = 0x0033, CB_TAG_VBOOT_WORKBUF = 0x0034, CB_TAG_MMC_INFO = 0x0035, CB_TAG_TPM_CB_LOG = 0x0036, CB_TAG_FMAP = 0x0037, CB_TAG_PLATFORM_BLOB_VERSION = 0x0038, CB_TAG_SMMSTOREV2 = 0x0039, CB_TAG_TPM_PPI_HANDOFF = 0x003a, CB_TAG_BOARD_CONFIG = 0x0040, CB_TAG_ACPI_CNVS = 0x0041, CB_TAG_TYPE_C_INFO = 0x0042, CB_TAG_ACPI_RSDP = 0x0043, CB_TAG_PCIE = 0x0044, CB_TAG_ROOT_BRIDGE_INFO = 0x0048, }; /* * Coreboot table header - located at a physical address found by scanning * low memory for the "LBIO" signature. */ struct cb_header { uint8_t signature[CB_HEADER_SIG_LEN]; uint32_t header_bytes; uint32_t header_checksum; uint32_t table_bytes; uint32_t table_checksum; uint32_t table_entries; } __packed; /* * Generic record header - every table entry starts with this. */ struct cb_record { uint32_t tag; uint32_t size; } __packed; /* * CB_TAG_FORWARD - pointer to the real table in high memory. */ struct cb_forward { uint32_t tag; uint32_t size; uint64_t forward; } __packed; /* * CB_TAG_MAINBOARD - board vendor and part number. * Strings are packed after the struct, indexed by vendor_idx and part_idx. */ struct cb_mainboard { uint32_t tag; uint32_t size; uint8_t vendor_idx; uint8_t part_idx; uint8_t strings[]; } __packed; /* * Variable-length string record - used by VERSION, BUILD, COMPILE_*, etc. */ struct cb_string { uint32_t tag; uint32_t size; uint8_t string[]; } __packed; /* * CB_TAG_SERIAL - serial port configuration. */ struct cb_serial { uint32_t tag; uint32_t size; uint32_t type; uint32_t baseaddr; uint32_t baud; uint32_t regwidth; uint32_t input_hertz; } __packed; /* * CB_TAG_CBMEM_CONSOLE - pointer to firmware console ring buffer. */ struct cb_cbmem_ref { uint32_t tag; uint32_t size; uint64_t cbmem_addr; } __packed; /* * CB_TAG_CBMEM_ENTRY - one per CBMEM region. */ struct cb_cbmem_entry { uint32_t tag; uint32_t size; uint64_t address; uint32_t entry_size; uint32_t id; } __packed; /* * CB_TAG_TSC_INFO - TSC frequency. */ struct cb_tsc_info { uint32_t tag; uint32_t size; uint32_t freq_khz; } __packed; /* * CB_TAG_VERSION_TIMESTAMP - build version timestamp. * timestamp is Unix time in seconds (seconds since 1970-01-01 UTC). */ struct cb_version_timestamp { uint32_t tag; uint32_t size; uint32_t timestamp; } __packed; /* * CB_TAG_BOARD_CONFIG - board identification and firmware config. */ struct cb_board_config { uint32_t tag; uint32_t size; uint64_t fw_config; uint32_t board_id; uint32_t ram_code; uint32_t sku_id; } __packed; /* * CB_TAG_BOOT_MEDIA_PARAMS - offsets and sizes on boot media. */ struct cb_boot_media_params { uint32_t tag; uint32_t size; uint64_t fmap_offset; uint64_t cbfs_offset; uint64_t cbfs_size; uint64_t boot_media_size; } __packed; /* * CB_TAG_MMC_INFO - early eMMC/MMC status. */ struct cb_mmc_info { uint32_t tag; uint32_t size; int32_t early_cmd1_status; } __packed; /* * CB_TAG_PCIE - PCIe controller base address. */ struct cb_pcie { uint32_t tag; uint32_t size; uint64_t ctrl_base; } __packed; /* * CB_TAG_MAC_ADDRS - factory-provisioned MAC addresses. */ struct cb_mac_address { uint8_t mac_addr[6]; uint8_t pad[2]; } __packed; struct cb_macs { uint32_t tag; uint32_t size; uint32_t count; struct cb_mac_address entries[]; } __packed; /* * CB_TAG_SPI_FLASH - SPI flash chip parameters. */ struct cb_flash_mmap_window { uint32_t flash_base; uint32_t host_base; uint32_t size; } __packed; struct cb_spi_flash { uint32_t tag; uint32_t size; uint32_t flash_size; uint32_t sector_size; uint8_t erase_cmd; uint8_t flags; uint16_t reserved; uint32_t mmap_count; struct cb_flash_mmap_window mmap_table[]; } __packed; /* * CB_TAG_CONSOLE - firmware console type. */ struct cb_console { uint32_t tag; uint32_t size; uint16_t type; uint8_t pad[2]; } __packed; #define CB_CONSOLE_SERIAL8250 0 #define CB_CONSOLE_VGA 1 /* obsolete */ #define CB_CONSOLE_EHCI 5 #define CB_CONSOLE_SERIAL8250MEM 6 /* * CB_TAG_FRAMEBUFFER - linear framebuffer info. * The orientation, flags, and pad fields were added later. * Minimum record size is up to reserved_mask_size (29 bytes). */ #define CB_FRAMEBUFFER_MIN_SIZE 29 struct cb_framebuffer { uint32_t tag; uint32_t size; uint64_t physical_address; uint32_t x_resolution; uint32_t y_resolution; uint32_t bytes_per_line; uint8_t bits_per_pixel; uint8_t red_mask_pos; uint8_t red_mask_size; uint8_t green_mask_pos; uint8_t green_mask_size; uint8_t blue_mask_pos; uint8_t blue_mask_size; uint8_t reserved_mask_pos; uint8_t reserved_mask_size; uint8_t orientation; uint8_t flags; uint8_t pad; } __packed; /* * CB_TAG_GPIO - GPIO pin states. */ struct cb_gpio { uint32_t port; uint32_t polarity; uint32_t value; uint8_t name[16]; } __packed; struct cb_gpios { uint32_t tag; uint32_t size; uint32_t count; struct cb_gpio entries[]; } __packed; /* * CB_TAG_TPM_PPI_HANDOFF - TPM Physical Presence Interface handoff. */ struct cb_tpm_ppi { uint32_t tag; uint32_t size; uint32_t ppi_address; uint8_t tpm_version; /* 1=TPM1.2, 2=TPM2.0 */ uint8_t ppi_version; /* BCD encoded */ uint8_t pad[2]; } __packed; /* * CB_TAG_SMMSTOREV2 - SMM-based variable store configuration. * * The mmap_addr field was added after the initial implementation. * Older coreboot emits a shorter record (32 bytes) without it. * Consumers must check rec->size to detect whether mmap_addr is present. */ #define CB_SMMSTOREV2_BASE_SIZE 32 /* size without mmap_addr */ struct cb_smmstorev2 { uint32_t tag; uint32_t size; uint32_t num_blocks; uint32_t block_size; uint32_t mmap_addr_lo; /* deprecated 32-bit address */ uint32_t com_buffer; uint32_t com_buffer_size; uint8_t apm_cmd; uint8_t unused[3]; /* Fields below only present if size > CB_SMMSTOREV2_BASE_SIZE */ uint64_t mmap_addr; /* 64-bit address (preferred) */ } __packed; /* * CB_TAG_ACPI_RSDP - ACPI Root System Description Pointer address. */ struct cb_acpi_rsdp { uint32_t tag; uint32_t size; uint64_t rsdp_pointer; } __packed; /* * CBMEM console ring buffer (in-memory structure at cbmem_addr). * Bit 31 of cursor indicates overflow (ring has wrapped). */ struct cbmem_console { uint32_t size; uint32_t cursor; uint8_t body[]; } __packed; #define CBMEM_CONSOLE_CURSOR_MASK ((1 << 28) - 1) #define CBMEM_CONSOLE_OVERFLOW (1 << 31) #define CB_MAX_MAC_ADDRS 8 #define CB_MAX_GPIOS 32 /* * Driver softc */ struct coreboot_softc { device_t dev; vm_paddr_t table_paddr; vm_size_t table_size; void *table_vaddr; char version[64]; char build[64]; char compile_time[64]; char compiler[128]; char extra_version[64]; char platform_blob_version[64]; char serialno[64]; uint32_t version_timestamp; int has_version_timestamp; char mb_vendor[64]; char mb_part[64]; uint32_t serial_baseaddr; uint32_t serial_baud; uint32_t serial_regwidth; int has_serial; uint32_t tsc_freq_khz; int has_tsc_info; uint64_t pcie_ctrl_base; int has_pcie; uint64_t fmap_offset; uint64_t cbfs_offset; uint64_t cbfs_size; uint64_t boot_media_size; int has_boot_media; int32_t mmc_early_cmd1_status; int has_mmc_info; vm_paddr_t console_paddr; vm_size_t console_size; uint32_t console_data_size; struct cbmem_console *console_vaddr; int has_console; struct cdev *console_cdev; uint32_t cbmem_count; struct cbmem_entry_info cbmem_entries[CB_MAX_CBMEM_ENTRIES]; struct cdev *cbmem_cdev; uint64_t fw_config; uint32_t board_id; uint32_t ram_code; uint32_t sku_id; int has_board_config; uint32_t mac_count; struct cb_mac_address macs[CB_MAX_MAC_ADDRS]; char mac_strs[CB_MAX_MAC_ADDRS][18]; uint64_t acpi_rsdp; int has_acpi_rsdp; uint32_t spi_flash_size; uint32_t spi_sector_size; uint8_t spi_erase_cmd; uint8_t spi_flags; int has_spi_flash; uint16_t console_type; int has_console_type; uint64_t fb_addr; uint32_t fb_x_res; uint32_t fb_y_res; uint32_t fb_stride; uint8_t fb_bpp; int has_framebuffer; uint32_t gpio_count; struct cb_gpio gpios[CB_MAX_GPIOS]; uint32_t tpm_ppi_addr; uint8_t tpm_version; int has_tpm; vm_paddr_t tpm_log_paddr; int has_tpm_log; vm_paddr_t acpi_gnvs_paddr; int has_acpi_gnvs; vm_paddr_t acpi_cnvs_paddr; int has_acpi_cnvs; vm_paddr_t vpd_paddr; int has_vpd; vm_paddr_t wifi_cal_paddr; int has_wifi_cal; vm_paddr_t fmap_paddr; int has_fmap; vm_paddr_t vboot_workbuf_paddr; int has_vboot_workbuf; vm_paddr_t type_c_info_paddr; int has_type_c_info; vm_paddr_t root_bridge_info_paddr; int has_root_bridge_info; uint32_t smmstore_num_blocks; uint32_t smmstore_block_size; uint64_t smmstore_mmap_addr; uint32_t smmstore_com_buffer; uint8_t smmstore_apm_cmd; int has_smmstore; vm_paddr_t timestamps_paddr; int has_timestamps; struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; }; /* * Generic ID-to-name linear search. * The table must be terminated by an entry with name == NULL. * Returns fallback if no match is found. */ struct cb_id_name { uint32_t id; const char *name; }; static __inline const char * cb_id_lookup(const struct cb_id_name *tbl, uint32_t id, const char *fallback) { int i; for (i = 0; tbl[i].name != NULL; i++) { if (tbl[i].id == id) return (tbl[i].name); } return (fallback); } /* * CBMEM ID to human-readable name lookup. */ static __inline const char * cbmem_id_to_name(uint32_t id) { static const struct cb_id_name names[] = { { CBMEM_ID_ACPI, "ACPI" }, { CBMEM_ID_ACPI_GNVS, "ACPI GNVS" }, { CBMEM_ID_AFTER_CAR, "AFTER CAR" }, { CBMEM_ID_CBTABLE, "COREBOOT" }, { CBMEM_ID_CBTABLE_FWD, "COREBOOT FWD" }, { CBMEM_ID_CBFS_RO_MCACHE, "RO MCACHE" }, { CBMEM_ID_CBFS_RW_MCACHE, "RW MCACHE" }, { CBMEM_ID_CONSOLE, "CONSOLE" }, { CBMEM_ID_ELOG, "ELOG" }, { CBMEM_ID_FMAP, "FMAP" }, { CBMEM_ID_FREESPACE, "FREE SPACE" }, { CBMEM_ID_FSP_RESERVED_MEMORY, "FSP MEMORY" }, { CBMEM_ID_FSP_RUNTIME, "FSP RUNTIME" }, { CBMEM_ID_FSPM_VERSION, "FSPM VERSION" }, { CBMEM_ID_IGD_OPREGION, "IGD OPREGION" }, { CBMEM_ID_IMD_ROOT, "IMD ROOT" }, { CBMEM_ID_IMD_SMALL, "IMD SMALL" }, { CBMEM_ID_MEMINFO, "MEM INFO" }, { CBMEM_ID_MPTABLE, "SMP TABLE" }, { CBMEM_ID_MRCDATA, "MRC DATA" }, { CBMEM_ID_PIRQ, "IRQ TABLE" }, { CBMEM_ID_POWER_STATE, "POWER STATE" }, { CBMEM_ID_RAM_OOPS, "RAMOOPS" }, { CBMEM_ID_RAMSTAGE, "RAMSTAGE" }, { CBMEM_ID_REFCODE, "REFCODE" }, { CBMEM_ID_RESUME, "ACPI RESUME" }, { CBMEM_ID_ROMSTAGE_INFO, "ROMSTAGE" }, { CBMEM_ID_ROMSTAGE_RAM_STACK, "ROMSTG STACK" }, { CBMEM_ID_ROOT, "CBMEM ROOT" }, { CBMEM_ID_SMBIOS, "SMBIOS" }, { CBMEM_ID_SMM_COMBUFFER, "SMM COMBUF" }, { CBMEM_ID_SMM_SAVE_SPACE, "SMM BACKUP" }, { CBMEM_ID_TIMESTAMP, "TIMESTAMP" }, { CBMEM_ID_VBOOT_WORKBUF, "VBOOT WORK" }, { CBMEM_ID_VPD, "VPD" }, { 0, NULL } }; return (cb_id_lookup(names, id, "UNKNOWN")); } /* * IP-style 16-bit checksum (RFC 1071) over 16-bit words. * When computed over data including its checksum field, result is 0. */ static __inline uint16_t cb_checksum(const void *ptr, size_t len) { const uint8_t *p = (const uint8_t *)ptr; uint32_t sum = 0; size_t i; for (i = 0; i + 1 < len; i += 2) sum += (uint32_t)p[i] | ((uint32_t)p[i + 1] << 8); if (i < len) sum += p[i]; while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); return ((uint16_t)~sum); } /* * Destroy a character device and clear the pointer. * Safe to call with a NULL cdev pointer. */ static __inline void coreboot_cdev_destroy(struct cdev **cdevp) { if (*cdevp != NULL) { destroy_dev(*cdevp); *cdevp = NULL; } } /* Functions exported from coreboot.c */ struct coreboot_softc *coreboot_get_softc(void); /* Functions exported from coreboot_console.c */ int coreboot_console_create(struct coreboot_softc *sc); void coreboot_console_destroy(struct coreboot_softc *sc); /* Functions exported from coreboot_cbmem.c */ int coreboot_cbmem_create(struct coreboot_softc *sc); void coreboot_cbmem_destroy(struct coreboot_softc *sc); /* Functions exported from coreboot_timestamps.c */ int coreboot_timestamps_register(struct coreboot_softc *sc, struct sysctl_oid *parent); #endif /* _DEV_COREBOOT_COREBOOT_H_ */