xref: /freebsd/sys/i386/i386/bios.c (revision c7a2b294f04ce55d5eaf1628e6bf965a57127ea5)
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