Files
Abdelkader Boudih 5f74217c05 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
2026-07-29 12:12:41 -07:00

152 lines
2.9 KiB
C

/*
* Copyright (c) 2026 Abdelkader Boudih <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/*
* /dev/cbmem — ioctl interface for CBMEM entry enumeration and read
*
* Provides structured access to coreboot's CBMEM entries without
* requiring /dev/mem. Entries can be listed (CBMEM_IOC_LIST) or
* read by ID (CBMEM_IOC_READ).
*/
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/ioccom.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/uio.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <dev/coreboot/coreboot.h>
static d_ioctl_t coreboot_cbmem_ioctl;
static struct cdevsw coreboot_cbmem_cdevsw = {
.d_version = D_VERSION,
.d_ioctl = coreboot_cbmem_ioctl,
.d_name = "cbmem",
};
/*
* Find a CBMEM entry by its ID.
*/
static struct cbmem_entry_info *
cbmem_find_entry(struct coreboot_softc *sc, uint32_t id)
{
uint32_t i;
for (i = 0; i < sc->cbmem_count; i++) {
if (sc->cbmem_entries[i].id == id)
return (&sc->cbmem_entries[i]);
}
return (NULL);
}
static int
coreboot_cbmem_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
struct thread *td)
{
struct coreboot_softc *sc;
int error;
sc = dev->si_drv1;
switch (cmd) {
case CBMEM_IOC_LIST: {
struct cbmem_list *list = (struct cbmem_list *)data;
list->count = sc->cbmem_count;
memcpy(list->entries, sc->cbmem_entries,
sc->cbmem_count * sizeof(struct cbmem_entry_info));
error = 0;
break;
}
case CBMEM_IOC_READ: {
struct cbmem_read_req *req = (struct cbmem_read_req *)data;
struct cbmem_entry_info *info;
void *mapped;
vm_size_t map_size;
uint64_t paddr;
info = cbmem_find_entry(sc, req->id);
if (info == NULL) {
error = ENOENT;
break;
}
if (req->offset >= info->size) {
error = EINVAL;
break;
}
if (req->size > info->size - req->offset)
req->size = info->size - req->offset;
if (req->size == 0) {
error = 0;
break;
}
if (info->address > UINT64_MAX - req->offset) {
error = EINVAL;
break;
}
paddr = info->address + req->offset;
map_size = req->size;
mapped = pmap_mapbios((vm_paddr_t)paddr, map_size);
if (mapped == NULL) {
error = ENOMEM;
break;
}
error = copyout(mapped, req->buffer, req->size);
pmap_unmapbios(mapped, map_size);
break;
}
default:
error = ENOTTY;
break;
}
return (error);
}
int
coreboot_cbmem_create(struct coreboot_softc *sc)
{
struct make_dev_args args;
int error;
if (sc->cbmem_count == 0)
return (ENXIO);
make_dev_args_init(&args);
args.mda_devsw = &coreboot_cbmem_cdevsw;
args.mda_uid = UID_ROOT;
args.mda_gid = GID_WHEEL;
args.mda_mode = 0440;
args.mda_si_drv1 = sc;
error = make_dev_s(&args, &sc->cbmem_cdev, "cbmem");
if (error != 0)
return (error);
return (0);
}
void
coreboot_cbmem_destroy(struct coreboot_softc *sc)
{
coreboot_cdev_destroy(&sc->cbmem_cdev);
}