xref: /netbsd-src/sys/arch/x86/x86/bios32.c (revision 476d979e207b384d910fb64db07dbddae9ce9f56)
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