/* $NetBSD: smbios.c,v 1.4 2021/09/16 22:19:10 andvar Exp $ */ /* * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1999, by UCHIYAMA Yasushi * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the developer may NOT be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1997-2001 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Basic interface to System Management BIOS (SMBIOS) tables. */ #include __KERNEL_RCSID(0, "$NetBSD: smbios.c,v 1.4 2021/09/16 22:19:10 andvar Exp $"); #include #include #include #include #include #include #define SMBIOS_MAKESIG(a, b, c, d) \ ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) struct smbios_entry smbios_entry; static dev_type_read(smbios_read); const struct cdevsw smbios_cdevsw = { .d_open = nullopen, .d_close = nullclose, .d_read = smbios_read, .d_write = nowrite, .d_ioctl = noioctl, .d_stop = nostop, .d_tty = notty, .d_poll = nopoll, .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, .d_flag = D_OTHER | D_MPSAFE, }; static void * smbios_map_memory(paddr_t pa, size_t size) { paddr_t spa, epa, curpa; vaddr_t va, curva; spa = trunc_page(pa); epa = round_page(pa + size); va = uvm_km_alloc(kernel_map, epa - spa, 0, UVM_KMF_VAONLY); if (va == 0) { return NULL; } for (curpa = spa, curva = va; curpa < epa; curpa += PAGE_SIZE, curva += PAGE_SIZE) { pmap_kenter_pa(curva, curpa, VM_PROT_READ, PMAP_WRITE_BACK); } pmap_update(pmap_kernel()); return (void *)(uintptr_t)(va + (pa - spa)); } static void smbios_unmap_memory(void *va, size_t size) { vaddr_t ova; vsize_t osz; ova = trunc_page((vaddr_t)va); osz = round_page((vaddr_t)va + size) - ova; pmap_kremove(ova, osz); pmap_update(pmap_kernel()); uvm_km_free(kernel_map, ova, osz, UVM_KMF_VAONLY); } /* * smbios_read -- * * Read data from an SMBIOS table that resides in physical memory. */ static int smbios_read(dev_t dev, struct uio *uio, int flag) { paddr_t pa; uint8_t *data; size_t len; int error; if (smbios_entry.addr == NULL) { return EIO; } if (uio->uio_rw != UIO_READ) { return EPERM; } pa = uio->uio_offset; if (pa == smbios_entry.hdrphys) { /* SMBIOS header */ len = uimin(0x20, uio->uio_resid); } else { /* Table data */ if (pa < smbios_entry.tabphys || pa >= smbios_entry.tabphys + smbios_entry.len) { return EFAULT; } len = uimin(smbios_entry.len - (pa - smbios_entry.tabphys), uio->uio_resid); } data = smbios_map_memory(pa, len); if (data == NULL) { return ENOMEM; } error = uiomove(data, len, uio); smbios_unmap_memory(data, len); return error; } int smbios2_check_header(const uint8_t *p) { const struct smbhdr *sh = (const struct smbhdr *)p; uint8_t chksum; int i; if (sh->sig != SMBIOS_MAKESIG('_', 'S', 'M', '_')) return 0; i = sh->len; for (chksum = 0; i--; ) chksum += p[i]; if (chksum != 0) return 0; p += 0x10; if (p[0] != '_' || p[1] != 'D' || p[2] != 'M' || p[3] != 'I' || p[4] != '_') return 0; for (chksum = 0, i = 0xf; i--; ) chksum += p[i]; if (chksum != 0) return 0; return 1; } int smbios3_check_header(const uint8_t *p) { const struct smb3hdr *sh = (const struct smb3hdr *)p; uint8_t chksum; int i; if (p[0] != '_' || p[1] != 'S' || p[2] != 'M' || p[3] != '3' || p[4] != '_') return 0; i = sh->len; for (chksum = 0; i--; ) chksum += p[i]; if (chksum != 0) return 0; if (sh->eprev != SMBIOS3_EPREV_3_0) return 0; return 1; } /* * smbios_find_table() takes a caller supplied smbios struct type and * a pointer to a handle (struct smbtable) returning one if the structure * is successfully located and zero otherwise. Callers should take care * to initilize the cookie field of the smbtable structure to zero before * the first invocation of this function. * Multiple tables of the same type can be located by repeadtly calling * smbios_find_table with the same arguments. */ int smbios_find_table(uint8_t type, struct smbtable *st) { uint8_t *va, *end; struct smbtblhdr *hdr; int ret = 0, tcount = 1; if (smbios_entry.addr == NULL) { return 0; } va = smbios_entry.addr; end = va + smbios_entry.len; /* * The cookie field of the smtable structure is used to locate * multiple instances of a table of an arbitrary type. Following the * successful location of a table, the type is encoded as bits 0:7 of * the cookie value, the offset in terms of the number of structures * preceding that referenced by the handle is encoded in bits 15:31. */ if ((st->cookie & 0xfff) == type && st->cookie >> 16) { if ((uint8_t *)st->hdr >= va && (uint8_t *)st->hdr < end) { hdr = st->hdr; if (hdr->type == type) { va = (uint8_t *)hdr + hdr->size; for (; va + 1 < end; va++) if (*va == 0 && *(va + 1) == 0) break; va+= 2; tcount = st->cookie >> 16; } } } for (; va + sizeof(struct smbtblhdr) < end && tcount <= smbios_entry.count; tcount++) { hdr = (struct smbtblhdr *)va; if (hdr->type == type) { ret = 1; st->hdr = hdr; st->tblhdr = va + sizeof(struct smbtblhdr); st->cookie = (tcount + 1) << 16 | type; break; } if (hdr->type == SMBIOS_TYPE_EOT) break; va+= hdr->size; for (; va + 1 < end; va++) if (*va == 0 && *(va + 1) == 0) break; va+=2; } return ret; } char * smbios_get_string(struct smbtable *st, uint8_t indx, char *dest, size_t len) { uint8_t *va, *end; char *ret = NULL; int i; KASSERT(smbios_entry.addr != NULL); va = (uint8_t *)st->hdr + st->hdr->size; end = smbios_entry.addr + smbios_entry.len; for (i = 1; va < end && i < indx && *va; i++) while (*va++) ; if (i == indx) { if (va + len < end) { ret = dest; memcpy(ret, va, len); ret[len - 1] = '\0'; } } return ret; }