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