bios.c revision 28981
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.4 1997/08/06 11:08:01 peter 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/md_var.h> 39 40#include <machine/pc/bios.h> 41 42#define BIOS_START 0xe0000 43#define BIOS_SIZE 0x20000 44 45/* exported lookup results */ 46struct bios32_SDentry PCIbios = {entry : 0}; 47struct SMBIOS_table *SMBIOStable = 0; 48struct DMI_table *DMItable = 0; 49 50static caddr_t bios32_SDCI = NULL; 51 52static void bios32_init(void *junk); 53 54/* start fairly early */ 55SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL); 56 57/* 58 * bios32_init 59 * 60 * Locate various bios32 entities. 61 */ 62static void 63bios32_init(void *junk) 64{ 65 u_long sigaddr; 66 struct bios32_SDheader *sdh; 67 struct SMBIOS_table *sbt; 68 struct DMI_table *dmit; 69 u_int8_t ck, *cv; 70 int i; 71 72 73 /* 74 * BIOS32 Service Directory 75 */ 76 77 /* look for the signature */ 78 if ((sigaddr = bios_sigsearch(0, "_32_", 4, 16, 0)) != 0) { 79 80 /* get a virtual pointer to the structure */ 81 sdh = (struct bios32_SDheader *)BIOS_PADDRTOVADDR(sigaddr); 82 for (cv = (u_int8_t *)sdh, ck = 0, i = 0; i < (sdh->len * 16); i++) { 83 ck += cv[i]; 84 } 85 /* If checksum is OK, enable use of the entrypoint */ 86 if (ck == 0) { 87 bios32_SDCI = (caddr_t)BIOS_PADDRTOVADDR(sdh->entry); 88 if (bootverbose) { 89 printf("Found BIOS32 Service Directory header at %p\n", sdh); 90 printf("Entry = 0x%x (%p) Rev = %d Len = %d\n", 91 sdh->entry, bios32_SDCI, sdh->revision, sdh->len); 92 } 93 /* See if there's a PCI BIOS entrypoint here */ 94 PCIbios.ident.id = 0x49435024; /* PCI systems should have this */ 95 if (!bios32_SDlookup(&PCIbios) && bootverbose) 96 printf("PCI BIOS entry at 0x%x\n", PCIbios.entry); 97 } else { 98 printf("Bad BIOS32 Service Directory!\n"); 99 } 100 } 101 102 /* 103 * System Management BIOS 104 */ 105 /* look for the SMBIOS signature */ 106 if ((sigaddr = bios_sigsearch(0, "_SM_", 4, 16, 0)) != 0) { 107 108 /* get a virtual pointer to the structure */ 109 sbt = (struct SMBIOS_table *)BIOS_PADDRTOVADDR(sigaddr); 110 for (cv = (u_int8_t *)sbt, ck = 0, i = 0; i < sbt->len; i++) { 111 ck += cv[i]; 112 } 113 /* if checksum is OK, we have action */ 114 if (ck == 0) { 115 SMBIOStable = sbt; /* save reference */ 116 DMItable = &sbt->dmi; /* contained within */ 117 if (bootverbose) { 118 printf("SMIBIOS header at %p\n", sbt); 119 printf("Version %d.%d\n", sbt->major, sbt->minor); 120 printf("Table at 0x%x, %d entries, %d bytes, largest entry %d bytes\n", 121 dmit->st_base, (int)dmit->st_entries, (int)dmit->st_size, 122 (int)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, %d entries, %d bytes\n", 145 dmit->st_base, (int)dmit->st_entries, 146 (int)dmit->st_size); 147 } 148 } else { 149 printf("Bad DMI table checksum!\n"); 150 } 151 } 152 153} 154 155/* 156 * bios32_SDlookup 157 * 158 * Query the BIOS32 Service Directory for the service named in (ent), 159 * returns nonzero if the lookup fails. The caller must fill in 160 * (ent->ident), the remainder are populated on a successful lookup. 161 */ 162int 163bios32_SDlookup(struct bios32_SDentry *ent) 164{ 165 struct bios32_args args; 166 167 if (bios32_SDCI != NULL) { 168 169 args.eax = ent->ident.id; /* set up arguments */ 170 args.ebx = args.ecx = args.edx = 0; 171 bios32(bios32_SDCI, &args); /* make the BIOS call */ 172 if ((args.eax & 0xff) == 0) { /* success? */ 173 ent->base = args.ebx; 174 ent->len = args.ecx; 175 ent->entry = args.edx; 176 return(0); /* all OK */ 177 } 178 } 179 return(1); /* failed */ 180} 181 182/* 183 * bios_sigsearch 184 * 185 * Search some or all of the BIOS region for a signature string. 186 * 187 * (start) Optional offset returned from this function 188 * (for searching for multiple matches), or NULL 189 * to start the search from the base of the BIOS. 190 * Note that this will be a _physical_ address in 191 * the range 0xe0000 - 0xfffff. 192 * (sig) is a pointer to the byte(s) of the signature. 193 * (siglen) number of bytes in the signature. 194 * (paralen) signature paragraph (alignment) size. 195 * (sigofs) offset of the signature within the paragraph. 196 * 197 * Returns the _physical_ address of the found signature, 0 if the 198 * signature was not found. 199 */ 200 201u_int32_t 202bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) 203{ 204 u_char *sp, *end; 205 int i; 206 207 /* compute the starting address */ 208 if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { 209 sp = (char *)BIOS_PADDRTOVADDR(start); 210 } else if (start == 0) { 211 sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); 212 } else { 213 return 0; /* bogus start address */ 214 } 215 216 /* compute the end address */ 217 end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); 218 219 /* loop searching */ 220 while ((sp + sigofs + siglen) < end) { 221 222 /* compare here */ 223 if (!bcmp(sp + sigofs, sig, siglen)) { 224 /* convert back to physical address */ 225 return((u_int32_t)BIOS_VADDRTOPADDR(sp)); 226 } 227 sp += paralen; 228 } 229 return(0); 230} 231 232 233 234