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