1 /* $NetBSD: bios32.c,v 1.7 2021/07/24 20:45:45 jmcneill 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 BIOS32 services.
86 */
87
88 #include <sys/cdefs.h>
89 __KERNEL_RCSID(0, "$NetBSD: bios32.c,v 1.7 2021/07/24 20:45:45 jmcneill Exp $");
90
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/device.h>
94
95 #include <dev/isa/isareg.h>
96 #include <machine/isa_machdep.h>
97
98 #include <machine/segments.h>
99 #include <machine/bios32.h>
100 #include <dev/smbiosvar.h>
101 #include <x86/smbios_machdep.h>
102 #include <x86/efi.h>
103
104 #include <uvm/uvm.h>
105
106 #include "ipmi.h"
107 #include "opt_xen.h"
108
109 #define BIOS32_START 0xe0000
110 #define BIOS32_SIZE 0x20000
111 #define BIOS32_END (BIOS32_START + BIOS32_SIZE - 0x10)
112
113 struct bios32_entry bios32_entry;
114
115 static void smbios2_map_kva(const uint8_t *);
116 static void smbios3_map_kva(const uint8_t *);
117
118 /*
119 * Initialize the BIOS32 interface.
120 */
121 void
bios32_init(void)122 bios32_init(void)
123 {
124 uint8_t *p;
125 #ifdef i386
126 paddr_t entry = 0;
127 unsigned char cksum;
128 int i;
129
130 for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS32_START);
131 p < (uint8_t *)ISA_HOLE_VADDR(BIOS32_END);
132 p += 16) {
133 if (*(int *)p != BIOS32_MAKESIG('_', '3', '2', '_'))
134 continue;
135
136 cksum = 0;
137 for (i = 0; i < 16; i++)
138 cksum += *(unsigned char *)(p + i);
139 if (cksum != 0)
140 continue;
141
142 if (*(p + 9) != 1)
143 continue;
144
145 entry = *(uint32_t *)(p + 4);
146
147 aprint_debug("BIOS32 rev. %d found at 0x%lx\n",
148 *(p + 8), (u_long)entry);
149
150 if (entry < BIOS32_START ||
151 entry >= BIOS32_END) {
152 aprint_error("BIOS32 entry point outside "
153 "allowable range\n");
154 entry = 0;
155 }
156 break;
157 }
158
159 if (entry != 0) {
160 bios32_entry.offset = (void *)ISA_HOLE_VADDR(entry);
161 bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL);
162 }
163 #endif
164
165 /* see if we have SMBIOS extensions */
166 #ifndef XENPV
167 if (efi_probe()) {
168 p = efi_getcfgtbl(&EFI_UUID_SMBIOS3);
169 if (p != NULL && smbios3_check_header(p)) {
170 smbios3_map_kva(p);
171 return;
172 }
173 p = efi_getcfgtbl(&EFI_UUID_SMBIOS);
174 if (p != NULL && smbios2_check_header(p)) {
175 smbios2_map_kva(p);
176 return;
177 }
178 }
179 #endif
180 for (p = ISA_HOLE_VADDR(SMBIOS_START);
181 p < (uint8_t *)ISA_HOLE_VADDR(SMBIOS_END); p+= 16) {
182 if (smbios3_check_header(p)) {
183 smbios3_map_kva(p);
184 return;
185 }
186 if (smbios2_check_header(p)) {
187 smbios2_map_kva(p);
188 return;
189 }
190 }
191 }
192
193 /*
194 * Call BIOS32 to locate the specified BIOS32 service, and fill
195 * in the entry point information.
196 */
197 int
bios32_service(uint32_t service,bios32_entry_t e,bios32_entry_info_t ei)198 bios32_service(uint32_t service, bios32_entry_t e, bios32_entry_info_t ei)
199 {
200 #ifdef i386
201 uint32_t eax, ebx, ecx, edx;
202 paddr_t entry;
203
204 if (bios32_entry.offset == 0)
205 return 0; /* BIOS32 not present */
206
207 __asm volatile("lcall *(%%edi)"
208 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
209 : "0" (service), "1" (0), "D" (&bios32_entry));
210
211 if ((eax & 0xff) != 0)
212 return 0; /* service not found */
213
214 entry = ebx + edx;
215
216 if (entry < BIOS32_START || entry >= BIOS32_END) {
217 aprint_error("BIOS32: entry point for service %c%c%c%c is "
218 "outside allowable range\n",
219 service & 0xff,
220 (service >> 8) & 0xff,
221 (service >> 16) & 0xff,
222 (service >> 24) & 0xff);
223 return 0;
224 }
225
226 e->offset = (void *)ISA_HOLE_VADDR(entry);
227 e->segment = GSEL(GCODE_SEL, SEL_KPL);
228
229 ei->bei_base = ebx;
230 ei->bei_size = ecx;
231 ei->bei_entry = entry;
232 #else
233 (void)service;
234 (void)e;
235 (void)ei;
236 panic("bios32_service not implemented on amd64");
237 #endif
238
239 return 1;
240 }
241
242 static void
smbios2_map_kva(const uint8_t * p)243 smbios2_map_kva(const uint8_t *p)
244 {
245 const struct smbhdr *sh = (const struct smbhdr *)p;
246 paddr_t pa, end;
247 vaddr_t eva;
248
249 pa = trunc_page(sh->addr);
250 end = round_page(sh->addr + sh->size);
251 eva = uvm_km_alloc(kernel_map, end - pa, 0, UVM_KMF_VAONLY);
252 if (eva == 0)
253 return;
254
255 smbios_entry.hdrphys = vtophys((vaddr_t)p);
256 smbios_entry.tabphys = sh->addr;
257 smbios_entry.addr = (uint8_t *)(eva + (sh->addr & PGOFSET));
258 smbios_entry.len = sh->size;
259 smbios_entry.rev = 0;
260 smbios_entry.mjr = sh->majrev;
261 smbios_entry.min = sh->minrev;
262 smbios_entry.doc = 0;
263 smbios_entry.count = sh->count;
264
265 for (; pa < end; pa+= NBPG, eva+= NBPG)
266 #ifdef XENPV
267 pmap_kenter_ma(eva, pa, VM_PROT_READ, 0);
268 #else
269 pmap_kenter_pa(eva, pa, VM_PROT_READ, 0);
270 #endif
271 pmap_update(pmap_kernel());
272
273 aprint_debug("SMBIOS rev. %d.%d @ 0x%lx (%d entries)\n",
274 sh->majrev, sh->minrev, (u_long)sh->addr, sh->count);
275 }
276
277 static void
smbios3_map_kva(const uint8_t * p)278 smbios3_map_kva(const uint8_t *p)
279 {
280 const struct smb3hdr *sh = (const struct smb3hdr *)p;
281 paddr_t pa, end;
282 vaddr_t eva;
283
284 pa = trunc_page(sh->addr);
285 end = round_page(sh->addr + sh->size);
286 eva = uvm_km_alloc(kernel_map, end - pa, 0, UVM_KMF_VAONLY);
287 if (eva == 0)
288 return;
289
290 smbios_entry.hdrphys = vtophys((vaddr_t)p);
291 smbios_entry.tabphys = sh->addr;
292 smbios_entry.addr = (uint8_t *)(eva + ((vaddr_t)sh->addr & PGOFSET));
293 smbios_entry.len = sh->size;
294 smbios_entry.rev = sh->eprev;
295 smbios_entry.mjr = sh->majrev;
296 smbios_entry.min = sh->minrev;
297 smbios_entry.doc = sh->docrev;
298 smbios_entry.count = UINT16_MAX;
299
300 for (; pa < end; pa += NBPG, eva += NBPG)
301 #ifdef XENPV
302 pmap_kenter_ma(eva, pa, VM_PROT_READ, 0);
303 #else
304 pmap_kenter_pa(eva, pa, VM_PROT_READ, 0);
305 #endif
306 pmap_update(pmap_kernel());
307
308 aprint_debug("SMBIOS rev. %d.%d.%d @ 0x%lx\n", sh->majrev,
309 sh->minrev, sh->docrev, (u_long)sh->addr);
310 }
311