1*5f74217cSAbdelkader Boudih /*
2*5f74217cSAbdelkader Boudih * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
3*5f74217cSAbdelkader Boudih *
4*5f74217cSAbdelkader Boudih * SPDX-License-Identifier: BSD-2-Clause
5*5f74217cSAbdelkader Boudih */
6*5f74217cSAbdelkader Boudih
7*5f74217cSAbdelkader Boudih /*
8*5f74217cSAbdelkader Boudih * /dev/cbmem — ioctl interface for CBMEM entry enumeration and read
9*5f74217cSAbdelkader Boudih *
10*5f74217cSAbdelkader Boudih * Provides structured access to coreboot's CBMEM entries without
11*5f74217cSAbdelkader Boudih * requiring /dev/mem. Entries can be listed (CBMEM_IOC_LIST) or
12*5f74217cSAbdelkader Boudih * read by ID (CBMEM_IOC_READ).
13*5f74217cSAbdelkader Boudih */
14*5f74217cSAbdelkader Boudih
15*5f74217cSAbdelkader Boudih #include <sys/systm.h>
16*5f74217cSAbdelkader Boudih #include <sys/bus.h>
17*5f74217cSAbdelkader Boudih #include <sys/conf.h>
18*5f74217cSAbdelkader Boudih #include <sys/ioccom.h>
19*5f74217cSAbdelkader Boudih #include <sys/kernel.h>
20*5f74217cSAbdelkader Boudih #include <sys/module.h>
21*5f74217cSAbdelkader Boudih #include <sys/uio.h>
22*5f74217cSAbdelkader Boudih
23*5f74217cSAbdelkader Boudih #include <vm/vm.h>
24*5f74217cSAbdelkader Boudih #include <vm/vm_param.h>
25*5f74217cSAbdelkader Boudih #include <vm/pmap.h>
26*5f74217cSAbdelkader Boudih
27*5f74217cSAbdelkader Boudih #include <dev/coreboot/coreboot.h>
28*5f74217cSAbdelkader Boudih
29*5f74217cSAbdelkader Boudih static d_ioctl_t coreboot_cbmem_ioctl;
30*5f74217cSAbdelkader Boudih
31*5f74217cSAbdelkader Boudih static struct cdevsw coreboot_cbmem_cdevsw = {
32*5f74217cSAbdelkader Boudih .d_version = D_VERSION,
33*5f74217cSAbdelkader Boudih .d_ioctl = coreboot_cbmem_ioctl,
34*5f74217cSAbdelkader Boudih .d_name = "cbmem",
35*5f74217cSAbdelkader Boudih };
36*5f74217cSAbdelkader Boudih
37*5f74217cSAbdelkader Boudih /*
38*5f74217cSAbdelkader Boudih * Find a CBMEM entry by its ID.
39*5f74217cSAbdelkader Boudih */
40*5f74217cSAbdelkader Boudih static struct cbmem_entry_info *
cbmem_find_entry(struct coreboot_softc * sc,uint32_t id)41*5f74217cSAbdelkader Boudih cbmem_find_entry(struct coreboot_softc *sc, uint32_t id)
42*5f74217cSAbdelkader Boudih {
43*5f74217cSAbdelkader Boudih uint32_t i;
44*5f74217cSAbdelkader Boudih
45*5f74217cSAbdelkader Boudih for (i = 0; i < sc->cbmem_count; i++) {
46*5f74217cSAbdelkader Boudih if (sc->cbmem_entries[i].id == id)
47*5f74217cSAbdelkader Boudih return (&sc->cbmem_entries[i]);
48*5f74217cSAbdelkader Boudih }
49*5f74217cSAbdelkader Boudih return (NULL);
50*5f74217cSAbdelkader Boudih }
51*5f74217cSAbdelkader Boudih
52*5f74217cSAbdelkader Boudih static int
coreboot_cbmem_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)53*5f74217cSAbdelkader Boudih coreboot_cbmem_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
54*5f74217cSAbdelkader Boudih struct thread *td)
55*5f74217cSAbdelkader Boudih {
56*5f74217cSAbdelkader Boudih struct coreboot_softc *sc;
57*5f74217cSAbdelkader Boudih int error;
58*5f74217cSAbdelkader Boudih
59*5f74217cSAbdelkader Boudih sc = dev->si_drv1;
60*5f74217cSAbdelkader Boudih
61*5f74217cSAbdelkader Boudih switch (cmd) {
62*5f74217cSAbdelkader Boudih case CBMEM_IOC_LIST: {
63*5f74217cSAbdelkader Boudih struct cbmem_list *list = (struct cbmem_list *)data;
64*5f74217cSAbdelkader Boudih
65*5f74217cSAbdelkader Boudih list->count = sc->cbmem_count;
66*5f74217cSAbdelkader Boudih memcpy(list->entries, sc->cbmem_entries,
67*5f74217cSAbdelkader Boudih sc->cbmem_count * sizeof(struct cbmem_entry_info));
68*5f74217cSAbdelkader Boudih error = 0;
69*5f74217cSAbdelkader Boudih break;
70*5f74217cSAbdelkader Boudih }
71*5f74217cSAbdelkader Boudih
72*5f74217cSAbdelkader Boudih case CBMEM_IOC_READ: {
73*5f74217cSAbdelkader Boudih struct cbmem_read_req *req = (struct cbmem_read_req *)data;
74*5f74217cSAbdelkader Boudih struct cbmem_entry_info *info;
75*5f74217cSAbdelkader Boudih void *mapped;
76*5f74217cSAbdelkader Boudih vm_size_t map_size;
77*5f74217cSAbdelkader Boudih uint64_t paddr;
78*5f74217cSAbdelkader Boudih
79*5f74217cSAbdelkader Boudih info = cbmem_find_entry(sc, req->id);
80*5f74217cSAbdelkader Boudih if (info == NULL) {
81*5f74217cSAbdelkader Boudih error = ENOENT;
82*5f74217cSAbdelkader Boudih break;
83*5f74217cSAbdelkader Boudih }
84*5f74217cSAbdelkader Boudih
85*5f74217cSAbdelkader Boudih if (req->offset >= info->size) {
86*5f74217cSAbdelkader Boudih error = EINVAL;
87*5f74217cSAbdelkader Boudih break;
88*5f74217cSAbdelkader Boudih }
89*5f74217cSAbdelkader Boudih
90*5f74217cSAbdelkader Boudih if (req->size > info->size - req->offset)
91*5f74217cSAbdelkader Boudih req->size = info->size - req->offset;
92*5f74217cSAbdelkader Boudih
93*5f74217cSAbdelkader Boudih if (req->size == 0) {
94*5f74217cSAbdelkader Boudih error = 0;
95*5f74217cSAbdelkader Boudih break;
96*5f74217cSAbdelkader Boudih }
97*5f74217cSAbdelkader Boudih
98*5f74217cSAbdelkader Boudih if (info->address > UINT64_MAX - req->offset) {
99*5f74217cSAbdelkader Boudih error = EINVAL;
100*5f74217cSAbdelkader Boudih break;
101*5f74217cSAbdelkader Boudih }
102*5f74217cSAbdelkader Boudih paddr = info->address + req->offset;
103*5f74217cSAbdelkader Boudih map_size = req->size;
104*5f74217cSAbdelkader Boudih mapped = pmap_mapbios((vm_paddr_t)paddr, map_size);
105*5f74217cSAbdelkader Boudih if (mapped == NULL) {
106*5f74217cSAbdelkader Boudih error = ENOMEM;
107*5f74217cSAbdelkader Boudih break;
108*5f74217cSAbdelkader Boudih }
109*5f74217cSAbdelkader Boudih
110*5f74217cSAbdelkader Boudih error = copyout(mapped, req->buffer, req->size);
111*5f74217cSAbdelkader Boudih
112*5f74217cSAbdelkader Boudih pmap_unmapbios(mapped, map_size);
113*5f74217cSAbdelkader Boudih break;
114*5f74217cSAbdelkader Boudih }
115*5f74217cSAbdelkader Boudih
116*5f74217cSAbdelkader Boudih default:
117*5f74217cSAbdelkader Boudih error = ENOTTY;
118*5f74217cSAbdelkader Boudih break;
119*5f74217cSAbdelkader Boudih }
120*5f74217cSAbdelkader Boudih
121*5f74217cSAbdelkader Boudih return (error);
122*5f74217cSAbdelkader Boudih }
123*5f74217cSAbdelkader Boudih
124*5f74217cSAbdelkader Boudih int
coreboot_cbmem_create(struct coreboot_softc * sc)125*5f74217cSAbdelkader Boudih coreboot_cbmem_create(struct coreboot_softc *sc)
126*5f74217cSAbdelkader Boudih {
127*5f74217cSAbdelkader Boudih struct make_dev_args args;
128*5f74217cSAbdelkader Boudih int error;
129*5f74217cSAbdelkader Boudih
130*5f74217cSAbdelkader Boudih if (sc->cbmem_count == 0)
131*5f74217cSAbdelkader Boudih return (ENXIO);
132*5f74217cSAbdelkader Boudih
133*5f74217cSAbdelkader Boudih make_dev_args_init(&args);
134*5f74217cSAbdelkader Boudih args.mda_devsw = &coreboot_cbmem_cdevsw;
135*5f74217cSAbdelkader Boudih args.mda_uid = UID_ROOT;
136*5f74217cSAbdelkader Boudih args.mda_gid = GID_WHEEL;
137*5f74217cSAbdelkader Boudih args.mda_mode = 0440;
138*5f74217cSAbdelkader Boudih args.mda_si_drv1 = sc;
139*5f74217cSAbdelkader Boudih error = make_dev_s(&args, &sc->cbmem_cdev, "cbmem");
140*5f74217cSAbdelkader Boudih if (error != 0)
141*5f74217cSAbdelkader Boudih return (error);
142*5f74217cSAbdelkader Boudih
143*5f74217cSAbdelkader Boudih return (0);
144*5f74217cSAbdelkader Boudih }
145*5f74217cSAbdelkader Boudih
146*5f74217cSAbdelkader Boudih void
coreboot_cbmem_destroy(struct coreboot_softc * sc)147*5f74217cSAbdelkader Boudih coreboot_cbmem_destroy(struct coreboot_softc *sc)
148*5f74217cSAbdelkader Boudih {
149*5f74217cSAbdelkader Boudih
150*5f74217cSAbdelkader Boudih coreboot_cdev_destroy(&sc->cbmem_cdev);
151*5f74217cSAbdelkader Boudih }
152