bios.c revision 27823
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$ 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 < 16; 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 %x\n", dmit->bcd_revision); 143 printf("Table at 0x%x, %hd entries, %hd bytes\n", 144 dmit->st_base, dmit->st_entries, dmit->st_size); 145 } 146 } else { 147 printf("Bad DMI table checksum!\n"); 148 } 149 } 150 151} 152 153/* 154 * bios32_SDlookup 155 * 156 * Query the BIOS32 Service Directory for the service named in (ent), 157 * returns nonzero if the lookup fails. The caller must fill in 158 * (ent->ident), the remainder are populated on a successful lookup. 159 */ 160int 161bios32_SDlookup(struct bios32_SDentry *ent) 162{ 163 struct bios32_args args; 164 165 if (bios32_SDCI != NULL) { 166 167 args.eax = ent->ident.id; /* set up arguments */ 168 args.ebx = args.ecx = args.edx = 0; 169 bios32(bios32_SDCI, &args); /* make the BIOS call */ 170 if ((args.eax & 0xff) == 0) { /* success? */ 171 ent->base = args.ebx; 172 ent->len = args.ecx; 173 ent->entry = args.edx; 174 return(0); /* all OK */ 175 } 176 } 177 return(1); /* failed */ 178} 179 180/* 181 * bios_sigsearch 182 * 183 * Search some or all of the BIOS region for a signature string. 184 * 185 * (start) Optional offset returned from this function 186 * (for searching for multiple matches), or NULL 187 * to start the search from the base of the BIOS. 188 * Note that this will be a _physical_ address in 189 * the range 0xe0000 - 0xfffff. 190 * (sig) is a pointer to the byte(s) of the signature. 191 * (siglen) number of bytes in the signature. 192 * (paralen) signature paragraph (alignment) size. 193 * (sigofs) offset of the signature within the paragraph. 194 * 195 * Returns the _physical_ address of the found signature, 0 if the 196 * signature was not found. 197 */ 198 199u_int32_t 200bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) 201{ 202 u_char *sp, *end; 203 int i; 204 205 /* compute the starting address */ 206 if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { 207 sp = (char *)BIOS_PADDRTOVADDR(start); 208 } else if (start == 0) { 209 sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); 210 } else { 211 return 0; /* bogus start address */ 212 } 213 214 /* compute the end address */ 215 end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); 216 217 /* loop searching */ 218 while ((sp + sigofs + siglen) < end) { 219 220 /* compare here */ 221 if (!memcmp(sp + sigofs, sig, siglen)) { 222 /* convert back to physical address */ 223 return((u_int32_t)BIOS_VADDRTOPADDR(sp)); 224 } 225 sp += paralen; 226 } 227 return(0); 228} 229 230 231 232