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 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 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 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 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