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.11 1998/07/15 03:58:57 bde 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 */ 46 struct bios32_SDentry PCIbios = {entry : 0}; 47 static struct SMBIOS_table *SMBIOStable = 0; 48 static struct DMI_table *DMItable = 0; 49 50 static caddr_t bios32_SDCI = NULL; 51 52 static void bios32_init(void *junk); 53 54 /* start fairly early */ 55 SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL); 56 57 /* 58 * bios32_init 59 * 60 * Locate various bios32 entities. 61 */ 62 static void 63 bios32_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 *)(uintptr_t)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) && (sdh->entry < (BIOS_START + BIOS_SIZE))) { 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 *)(uintptr_t)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 sbt->dmi.st_base, (int)sbt->dmi.st_entries, (int)sbt->dmi.st_size, 122 (int)sbt->st_maxsize); 123 } 124 } else { 125 printf("Bad SMBIOS table checksum!\n"); 126 } 127 128 } 129 130 /* look for the DMI signature */ 131 if ((sigaddr = bios_sigsearch(0, "_DMI_", 5, 16, 0)) != 0) { 132 133 /* get a virtual pointer to the structure */ 134 dmit = (struct DMI_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 135 for (cv = (u_int8_t *)dmit, ck = 0, i = 0; i < 15; i++) { 136 ck += cv[i]; 137 } 138 /* if checksum is OK, we have action */ 139 if (ck == 0) { 140 DMItable = dmit; /* save reference */ 141 if (bootverbose) { 142 printf("DMI header at %p\n", dmit); 143 printf("Version %d.%d\n", (dmit->bcd_revision >> 4), 144 (dmit->bcd_revision & 0x0f)); 145 printf("Table at 0x%x, %d entries, %d bytes\n", 146 dmit->st_base, (int)dmit->st_entries, 147 (int)dmit->st_size); 148 } 149 } else { 150 printf("Bad DMI table checksum!\n"); 151 } 152 } 153 if (bootverbose) { 154 /* look for other know signatures */ 155 printf("Other BIOS signatures found:\n"); 156 printf("ACPI: %08x\n", bios_sigsearch(0, "RST PTR", 8, 16, 0)); 157 printf("$PnP: %08x\n", bios_sigsearch(0, "$PnP", 4, 16, 0)); 158 } 159 } 160 161 /* 162 * bios32_SDlookup 163 * 164 * Query the BIOS32 Service Directory for the service named in (ent), 165 * returns nonzero if the lookup fails. The caller must fill in 166 * (ent->ident), the remainder are populated on a successful lookup. 167 */ 168 int 169 bios32_SDlookup(struct bios32_SDentry *ent) 170 { 171 struct bios32_args args; 172 173 if (bios32_SDCI != NULL) { 174 175 args.eax = ent->ident.id; /* set up arguments */ 176 args.ebx = args.ecx = args.edx = 0; 177 bios32(bios32_SDCI, &args); /* make the BIOS call */ 178 if ((args.eax & 0xff) == 0) { /* success? */ 179 ent->base = args.ebx; 180 ent->len = args.ecx; 181 ent->entry = args.edx; 182 return(0); /* all OK */ 183 } 184 } 185 return(1); /* failed */ 186 } 187 188 /* 189 * bios_sigsearch 190 * 191 * Search some or all of the BIOS region for a signature string. 192 * 193 * (start) Optional offset returned from this function 194 * (for searching for multiple matches), or NULL 195 * to start the search from the base of the BIOS. 196 * Note that this will be a _physical_ address in 197 * the range 0xe0000 - 0xfffff. 198 * (sig) is a pointer to the byte(s) of the signature. 199 * (siglen) number of bytes in the signature. 200 * (paralen) signature paragraph (alignment) size. 201 * (sigofs) offset of the signature within the paragraph. 202 * 203 * Returns the _physical_ address of the found signature, 0 if the 204 * signature was not found. 205 */ 206 207 u_int32_t 208 bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) 209 { 210 u_char *sp, *end; 211 212 /* compute the starting address */ 213 if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { 214 sp = (char *)BIOS_PADDRTOVADDR(start); 215 } else if (start == 0) { 216 sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); 217 } else { 218 return 0; /* bogus start address */ 219 } 220 221 /* compute the end address */ 222 end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); 223 224 /* loop searching */ 225 while ((sp + sigofs + siglen) < end) { 226 227 /* compare here */ 228 if (!bcmp(sp + sigofs, sig, siglen)) { 229 /* convert back to physical address */ 230 return((u_int32_t)BIOS_VADDRTOPADDR(sp)); 231 } 232 sp += paralen; 233 } 234 return(0); 235 } 236 237 238 239