bios.c revision 27872
1/*- 2 * Copyright (c) 1997 Michael Smith 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: bios.c,v 1.1 1997/08/01 06:07:11 msmith Exp $ 27 */ 28 29/* 30 * Code for dealing with the BIOS in x86 PC systems. 31 */ 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <vm/vm.h> 37#include <vm/pmap.h> 38#include <machine/pmap.h> 39#include <machine/md_var.h> 40 41#include <machine/pc/bios.h> 42 43#define BIOS_START 0xe0000 44#define BIOS_SIZE 0x20000 45 46/* exported lookup results */ 47struct bios32_SDentry PCIbios = {entry : 0}; 48struct SMBIOS_table *SMBIOStable = 0; 49struct DMI_table *DMItable = 0; 50 51static caddr_t bios32_SDCI = NULL; 52 53static void bios32_init(void *junk); 54 55/* start fairly early */ 56SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL); 57 58/* 59 * bios32_init 60 * 61 * Locate various bios32 entities. 62 */ 63static void 64bios32_init(void *junk) 65{ 66 u_long sigaddr; 67 struct bios32_SDheader *sdh; 68 struct SMBIOS_table *sbt; 69 struct DMI_table *dmit; 70 u_int8_t ck, *cv; 71 int i; 72 73 74 /* 75 * BIOS32 Service Directory 76 */ 77 78 /* look for the signature */ 79 if ((sigaddr = bios_sigsearch(0, "_32_", 4, 16, 0)) != 0) { 80 81 /* get a virtual pointer to the structure */ 82 sdh = (struct bios32_SDheader *)BIOS_PADDRTOVADDR(sigaddr); 83 for (cv = (u_int8_t *)sdh, ck = 0, i = 0; i < (sdh->len * 16); i++) { 84 ck += cv[i]; 85 } 86 /* If checksum is OK, enable use of the entrypoint */ 87 if (ck == 0) { 88 bios32_SDCI = (caddr_t)BIOS_PADDRTOVADDR(sdh->entry); 89 if (bootverbose) { 90 printf("Found BIOS32 Service Directory header at %p\n", sdh); 91 printf("Entry = 0x%x (%p) Rev = %d Len = %d\n", 92 sdh->entry, bios32_SDCI, sdh->revision, sdh->len); 93 } 94 /* See if there's a PCI BIOS entrypoint here */ 95 PCIbios.ident.id = 0x49435024; /* PCI systems should have this */ 96 if (!bios32_SDlookup(&PCIbios) && bootverbose) 97 printf("PCI BIOS entry at 0x%x\n", PCIbios.entry); 98 } else { 99 printf("Bad BIOS32 Service Directory!\n"); 100 } 101 } 102 103 /* 104 * System Management BIOS 105 */ 106 /* look for the SMBIOS signature */ 107 if ((sigaddr = bios_sigsearch(0, "_SM_", 4, 16, 0)) != 0) { 108 109 /* get a virtual pointer to the structure */ 110 sbt = (struct SMBIOS_table *)BIOS_PADDRTOVADDR(sigaddr); 111 for (cv = (u_int8_t *)sbt, ck = 0, i = 0; i < sbt->len; i++) { 112 ck += cv[i]; 113 } 114 /* if checksum is OK, we have action */ 115 if (ck == 0) { 116 SMBIOStable = sbt; /* save reference */ 117 DMItable = &sbt->dmi; /* contained within */ 118 if (bootverbose) { 119 printf("SMIBIOS header at %p\n", sbt); 120 printf("Version %d.%d\n", sbt->major, sbt->minor); 121 printf("Table at 0x%x, %hd entries, %hd bytes, largest entry %hd bytes\n", 122 dmit->st_base, dmit->st_entries, dmit->st_size, sbt->st_maxsize); 123 } 124 } else { 125 printf("Bad SMBIOS table checksum!\n"); 126 } 127 128 } 129 /* look for the DMI signature */ 130 if ((sigaddr = bios_sigsearch(0, "_DMI_", 5, 16, 0)) != 0) { 131 132 /* get a virtual pointer to the structure */ 133 dmit = (struct DMI_table *)BIOS_PADDRTOVADDR(sigaddr); 134 for (cv = (u_int8_t *)dmit, ck = 0, i = 0; i < 15; i++) { 135 ck += cv[i]; 136 } 137 /* if checksum is OK, we have action */ 138 if (ck == 0) { 139 DMItable = dmit; /* save reference */ 140 if (bootverbose) { 141 printf("DMI header at %p\n", dmit); 142 printf("Version %d.%d\n", (dmit->bcd_revision >> 4), 143 (dmit->bcd_revision & 0x0f)); 144 printf("Table at 0x%x, %hd entries, %hd bytes\n", 145 dmit->st_base, dmit->st_entries, dmit->st_size); 146 } 147 } else { 148 printf("Bad DMI table checksum!\n"); 149 } 150 } 151 152} 153 154/* 155 * bios32_SDlookup 156 * 157 * Query the BIOS32 Service Directory for the service named in (ent), 158 * returns nonzero if the lookup fails. The caller must fill in 159 * (ent->ident), the remainder are populated on a successful lookup. 160 */ 161int 162bios32_SDlookup(struct bios32_SDentry *ent) 163{ 164 struct bios32_args args; 165 166 if (bios32_SDCI != NULL) { 167 168 args.eax = ent->ident.id; /* set up arguments */ 169 args.ebx = args.ecx = args.edx = 0; 170 bios32(bios32_SDCI, &args); /* make the BIOS call */ 171 if ((args.eax & 0xff) == 0) { /* success? */ 172 ent->base = args.ebx; 173 ent->len = args.ecx; 174 ent->entry = args.edx; 175 return(0); /* all OK */ 176 } 177 } 178 return(1); /* failed */ 179} 180 181/* 182 * bios_sigsearch 183 * 184 * Search some or all of the BIOS region for a signature string. 185 * 186 * (start) Optional offset returned from this function 187 * (for searching for multiple matches), or NULL 188 * to start the search from the base of the BIOS. 189 * Note that this will be a _physical_ address in 190 * the range 0xe0000 - 0xfffff. 191 * (sig) is a pointer to the byte(s) of the signature. 192 * (siglen) number of bytes in the signature. 193 * (paralen) signature paragraph (alignment) size. 194 * (sigofs) offset of the signature within the paragraph. 195 * 196 * Returns the _physical_ address of the found signature, 0 if the 197 * signature was not found. 198 */ 199 200u_int32_t 201bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) 202{ 203 u_char *sp, *end; 204 int i; 205 206 /* compute the starting address */ 207 if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { 208 sp = (char *)BIOS_PADDRTOVADDR(start); 209 } else if (start == 0) { 210 sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); 211 } else { 212 return 0; /* bogus start address */ 213 } 214 215 /* compute the end address */ 216 end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); 217 218 /* loop searching */ 219 while ((sp + sigofs + siglen) < end) { 220 221 /* compare here */ 222 if (!memcmp(sp + sigofs, sig, siglen)) { 223 /* convert back to physical address */ 224 return((u_int32_t)BIOS_VADDRTOPADDR(sp)); 225 } 226 sp += paralen; 227 } 228 return(0); 229} 230 231 232 233