xref: /freebsd/sys/dev/coreboot/coreboot_cbmem.c (revision 5f74217c05a99f38a31a6e4950220964595d4ac8)
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