1 /****************************************************************************
3 * BIOS emulator and interface
4 * to Realmode X86 Emulator Library
6 * Copyright (C) 1996-1999 SciTech Software, Inc.
8 * ========================================================================
10 * Permission to use, copy, modify, distribute, and sell this software and
11 * its documentation for any purpose is hereby granted without fee,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation, and that the name of the authors not be used
15 * in advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission. The authors makes no
17 * representations about the suitability of this software for any purpose.
18 * It is provided "as is" without express or implied warranty.
20 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 * PERFORMANCE OF THIS SOFTWARE.
28 * ========================================================================
32 * Developer: Kendall Bennett
34 * Description: Module to implement warm booting of all PCI/AGP controllers
35 * on the bus. We use the x86 real mode emulator to run the
36 * BIOS on the primary and secondary controllers to bring
39 ****************************************************************************/
50 /*------------------------- Global Variables ------------------------------*/
52 static PCIDeviceInfo PCI[MAX_PCI_DEVICES];
53 static int NumPCI = -1;
54 static int BridgeIndex[MAX_PCI_DEVICES] = {0};
55 static int NumBridges;
56 static PCIBridgeInfo *AGPBridge = NULL;
57 static int DeviceIndex[MAX_PCI_DEVICES] = {0};
58 static int NumDevices;
59 static u32 debugFlags = 0;
60 static BE_VGAInfo VGAInfo[MAX_PCI_DEVICES] = {{0}};
61 static ibool useV86 = false;
62 static ibool forcePost = false;
64 /* Length of the BIOS image */
66 #define MAX_BIOSLEN (64 * 1024L)
67 #define FINAL_BIOSLEN (32 * 1024L)
69 /* Macro to determine if the VGA is enabled and responding */
71 #define VGA_NOT_ACTIVE() (forcePost || (PM_inpb(0x3CC) == 0xFF) || ((PM_inpb(0x3CC) & 0x2) == 0))
73 #define ENABLE_DEVICE(device) \
74 PCI_writePCIRegB(0x4,PCI[DeviceIndex[device]].Command | 0x7,device)
76 #define DISABLE_DEVICE(device) \
77 PCI_writePCIRegB(0x4,0,device)
79 /* Macros to enable and disable AGP VGA resources */
81 #define ENABLE_AGP_VGA() \
82 PCI_accessReg(0x3E,AGPBridge->BridgeControl | 0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
84 #define DISABLE_AGP_VGA() \
85 PCI_accessReg(0x3E,AGPBridge->BridgeControl & ~0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
87 #define RESTORE_AGP_VGA() \
88 PCI_accessReg(0x3E,AGPBridge->BridgeControl,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
90 /*-------------------------- Implementation -------------------------------*/
92 /****************************************************************************
94 The address to use to map the secondary BIOS (PCI/AGP devices)
97 Searches all the PCI base address registers for the device looking for a
98 memory mapping that is large enough to hold our ROM BIOS. We usually end up
99 finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
100 to map the BIOS for the device into. We use a mapping that is already
101 assigned to the device to ensure the memory range will be passed through
102 by any PCI->PCI or AGP->PCI bridge that may be present.
104 NOTE: Usually this function is only used for AGP devices, but it may be
105 used for PCI devices that have already been POST'ed and the BIOS
106 ROM base address has been zero'ed out.
107 ****************************************************************************/
108 static ulong PCI_findBIOSAddr(
114 for (bar = 0x10; bar <= 0x14; bar++) {
115 base = PCI_readPCIRegL(bar,device) & ~0xFF;
117 PCI_writePCIRegL(bar,0xFFFFFFFF,device);
118 size = PCI_readPCIRegL(bar,device) & ~0xFF;
120 PCI_writePCIRegL(bar,0,device);
121 if (size >= MAX_BIOSLEN)
128 /****************************************************************************
130 Re-writes the PCI base address registers for the secondary PCI controller
131 with the values from our initial PCI bus enumeration. This fixes up the
132 values after we have POST'ed the secondary display controller BIOS, which
133 may have incorrectly re-programmed the base registers the same as the
134 primary display controller (the case for identical S3 cards).
135 ****************************************************************************/
136 static void _PCI_fixupSecondaryBARs(void)
140 for (i = 0; i < NumDevices; i++) {
141 PCI_writePCIRegL(0x10,PCI[DeviceIndex[i]].BaseAddress10,i);
142 PCI_writePCIRegL(0x14,PCI[DeviceIndex[i]].BaseAddress14,i);
143 PCI_writePCIRegL(0x18,PCI[DeviceIndex[i]].BaseAddress18,i);
144 PCI_writePCIRegL(0x1C,PCI[DeviceIndex[i]].BaseAddress1C,i);
145 PCI_writePCIRegL(0x20,PCI[DeviceIndex[i]].BaseAddress20,i);
146 PCI_writePCIRegL(0x24,PCI[DeviceIndex[i]].BaseAddress24,i);
150 /****************************************************************************
152 True if successfully initialised, false if not.
155 This function executes the BIOS POST code on the controller. We assume that
156 at this stage the controller has its I/O and memory space enabled and
157 that all other controllers are in a disabled state.
158 ****************************************************************************/
159 static void PCI_doBIOSPOST(
168 /* Determine the value to store in AX for BIOS POST */
169 regs.x.ax = (u16)(PCI[DeviceIndex[device]].slot.i >> 8);
171 /* Post the BIOS using the PM functions (ie: v86 mode on Linux) */
172 if (!PM_doBIOSPOST(regs.x.ax,BIOSPhysAddr,mappedBIOS,BIOSLen)) {
173 /* If the PM function fails, this probably means are we are on */
174 /* DOS and can't re-map the real mode 0xC0000 region. In thise */
175 /* case if the device is the primary, we can use the real */
176 /* BIOS at 0xC0000 directly. */
178 PM_doBIOSPOST(regs.x.ax,0xC0000,mappedBIOS,BIOSLen);
182 /* Setup the X86 emulator for the VGA BIOS */
183 BE_setVGA(&VGAInfo[device]);
185 /* Execute the BIOS POST code */
186 BE_callRealMode(0xC000,0x0003,®s,&sregs);
188 /* Cleanup and exit */
189 BE_getVGA(&VGAInfo[device]);
193 /****************************************************************************
195 True if successfully initialised, false if not.
198 Loads and POST's the secondary controllers BIOS, directly from the BIOS
199 image we can extract over the PCI bus.
200 ****************************************************************************/
201 static ibool PCI_postControllers(void)
204 ulong BIOSImageLen,mappedBIOSPhys;
205 uchar *mappedBIOS,*copyOfBIOS;
206 char filename[_MAX_PATH];
209 /* Disable the primary display controller and AGP VGA pass-through */
214 /* Now POST all the secondary controllers */
215 for (device = 0; device < NumDevices; device++) {
216 /* Skip the device if it is not enabled (probably an ISA device) */
217 if (DeviceIndex[device] == -1)
220 /* Enable secondary display controller. If the secondary controller */
221 /* is on the AGP bus, then enable VGA resources for the AGP device. */
222 ENABLE_DEVICE(device);
223 if (AGPBridge && AGPBridge->SecondayBusNumber == PCI[DeviceIndex[device]].slot.p.Bus)
226 /* Check if the controller has already been POST'ed */
227 if (VGA_NOT_ACTIVE()) {
228 /* Find a viable place to map the secondary PCI BIOS image and map it */
229 printk("Device %d not enabled, so attempting warm boot it\n", device);
231 /* For AGP devices (and PCI devices that do have the ROM base */
232 /* address zero'ed out) we have to map the BIOS to a location */
233 /* that is passed by the AGP bridge to the bus. Some AGP devices */
234 /* have the ROM base address already set up for us, and some */
235 /* do not (we map to one of the existing BAR locations in */
238 if (PCI[DeviceIndex[device]].ROMBaseAddress != 0)
239 mappedBIOSPhys = PCI[DeviceIndex[device]].ROMBaseAddress & ~0xF;
241 mappedBIOSPhys = PCI_findBIOSAddr(device);
242 printk("Mapping BIOS image to 0x%08X\n", mappedBIOSPhys);
243 mappedBIOS = PM_mapPhysicalAddr(mappedBIOSPhys,MAX_BIOSLEN-1,false);
244 PCI_writePCIRegL(0x30,mappedBIOSPhys | 0x1,device);
245 BIOSImageLen = mappedBIOS[2] * 512;
246 if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL)
248 memcpy(copyOfBIOS,mappedBIOS,BIOSImageLen);
249 PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
251 /* Allocate memory to store copy of BIOS from secondary controllers */
252 VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
253 VGAInfo[device].BIOSImage = copyOfBIOS;
254 VGAInfo[device].BIOSImageLen = BIOSImageLen;
256 /* Restore device mappings */
257 PCI_writePCIRegL(0x30,PCI[DeviceIndex[device]].ROMBaseAddress,device);
258 PCI_writePCIRegL(0x10,PCI[DeviceIndex[device]].BaseAddress10,device);
259 PCI_writePCIRegL(0x14,PCI[DeviceIndex[device]].BaseAddress14,device);
261 /* Now execute the BIOS POST for the device */
262 if (copyOfBIOS[0] == 0x55 && copyOfBIOS[1] == 0xAA) {
263 printk("Executing BIOS POST for controller.\n");
264 PCI_doBIOSPOST(device,mappedBIOSPhys,copyOfBIOS,BIOSImageLen);
267 /* Reset the size of the BIOS image to the final size */
268 VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
270 /* Save the BIOS and interrupt vector information to disk */
271 sprintf(filename,"%s/bios.%02d",PM_getNucleusConfigPath(),device);
272 if ((f = fopen(filename,"wb")) != NULL) {
273 fwrite(copyOfBIOS,1,FINAL_BIOSLEN,f);
274 fwrite(VGAInfo[device].LowMem,1,sizeof(VGAInfo[device].LowMem),f);
279 /* Allocate memory to store copy of BIOS from secondary controllers */
280 if ((copyOfBIOS = malloc(FINAL_BIOSLEN)) == NULL)
282 VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
283 VGAInfo[device].BIOSImage = copyOfBIOS;
284 VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
286 /* Load the BIOS and interrupt vector information from disk */
287 sprintf(filename,"%s/bios.%02d",PM_getNucleusConfigPath(),device);
288 if ((f = fopen(filename,"rb")) != NULL) {
289 fread(copyOfBIOS,1,FINAL_BIOSLEN,f);
290 fread(VGAInfo[device].LowMem,1,sizeof(VGAInfo[device].LowMem),f);
295 /* Fix up all the secondary PCI base address registers */
296 /* (restores them all from the values we read previously) */
297 _PCI_fixupSecondaryBARs();
299 /* Disable the secondary controller and AGP VGA pass-through */
300 DISABLE_DEVICE(device);
305 /* Reenable primary display controller and reset AGP bridge control */
310 /* Free physical BIOS image mapping */
311 PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
313 /* Restore the X86 emulator BIOS info to primary controller */
315 BE_setVGA(&VGAInfo[0]);
319 /****************************************************************************
321 Enumerates the PCI bus and dumps the PCI configuration information to the
323 ****************************************************************************/
324 static void EnumeratePCI(void)
329 printk("Displaying enumeration of PCI bus (%d devices, %d display devices)\n",
331 for (index = 0; index < NumDevices; index++)
332 printk(" Display device %d is PCI device %d\n",index,DeviceIndex[index]);
334 printk("Bus Slot Fnc DeviceID SubSystem Rev Class IRQ Int Cmd\n");
335 for (i = 0; i < NumPCI; i++) {
336 printk("%2d %2d %2d %04X:%04X %04X:%04X %02X %02X:%02X %02X %02X %04X ",
338 PCI[i].slot.p.Device,
339 PCI[i].slot.p.Function,
342 PCI[i].SubSystemVendorID,
347 PCI[i].InterruptLine,
350 for (index = 0; index < NumDevices; index++) {
351 if (DeviceIndex[index] == i)
354 if (index < NumDevices)
355 printk("<- %d\n", index);
360 printk("DeviceID Stat Ifc Cch Lat Hdr BIST\n");
361 for (i = 0; i < NumPCI; i++) {
362 printk("%04X:%04X %04X %02X %02X %02X %02X %02X ",
367 PCI[i].CacheLineSize,
371 for (index = 0; index < NumDevices; index++) {
372 if (DeviceIndex[index] == i)
375 if (index < NumDevices)
376 printk("<- %d\n", index);
381 printk("DeviceID Base10h Base14h Base18h Base1Ch Base20h Base24h ROMBase\n");
382 for (i = 0; i < NumPCI; i++) {
383 printk("%04X:%04X %08X %08X %08X %08X %08X %08X %08X ",
386 PCI[i].BaseAddress10,
387 PCI[i].BaseAddress14,
388 PCI[i].BaseAddress18,
389 PCI[i].BaseAddress1C,
390 PCI[i].BaseAddress20,
391 PCI[i].BaseAddress24,
392 PCI[i].ROMBaseAddress);
393 for (index = 0; index < NumDevices; index++) {
394 if (DeviceIndex[index] == i)
397 if (index < NumDevices)
398 printk("<- %d\n", index);
403 printk("DeviceID BAR10Len BAR14Len BAR18Len BAR1CLen BAR20Len BAR24Len ROMLen\n");
404 for (i = 0; i < NumPCI; i++) {
405 printk("%04X:%04X %08X %08X %08X %08X %08X %08X %08X ",
408 PCI[i].BaseAddress10Len,
409 PCI[i].BaseAddress14Len,
410 PCI[i].BaseAddress18Len,
411 PCI[i].BaseAddress1CLen,
412 PCI[i].BaseAddress20Len,
413 PCI[i].BaseAddress24Len,
414 PCI[i].ROMBaseAddressLen);
415 for (index = 0; index < NumDevices; index++) {
416 if (DeviceIndex[index] == i)
419 if (index < NumDevices)
420 printk("<- %d\n", index);
425 printk("Displaying enumeration of %d bridge devices\n",NumBridges);
427 printk("DeviceID P# S# B# IOB IOL MemBase MemLimit PreBase PreLimit Ctrl\n");
428 for (i = 0; i < NumBridges; i++) {
429 info = (PCIBridgeInfo*)&PCI[BridgeIndex[i]];
430 printk("%04X:%04X %02X %02X %02X %04X %04X %08X %08X %08X %08X %04X\n",
433 info->PrimaryBusNumber,
434 info->SecondayBusNumber,
435 info->SubordinateBusNumber,
436 ((u16)info->IOBase << 8) & 0xF000,
438 ((u16)info->IOLimit << 8) | 0xFFF : 0,
439 ((u32)info->MemoryBase << 16) & 0xFFF00000,
441 ((u32)info->MemoryLimit << 16) | 0xFFFFF : 0,
442 ((u32)info->PrefetchableMemoryBase << 16) & 0xFFF00000,
443 info->PrefetchableMemoryLimit ?
444 ((u32)info->PrefetchableMemoryLimit << 16) | 0xFFFFF : 0,
445 info->BridgeControl);
450 /****************************************************************************
452 Number of display devices found.
455 This function enumerates the number of available display devices on the
456 PCI bus, and returns the number found.
457 ****************************************************************************/
458 static int PCI_enumerateDevices(void)
463 /* If this is the first time we have been called, enumerate all */
464 /* devices on the PCI bus. */
466 for (i = 0; i < MAX_PCI_DEVICES; i++)
467 PCI[i].dwSize = sizeof(PCI[i]);
468 if ((NumPCI = PCI_enumerate(PCI,MAX_PCI_DEVICES)) == 0)
471 /* Build a list of all PCI bridge devices */
472 for (i = 0,NumBridges = 0,BridgeIndex[0] = -1; i < NumPCI; i++) {
473 if (PCI[i].BaseClass == PCI_BRIDGE_CLASS) {
474 if (NumBridges < MAX_PCI_DEVICES)
475 BridgeIndex[NumBridges++] = i;
479 /* Now build a list of all display class devices */
480 for (i = 0,NumDevices = 1,DeviceIndex[0] = -1; i < NumPCI; i++) {
481 if (PCI_IS_DISPLAY_CLASS(&PCI[i])) {
482 if ((PCI[i].Command & 0x3) == 0x3) {
486 if (NumDevices < MAX_PCI_DEVICES)
487 DeviceIndex[NumDevices++] = i;
489 if (PCI[i].slot.p.Bus != 0) {
490 /* This device is on a different bus than the primary */
491 /* PCI bus, so it is probably an AGP device. Find the */
492 /* AGP bus device that controls that bus so we can */
494 for (j = 0; j < NumBridges; j++) {
495 info = (PCIBridgeInfo*)&PCI[BridgeIndex[j]];
496 if (info->SecondayBusNumber == PCI[i].slot.p.Bus) {
505 /* Enumerate all PCI and bridge devices to log file */
513 void printk(const char *fmt, ...)
516 va_start(argptr, fmt);
517 vfprintf(logfile, fmt, argptr);
522 int main(int argc,char *argv[])
525 if (stricmp(argv[1],"-usev86") == 0) {
528 else if (stricmp(argv[1],"-force") == 0) {
532 else if (stricmp(argv[1],"-decode") == 0) {
533 debugFlags |= DEBUG_DECODE_F;
535 else if (stricmp(argv[1],"-iotrace") == 0) {
536 debugFlags |= DEBUG_IO_TRACE_F;
540 printf("Usage: warmboot [-usev86] [-force] [-decode] [-iotrace]\n");
546 if ((logfile = fopen("warmboot.log","w")) == NULL)
551 /* Initialise the x86 BIOS emulator */
552 BE_init(false,debugFlags,65536,&VGAInfo[0]);
555 /* Enumerate all devices (which POST's them at the same time) */
556 if (PCI_enumerateDevices() < 1) {
557 printk("No PCI display devices found!\n");
561 /* Post all the display controller BIOS'es */
562 PCI_postControllers();
564 /* Cleanup and exit the emulator */