]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / biosemu / warmboot.c
1 /****************************************************************************
2 *
3 *                        BIOS emulator and interface
4 *                      to Realmode X86 Emulator Library
5 *
6 *               Copyright (C) 1996-1999 SciTech Software, Inc.
7 *
8 *  ========================================================================
9 *
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.
19 *
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.
27 *
28 *  ========================================================================
29 *
30 * Language:     ANSI C
31 * Environment:  Any
32 * Developer:    Kendall Bennett
33 *
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
37 *               the cards up.
38 *
39 ****************************************************************************/
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include "biosemu.h"
46 #ifndef _MAX_PATH
47 #define _MAX_PATH 256
48 #endif
49
50 /*------------------------- Global Variables ------------------------------*/
51
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;
63
64 /* Length of the BIOS image */
65
66 #define MAX_BIOSLEN         (64 * 1024L)
67 #define FINAL_BIOSLEN       (32 * 1024L)
68
69 /* Macro to determine if the VGA is enabled and responding */
70
71 #define VGA_NOT_ACTIVE()    (forcePost || (PM_inpb(0x3CC) == 0xFF) || ((PM_inpb(0x3CC) & 0x2) == 0))
72
73 #define ENABLE_DEVICE(device)   \
74     PCI_writePCIRegB(0x4,PCI[DeviceIndex[device]].Command | 0x7,device)
75
76 #define DISABLE_DEVICE(device)  \
77     PCI_writePCIRegB(0x4,0,device)
78
79 /* Macros to enable and disable AGP VGA resources */
80
81 #define ENABLE_AGP_VGA()    \
82     PCI_accessReg(0x3E,AGPBridge->BridgeControl | 0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
83
84 #define DISABLE_AGP_VGA()   \
85     PCI_accessReg(0x3E,AGPBridge->BridgeControl & ~0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
86
87 #define RESTORE_AGP_VGA()   \
88     PCI_accessReg(0x3E,AGPBridge->BridgeControl,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
89
90 /*-------------------------- Implementation -------------------------------*/
91
92 /****************************************************************************
93 RETURNS:
94 The address to use to map the secondary BIOS (PCI/AGP devices)
95
96 REMARKS:
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.
103
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(
109     int device)
110 {
111     ulong   base,size;
112     int     bar;
113
114     for (bar = 0x10; bar <= 0x14; bar++) {
115         base = PCI_readPCIRegL(bar,device) & ~0xFF;
116         if (!(base & 0x1)) {
117             PCI_writePCIRegL(bar,0xFFFFFFFF,device);
118             size = PCI_readPCIRegL(bar,device) & ~0xFF;
119             size = ~size+1;
120             PCI_writePCIRegL(bar,0,device);
121             if (size >= MAX_BIOSLEN)
122                 return base;
123             }
124         }
125     return 0;
126 }
127
128 /****************************************************************************
129 REMARKS:
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)
137 {
138     int i;
139
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);
147         }
148 }
149
150 /****************************************************************************
151 RETURNS:
152 True if successfully initialised, false if not.
153
154 REMARKS:
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(
160     int device,
161     ulong BIOSPhysAddr,
162     void *mappedBIOS,
163     ulong BIOSLen)
164 {
165     RMREGS          regs;
166     RMSREGS         sregs;
167
168     // Determine the value to store in AX for BIOS POST
169     regs.x.ax = (u16)(PCI[DeviceIndex[device]].slot.i >> 8);
170     if (useV86) {
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.
177             if (device == 0)
178                 PM_doBIOSPOST(regs.x.ax,0xC0000,mappedBIOS,BIOSLen);
179             }
180         }
181     else {
182         // Setup the X86 emulator for the VGA BIOS
183         BE_setVGA(&VGAInfo[device]);
184
185         // Execute the BIOS POST code
186         BE_callRealMode(0xC000,0x0003,&regs,&sregs);
187
188         // Cleanup and exit
189         BE_getVGA(&VGAInfo[device]);
190         }
191 }
192
193 /****************************************************************************
194 RETURNS:
195 True if successfully initialised, false if not.
196
197 REMARKS:
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)
202 {
203     int     device;
204     ulong   BIOSImageLen,mappedBIOSPhys;
205     uchar   *mappedBIOS,*copyOfBIOS;
206     char    filename[_MAX_PATH];
207     FILE    *f;
208
209     // Disable the primary display controller and AGP VGA pass-through
210     DISABLE_DEVICE(0);
211     if (AGPBridge)
212         DISABLE_AGP_VGA();
213
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)
218             continue;
219
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)
224             ENABLE_AGP_VGA();
225
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);
230
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
236             // this case).
237             mappedBIOS = NULL;
238             if (PCI[DeviceIndex[device]].ROMBaseAddress != 0)
239                 mappedBIOSPhys = PCI[DeviceIndex[device]].ROMBaseAddress & ~0xF;
240             else
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)
247                 return false;
248             memcpy(copyOfBIOS,mappedBIOS,BIOSImageLen);
249             PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
250
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;
255
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);
260
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);
265                 }
266
267             // Reset the size of the BIOS image to the final size
268             VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
269
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);
275                 fclose(f);
276                 }
277             }
278         else {
279             // Allocate memory to store copy of BIOS from secondary controllers
280             if ((copyOfBIOS = malloc(FINAL_BIOSLEN)) == NULL)
281                 return false;
282             VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
283             VGAInfo[device].BIOSImage = copyOfBIOS;
284             VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
285
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);
291                 fclose(f);
292                 }
293             }
294
295         // Fix up all the secondary PCI base address registers
296         // (restores them all from the values we read previously)
297         _PCI_fixupSecondaryBARs();
298
299         // Disable the secondary controller and AGP VGA pass-through
300         DISABLE_DEVICE(device);
301         if (AGPBridge)
302             DISABLE_AGP_VGA();
303         }
304
305     // Reenable primary display controller and reset AGP bridge control
306     if (AGPBridge)
307         RESTORE_AGP_VGA();
308     ENABLE_DEVICE(0);
309
310     // Free physical BIOS image mapping
311     PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
312
313     // Restore the X86 emulator BIOS info to primary controller
314     if (!useV86)
315         BE_setVGA(&VGAInfo[0]);
316     return true;
317 }
318
319 /****************************************************************************
320 REMARKS:
321 Enumerates the PCI bus and dumps the PCI configuration information to the
322 log file.
323 ****************************************************************************/
324 static void EnumeratePCI(void)
325 {
326     int             i,index;
327     PCIBridgeInfo   *info;
328
329     printk("Displaying enumeration of PCI bus (%d devices, %d display devices)\n",
330         NumPCI, NumDevices);
331     for (index = 0; index < NumDevices; index++)
332         printk("  Display device %d is PCI device %d\n",index,DeviceIndex[index]);
333     printk("\n");
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   ",
337             PCI[i].slot.p.Bus,
338             PCI[i].slot.p.Device,
339             PCI[i].slot.p.Function,
340             PCI[i].VendorID,
341             PCI[i].DeviceID,
342             PCI[i].SubSystemVendorID,
343             PCI[i].SubSystemID,
344             PCI[i].RevID,
345             PCI[i].BaseClass,
346             PCI[i].SubClass,
347             PCI[i].InterruptLine,
348             PCI[i].InterruptPin,
349             PCI[i].Command);
350         for (index = 0; index < NumDevices; index++) {
351             if (DeviceIndex[index] == i)
352                 break;
353             }
354         if (index < NumDevices)
355             printk("<- %d\n", index);
356         else
357             printk("\n");
358         }
359     printk("\n");
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   ",
363             PCI[i].VendorID,
364             PCI[i].DeviceID,
365             PCI[i].Status,
366             PCI[i].Interface,
367             PCI[i].CacheLineSize,
368             PCI[i].LatencyTimer,
369             PCI[i].HeaderType,
370             PCI[i].BIST);
371         for (index = 0; index < NumDevices; index++) {
372             if (DeviceIndex[index] == i)
373                 break;
374             }
375         if (index < NumDevices)
376             printk("<- %d\n", index);
377         else
378             printk("\n");
379         }
380     printk("\n");
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 ",
384             PCI[i].VendorID,
385             PCI[i].DeviceID,
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)
395                 break;
396             }
397         if (index < NumDevices)
398             printk("<- %d\n", index);
399         else
400             printk("\n");
401         }
402     printk("\n");
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 ",
406             PCI[i].VendorID,
407             PCI[i].DeviceID,
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)
417                 break;
418             }
419         if (index < NumDevices)
420             printk("<- %d\n", index);
421         else
422             printk("\n");
423         }
424     printk("\n");
425     printk("Displaying enumeration of %d bridge devices\n",NumBridges);
426     printk("\n");
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",
431             info->VendorID,
432             info->DeviceID,
433             info->PrimaryBusNumber,
434             info->SecondayBusNumber,
435             info->SubordinateBusNumber,
436             ((u16)info->IOBase << 8) & 0xF000,
437             info->IOLimit ?
438                 ((u16)info->IOLimit << 8) | 0xFFF : 0,
439             ((u32)info->MemoryBase << 16) & 0xFFF00000,
440             info->MemoryLimit ?
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);
446         }
447     printk("\n");
448 }
449
450 /****************************************************************************
451 RETURNS:
452 Number of display devices found.
453
454 REMARKS:
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)
459 {
460     int             i,j;
461     PCIBridgeInfo   *info;
462
463     // If this is the first time we have been called, enumerate all
464     // devices on the PCI bus.
465     if (NumPCI == -1) {
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)
469             return -1;
470
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;
476                 }
477             }
478
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) {
483                     DeviceIndex[0] = i;
484                     }
485                 else {
486                     if (NumDevices < MAX_PCI_DEVICES)
487                         DeviceIndex[NumDevices++] = i;
488                     }
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
493                     // control it.
494                     for (j = 0; j < NumBridges; j++) {
495                         info = (PCIBridgeInfo*)&PCI[BridgeIndex[j]];
496                         if (info->SecondayBusNumber == PCI[i].slot.p.Bus) {
497                             AGPBridge = info;
498                             break;
499                             }
500                         }
501                     }
502                 }
503             }
504
505         // Enumerate all PCI and bridge devices to log file
506         EnumeratePCI();
507         }
508     return NumDevices;
509 }
510
511 FILE *logfile;
512
513 void printk(const char *fmt, ...)
514 {
515     va_list argptr;
516     va_start(argptr, fmt);
517     vfprintf(logfile, fmt, argptr);
518     fflush(logfile);
519     va_end(argptr);
520 }
521
522 int main(int argc,char *argv[])
523 {
524     while (argc > 1) {
525         if (stricmp(argv[1],"-usev86") == 0) {
526             useV86 = true;
527             }
528         else if (stricmp(argv[1],"-force") == 0) {
529             forcePost = true;
530             }
531 #ifdef  DEBUG
532         else if (stricmp(argv[1],"-decode") == 0) {
533             debugFlags |= DEBUG_DECODE_F;
534             }
535         else if (stricmp(argv[1],"-iotrace") == 0) {
536             debugFlags |= DEBUG_IO_TRACE_F;
537             }
538 #endif
539         else {
540             printf("Usage: warmboot [-usev86] [-force] [-decode] [-iotrace]\n");
541             exit(-1);
542             }
543         argc--;
544         argv++;
545         }
546     if ((logfile = fopen("warmboot.log","w")) == NULL)
547         exit(1);
548
549     PM_init();
550     if (!useV86) {
551         // Initialise the x86 BIOS emulator
552         BE_init(false,debugFlags,65536,&VGAInfo[0]);
553         }
554
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");
558         return -1;
559         }
560
561     // Post all the display controller BIOS'es
562     PCI_postControllers();
563
564     // Cleanup and exit the emulator
565     if (!useV86)
566         BE_exit();
567     fclose(logfile);
568     return 0;
569 }