1*b5860281Sandvar /* $NetBSD: smbios.c,v 1.4 2021/09/16 22:19:10 andvar Exp $ */
2b2c90ce3Sjmcneill
3b2c90ce3Sjmcneill /*
4b2c90ce3Sjmcneill * Copyright (c) 1999 The NetBSD Foundation, Inc.
5b2c90ce3Sjmcneill * All rights reserved.
6b2c90ce3Sjmcneill *
7b2c90ce3Sjmcneill * This code is derived from software contributed to The NetBSD Foundation
8b2c90ce3Sjmcneill * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9b2c90ce3Sjmcneill * NASA Ames Research Center.
10b2c90ce3Sjmcneill *
11b2c90ce3Sjmcneill * Redistribution and use in source and binary forms, with or without
12b2c90ce3Sjmcneill * modification, are permitted provided that the following conditions
13b2c90ce3Sjmcneill * are met:
14b2c90ce3Sjmcneill * 1. Redistributions of source code must retain the above copyright
15b2c90ce3Sjmcneill * notice, this list of conditions and the following disclaimer.
16b2c90ce3Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
17b2c90ce3Sjmcneill * notice, this list of conditions and the following disclaimer in the
18b2c90ce3Sjmcneill * documentation and/or other materials provided with the distribution.
19b2c90ce3Sjmcneill *
20b2c90ce3Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21b2c90ce3Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22b2c90ce3Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23b2c90ce3Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24b2c90ce3Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25b2c90ce3Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26b2c90ce3Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27b2c90ce3Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28b2c90ce3Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29b2c90ce3Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30b2c90ce3Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
31b2c90ce3Sjmcneill */
32b2c90ce3Sjmcneill
33b2c90ce3Sjmcneill /*
34b2c90ce3Sjmcneill * Copyright (c) 1999, by UCHIYAMA Yasushi
35b2c90ce3Sjmcneill * All rights reserved.
36b2c90ce3Sjmcneill *
37b2c90ce3Sjmcneill * Redistribution and use in source and binary forms, with or without
38b2c90ce3Sjmcneill * modification, are permitted provided that the following conditions
39b2c90ce3Sjmcneill * are met:
40b2c90ce3Sjmcneill * 1. Redistributions of source code must retain the above copyright
41b2c90ce3Sjmcneill * notice, this list of conditions and the following disclaimer.
42b2c90ce3Sjmcneill * 2. The name of the developer may NOT be used to endorse or promote products
43b2c90ce3Sjmcneill * derived from this software without specific prior written permission.
44b2c90ce3Sjmcneill *
45b2c90ce3Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46b2c90ce3Sjmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47b2c90ce3Sjmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48b2c90ce3Sjmcneill * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49b2c90ce3Sjmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50b2c90ce3Sjmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51b2c90ce3Sjmcneill * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52b2c90ce3Sjmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53b2c90ce3Sjmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54b2c90ce3Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55b2c90ce3Sjmcneill * SUCH DAMAGE.
56b2c90ce3Sjmcneill */
57b2c90ce3Sjmcneill
58b2c90ce3Sjmcneill /*
59b2c90ce3Sjmcneill * Copyright (c) 1997-2001 Michael Shalayeff
60b2c90ce3Sjmcneill * All rights reserved.
61b2c90ce3Sjmcneill *
62b2c90ce3Sjmcneill * Redistribution and use in source and binary forms, with or without
63b2c90ce3Sjmcneill * modification, are permitted provided that the following conditions
64b2c90ce3Sjmcneill * are met:
65b2c90ce3Sjmcneill * 1. Redistributions of source code must retain the above copyright
66b2c90ce3Sjmcneill * notice, this list of conditions and the following disclaimer.
67b2c90ce3Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
68b2c90ce3Sjmcneill * notice, this list of conditions and the following disclaimer in the
69b2c90ce3Sjmcneill * documentation and/or other materials provided with the distribution.
70b2c90ce3Sjmcneill *
71b2c90ce3Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
72b2c90ce3Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
73b2c90ce3Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
74b2c90ce3Sjmcneill * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
75b2c90ce3Sjmcneill * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
76b2c90ce3Sjmcneill * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
77b2c90ce3Sjmcneill * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
78b2c90ce3Sjmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
79b2c90ce3Sjmcneill * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
80b2c90ce3Sjmcneill * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
81b2c90ce3Sjmcneill * THE POSSIBILITY OF SUCH DAMAGE.
82b2c90ce3Sjmcneill */
83b2c90ce3Sjmcneill
84b2c90ce3Sjmcneill /*
85b2c90ce3Sjmcneill * Basic interface to System Management BIOS (SMBIOS) tables.
86b2c90ce3Sjmcneill */
87b2c90ce3Sjmcneill
88b2c90ce3Sjmcneill #include <sys/cdefs.h>
89*b5860281Sandvar __KERNEL_RCSID(0, "$NetBSD: smbios.c,v 1.4 2021/09/16 22:19:10 andvar Exp $");
90b2c90ce3Sjmcneill
91b2c90ce3Sjmcneill #include <sys/param.h>
92065fe7e8Sjmcneill #include <sys/conf.h>
93b2c90ce3Sjmcneill #include <sys/systm.h>
94b2c90ce3Sjmcneill #include <sys/device.h>
95b2c90ce3Sjmcneill
96065fe7e8Sjmcneill #include <uvm/uvm_extern.h>
97065fe7e8Sjmcneill
98b2c90ce3Sjmcneill #include <dev/smbiosvar.h>
99b2c90ce3Sjmcneill
100b2c90ce3Sjmcneill #define SMBIOS_MAKESIG(a, b, c, d) \
101b2c90ce3Sjmcneill ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
102b2c90ce3Sjmcneill
103b2c90ce3Sjmcneill struct smbios_entry smbios_entry;
104b2c90ce3Sjmcneill
105065fe7e8Sjmcneill static dev_type_read(smbios_read);
106065fe7e8Sjmcneill
107065fe7e8Sjmcneill const struct cdevsw smbios_cdevsw = {
108065fe7e8Sjmcneill .d_open = nullopen,
109065fe7e8Sjmcneill .d_close = nullclose,
110065fe7e8Sjmcneill .d_read = smbios_read,
111065fe7e8Sjmcneill .d_write = nowrite,
112065fe7e8Sjmcneill .d_ioctl = noioctl,
113065fe7e8Sjmcneill .d_stop = nostop,
114065fe7e8Sjmcneill .d_tty = notty,
115065fe7e8Sjmcneill .d_poll = nopoll,
116065fe7e8Sjmcneill .d_mmap = nommap,
117065fe7e8Sjmcneill .d_kqfilter = nokqfilter,
118065fe7e8Sjmcneill .d_discard = nodiscard,
119065fe7e8Sjmcneill .d_flag = D_OTHER | D_MPSAFE,
120065fe7e8Sjmcneill };
121065fe7e8Sjmcneill
122065fe7e8Sjmcneill static void *
smbios_map_memory(paddr_t pa,size_t size)123065fe7e8Sjmcneill smbios_map_memory(paddr_t pa, size_t size)
124065fe7e8Sjmcneill {
125065fe7e8Sjmcneill paddr_t spa, epa, curpa;
126065fe7e8Sjmcneill vaddr_t va, curva;
127065fe7e8Sjmcneill
128065fe7e8Sjmcneill spa = trunc_page(pa);
129065fe7e8Sjmcneill epa = round_page(pa + size);
130065fe7e8Sjmcneill
131065fe7e8Sjmcneill va = uvm_km_alloc(kernel_map, epa - spa, 0, UVM_KMF_VAONLY);
132065fe7e8Sjmcneill if (va == 0) {
133065fe7e8Sjmcneill return NULL;
134065fe7e8Sjmcneill }
135065fe7e8Sjmcneill
136065fe7e8Sjmcneill for (curpa = spa, curva = va; curpa < epa; curpa += PAGE_SIZE, curva += PAGE_SIZE) {
137065fe7e8Sjmcneill pmap_kenter_pa(curva, curpa, VM_PROT_READ, PMAP_WRITE_BACK);
138065fe7e8Sjmcneill }
139065fe7e8Sjmcneill pmap_update(pmap_kernel());
140065fe7e8Sjmcneill
141cee3dc82Sjmcneill return (void *)(uintptr_t)(va + (pa - spa));
142065fe7e8Sjmcneill }
143065fe7e8Sjmcneill
144065fe7e8Sjmcneill static void
smbios_unmap_memory(void * va,size_t size)145065fe7e8Sjmcneill smbios_unmap_memory(void *va, size_t size)
146065fe7e8Sjmcneill {
147065fe7e8Sjmcneill vaddr_t ova;
148065fe7e8Sjmcneill vsize_t osz;
149065fe7e8Sjmcneill
150065fe7e8Sjmcneill ova = trunc_page((vaddr_t)va);
151065fe7e8Sjmcneill osz = round_page((vaddr_t)va + size) - ova;
152065fe7e8Sjmcneill
153065fe7e8Sjmcneill pmap_kremove(ova, osz);
154065fe7e8Sjmcneill pmap_update(pmap_kernel());
155065fe7e8Sjmcneill uvm_km_free(kernel_map, ova, osz, UVM_KMF_VAONLY);
156065fe7e8Sjmcneill }
157065fe7e8Sjmcneill
158065fe7e8Sjmcneill /*
159065fe7e8Sjmcneill * smbios_read --
160065fe7e8Sjmcneill *
161065fe7e8Sjmcneill * Read data from an SMBIOS table that resides in physical memory.
162065fe7e8Sjmcneill */
163065fe7e8Sjmcneill static int
smbios_read(dev_t dev,struct uio * uio,int flag)164065fe7e8Sjmcneill smbios_read(dev_t dev, struct uio *uio, int flag)
165065fe7e8Sjmcneill {
166065fe7e8Sjmcneill paddr_t pa;
167065fe7e8Sjmcneill uint8_t *data;
168065fe7e8Sjmcneill size_t len;
169065fe7e8Sjmcneill int error;
170065fe7e8Sjmcneill
171065fe7e8Sjmcneill if (smbios_entry.addr == NULL) {
172065fe7e8Sjmcneill return EIO;
173065fe7e8Sjmcneill }
174065fe7e8Sjmcneill if (uio->uio_rw != UIO_READ) {
175065fe7e8Sjmcneill return EPERM;
176065fe7e8Sjmcneill }
177065fe7e8Sjmcneill
178065fe7e8Sjmcneill pa = uio->uio_offset;
179065fe7e8Sjmcneill if (pa == smbios_entry.hdrphys) {
180065fe7e8Sjmcneill /* SMBIOS header */
181065fe7e8Sjmcneill len = uimin(0x20, uio->uio_resid);
182065fe7e8Sjmcneill
183065fe7e8Sjmcneill } else {
184065fe7e8Sjmcneill /* Table data */
185065fe7e8Sjmcneill if (pa < smbios_entry.tabphys ||
186065fe7e8Sjmcneill pa >= smbios_entry.tabphys + smbios_entry.len) {
187065fe7e8Sjmcneill return EFAULT;
188065fe7e8Sjmcneill }
189065fe7e8Sjmcneill len = uimin(smbios_entry.len - (pa - smbios_entry.tabphys),
190065fe7e8Sjmcneill uio->uio_resid);
191065fe7e8Sjmcneill }
192065fe7e8Sjmcneill
193065fe7e8Sjmcneill data = smbios_map_memory(pa, len);
194065fe7e8Sjmcneill if (data == NULL) {
195065fe7e8Sjmcneill return ENOMEM;
196065fe7e8Sjmcneill }
197065fe7e8Sjmcneill error = uiomove(data, len, uio);
198065fe7e8Sjmcneill smbios_unmap_memory(data, len);
199065fe7e8Sjmcneill
200065fe7e8Sjmcneill return error;
201065fe7e8Sjmcneill }
202065fe7e8Sjmcneill
203b2c90ce3Sjmcneill int
smbios2_check_header(const uint8_t * p)204b2c90ce3Sjmcneill smbios2_check_header(const uint8_t *p)
205b2c90ce3Sjmcneill {
206b2c90ce3Sjmcneill const struct smbhdr *sh = (const struct smbhdr *)p;
207b2c90ce3Sjmcneill uint8_t chksum;
208b2c90ce3Sjmcneill int i;
209b2c90ce3Sjmcneill
210b2c90ce3Sjmcneill if (sh->sig != SMBIOS_MAKESIG('_', 'S', 'M', '_'))
211b2c90ce3Sjmcneill return 0;
212b2c90ce3Sjmcneill i = sh->len;
213b2c90ce3Sjmcneill for (chksum = 0; i--; )
214b2c90ce3Sjmcneill chksum += p[i];
215b2c90ce3Sjmcneill if (chksum != 0)
216b2c90ce3Sjmcneill return 0;
217b2c90ce3Sjmcneill p += 0x10;
218b2c90ce3Sjmcneill if (p[0] != '_' || p[1] != 'D' || p[2] != 'M' ||
219b2c90ce3Sjmcneill p[3] != 'I' || p[4] != '_')
220b2c90ce3Sjmcneill return 0;
221b2c90ce3Sjmcneill for (chksum = 0, i = 0xf; i--; )
222b2c90ce3Sjmcneill chksum += p[i];
223b2c90ce3Sjmcneill if (chksum != 0)
224b2c90ce3Sjmcneill return 0;
225b2c90ce3Sjmcneill
226b2c90ce3Sjmcneill return 1;
227b2c90ce3Sjmcneill }
228b2c90ce3Sjmcneill
229b2c90ce3Sjmcneill int
smbios3_check_header(const uint8_t * p)230b2c90ce3Sjmcneill smbios3_check_header(const uint8_t *p)
231b2c90ce3Sjmcneill {
232b2c90ce3Sjmcneill const struct smb3hdr *sh = (const struct smb3hdr *)p;
233b2c90ce3Sjmcneill uint8_t chksum;
234b2c90ce3Sjmcneill int i;
235b2c90ce3Sjmcneill
236b2c90ce3Sjmcneill if (p[0] != '_' || p[1] != 'S' || p[2] != 'M' ||
237b2c90ce3Sjmcneill p[3] != '3' || p[4] != '_')
238b2c90ce3Sjmcneill return 0;
239b2c90ce3Sjmcneill i = sh->len;
240b2c90ce3Sjmcneill for (chksum = 0; i--; )
241b2c90ce3Sjmcneill chksum += p[i];
242b2c90ce3Sjmcneill if (chksum != 0)
243b2c90ce3Sjmcneill return 0;
244b2c90ce3Sjmcneill if (sh->eprev != SMBIOS3_EPREV_3_0)
245b2c90ce3Sjmcneill return 0;
246b2c90ce3Sjmcneill
247b2c90ce3Sjmcneill return 1;
248b2c90ce3Sjmcneill }
249b2c90ce3Sjmcneill
250b2c90ce3Sjmcneill /*
251b2c90ce3Sjmcneill * smbios_find_table() takes a caller supplied smbios struct type and
252b2c90ce3Sjmcneill * a pointer to a handle (struct smbtable) returning one if the structure
253b2c90ce3Sjmcneill * is successfully located and zero otherwise. Callers should take care
254b2c90ce3Sjmcneill * to initilize the cookie field of the smbtable structure to zero before
255b2c90ce3Sjmcneill * the first invocation of this function.
256b2c90ce3Sjmcneill * Multiple tables of the same type can be located by repeadtly calling
257b2c90ce3Sjmcneill * smbios_find_table with the same arguments.
258b2c90ce3Sjmcneill */
259b2c90ce3Sjmcneill int
smbios_find_table(uint8_t type,struct smbtable * st)260b2c90ce3Sjmcneill smbios_find_table(uint8_t type, struct smbtable *st)
261b2c90ce3Sjmcneill {
262b2c90ce3Sjmcneill uint8_t *va, *end;
263b2c90ce3Sjmcneill struct smbtblhdr *hdr;
264b2c90ce3Sjmcneill int ret = 0, tcount = 1;
265b2c90ce3Sjmcneill
266b2c90ce3Sjmcneill if (smbios_entry.addr == NULL) {
267b2c90ce3Sjmcneill return 0;
268b2c90ce3Sjmcneill }
269b2c90ce3Sjmcneill
270b2c90ce3Sjmcneill va = smbios_entry.addr;
271b2c90ce3Sjmcneill end = va + smbios_entry.len;
272b2c90ce3Sjmcneill
273b2c90ce3Sjmcneill /*
274b2c90ce3Sjmcneill * The cookie field of the smtable structure is used to locate
275b2c90ce3Sjmcneill * multiple instances of a table of an arbitrary type. Following the
276*b5860281Sandvar * successful location of a table, the type is encoded as bits 0:7 of
277b2c90ce3Sjmcneill * the cookie value, the offset in terms of the number of structures
278b2c90ce3Sjmcneill * preceding that referenced by the handle is encoded in bits 15:31.
279b2c90ce3Sjmcneill */
280b2c90ce3Sjmcneill if ((st->cookie & 0xfff) == type && st->cookie >> 16) {
281b2c90ce3Sjmcneill if ((uint8_t *)st->hdr >= va && (uint8_t *)st->hdr < end) {
282b2c90ce3Sjmcneill hdr = st->hdr;
283b2c90ce3Sjmcneill if (hdr->type == type) {
284b2c90ce3Sjmcneill va = (uint8_t *)hdr + hdr->size;
285b2c90ce3Sjmcneill for (; va + 1 < end; va++)
286b2c90ce3Sjmcneill if (*va == 0 && *(va + 1) == 0)
287b2c90ce3Sjmcneill break;
288b2c90ce3Sjmcneill va+= 2;
289b2c90ce3Sjmcneill tcount = st->cookie >> 16;
290b2c90ce3Sjmcneill }
291b2c90ce3Sjmcneill }
292b2c90ce3Sjmcneill }
293b2c90ce3Sjmcneill for (; va + sizeof(struct smbtblhdr) < end && tcount <=
294b2c90ce3Sjmcneill smbios_entry.count; tcount++) {
295b2c90ce3Sjmcneill hdr = (struct smbtblhdr *)va;
296b2c90ce3Sjmcneill if (hdr->type == type) {
297b2c90ce3Sjmcneill ret = 1;
298b2c90ce3Sjmcneill st->hdr = hdr;
299b2c90ce3Sjmcneill st->tblhdr = va + sizeof(struct smbtblhdr);
300b2c90ce3Sjmcneill st->cookie = (tcount + 1) << 16 | type;
301b2c90ce3Sjmcneill break;
302b2c90ce3Sjmcneill }
303b2c90ce3Sjmcneill if (hdr->type == SMBIOS_TYPE_EOT)
304b2c90ce3Sjmcneill break;
305b2c90ce3Sjmcneill va+= hdr->size;
306b2c90ce3Sjmcneill for (; va + 1 < end; va++)
307b2c90ce3Sjmcneill if (*va == 0 && *(va + 1) == 0)
308b2c90ce3Sjmcneill break;
309b2c90ce3Sjmcneill va+=2;
310b2c90ce3Sjmcneill }
311b2c90ce3Sjmcneill
312b2c90ce3Sjmcneill return ret;
313b2c90ce3Sjmcneill }
314b2c90ce3Sjmcneill
315b2c90ce3Sjmcneill char *
smbios_get_string(struct smbtable * st,uint8_t indx,char * dest,size_t len)316b2c90ce3Sjmcneill smbios_get_string(struct smbtable *st, uint8_t indx, char *dest, size_t len)
317b2c90ce3Sjmcneill {
318b2c90ce3Sjmcneill uint8_t *va, *end;
319b2c90ce3Sjmcneill char *ret = NULL;
320b2c90ce3Sjmcneill int i;
321b2c90ce3Sjmcneill
322b2c90ce3Sjmcneill KASSERT(smbios_entry.addr != NULL);
323b2c90ce3Sjmcneill
324b2c90ce3Sjmcneill va = (uint8_t *)st->hdr + st->hdr->size;
325b2c90ce3Sjmcneill end = smbios_entry.addr + smbios_entry.len;
326b2c90ce3Sjmcneill for (i = 1; va < end && i < indx && *va; i++)
327b2c90ce3Sjmcneill while (*va++)
328b2c90ce3Sjmcneill ;
329b2c90ce3Sjmcneill if (i == indx) {
330b2c90ce3Sjmcneill if (va + len < end) {
331b2c90ce3Sjmcneill ret = dest;
332b2c90ce3Sjmcneill memcpy(ret, va, len);
333b2c90ce3Sjmcneill ret[len - 1] = '\0';
334b2c90ce3Sjmcneill }
335b2c90ce3Sjmcneill }
336b2c90ce3Sjmcneill
337b2c90ce3Sjmcneill return ret;
338b2c90ce3Sjmcneill }
339