diff options
author | msmith <msmith@FreeBSD.org> | 1997-08-01 06:07:13 +0000 |
---|---|---|
committer | msmith <msmith@FreeBSD.org> | 1997-08-01 06:07:13 +0000 |
commit | 21f15a78ef25cafe5568ee6a7eb4673f2d7faedf (patch) | |
tree | a48d4d4bb24b7b4537eb43fe9f3962708ea01019 /sys | |
parent | 1e5dfe8d05b6b1114b99a9f099d18af39f65c50a (diff) | |
download | FreeBSD-src-21f15a78ef25cafe5568ee6a7eb4673f2d7faedf.zip FreeBSD-src-21f15a78ef25cafe5568ee6a7eb4673f2d7faedf.tar.gz |
Support functions for working with x86 PC-architecture BIOS.
Initially functionality is confined to 32-bit BIOS functions, however
it is envisioned that BIOS support may be enlisted for other
activities in the future.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/bios.c | 231 | ||||
-rw-r--r-- | sys/i386/i386/bios.c | 231 | ||||
-rw-r--r-- | sys/i386/i386/bioscall.s | 59 |
3 files changed, 521 insertions, 0 deletions
diff --git a/sys/amd64/amd64/bios.c b/sys/amd64/amd64/bios.c new file mode 100644 index 0000000..256bb8b --- /dev/null +++ b/sys/amd64/amd64/bios.c @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 1997 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +/* + * Code for dealing with the BIOS in x86 PC systems. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/pmap.h> +#include <machine/md_var.h> + +#include <machine/pc/bios.h> + +#define BIOS_START 0xe0000 +#define BIOS_SIZE 0x20000 + +/* exported lookup results */ +struct bios32_SDentry PCIbios = {entry : 0}; +struct SMBIOS_table *SMBIOStable = 0; +struct DMI_table *DMItable = 0; + +static caddr_t bios32_SDCI = NULL; + +static void bios32_init(void *junk); + +/* start fairly early */ +SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL); + +/* + * bios32_init + * + * Locate various bios32 entities. + */ +static void +bios32_init(void *junk) +{ + u_long sigaddr; + struct bios32_SDheader *sdh; + struct SMBIOS_table *sbt; + struct DMI_table *dmit; + u_int8_t ck, *cv; + int i; + + + /* + * BIOS32 Service Directory + */ + + /* look for the signature */ + if ((sigaddr = bios_sigsearch(0, "_32_", 4, 16, 0)) != 0) { + + /* get a virtual pointer to the structure */ + sdh = (struct bios32_SDheader *)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)sdh, ck = 0, i = 0; i < (sdh->len * 16); i++) { + ck += cv[i]; + } + /* If checksum is OK, enable use of the entrypoint */ + if (ck == 0) { + bios32_SDCI = (caddr_t)BIOS_PADDRTOVADDR(sdh->entry); + if (bootverbose) { + printf("Found BIOS32 Service Directory header at %p\n", sdh); + printf("Entry = 0x%x (%p) Rev = %d Len = %d\n", + sdh->entry, bios32_SDCI, sdh->revision, sdh->len); + } + /* See if there's a PCI BIOS entrypoint here */ + PCIbios.ident.id = 0x49435024; /* PCI systems should have this */ + if (!bios32_SDlookup(&PCIbios) && bootverbose) + printf("PCI BIOS entry at 0x%x\n", PCIbios.entry); + } else { + printf("Bad BIOS32 Service Directory!\n"); + } + } + + /* + * System Management BIOS + */ + /* look for the SMBIOS signature */ + if ((sigaddr = bios_sigsearch(0, "_SM_", 4, 16, 0)) != 0) { + + /* get a virtual pointer to the structure */ + sbt = (struct SMBIOS_table *)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)sbt, ck = 0, i = 0; i < sbt->len; i++) { + ck += cv[i]; + } + /* if checksum is OK, we have action */ + if (ck == 0) { + SMBIOStable = sbt; /* save reference */ + DMItable = &sbt->dmi; /* contained within */ + if (bootverbose) { + printf("SMIBIOS header at %p\n", sbt); + printf("Version %d.%d\n", sbt->major, sbt->minor); + printf("Table at 0x%x, %hd entries, %hd bytes, largest entry %hd bytes\n", + dmit->st_base, dmit->st_entries, dmit->st_size, sbt->st_maxsize); + } + } else { + printf("Bad SMBIOS table checksum!\n"); + } + + } + /* look for the DMI signature */ + if ((sigaddr = bios_sigsearch(0, "_DMI_", 5, 16, 0)) != 0) { + + /* get a virtual pointer to the structure */ + dmit = (struct DMI_table *)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)dmit, ck = 0, i = 0; i < 16; i++) { + ck += cv[i]; + } + /* if checksum is OK, we have action */ + if (ck == 0) { + DMItable = dmit; /* save reference */ + if (bootverbose) { + printf("DMI header at %p\n", dmit); + printf("Version %x\n", dmit->bcd_revision); + printf("Table at 0x%x, %hd entries, %hd bytes\n", + dmit->st_base, dmit->st_entries, dmit->st_size); + } + } else { + printf("Bad DMI table checksum!\n"); + } + } + +} + +/* + * bios32_SDlookup + * + * Query the BIOS32 Service Directory for the service named in (ent), + * returns nonzero if the lookup fails. The caller must fill in + * (ent->ident), the remainder are populated on a successful lookup. + */ +int +bios32_SDlookup(struct bios32_SDentry *ent) +{ + struct bios32_args args; + + if (bios32_SDCI != NULL) { + + args.eax = ent->ident.id; /* set up arguments */ + args.ebx = args.ecx = args.edx = 0; + bios32(bios32_SDCI, &args); /* make the BIOS call */ + if ((args.eax & 0xff) == 0) { /* success? */ + ent->base = args.ebx; + ent->len = args.ecx; + ent->entry = args.edx; + return(0); /* all OK */ + } + } + return(1); /* failed */ +} + +/* + * bios_sigsearch + * + * Search some or all of the BIOS region for a signature string. + * + * (start) Optional offset returned from this function + * (for searching for multiple matches), or NULL + * to start the search from the base of the BIOS. + * Note that this will be a _physical_ address in + * the range 0xe0000 - 0xfffff. + * (sig) is a pointer to the byte(s) of the signature. + * (siglen) number of bytes in the signature. + * (paralen) signature paragraph (alignment) size. + * (sigofs) offset of the signature within the paragraph. + * + * Returns the _physical_ address of the found signature, 0 if the + * signature was not found. + */ + +u_int32_t +bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) +{ + u_char *sp, *end; + int i; + + /* compute the starting address */ + if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { + sp = (char *)BIOS_PADDRTOVADDR(start); + } else if (start == 0) { + sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); + } else { + return 0; /* bogus start address */ + } + + /* compute the end address */ + end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); + + /* loop searching */ + while ((sp + sigofs + siglen) < end) { + + /* compare here */ + if (!memcmp(sp + sigofs, sig, siglen)) { + /* convert back to physical address */ + return((u_int32_t)BIOS_VADDRTOPADDR(sp)); + } + sp += paralen; + } + return(0); +} + + + diff --git a/sys/i386/i386/bios.c b/sys/i386/i386/bios.c new file mode 100644 index 0000000..256bb8b --- /dev/null +++ b/sys/i386/i386/bios.c @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 1997 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +/* + * Code for dealing with the BIOS in x86 PC systems. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/pmap.h> +#include <machine/md_var.h> + +#include <machine/pc/bios.h> + +#define BIOS_START 0xe0000 +#define BIOS_SIZE 0x20000 + +/* exported lookup results */ +struct bios32_SDentry PCIbios = {entry : 0}; +struct SMBIOS_table *SMBIOStable = 0; +struct DMI_table *DMItable = 0; + +static caddr_t bios32_SDCI = NULL; + +static void bios32_init(void *junk); + +/* start fairly early */ +SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL); + +/* + * bios32_init + * + * Locate various bios32 entities. + */ +static void +bios32_init(void *junk) +{ + u_long sigaddr; + struct bios32_SDheader *sdh; + struct SMBIOS_table *sbt; + struct DMI_table *dmit; + u_int8_t ck, *cv; + int i; + + + /* + * BIOS32 Service Directory + */ + + /* look for the signature */ + if ((sigaddr = bios_sigsearch(0, "_32_", 4, 16, 0)) != 0) { + + /* get a virtual pointer to the structure */ + sdh = (struct bios32_SDheader *)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)sdh, ck = 0, i = 0; i < (sdh->len * 16); i++) { + ck += cv[i]; + } + /* If checksum is OK, enable use of the entrypoint */ + if (ck == 0) { + bios32_SDCI = (caddr_t)BIOS_PADDRTOVADDR(sdh->entry); + if (bootverbose) { + printf("Found BIOS32 Service Directory header at %p\n", sdh); + printf("Entry = 0x%x (%p) Rev = %d Len = %d\n", + sdh->entry, bios32_SDCI, sdh->revision, sdh->len); + } + /* See if there's a PCI BIOS entrypoint here */ + PCIbios.ident.id = 0x49435024; /* PCI systems should have this */ + if (!bios32_SDlookup(&PCIbios) && bootverbose) + printf("PCI BIOS entry at 0x%x\n", PCIbios.entry); + } else { + printf("Bad BIOS32 Service Directory!\n"); + } + } + + /* + * System Management BIOS + */ + /* look for the SMBIOS signature */ + if ((sigaddr = bios_sigsearch(0, "_SM_", 4, 16, 0)) != 0) { + + /* get a virtual pointer to the structure */ + sbt = (struct SMBIOS_table *)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)sbt, ck = 0, i = 0; i < sbt->len; i++) { + ck += cv[i]; + } + /* if checksum is OK, we have action */ + if (ck == 0) { + SMBIOStable = sbt; /* save reference */ + DMItable = &sbt->dmi; /* contained within */ + if (bootverbose) { + printf("SMIBIOS header at %p\n", sbt); + printf("Version %d.%d\n", sbt->major, sbt->minor); + printf("Table at 0x%x, %hd entries, %hd bytes, largest entry %hd bytes\n", + dmit->st_base, dmit->st_entries, dmit->st_size, sbt->st_maxsize); + } + } else { + printf("Bad SMBIOS table checksum!\n"); + } + + } + /* look for the DMI signature */ + if ((sigaddr = bios_sigsearch(0, "_DMI_", 5, 16, 0)) != 0) { + + /* get a virtual pointer to the structure */ + dmit = (struct DMI_table *)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)dmit, ck = 0, i = 0; i < 16; i++) { + ck += cv[i]; + } + /* if checksum is OK, we have action */ + if (ck == 0) { + DMItable = dmit; /* save reference */ + if (bootverbose) { + printf("DMI header at %p\n", dmit); + printf("Version %x\n", dmit->bcd_revision); + printf("Table at 0x%x, %hd entries, %hd bytes\n", + dmit->st_base, dmit->st_entries, dmit->st_size); + } + } else { + printf("Bad DMI table checksum!\n"); + } + } + +} + +/* + * bios32_SDlookup + * + * Query the BIOS32 Service Directory for the service named in (ent), + * returns nonzero if the lookup fails. The caller must fill in + * (ent->ident), the remainder are populated on a successful lookup. + */ +int +bios32_SDlookup(struct bios32_SDentry *ent) +{ + struct bios32_args args; + + if (bios32_SDCI != NULL) { + + args.eax = ent->ident.id; /* set up arguments */ + args.ebx = args.ecx = args.edx = 0; + bios32(bios32_SDCI, &args); /* make the BIOS call */ + if ((args.eax & 0xff) == 0) { /* success? */ + ent->base = args.ebx; + ent->len = args.ecx; + ent->entry = args.edx; + return(0); /* all OK */ + } + } + return(1); /* failed */ +} + +/* + * bios_sigsearch + * + * Search some or all of the BIOS region for a signature string. + * + * (start) Optional offset returned from this function + * (for searching for multiple matches), or NULL + * to start the search from the base of the BIOS. + * Note that this will be a _physical_ address in + * the range 0xe0000 - 0xfffff. + * (sig) is a pointer to the byte(s) of the signature. + * (siglen) number of bytes in the signature. + * (paralen) signature paragraph (alignment) size. + * (sigofs) offset of the signature within the paragraph. + * + * Returns the _physical_ address of the found signature, 0 if the + * signature was not found. + */ + +u_int32_t +bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) +{ + u_char *sp, *end; + int i; + + /* compute the starting address */ + if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { + sp = (char *)BIOS_PADDRTOVADDR(start); + } else if (start == 0) { + sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); + } else { + return 0; /* bogus start address */ + } + + /* compute the end address */ + end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); + + /* loop searching */ + while ((sp + sigofs + siglen) < end) { + + /* compare here */ + if (!memcmp(sp + sigofs, sig, siglen)) { + /* convert back to physical address */ + return((u_int32_t)BIOS_VADDRTOPADDR(sp)); + } + sp += paralen; + } + return(0); +} + + + diff --git a/sys/i386/i386/bioscall.s b/sys/i386/i386/bioscall.s new file mode 100644 index 0000000..a041e0b --- /dev/null +++ b/sys/i386/i386/bioscall.s @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1997 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +/* + * Functions for calling x86 BIOS functions from the BSD kernel + */ + +#include <machine/asmacros.h> + + .text +/* + * bios32(caddr_t func_addr, bios32_args *args) + */ + +ENTRY(bios32) + pushl %ebx + pushl %esi + movl (2*4+2*4)(%esp), %esi + movl 0(%esi), %eax + movl 4(%esi), %ebx + movl 8(%esi), %ecx + movl 12(%esi), %edx + movl (2*4+1*4)(%esp), %esi + mov %cs, %di + pushl %edi /* really lcall/lret */ + call %esi + movl (2*4+2*4)(%esp), %esi + movl %eax, 0(%esi) + movl %ebx, 4(%esi) + movl %ecx, 8(%esi) + movl %edx, 12(%esi) + popl %esi + popl %ebx + ret |