summaryrefslogtreecommitdiffstats
path: root/board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c')
-rw-r--r--board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c b/board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c
new file mode 100644
index 0000000000..96fa5a0e0f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/biosemu/warmboot.c
@@ -0,0 +1,569 @@
+/****************************************************************************
+*
+* BIOS emulator and interface
+* to Realmode X86 Emulator Library
+*
+* Copyright (C) 1996-1999 SciTech Software, Inc.
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+* Developer: Kendall Bennett
+*
+* Description: Module to implement warm booting of all PCI/AGP controllers
+* on the bus. We use the x86 real mode emulator to run the
+* BIOS on the primary and secondary controllers to bring
+* the cards up.
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "biosemu.h"
+#ifndef _MAX_PATH
+#define _MAX_PATH 256
+#endif
+
+/*------------------------- Global Variables ------------------------------*/
+
+static PCIDeviceInfo PCI[MAX_PCI_DEVICES];
+static int NumPCI = -1;
+static int BridgeIndex[MAX_PCI_DEVICES] = {0};
+static int NumBridges;
+static PCIBridgeInfo *AGPBridge = NULL;
+static int DeviceIndex[MAX_PCI_DEVICES] = {0};
+static int NumDevices;
+static u32 debugFlags = 0;
+static BE_VGAInfo VGAInfo[MAX_PCI_DEVICES] = {{0}};
+static ibool useV86 = false;
+static ibool forcePost = false;
+
+/* Length of the BIOS image */
+
+#define MAX_BIOSLEN (64 * 1024L)
+#define FINAL_BIOSLEN (32 * 1024L)
+
+/* Macro to determine if the VGA is enabled and responding */
+
+#define VGA_NOT_ACTIVE() (forcePost || (PM_inpb(0x3CC) == 0xFF) || ((PM_inpb(0x3CC) & 0x2) == 0))
+
+#define ENABLE_DEVICE(device) \
+ PCI_writePCIRegB(0x4,PCI[DeviceIndex[device]].Command | 0x7,device)
+
+#define DISABLE_DEVICE(device) \
+ PCI_writePCIRegB(0x4,0,device)
+
+/* Macros to enable and disable AGP VGA resources */
+
+#define ENABLE_AGP_VGA() \
+ PCI_accessReg(0x3E,AGPBridge->BridgeControl | 0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
+
+#define DISABLE_AGP_VGA() \
+ PCI_accessReg(0x3E,AGPBridge->BridgeControl & ~0x8,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
+
+#define RESTORE_AGP_VGA() \
+ PCI_accessReg(0x3E,AGPBridge->BridgeControl,PCI_WRITE_WORD,(PCIDeviceInfo*)AGPBridge)
+
+/*-------------------------- Implementation -------------------------------*/
+
+/****************************************************************************
+RETURNS:
+The address to use to map the secondary BIOS (PCI/AGP devices)
+
+REMARKS:
+Searches all the PCI base address registers for the device looking for a
+memory mapping that is large enough to hold our ROM BIOS. We usually end up
+finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
+to map the BIOS for the device into. We use a mapping that is already
+assigned to the device to ensure the memory range will be passed through
+by any PCI->PCI or AGP->PCI bridge that may be present.
+
+NOTE: Usually this function is only used for AGP devices, but it may be
+ used for PCI devices that have already been POST'ed and the BIOS
+ ROM base address has been zero'ed out.
+****************************************************************************/
+static ulong PCI_findBIOSAddr(
+ int device)
+{
+ ulong base,size;
+ int bar;
+
+ for (bar = 0x10; bar <= 0x14; bar++) {
+ base = PCI_readPCIRegL(bar,device) & ~0xFF;
+ if (!(base & 0x1)) {
+ PCI_writePCIRegL(bar,0xFFFFFFFF,device);
+ size = PCI_readPCIRegL(bar,device) & ~0xFF;
+ size = ~size+1;
+ PCI_writePCIRegL(bar,0,device);
+ if (size >= MAX_BIOSLEN)
+ return base;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Re-writes the PCI base address registers for the secondary PCI controller
+with the values from our initial PCI bus enumeration. This fixes up the
+values after we have POST'ed the secondary display controller BIOS, which
+may have incorrectly re-programmed the base registers the same as the
+primary display controller (the case for identical S3 cards).
+****************************************************************************/
+static void _PCI_fixupSecondaryBARs(void)
+{
+ int i;
+
+ for (i = 0; i < NumDevices; i++) {
+ PCI_writePCIRegL(0x10,PCI[DeviceIndex[i]].BaseAddress10,i);
+ PCI_writePCIRegL(0x14,PCI[DeviceIndex[i]].BaseAddress14,i);
+ PCI_writePCIRegL(0x18,PCI[DeviceIndex[i]].BaseAddress18,i);
+ PCI_writePCIRegL(0x1C,PCI[DeviceIndex[i]].BaseAddress1C,i);
+ PCI_writePCIRegL(0x20,PCI[DeviceIndex[i]].BaseAddress20,i);
+ PCI_writePCIRegL(0x24,PCI[DeviceIndex[i]].BaseAddress24,i);
+ }
+}
+
+/****************************************************************************
+RETURNS:
+True if successfully initialised, false if not.
+
+REMARKS:
+This function executes the BIOS POST code on the controller. We assume that
+at this stage the controller has its I/O and memory space enabled and
+that all other controllers are in a disabled state.
+****************************************************************************/
+static void PCI_doBIOSPOST(
+ int device,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+
+ // Determine the value to store in AX for BIOS POST
+ regs.x.ax = (u16)(PCI[DeviceIndex[device]].slot.i >> 8);
+ if (useV86) {
+ // Post the BIOS using the PM functions (ie: v86 mode on Linux)
+ if (!PM_doBIOSPOST(regs.x.ax,BIOSPhysAddr,mappedBIOS,BIOSLen)) {
+ // If the PM function fails, this probably means are we are on
+ // DOS and can't re-map the real mode 0xC0000 region. In thise
+ // case if the device is the primary, we can use the real
+ // BIOS at 0xC0000 directly.
+ if (device == 0)
+ PM_doBIOSPOST(regs.x.ax,0xC0000,mappedBIOS,BIOSLen);
+ }
+ }
+ else {
+ // Setup the X86 emulator for the VGA BIOS
+ BE_setVGA(&VGAInfo[device]);
+
+ // Execute the BIOS POST code
+ BE_callRealMode(0xC000,0x0003,&regs,&sregs);
+
+ // Cleanup and exit
+ BE_getVGA(&VGAInfo[device]);
+ }
+}
+
+/****************************************************************************
+RETURNS:
+True if successfully initialised, false if not.
+
+REMARKS:
+Loads and POST's the secondary controllers BIOS, directly from the BIOS
+image we can extract over the PCI bus.
+****************************************************************************/
+static ibool PCI_postControllers(void)
+{
+ int device;
+ ulong BIOSImageLen,mappedBIOSPhys;
+ uchar *mappedBIOS,*copyOfBIOS;
+ char filename[_MAX_PATH];
+ FILE *f;
+
+ // Disable the primary display controller and AGP VGA pass-through
+ DISABLE_DEVICE(0);
+ if (AGPBridge)
+ DISABLE_AGP_VGA();
+
+ // Now POST all the secondary controllers
+ for (device = 0; device < NumDevices; device++) {
+ // Skip the device if it is not enabled (probably an ISA device)
+ if (DeviceIndex[device] == -1)
+ continue;
+
+ // Enable secondary display controller. If the secondary controller
+ // is on the AGP bus, then enable VGA resources for the AGP device.
+ ENABLE_DEVICE(device);
+ if (AGPBridge && AGPBridge->SecondayBusNumber == PCI[DeviceIndex[device]].slot.p.Bus)
+ ENABLE_AGP_VGA();
+
+ // Check if the controller has already been POST'ed
+ if (VGA_NOT_ACTIVE()) {
+ // Find a viable place to map the secondary PCI BIOS image and map it
+ printk("Device %d not enabled, so attempting warm boot it\n", device);
+
+ // For AGP devices (and PCI devices that do have the ROM base
+ // address zero'ed out) we have to map the BIOS to a location
+ // that is passed by the AGP bridge to the bus. Some AGP devices
+ // have the ROM base address already set up for us, and some
+ // do not (we map to one of the existing BAR locations in
+ // this case).
+ mappedBIOS = NULL;
+ if (PCI[DeviceIndex[device]].ROMBaseAddress != 0)
+ mappedBIOSPhys = PCI[DeviceIndex[device]].ROMBaseAddress & ~0xF;
+ else
+ mappedBIOSPhys = PCI_findBIOSAddr(device);
+ printk("Mapping BIOS image to 0x%08X\n", mappedBIOSPhys);
+ mappedBIOS = PM_mapPhysicalAddr(mappedBIOSPhys,MAX_BIOSLEN-1,false);
+ PCI_writePCIRegL(0x30,mappedBIOSPhys | 0x1,device);
+ BIOSImageLen = mappedBIOS[2] * 512;
+ if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL)
+ return false;
+ memcpy(copyOfBIOS,mappedBIOS,BIOSImageLen);
+ PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
+
+ // Allocate memory to store copy of BIOS from secondary controllers
+ VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
+ VGAInfo[device].BIOSImage = copyOfBIOS;
+ VGAInfo[device].BIOSImageLen = BIOSImageLen;
+
+ // Restore device mappings
+ PCI_writePCIRegL(0x30,PCI[DeviceIndex[device]].ROMBaseAddress,device);
+ PCI_writePCIRegL(0x10,PCI[DeviceIndex[device]].BaseAddress10,device);
+ PCI_writePCIRegL(0x14,PCI[DeviceIndex[device]].BaseAddress14,device);
+
+ // Now execute the BIOS POST for the device
+ if (copyOfBIOS[0] == 0x55 && copyOfBIOS[1] == 0xAA) {
+ printk("Executing BIOS POST for controller.\n");
+ PCI_doBIOSPOST(device,mappedBIOSPhys,copyOfBIOS,BIOSImageLen);
+ }
+
+ // Reset the size of the BIOS image to the final size
+ VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
+
+ // Save the BIOS and interrupt vector information to disk
+ sprintf(filename,"%s/bios.%02d",PM_getNucleusConfigPath(),device);
+ if ((f = fopen(filename,"wb")) != NULL) {
+ fwrite(copyOfBIOS,1,FINAL_BIOSLEN,f);
+ fwrite(VGAInfo[device].LowMem,1,sizeof(VGAInfo[device].LowMem),f);
+ fclose(f);
+ }
+ }
+ else {
+ // Allocate memory to store copy of BIOS from secondary controllers
+ if ((copyOfBIOS = malloc(FINAL_BIOSLEN)) == NULL)
+ return false;
+ VGAInfo[device].pciInfo = &PCI[DeviceIndex[device]];
+ VGAInfo[device].BIOSImage = copyOfBIOS;
+ VGAInfo[device].BIOSImageLen = FINAL_BIOSLEN;
+
+ // Load the BIOS and interrupt vector information from disk
+ sprintf(filename,"%s/bios.%02d",PM_getNucleusConfigPath(),device);
+ if ((f = fopen(filename,"rb")) != NULL) {
+ fread(copyOfBIOS,1,FINAL_BIOSLEN,f);
+ fread(VGAInfo[device].LowMem,1,sizeof(VGAInfo[device].LowMem),f);
+ fclose(f);
+ }
+ }
+
+ // Fix up all the secondary PCI base address registers
+ // (restores them all from the values we read previously)
+ _PCI_fixupSecondaryBARs();
+
+ // Disable the secondary controller and AGP VGA pass-through
+ DISABLE_DEVICE(device);
+ if (AGPBridge)
+ DISABLE_AGP_VGA();
+ }
+
+ // Reenable primary display controller and reset AGP bridge control
+ if (AGPBridge)
+ RESTORE_AGP_VGA();
+ ENABLE_DEVICE(0);
+
+ // Free physical BIOS image mapping
+ PM_freePhysicalAddr(mappedBIOS,MAX_BIOSLEN-1);
+
+ // Restore the X86 emulator BIOS info to primary controller
+ if (!useV86)
+ BE_setVGA(&VGAInfo[0]);
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Enumerates the PCI bus and dumps the PCI configuration information to the
+log file.
+****************************************************************************/
+static void EnumeratePCI(void)
+{
+ int i,index;
+ PCIBridgeInfo *info;
+
+ printk("Displaying enumeration of PCI bus (%d devices, %d display devices)\n",
+ NumPCI, NumDevices);
+ for (index = 0; index < NumDevices; index++)
+ printk(" Display device %d is PCI device %d\n",index,DeviceIndex[index]);
+ printk("\n");
+ printk("Bus Slot Fnc DeviceID SubSystem Rev Class IRQ Int Cmd\n");
+ for (i = 0; i < NumPCI; i++) {
+ printk("%2d %2d %2d %04X:%04X %04X:%04X %02X %02X:%02X %02X %02X %04X ",
+ PCI[i].slot.p.Bus,
+ PCI[i].slot.p.Device,
+ PCI[i].slot.p.Function,
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].SubSystemVendorID,
+ PCI[i].SubSystemID,
+ PCI[i].RevID,
+ PCI[i].BaseClass,
+ PCI[i].SubClass,
+ PCI[i].InterruptLine,
+ PCI[i].InterruptPin,
+ PCI[i].Command);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printk("<- %d\n", index);
+ else
+ printk("\n");
+ }
+ printk("\n");
+ printk("DeviceID Stat Ifc Cch Lat Hdr BIST\n");
+ for (i = 0; i < NumPCI; i++) {
+ printk("%04X:%04X %04X %02X %02X %02X %02X %02X ",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].Status,
+ PCI[i].Interface,
+ PCI[i].CacheLineSize,
+ PCI[i].LatencyTimer,
+ PCI[i].HeaderType,
+ PCI[i].BIST);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printk("<- %d\n", index);
+ else
+ printk("\n");
+ }
+ printk("\n");
+ printk("DeviceID Base10h Base14h Base18h Base1Ch Base20h Base24h ROMBase\n");
+ for (i = 0; i < NumPCI; i++) {
+ printk("%04X:%04X %08X %08X %08X %08X %08X %08X %08X ",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].BaseAddress10,
+ PCI[i].BaseAddress14,
+ PCI[i].BaseAddress18,
+ PCI[i].BaseAddress1C,
+ PCI[i].BaseAddress20,
+ PCI[i].BaseAddress24,
+ PCI[i].ROMBaseAddress);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printk("<- %d\n", index);
+ else
+ printk("\n");
+ }
+ printk("\n");
+ printk("DeviceID BAR10Len BAR14Len BAR18Len BAR1CLen BAR20Len BAR24Len ROMLen\n");
+ for (i = 0; i < NumPCI; i++) {
+ printk("%04X:%04X %08X %08X %08X %08X %08X %08X %08X ",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].BaseAddress10Len,
+ PCI[i].BaseAddress14Len,
+ PCI[i].BaseAddress18Len,
+ PCI[i].BaseAddress1CLen,
+ PCI[i].BaseAddress20Len,
+ PCI[i].BaseAddress24Len,
+ PCI[i].ROMBaseAddressLen);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printk("<- %d\n", index);
+ else
+ printk("\n");
+ }
+ printk("\n");
+ printk("Displaying enumeration of %d bridge devices\n",NumBridges);
+ printk("\n");
+ printk("DeviceID P# S# B# IOB IOL MemBase MemLimit PreBase PreLimit Ctrl\n");
+ for (i = 0; i < NumBridges; i++) {
+ info = (PCIBridgeInfo*)&PCI[BridgeIndex[i]];
+ printk("%04X:%04X %02X %02X %02X %04X %04X %08X %08X %08X %08X %04X\n",
+ info->VendorID,
+ info->DeviceID,
+ info->PrimaryBusNumber,
+ info->SecondayBusNumber,
+ info->SubordinateBusNumber,
+ ((u16)info->IOBase << 8) & 0xF000,
+ info->IOLimit ?
+ ((u16)info->IOLimit << 8) | 0xFFF : 0,
+ ((u32)info->MemoryBase << 16) & 0xFFF00000,
+ info->MemoryLimit ?
+ ((u32)info->MemoryLimit << 16) | 0xFFFFF : 0,
+ ((u32)info->PrefetchableMemoryBase << 16) & 0xFFF00000,
+ info->PrefetchableMemoryLimit ?
+ ((u32)info->PrefetchableMemoryLimit << 16) | 0xFFFFF : 0,
+ info->BridgeControl);
+ }
+ printk("\n");
+}
+
+/****************************************************************************
+RETURNS:
+Number of display devices found.
+
+REMARKS:
+This function enumerates the number of available display devices on the
+PCI bus, and returns the number found.
+****************************************************************************/
+static int PCI_enumerateDevices(void)
+{
+ int i,j;
+ PCIBridgeInfo *info;
+
+ // If this is the first time we have been called, enumerate all
+ // devices on the PCI bus.
+ if (NumPCI == -1) {
+ for (i = 0; i < MAX_PCI_DEVICES; i++)
+ PCI[i].dwSize = sizeof(PCI[i]);
+ if ((NumPCI = PCI_enumerate(PCI,MAX_PCI_DEVICES)) == 0)
+ return -1;
+
+ // Build a list of all PCI bridge devices
+ for (i = 0,NumBridges = 0,BridgeIndex[0] = -1; i < NumPCI; i++) {
+ if (PCI[i].BaseClass == PCI_BRIDGE_CLASS) {
+ if (NumBridges < MAX_PCI_DEVICES)
+ BridgeIndex[NumBridges++] = i;
+ }
+ }
+
+ // Now build a list of all display class devices
+ for (i = 0,NumDevices = 1,DeviceIndex[0] = -1; i < NumPCI; i++) {
+ if (PCI_IS_DISPLAY_CLASS(&PCI[i])) {
+ if ((PCI[i].Command & 0x3) == 0x3) {
+ DeviceIndex[0] = i;
+ }
+ else {
+ if (NumDevices < MAX_PCI_DEVICES)
+ DeviceIndex[NumDevices++] = i;
+ }
+ if (PCI[i].slot.p.Bus != 0) {
+ // This device is on a different bus than the primary
+ // PCI bus, so it is probably an AGP device. Find the
+ // AGP bus device that controls that bus so we can
+ // control it.
+ for (j = 0; j < NumBridges; j++) {
+ info = (PCIBridgeInfo*)&PCI[BridgeIndex[j]];
+ if (info->SecondayBusNumber == PCI[i].slot.p.Bus) {
+ AGPBridge = info;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Enumerate all PCI and bridge devices to log file
+ EnumeratePCI();
+ }
+ return NumDevices;
+}
+
+FILE *logfile;
+
+void printk(const char *fmt, ...)
+{
+ va_list argptr;
+ va_start(argptr, fmt);
+ vfprintf(logfile, fmt, argptr);
+ fflush(logfile);
+ va_end(argptr);
+}
+
+int main(int argc,char *argv[])
+{
+ while (argc > 1) {
+ if (stricmp(argv[1],"-usev86") == 0) {
+ useV86 = true;
+ }
+ else if (stricmp(argv[1],"-force") == 0) {
+ forcePost = true;
+ }
+#ifdef DEBUG
+ else if (stricmp(argv[1],"-decode") == 0) {
+ debugFlags |= DEBUG_DECODE_F;
+ }
+ else if (stricmp(argv[1],"-iotrace") == 0) {
+ debugFlags |= DEBUG_IO_TRACE_F;
+ }
+#endif
+ else {
+ printf("Usage: warmboot [-usev86] [-force] [-decode] [-iotrace]\n");
+ exit(-1);
+ }
+ argc--;
+ argv++;
+ }
+ if ((logfile = fopen("warmboot.log","w")) == NULL)
+ exit(1);
+
+ PM_init();
+ if (!useV86) {
+ // Initialise the x86 BIOS emulator
+ BE_init(false,debugFlags,65536,&VGAInfo[0]);
+ }
+
+ // Enumerate all devices (which POST's them at the same time)
+ if (PCI_enumerateDevices() < 1) {
+ printk("No PCI display devices found!\n");
+ return -1;
+ }
+
+ // Post all the display controller BIOS'es
+ PCI_postControllers();
+
+ // Cleanup and exit the emulator
+ if (!useV86)
+ BE_exit();
+ fclose(logfile);
+ return 0;
+}
OpenPOWER on IntegriCloud