1 /* $NetBSD: smbios.c,v 1.4 2021/09/16 22:19:10 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1999, by UCHIYAMA Yasushi 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. The name of the developer may NOT be used to endorse or promote products 43 * derived from this software without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 /* 59 * Copyright (c) 1997-2001 Michael Shalayeff 60 * All rights reserved. 61 * 62 * Redistribution and use in source and binary forms, with or without 63 * modification, are permitted provided that the following conditions 64 * are met: 65 * 1. Redistributions of source code must retain the above copyright 66 * notice, this list of conditions and the following disclaimer. 67 * 2. Redistributions in binary form must reproduce the above copyright 68 * notice, this list of conditions and the following disclaimer in the 69 * documentation and/or other materials provided with the distribution. 70 * 71 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 72 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 73 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 74 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 75 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 76 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 77 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 78 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 79 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 80 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 81 * THE POSSIBILITY OF SUCH DAMAGE. 82 */ 83 84 /* 85 * Basic interface to System Management BIOS (SMBIOS) tables. 86 */ 87 88 #include <sys/cdefs.h> 89 __KERNEL_RCSID(0, "$NetBSD: smbios.c,v 1.4 2021/09/16 22:19:10 andvar Exp $"); 90 91 #include <sys/param.h> 92 #include <sys/conf.h> 93 #include <sys/systm.h> 94 #include <sys/device.h> 95 96 #include <uvm/uvm_extern.h> 97 98 #include <dev/smbiosvar.h> 99 100 #define SMBIOS_MAKESIG(a, b, c, d) \ 101 ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) 102 103 struct smbios_entry smbios_entry; 104 105 static dev_type_read(smbios_read); 106 107 const struct cdevsw smbios_cdevsw = { 108 .d_open = nullopen, 109 .d_close = nullclose, 110 .d_read = smbios_read, 111 .d_write = nowrite, 112 .d_ioctl = noioctl, 113 .d_stop = nostop, 114 .d_tty = notty, 115 .d_poll = nopoll, 116 .d_mmap = nommap, 117 .d_kqfilter = nokqfilter, 118 .d_discard = nodiscard, 119 .d_flag = D_OTHER | D_MPSAFE, 120 }; 121 122 static void * 123 smbios_map_memory(paddr_t pa, size_t size) 124 { 125 paddr_t spa, epa, curpa; 126 vaddr_t va, curva; 127 128 spa = trunc_page(pa); 129 epa = round_page(pa + size); 130 131 va = uvm_km_alloc(kernel_map, epa - spa, 0, UVM_KMF_VAONLY); 132 if (va == 0) { 133 return NULL; 134 } 135 136 for (curpa = spa, curva = va; curpa < epa; curpa += PAGE_SIZE, curva += PAGE_SIZE) { 137 pmap_kenter_pa(curva, curpa, VM_PROT_READ, PMAP_WRITE_BACK); 138 } 139 pmap_update(pmap_kernel()); 140 141 return (void *)(uintptr_t)(va + (pa - spa)); 142 } 143 144 static void 145 smbios_unmap_memory(void *va, size_t size) 146 { 147 vaddr_t ova; 148 vsize_t osz; 149 150 ova = trunc_page((vaddr_t)va); 151 osz = round_page((vaddr_t)va + size) - ova; 152 153 pmap_kremove(ova, osz); 154 pmap_update(pmap_kernel()); 155 uvm_km_free(kernel_map, ova, osz, UVM_KMF_VAONLY); 156 } 157 158 /* 159 * smbios_read -- 160 * 161 * Read data from an SMBIOS table that resides in physical memory. 162 */ 163 static int 164 smbios_read(dev_t dev, struct uio *uio, int flag) 165 { 166 paddr_t pa; 167 uint8_t *data; 168 size_t len; 169 int error; 170 171 if (smbios_entry.addr == NULL) { 172 return EIO; 173 } 174 if (uio->uio_rw != UIO_READ) { 175 return EPERM; 176 } 177 178 pa = uio->uio_offset; 179 if (pa == smbios_entry.hdrphys) { 180 /* SMBIOS header */ 181 len = uimin(0x20, uio->uio_resid); 182 183 } else { 184 /* Table data */ 185 if (pa < smbios_entry.tabphys || 186 pa >= smbios_entry.tabphys + smbios_entry.len) { 187 return EFAULT; 188 } 189 len = uimin(smbios_entry.len - (pa - smbios_entry.tabphys), 190 uio->uio_resid); 191 } 192 193 data = smbios_map_memory(pa, len); 194 if (data == NULL) { 195 return ENOMEM; 196 } 197 error = uiomove(data, len, uio); 198 smbios_unmap_memory(data, len); 199 200 return error; 201 } 202 203 int 204 smbios2_check_header(const uint8_t *p) 205 { 206 const struct smbhdr *sh = (const struct smbhdr *)p; 207 uint8_t chksum; 208 int i; 209 210 if (sh->sig != SMBIOS_MAKESIG('_', 'S', 'M', '_')) 211 return 0; 212 i = sh->len; 213 for (chksum = 0; i--; ) 214 chksum += p[i]; 215 if (chksum != 0) 216 return 0; 217 p += 0x10; 218 if (p[0] != '_' || p[1] != 'D' || p[2] != 'M' || 219 p[3] != 'I' || p[4] != '_') 220 return 0; 221 for (chksum = 0, i = 0xf; i--; ) 222 chksum += p[i]; 223 if (chksum != 0) 224 return 0; 225 226 return 1; 227 } 228 229 int 230 smbios3_check_header(const uint8_t *p) 231 { 232 const struct smb3hdr *sh = (const struct smb3hdr *)p; 233 uint8_t chksum; 234 int i; 235 236 if (p[0] != '_' || p[1] != 'S' || p[2] != 'M' || 237 p[3] != '3' || p[4] != '_') 238 return 0; 239 i = sh->len; 240 for (chksum = 0; i--; ) 241 chksum += p[i]; 242 if (chksum != 0) 243 return 0; 244 if (sh->eprev != SMBIOS3_EPREV_3_0) 245 return 0; 246 247 return 1; 248 } 249 250 /* 251 * smbios_find_table() takes a caller supplied smbios struct type and 252 * a pointer to a handle (struct smbtable) returning one if the structure 253 * is successfully located and zero otherwise. Callers should take care 254 * to initilize the cookie field of the smbtable structure to zero before 255 * the first invocation of this function. 256 * Multiple tables of the same type can be located by repeadtly calling 257 * smbios_find_table with the same arguments. 258 */ 259 int 260 smbios_find_table(uint8_t type, struct smbtable *st) 261 { 262 uint8_t *va, *end; 263 struct smbtblhdr *hdr; 264 int ret = 0, tcount = 1; 265 266 if (smbios_entry.addr == NULL) { 267 return 0; 268 } 269 270 va = smbios_entry.addr; 271 end = va + smbios_entry.len; 272 273 /* 274 * The cookie field of the smtable structure is used to locate 275 * multiple instances of a table of an arbitrary type. Following the 276 * successful location of a table, the type is encoded as bits 0:7 of 277 * the cookie value, the offset in terms of the number of structures 278 * preceding that referenced by the handle is encoded in bits 15:31. 279 */ 280 if ((st->cookie & 0xfff) == type && st->cookie >> 16) { 281 if ((uint8_t *)st->hdr >= va && (uint8_t *)st->hdr < end) { 282 hdr = st->hdr; 283 if (hdr->type == type) { 284 va = (uint8_t *)hdr + hdr->size; 285 for (; va + 1 < end; va++) 286 if (*va == 0 && *(va + 1) == 0) 287 break; 288 va+= 2; 289 tcount = st->cookie >> 16; 290 } 291 } 292 } 293 for (; va + sizeof(struct smbtblhdr) < end && tcount <= 294 smbios_entry.count; tcount++) { 295 hdr = (struct smbtblhdr *)va; 296 if (hdr->type == type) { 297 ret = 1; 298 st->hdr = hdr; 299 st->tblhdr = va + sizeof(struct smbtblhdr); 300 st->cookie = (tcount + 1) << 16 | type; 301 break; 302 } 303 if (hdr->type == SMBIOS_TYPE_EOT) 304 break; 305 va+= hdr->size; 306 for (; va + 1 < end; va++) 307 if (*va == 0 && *(va + 1) == 0) 308 break; 309 va+=2; 310 } 311 312 return ret; 313 } 314 315 char * 316 smbios_get_string(struct smbtable *st, uint8_t indx, char *dest, size_t len) 317 { 318 uint8_t *va, *end; 319 char *ret = NULL; 320 int i; 321 322 KASSERT(smbios_entry.addr != NULL); 323 324 va = (uint8_t *)st->hdr + st->hdr->size; 325 end = smbios_entry.addr + smbios_entry.len; 326 for (i = 1; va < end && i < indx && *va; i++) 327 while (*va++) 328 ; 329 if (i == indx) { 330 if (va + len < end) { 331 ret = dest; 332 memcpy(ret, va, len); 333 ret[len - 1] = '\0'; 334 } 335 } 336 337 return ret; 338 } 339