mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-31 12:56:10 +01:00
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
152 lines
2.9 KiB
C
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);
|
|
}
|