1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			3091 lines
		
	
	
		
			102 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3091 lines
		
	
	
		
			102 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
| Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions
 | |
| of the BSD License which accompanies this distribution.  The
 | |
| full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "LegacyBiosInterface.h"
 | |
| #include <IndustryStandard/Pci30.h>
 | |
| 
 | |
| #define PCI_START_ADDRESS(x)   (((x) + 0x7ff) & ~0x7ff)
 | |
| 
 | |
| #define MAX_BRIDGE_INDEX  0x20
 | |
| typedef struct {
 | |
|   UINTN PciSegment;
 | |
|   UINTN PciBus;
 | |
|   UINTN PciDevice;
 | |
|   UINTN PciFunction;
 | |
|   UINT8 PrimaryBus;
 | |
|   UINT8 SecondaryBus;
 | |
|   UINT8 SubordinateBus;
 | |
| } BRIDGE_TABLE;
 | |
| 
 | |
| #define ROM_MAX_ENTRIES 24
 | |
| BRIDGE_TABLE                        Bridges[MAX_BRIDGE_INDEX];
 | |
| UINTN                               SortedBridgeIndex[MAX_BRIDGE_INDEX];
 | |
| UINTN                               NumberOfBridges;
 | |
| LEGACY_PNP_EXPANSION_HEADER  *mBasePnpPtr;
 | |
| UINT16                              mBbsRomSegment;
 | |
| UINTN                               mHandleCount;
 | |
| EFI_HANDLE                          mVgaHandle;
 | |
| BOOLEAN                             mIgnoreBbsUpdateFlag;
 | |
| BOOLEAN                             mVgaInstallationInProgress  = FALSE;
 | |
| UINT32                              mRomCount                   = 0x00;
 | |
| ROM_INSTANCE_ENTRY                  mRomEntry[ROM_MAX_ENTRIES];
 | |
| EDKII_IOMMU_PROTOCOL                *mIoMmu;
 | |
| 
 | |
| /**
 | |
|   Query shadowed legacy ROM parameters registered by RomShadow() previously.
 | |
| 
 | |
|   @param  PciHandle        PCI device whos ROM has been shadowed
 | |
|   @param  DiskStart        DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
 | |
|   @param  DiskEnd          DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
 | |
|   @param  RomShadowAddress Address where ROM was shadowed
 | |
|   @param  ShadowedSize     Runtime size of ROM
 | |
| 
 | |
|   @retval EFI_SUCCESS      Query Logging successful.
 | |
|   @retval EFI_NOT_FOUND    No logged data found about PciHandle.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetShadowedRomParameters (
 | |
|   IN EFI_HANDLE                         PciHandle,
 | |
|   OUT UINT8                             *DiskStart,         OPTIONAL
 | |
|   OUT UINT8                             *DiskEnd,           OPTIONAL
 | |
|   OUT VOID                              **RomShadowAddress, OPTIONAL
 | |
|   OUT UINTN                             *ShadowedSize       OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
|   UINTN               Index;
 | |
|   UINTN               PciSegment;
 | |
|   UINTN               PciBus;
 | |
|   UINTN               PciDevice;
 | |
|   UINTN               PciFunction;
 | |
| 
 | |
|   //
 | |
|   // Get the PCI I/O Protocol on PciHandle
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   PciHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the location of the PCI device
 | |
|   //
 | |
|   PciIo->GetLocation (
 | |
|            PciIo,
 | |
|            &PciSegment,
 | |
|            &PciBus,
 | |
|            &PciDevice,
 | |
|            &PciFunction
 | |
|            );
 | |
| 
 | |
|   for(Index = 0; Index < mRomCount; Index++) {
 | |
|     if ((mRomEntry[Index].PciSegment == PciSegment) &&
 | |
|         (mRomEntry[Index].PciBus == PciBus)         &&
 | |
|         (mRomEntry[Index].PciDevice == PciDevice)   &&
 | |
|         (mRomEntry[Index].PciFunction == PciFunction)) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Index == mRomCount) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (DiskStart != NULL) {
 | |
|     *DiskStart = mRomEntry[Index].DiskStart;
 | |
|   }
 | |
| 
 | |
|   if (DiskEnd != NULL) {
 | |
|     *DiskEnd = mRomEntry[Index].DiskEnd;
 | |
|   }
 | |
| 
 | |
|   if (RomShadowAddress != NULL) {
 | |
|     *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;
 | |
|   }
 | |
| 
 | |
|   if (ShadowedSize != NULL) {
 | |
|     *ShadowedSize = mRomEntry[Index].ShadowedSize;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Every legacy ROM that is shadowed by the Legacy BIOS driver will be
 | |
|   registered into this API so that the policy code can know what has
 | |
|   happend
 | |
| 
 | |
|   @param  PciHandle              PCI device whos ROM is being shadowed
 | |
|   @param  ShadowAddress          Address that ROM was shadowed
 | |
|   @param  ShadowedSize           Runtime size of ROM
 | |
|   @param  DiskStart              DiskStart value from
 | |
|                                  EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
 | |
|   @param  DiskEnd                DiskEnd value from
 | |
|                                  EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
 | |
| 
 | |
|   @retval EFI_SUCCESS            Logging successful.
 | |
|   @retval EFI_OUT_OF_RESOURCES   No remaining room for registering another option
 | |
|                                  ROM.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| RomShadow (
 | |
|   IN  EFI_HANDLE                                  PciHandle,
 | |
|   IN  UINT32                                      ShadowAddress,
 | |
|   IN  UINT32                                      ShadowedSize,
 | |
|   IN  UINT8                                       DiskStart,
 | |
|   IN  UINT8                                       DiskEnd
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
| 
 | |
|   //
 | |
|   // See if there is room to register another option ROM
 | |
|   //
 | |
|   if (mRomCount >= ROM_MAX_ENTRIES) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Get the PCI I/O Protocol on PciHandle
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   PciHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Get the location of the PCI device
 | |
|   //
 | |
|   PciIo->GetLocation (
 | |
|            PciIo,
 | |
|            &mRomEntry[mRomCount].PciSegment,
 | |
|            &mRomEntry[mRomCount].PciBus,
 | |
|            &mRomEntry[mRomCount].PciDevice,
 | |
|            &mRomEntry[mRomCount].PciFunction
 | |
|            );
 | |
|   mRomEntry[mRomCount].ShadowAddress = ShadowAddress;
 | |
|   mRomEntry[mRomCount].ShadowedSize  = ShadowedSize;
 | |
|   mRomEntry[mRomCount].DiskStart     = DiskStart;
 | |
|   mRomEntry[mRomCount].DiskEnd       = DiskEnd;
 | |
| 
 | |
|   mRomCount++;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
 | |
|   information represents every call to RomShadow ()
 | |
| 
 | |
|   @param  PciHandle              PCI device to get status for
 | |
| 
 | |
|   @retval EFI_SUCCESS            Legacy ROM loaded for this device
 | |
|   @retval EFI_NOT_FOUND          No Legacy ROM loaded for this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IsLegacyRom (
 | |
|   IN  EFI_HANDLE                PciHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
|   UINTN               Index;
 | |
|   UINTN               Segment;
 | |
|   UINTN               Bus;
 | |
|   UINTN               Device;
 | |
|   UINTN               Function;
 | |
| 
 | |
|   //
 | |
|   // Get the PCI I/O Protocol on PciHandle
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   PciHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Get the location of the PCI device
 | |
|   //
 | |
|   PciIo->GetLocation (
 | |
|            PciIo,
 | |
|            &Segment,
 | |
|            &Bus,
 | |
|            &Device,
 | |
|            &Function
 | |
|            );
 | |
| 
 | |
|   //
 | |
|   // See if the option ROM from PciHandle has been previously posted
 | |
|   //
 | |
|   for (Index = 0; Index < mRomCount; Index++) {
 | |
|     if (mRomEntry[Index].PciSegment == Segment &&
 | |
|         mRomEntry[Index].PciBus == Bus &&
 | |
|         mRomEntry[Index].PciDevice == Device &&
 | |
|         mRomEntry[Index].PciFunction == Function
 | |
|         ) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
 | |
|   related information from the header.
 | |
| 
 | |
|   @param  Csm16Revision           The PCI interface version of underlying CSM16
 | |
|   @param  VendorId                Vendor ID of the PCI device
 | |
|   @param  DeviceId                Device ID of the PCI device
 | |
|   @param  Rom                     On input pointing to beginning of the raw PCI OpROM
 | |
|                                   On output pointing to the first legacy PCI OpROM
 | |
|   @param  ImageSize               On input is the size of Raw PCI Rom
 | |
|                                   On output is the size of the first legacy PCI ROM
 | |
|   @param  MaxRuntimeImageLength   The max runtime image length only valid if OpRomRevision >= 3
 | |
|   @param  OpRomRevision           Revision of the PCI Rom
 | |
|   @param  ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
 | |
| 
 | |
|   @retval EFI_SUCCESS             Successfully find the legacy PCI ROM
 | |
|   @retval EFI_NOT_FOUND           Failed to find the legacy PCI ROM
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetPciLegacyRom (
 | |
|   IN     UINT16 Csm16Revision,
 | |
|   IN     UINT16 VendorId,
 | |
|   IN     UINT16 DeviceId,
 | |
|   IN OUT VOID   **Rom,
 | |
|   IN OUT UINTN  *ImageSize,
 | |
|   OUT    UINTN  *MaxRuntimeImageLength,   OPTIONAL
 | |
|   OUT    UINT8  *OpRomRevision,           OPTIONAL
 | |
|   OUT    VOID   **ConfigUtilityCodeHeader OPTIONAL
 | |
|   )
 | |
| {
 | |
|   BOOLEAN                 Match;
 | |
|   UINT16                  *DeviceIdList;
 | |
|   EFI_PCI_ROM_HEADER      RomHeader;
 | |
|   PCI_3_0_DATA_STRUCTURE  *Pcir;
 | |
|   VOID                    *BackupImage;
 | |
|   VOID                    *BestImage;
 | |
| 
 | |
| 
 | |
|   if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   BestImage     = NULL;
 | |
|   BackupImage   = NULL;
 | |
|   RomHeader.Raw = *Rom;
 | |
|   while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
 | |
|     if (RomHeader.Generic->PcirOffset == 0 ||
 | |
|         (RomHeader.Generic->PcirOffset & 3) !=0 ||
 | |
|         *ImageSize < RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
 | |
|     //
 | |
|     // Check signature in the PCI Data Structure.
 | |
|     //
 | |
|     if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (((UINTN)RomHeader.Raw - (UINTN)*Rom) + Pcir->ImageLength * 512 > *ImageSize) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
 | |
|       Match = FALSE;
 | |
|       if (Pcir->VendorId == VendorId) {
 | |
|         if (Pcir->DeviceId == DeviceId) {
 | |
|           Match = TRUE;
 | |
|         } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {
 | |
|           DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);
 | |
|           //
 | |
|           // Checking the device list
 | |
|           //
 | |
|           while (*DeviceIdList != 0) {
 | |
|             if (*DeviceIdList == DeviceId) {
 | |
|               Match = TRUE;
 | |
|               break;
 | |
|             }
 | |
|             DeviceIdList ++;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Match) {
 | |
|         if (Csm16Revision >= 0x0300) {
 | |
|           //
 | |
|           // Case 1: CSM16 3.0
 | |
|           //
 | |
|           if (Pcir->Revision >= 3) {
 | |
|             //
 | |
|             // case 1.1: meets OpRom 3.0
 | |
|             //           Perfect!!!
 | |
|             //
 | |
|             BestImage  = RomHeader.Raw;
 | |
|             break;
 | |
|           } else {
 | |
|             //
 | |
|             // case 1.2: meets OpRom 2.x
 | |
|             //           Store it and try to find the OpRom 3.0
 | |
|             //
 | |
|             BackupImage = RomHeader.Raw;
 | |
|           }
 | |
|         } else {
 | |
|           //
 | |
|           // Case 2: CSM16 2.x
 | |
|           //
 | |
|           if (Pcir->Revision >= 3) {
 | |
|             //
 | |
|             // case 2.1: meets OpRom 3.0
 | |
|             //           Store it and try to find the OpRom 2.x
 | |
|             //
 | |
|             BackupImage = RomHeader.Raw;
 | |
|           } else {
 | |
|             //
 | |
|             // case 2.2: meets OpRom 2.x
 | |
|             //           Perfect!!!
 | |
|             //
 | |
|             BestImage   = RomHeader.Raw;
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if ((Pcir->Indicator & 0x80) == 0x80) {
 | |
|       break;
 | |
|     } else {
 | |
|       RomHeader.Raw += 512 * Pcir->ImageLength;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (BestImage == NULL) {
 | |
|     if (BackupImage == NULL) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|     //
 | |
|     // The versions of CSM16 and OpRom don't match exactly
 | |
|     //
 | |
|     BestImage = BackupImage;
 | |
|   }
 | |
|   RomHeader.Raw = BestImage;
 | |
|   Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
 | |
|   *Rom       = BestImage;
 | |
|   *ImageSize = Pcir->ImageLength * 512;
 | |
| 
 | |
|   if (MaxRuntimeImageLength != NULL) {
 | |
|     if (Pcir->Revision < 3) {
 | |
|       *MaxRuntimeImageLength = 0;
 | |
|     } else {
 | |
|       *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (OpRomRevision != NULL) {
 | |
|     //
 | |
|     // Optional return PCI Data Structure revision
 | |
|     //
 | |
|     if (Pcir->Length >= 0x1C) {
 | |
|       *OpRomRevision = Pcir->Revision;
 | |
|     } else {
 | |
|       *OpRomRevision = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (ConfigUtilityCodeHeader != NULL) {
 | |
|     //
 | |
|     // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
 | |
|     //
 | |
|     if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {
 | |
|       *ConfigUtilityCodeHeader = NULL;
 | |
|     } else {
 | |
|       *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build a table of bridge info for PIRQ translation.
 | |
| 
 | |
|   @param  RoutingTable         RoutingTable obtained from Platform.
 | |
|   @param  RoutingTableEntries  Number of RoutingTable entries.
 | |
| 
 | |
|   @retval EFI_SUCCESS          New Subordinate bus.
 | |
|   @retval EFI_NOT_FOUND        No more Subordinate busses.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CreateBridgeTable (
 | |
|   IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,
 | |
|   IN UINTN                                RoutingTableEntries
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   UINTN               HandleCount;
 | |
|   EFI_HANDLE          *HandleBuffer;
 | |
|   UINTN               BridgeIndex;
 | |
|   UINTN               Index;
 | |
|   UINTN               Index1;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
|   PCI_TYPE01          PciConfigHeader;
 | |
|   BRIDGE_TABLE        SlotBridges[MAX_BRIDGE_INDEX];
 | |
|   UINTN               SlotBridgeIndex;
 | |
| 
 | |
|   BridgeIndex = 0x00;
 | |
|   SlotBridgeIndex = 0x00;
 | |
| 
 | |
|   //
 | |
|   // Assumption is table is built from low bus to high bus numbers.
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     (VOID **) &PciIo
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     PciIo->Pci.Read (
 | |
|                  PciIo,
 | |
|                  EfiPciIoWidthUint32,
 | |
|                  0,
 | |
|                  sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                  &PciConfigHeader
 | |
|                  );
 | |
| 
 | |
|     if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {
 | |
|       PciIo->GetLocation (
 | |
|                PciIo,
 | |
|                &Bridges[BridgeIndex].PciSegment,
 | |
|                &Bridges[BridgeIndex].PciBus,
 | |
|                &Bridges[BridgeIndex].PciDevice,
 | |
|                &Bridges[BridgeIndex].PciFunction
 | |
|                );
 | |
| 
 | |
|       Bridges[BridgeIndex].PrimaryBus     = PciConfigHeader.Bridge.PrimaryBus;
 | |
| 
 | |
|       Bridges[BridgeIndex].SecondaryBus   = PciConfigHeader.Bridge.SecondaryBus;
 | |
| 
 | |
|       Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;
 | |
| 
 | |
|       for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){
 | |
|         //
 | |
|         // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
 | |
|         // Once we find one, store it in the SlotBridges[]
 | |
|         //
 | |
|         if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)
 | |
|            && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {
 | |
|           CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));
 | |
|           SlotBridgeIndex++;
 | |
| 
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       ++BridgeIndex;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Pack up Bridges by removing those useless ones
 | |
|   //
 | |
|   for (Index = 0; Index < BridgeIndex;){
 | |
|     for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {
 | |
|       if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||
 | |
|         ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {
 | |
|         //
 | |
|         // We have found one that meets our criteria
 | |
|         //
 | |
|         Index++;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // This one doesn't meet criteria, pack it
 | |
|     //
 | |
|     if (Index1 >= SlotBridgeIndex) {
 | |
|       for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {
 | |
|         CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));
 | |
|       }
 | |
| 
 | |
|       BridgeIndex--;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   NumberOfBridges = BridgeIndex;
 | |
| 
 | |
|   //
 | |
|   // Sort bridges low to high by Secondary bus followed by subordinate bus
 | |
|   //
 | |
|   if (NumberOfBridges > 1) {
 | |
|     Index = 0;
 | |
|     do {
 | |
|       SortedBridgeIndex[Index] = Index;
 | |
|       ++Index;
 | |
|     } while (Index < NumberOfBridges);
 | |
| 
 | |
|     for (Index = 0; Index < NumberOfBridges - 1; Index++) {
 | |
|       for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {
 | |
|         if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {
 | |
|           SortedBridgeIndex[Index]  = Index1;
 | |
|           SortedBridgeIndex[Index1] = Index;
 | |
|         }
 | |
| 
 | |
|         if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&
 | |
|             (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)
 | |
|             ) {
 | |
|           SortedBridgeIndex[Index]  = Index1;
 | |
|           SortedBridgeIndex[Index1] = Index;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   FreePool (HandleBuffer);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find base Bridge for device.
 | |
| 
 | |
|   @param  Private                Legacy  BIOS Instance data
 | |
|   @param  PciBus                 Input = Bus of device.
 | |
|   @param  PciDevice              Input = Device.
 | |
|   @param  RoutingTable           The platform specific routing table
 | |
|   @param  RoutingTableEntries    Number of entries in table
 | |
| 
 | |
|   @retval EFI_SUCCESS            At base bus.
 | |
|   @retval EFI_NOT_FOUND          Behind a bridge.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetBaseBus (
 | |
|   IN  LEGACY_BIOS_INSTANCE        *Private,
 | |
|   IN UINTN                        PciBus,
 | |
|   IN UINTN                        PciDevice,
 | |
|   IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
 | |
|   IN UINTN                        RoutingTableEntries
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
|   for (Index = 0; Index < RoutingTableEntries; Index++) {
 | |
|     if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Translate PIRQ through busses
 | |
| 
 | |
|   @param  Private              Legacy  BIOS Instance data
 | |
|   @param  PciBus               Input = Bus of device. Output = Translated Bus
 | |
|   @param  PciDevice            Input = Device. Output = Translated Device
 | |
|   @param  PciFunction          Input = Function. Output = Translated Function
 | |
|   @param  PirqIndex            Input = Original PIRQ index. If single function
 | |
|                                   device then 0, otherwise 0-3.
 | |
|                                Output = Translated Index
 | |
| 
 | |
|   @retval EFI_SUCCESS          Pirq successfully translated.
 | |
|   @retval EFI_NOT_FOUND        The device is not behind any known bridge.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| TranslateBusPirq (
 | |
|   IN  LEGACY_BIOS_INSTANCE            *Private,
 | |
|   IN OUT UINTN                        *PciBus,
 | |
|   IN OUT UINTN                        *PciDevice,
 | |
|   IN OUT UINTN                        *PciFunction,
 | |
|   IN OUT UINT8                        *PirqIndex
 | |
|   )
 | |
| {
 | |
|   /*
 | |
|   This routine traverses the PCI busses from base slot
 | |
|   and translates the PIRQ register to the appropriate one.
 | |
| 
 | |
|   Example:
 | |
| 
 | |
|   Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
 | |
|     Primary bus# = 0
 | |
|     Secondary bus # = 1
 | |
|     Subordinate bus # is highest bus # behind this bus
 | |
|        Bus 1, Device 0 is Slot 0 and is not a bridge.
 | |
|        Bus 1, Device 1 is Slot 1 and is a bridge.
 | |
|          Slot PIRQ routing is A,B,C,D.
 | |
|          Primary bus # = 1
 | |
|          Secondary bus # = 2
 | |
|          Subordinate bus # = 5
 | |
|             Bus 2, Device 6 is a bridge. It has no bridges behind it.
 | |
|               Primary bus # = 2
 | |
|               Secondary bus # = 3
 | |
|               Subordinate bus # = 3
 | |
|               Bridge PIRQ routing is C,D,A,B
 | |
|             Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
 | |
|               Primary bus # = 2
 | |
|               Secondary bus = 4   Device 6 takes bus 2.
 | |
|               Subordinate bus = 5.
 | |
|               Bridge PIRQ routing is D,A,B,C
 | |
|                  Bus 4, Device 2 is a bridge. It has no bridges behind it.
 | |
|                    Primary bus # = 4
 | |
|                    Secondary bus # = 5
 | |
|                    Subordinate bus = 5
 | |
|                    Bridge PIRQ routing is B,C,D,A
 | |
|                       Bus 5, Device 1 is to be programmed.
 | |
|                          Device PIRQ routing is C,D,A,B
 | |
| 
 | |
| 
 | |
| Search busses starting from slot bus for final bus >= Secondary bus and
 | |
| final bus <= Suborninate bus. Assumption is bus entries increase in bus
 | |
| number.
 | |
| Starting PIRQ is A,B,C,D.
 | |
| Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
 | |
|   7 modulo 4 giving (D,A,B,C).
 | |
| Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
 | |
|   (B,C,D,A).
 | |
| No other busses match criteria. Device to be programmed is Bus 5, Device 1.
 | |
| Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
 | |
| 
 | |
| */
 | |
|   UINTN LocalBus;
 | |
|   UINTN LocalDevice;
 | |
|   UINTN BaseBus;
 | |
|   UINTN BaseDevice;
 | |
|   UINTN BaseFunction;
 | |
|   UINT8 LocalPirqIndex;
 | |
|   BOOLEAN BaseIndexFlag;
 | |
|   UINTN BridgeIndex;
 | |
|   UINTN SBridgeIndex;
 | |
|   BaseIndexFlag   = FALSE;
 | |
|   BridgeIndex     = 0x00;
 | |
| 
 | |
|   LocalPirqIndex  = *PirqIndex;
 | |
|   LocalBus        = *PciBus;
 | |
|   LocalDevice     = *PciDevice;
 | |
|   BaseBus         = *PciBus;
 | |
|   BaseDevice      = *PciDevice;
 | |
|   BaseFunction    = *PciFunction;
 | |
| 
 | |
|   //
 | |
|   // LocalPirqIndex list PIRQs in rotated fashion
 | |
|   // = 0  A,B,C,D
 | |
|   // = 1  B,C,D,A
 | |
|   // = 2  C,D,A,B
 | |
|   // = 3  D,A,B,C
 | |
|   //
 | |
| 
 | |
|   for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {
 | |
|     SBridgeIndex = SortedBridgeIndex[BridgeIndex];
 | |
|     //
 | |
|     // Check if device behind this bridge
 | |
|     //
 | |
|     if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {
 | |
|       //
 | |
|       // If BaseIndexFlag = FALSE then have found base bridge, i.e
 | |
|       // bridge in slot. Save info for use by IRQ routing table.
 | |
|       //
 | |
|       if (!BaseIndexFlag) {
 | |
|         BaseBus       = Bridges[SBridgeIndex].PciBus;
 | |
|         BaseDevice    = Bridges[SBridgeIndex].PciDevice;
 | |
|         BaseFunction  = Bridges[SBridgeIndex].PciFunction;
 | |
|         BaseIndexFlag = TRUE;
 | |
|       } else {
 | |
|         LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Check if at device. If not get new PCI location & PIRQ
 | |
|       //
 | |
|       if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {
 | |
|         //
 | |
|         // Translate PIRQ
 | |
|         //
 | |
|         LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
 | |
|   //
 | |
|   if(BridgeIndex >= NumberOfBridges){
 | |
|     DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));
 | |
|   }
 | |
| 
 | |
|   *PirqIndex    = LocalPirqIndex;
 | |
|   *PciBus       = BaseBus;
 | |
|   *PciDevice    = BaseDevice;
 | |
|   *PciFunction  = BaseFunction;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Copy the $PIR table as required.
 | |
| 
 | |
|   @param  Private                Legacy  BIOS Instance data
 | |
|   @param  RoutingTable           Pointer to IRQ routing table
 | |
|   @param  RoutingTableEntries    IRQ routing table entries
 | |
|   @param  PirqTable              Pointer to $PIR table
 | |
|   @param  PirqTableSize          Length of table
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CopyPirqTable (
 | |
|   IN  LEGACY_BIOS_INSTANCE                *Private,
 | |
|   IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,
 | |
|   IN UINTN                                RoutingTableEntries,
 | |
|   IN EFI_LEGACY_PIRQ_TABLE_HEADER         *PirqTable,
 | |
|   IN UINTN                                PirqTableSize
 | |
|   )
 | |
| {
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   UINT32                Granularity;
 | |
| 
 | |
|   //
 | |
|   // Copy $PIR table, if it exists.
 | |
|   //
 | |
|   if (PirqTable != NULL) {
 | |
|     Private->LegacyRegion->UnLock (
 | |
|                             Private->LegacyRegion,
 | |
|                             0xE0000,
 | |
|                             0x20000,
 | |
|                             &Granularity
 | |
|                             );
 | |
| 
 | |
|     Private->InternalIrqRoutingTable  = RoutingTable;
 | |
|     Private->NumberIrqRoutingEntries  = (UINT16) (RoutingTableEntries);
 | |
|     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|     Regs.X.AX = Legacy16GetTableAddress;
 | |
|     Regs.X.CX = (UINT16) PirqTableSize;
 | |
|     //
 | |
|     // Allocate at F segment according to PCI IRQ Routing Table Specification
 | |
|     //
 | |
|     Regs.X.BX = (UINT16) 0x1;
 | |
|     //
 | |
|     // 16-byte boundary alignment requirement according to
 | |
|     // PCI IRQ Routing Table Specification
 | |
|     //
 | |
|     Regs.X.DX = 0x10;
 | |
|     Private->LegacyBios.FarCall86 (
 | |
|       &Private->LegacyBios,
 | |
|       Private->Legacy16CallSegment,
 | |
|       Private->Legacy16CallOffset,
 | |
|       &Regs,
 | |
|       NULL,
 | |
|       0
 | |
|       );
 | |
| 
 | |
|     Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
 | |
|     if (Regs.X.AX != 0) {
 | |
|       DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));
 | |
|     } else {
 | |
|       DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));
 | |
|       Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;
 | |
|       CopyMem (
 | |
|         (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,
 | |
|         PirqTable,
 | |
|         PirqTableSize
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
 | |
|     Private->LegacyRegion->Lock (
 | |
|                              Private->LegacyRegion,
 | |
|                              0xE0000,
 | |
|                              0x20000,
 | |
|                              &Granularity
 | |
|                              );
 | |
|   }
 | |
| 
 | |
|   Private->PciInterruptLine = TRUE;
 | |
|   mHandleCount              = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
 | |
| 
 | |
|   @param  PciHandle               The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| DumpPciHandle (
 | |
|   IN EFI_LEGACY_INSTALL_PCI_HANDLER  *PciHandle
 | |
|   )
 | |
| {
 | |
|   DEBUG ((EFI_D_INFO, "PciBus             - %02x\n", (UINTN)PciHandle->PciBus));
 | |
|   DEBUG ((EFI_D_INFO, "PciDeviceFun       - %02x\n", (UINTN)PciHandle->PciDeviceFun));
 | |
|   DEBUG ((EFI_D_INFO, "PciSegment         - %02x\n", (UINTN)PciHandle->PciSegment));
 | |
|   DEBUG ((EFI_D_INFO, "PciClass           - %02x\n", (UINTN)PciHandle->PciClass));
 | |
|   DEBUG ((EFI_D_INFO, "PciSubclass        - %02x\n", (UINTN)PciHandle->PciSubclass));
 | |
|   DEBUG ((EFI_D_INFO, "PciInterface       - %02x\n", (UINTN)PciHandle->PciInterface));
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "PrimaryIrq         - %02x\n", (UINTN)PciHandle->PrimaryIrq));
 | |
|   DEBUG ((EFI_D_INFO, "PrimaryReserved    - %02x\n", (UINTN)PciHandle->PrimaryReserved));
 | |
|   DEBUG ((EFI_D_INFO, "PrimaryControl     - %04x\n", (UINTN)PciHandle->PrimaryControl));
 | |
|   DEBUG ((EFI_D_INFO, "PrimaryBase        - %04x\n", (UINTN)PciHandle->PrimaryBase));
 | |
|   DEBUG ((EFI_D_INFO, "PrimaryBusMaster   - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "SecondaryIrq       - %02x\n", (UINTN)PciHandle->SecondaryIrq));
 | |
|   DEBUG ((EFI_D_INFO, "SecondaryReserved  - %02x\n", (UINTN)PciHandle->SecondaryReserved));
 | |
|   DEBUG ((EFI_D_INFO, "SecondaryControl   - %04x\n", (UINTN)PciHandle->SecondaryControl));
 | |
|   DEBUG ((EFI_D_INFO, "SecondaryBase      - %04x\n", (UINTN)PciHandle->SecondaryBase));
 | |
|   DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Copy the $PIR table as required.
 | |
| 
 | |
|   @param  Private                Legacy  BIOS Instance data
 | |
|   @param  PciIo                  Pointer to PCI_IO protocol
 | |
|   @param  PciIrq                 Pci IRQ number
 | |
|   @param  PciConfigHeader        Type00 Pci configuration header
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| InstallLegacyIrqHandler (
 | |
|   IN LEGACY_BIOS_INSTANCE       *Private,
 | |
|   IN EFI_PCI_IO_PROTOCOL        *PciIo,
 | |
|   IN UINT8                      PciIrq,
 | |
|   IN PCI_TYPE00                 *PciConfigHeader
 | |
|   )
 | |
| {
 | |
|   EFI_IA32_REGISTER_SET     Regs;
 | |
|   UINT16                    LegMask;
 | |
|   UINTN                     PciSegment;
 | |
|   UINTN                     PciBus;
 | |
|   UINTN                     PciDevice;
 | |
|   UINTN                     PciFunction;
 | |
|   EFI_LEGACY_8259_PROTOCOL  *Legacy8259;
 | |
|   UINT16                    PrimaryMaster;
 | |
|   UINT16                    SecondaryMaster;
 | |
|   UINTN                     TempData;
 | |
|   UINTN                     RegisterAddress;
 | |
|   UINT32                    Granularity;
 | |
| 
 | |
|   PrimaryMaster   = 0;
 | |
|   SecondaryMaster = 0;
 | |
|   Legacy8259      = Private->Legacy8259;
 | |
|   //
 | |
|   // Disable interrupt in PIC, in case shared, to prevent an
 | |
|   // interrupt from occuring.
 | |
|   //
 | |
|   Legacy8259->GetMask (
 | |
|                 Legacy8259,
 | |
|                 &LegMask,
 | |
|                 NULL,
 | |
|                 NULL,
 | |
|                 NULL
 | |
|                 );
 | |
| 
 | |
|   LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));
 | |
| 
 | |
|   Legacy8259->SetMask (
 | |
|                 Legacy8259,
 | |
|                 &LegMask,
 | |
|                 NULL,
 | |
|                 NULL,
 | |
|                 NULL
 | |
|                 );
 | |
| 
 | |
|   PciIo->GetLocation (
 | |
|           PciIo,
 | |
|           &PciSegment,
 | |
|           &PciBus,
 | |
|           &PciDevice,
 | |
|           &PciFunction
 | |
|           );
 | |
|   Private->IntThunk->PciHandler.PciBus              = (UINT8) PciBus;
 | |
|   Private->IntThunk->PciHandler.PciDeviceFun        = (UINT8) ((PciDevice << 3) + PciFunction);
 | |
|   Private->IntThunk->PciHandler.PciSegment          = (UINT8) PciSegment;
 | |
|   Private->IntThunk->PciHandler.PciClass            = PciConfigHeader->Hdr.ClassCode[2];
 | |
|   Private->IntThunk->PciHandler.PciSubclass         = PciConfigHeader->Hdr.ClassCode[1];
 | |
|   Private->IntThunk->PciHandler.PciInterface        = PciConfigHeader->Hdr.ClassCode[0];
 | |
| 
 | |
|   //
 | |
|   // Use native mode base address registers in two cases:
 | |
|   // 1. Programming Interface (PI) register indicates Primary Controller is
 | |
|   // in native mode OR
 | |
|   // 2. PCI device Sub Class Code is not IDE
 | |
|   //
 | |
|   Private->IntThunk->PciHandler.PrimaryBusMaster  = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);
 | |
|   if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
 | |
|     Private->IntThunk->PciHandler.PrimaryIrq      = PciIrq;
 | |
|     Private->IntThunk->PciHandler.PrimaryBase     = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);
 | |
|     Private->IntThunk->PciHandler.PrimaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);
 | |
|   } else {
 | |
|     Private->IntThunk->PciHandler.PrimaryIrq      = 14;
 | |
|     Private->IntThunk->PciHandler.PrimaryBase     = 0x1f0;
 | |
|     Private->IntThunk->PciHandler.PrimaryControl  = 0x3f6;
 | |
|   }
 | |
|   //
 | |
|   // Secondary controller data
 | |
|   //
 | |
|   if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {
 | |
|     Private->IntThunk->PciHandler.SecondaryBusMaster  = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);
 | |
|     PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);
 | |
|     SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);
 | |
| 
 | |
|     //
 | |
|     // Clear pending interrupts in Bus Master registers
 | |
|     //
 | |
|     IoWrite16 (PrimaryMaster, 0x04);
 | |
|     IoWrite16 (SecondaryMaster, 0x04);
 | |
| 
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Use native mode base address registers in two cases:
 | |
|   // 1. Programming Interface (PI) register indicates Secondary Controller is
 | |
|   // in native mode OR
 | |
|   // 2. PCI device Sub Class Code is not IDE
 | |
|   //
 | |
|   if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
 | |
|     Private->IntThunk->PciHandler.SecondaryIrq      = PciIrq;
 | |
|     Private->IntThunk->PciHandler.SecondaryBase     = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);
 | |
|     Private->IntThunk->PciHandler.SecondaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);
 | |
|   } else {
 | |
| 
 | |
|     Private->IntThunk->PciHandler.SecondaryIrq      = 15;
 | |
|     Private->IntThunk->PciHandler.SecondaryBase     = 0x170;
 | |
|     Private->IntThunk->PciHandler.SecondaryControl  = 0x376;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Clear pending interrupts in IDE Command Block Status reg before we
 | |
|   // Thunk to CSM16 below.  Don't want a pending Interrupt before we
 | |
|   // install the handlers as wierd corruption would occur and hang system.
 | |
|   //
 | |
|   //
 | |
|   // Read IDE CMD blk status reg to clear out any pending interrupts.
 | |
|   // Do here for Primary and Secondary IDE channels
 | |
|   //
 | |
|   RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;
 | |
|   IoRead8 (RegisterAddress);
 | |
|   RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;
 | |
|   IoRead8 (RegisterAddress);
 | |
| 
 | |
|   Private->IntThunk->PciHandler.PrimaryReserved   = 0;
 | |
|   Private->IntThunk->PciHandler.SecondaryReserved = 0;
 | |
|   Private->LegacyRegion->UnLock (
 | |
|                            Private->LegacyRegion,
 | |
|                            0xE0000,
 | |
|                            0x20000,
 | |
|                            &Granularity
 | |
|                            );
 | |
| 
 | |
|   Regs.X.AX = Legacy16InstallPciHandler;
 | |
|   TempData  = (UINTN) &Private->IntThunk->PciHandler;
 | |
|   Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
 | |
|   Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
 | |
| 
 | |
|   DumpPciHandle (&Private->IntThunk->PciHandler);
 | |
| 
 | |
|   Private->LegacyBios.FarCall86 (
 | |
|     &Private->LegacyBios,
 | |
|     Private->Legacy16CallSegment,
 | |
|     Private->Legacy16CallOffset,
 | |
|     &Regs,
 | |
|     NULL,
 | |
|     0
 | |
|     );
 | |
| 
 | |
|   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
 | |
|   Private->LegacyRegion->Lock (
 | |
|                            Private->LegacyRegion,
 | |
|                            0xE0000,
 | |
|                            0x20000,
 | |
|                            &Granularity
 | |
|                            );
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Program the interrupt routing register in all the PCI devices. On a PC AT system
 | |
|   this register contains the 8259 IRQ vector that matches it's PCI interrupt.
 | |
| 
 | |
|   @param  Private                Legacy  BIOS Instance data
 | |
| 
 | |
|   @retval EFI_SUCCESS            Succeed.
 | |
|   @retval EFI_ALREADY_STARTED    All PCI devices have been processed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PciProgramAllInterruptLineRegisters (
 | |
|   IN  LEGACY_BIOS_INSTANCE      *Private
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_PCI_IO_PROTOCOL               *PciIo;
 | |
|   EFI_LEGACY_8259_PROTOCOL          *Legacy8259;
 | |
|   EFI_LEGACY_INTERRUPT_PROTOCOL     *LegacyInterrupt;
 | |
|   EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
 | |
|   UINT8                             InterruptPin;
 | |
|   UINTN                             Index;
 | |
|   UINTN                             HandleCount;
 | |
|   EFI_HANDLE                        *HandleBuffer;
 | |
|   UINTN                             MassStorageHandleCount;
 | |
|   EFI_HANDLE                        *MassStorageHandleBuffer;
 | |
|   UINTN                             MassStorageHandleIndex;
 | |
|   UINT8                             PciIrq;
 | |
|   UINT16                            Command;
 | |
|   UINTN                             PciSegment;
 | |
|   UINTN                             PciBus;
 | |
|   UINTN                             PciDevice;
 | |
|   UINTN                             PciFunction;
 | |
|   EFI_LEGACY_IRQ_ROUTING_ENTRY      *RoutingTable;
 | |
|   UINTN                             RoutingTableEntries;
 | |
|   UINT16                            LegMask;
 | |
|   UINT16                            LegEdgeLevel;
 | |
|   PCI_TYPE00                        PciConfigHeader;
 | |
|   EFI_LEGACY_PIRQ_TABLE_HEADER      *PirqTable;
 | |
|   UINTN                             PirqTableSize;
 | |
|   UINTN                             Flags;
 | |
|   HDD_INFO                          *HddInfo;
 | |
|   UINT64                            Supports;
 | |
| 
 | |
|   //
 | |
|   // Note - This routine use to return immediately if Private->PciInterruptLine
 | |
|   //        was true. Routine changed since resets etc can cause not all
 | |
|   //        PciIo protocols to be registered the first time through.
 | |
|   // New algorithm is to do the copy $PIR table on first pass and save
 | |
|   // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
 | |
|   // a larger handle count then proceed with body of function else return
 | |
|   // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
 | |
|   // If zero then function unprogrammed else skip function.
 | |
|   //
 | |
|   Legacy8259          = Private->Legacy8259;
 | |
|   LegacyInterrupt     = Private->LegacyInterrupt;
 | |
|   LegacyBiosPlatform  = Private->LegacyBiosPlatform;
 | |
| 
 | |
|   LegacyBiosPlatform->GetRoutingTable (
 | |
|                         Private->LegacyBiosPlatform,
 | |
|                         (VOID *) &RoutingTable,
 | |
|                         &RoutingTableEntries,
 | |
|                         (VOID *) &PirqTable,
 | |
|                         &PirqTableSize,
 | |
|                         NULL,
 | |
|                         NULL
 | |
|                         );
 | |
|   CreateBridgeTable (RoutingTable, RoutingTableEntries);
 | |
| 
 | |
|   if (!Private->PciInterruptLine) {
 | |
|     CopyPirqTable (
 | |
|       Private,
 | |
|       RoutingTable,
 | |
|       RoutingTableEntries,
 | |
|       PirqTable,
 | |
|       PirqTableSize
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   if (HandleCount == mHandleCount) {
 | |
|     FreePool (HandleBuffer);
 | |
|     return EFI_ALREADY_STARTED;
 | |
|   }
 | |
| 
 | |
|   if (mHandleCount == 0x00) {
 | |
|     mHandleCount = HandleCount;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
|     //
 | |
|     // If VGA then only do VGA to allow drives fore time to spin up
 | |
|     // otherwise assign PCI IRQs to all potential devices.
 | |
|     //
 | |
|     if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {
 | |
|       continue;
 | |
|     } else {
 | |
|       //
 | |
|       // Force code to go through all handles next time called if video.
 | |
|       // This will catch case where HandleCount doesn't change but want
 | |
|       //  to get drive info etc.
 | |
|       //
 | |
|       mHandleCount = 0x00;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     (VOID **) &PciIo
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     //
 | |
|     // Test whether the device can be enabled or not.
 | |
|     // If it can't be enabled, then just skip it to avoid further operation.
 | |
|     //
 | |
|     PciIo->Pci.Read (
 | |
|                  PciIo,
 | |
|                  EfiPciIoWidthUint32,
 | |
|                  0,
 | |
|                  sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                  &PciConfigHeader
 | |
|                  );
 | |
|     Command = PciConfigHeader.Hdr.Command;
 | |
| 
 | |
|     //
 | |
|     // Note PciIo->Attributes does not program the PCI command register
 | |
|     //
 | |
|     Status = PciIo->Attributes (
 | |
|                       PciIo,
 | |
|                       EfiPciIoAttributeOperationSupported,
 | |
|                       0,
 | |
|                       &Supports
 | |
|                       );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
 | |
|       Status = PciIo->Attributes (
 | |
|                         PciIo,
 | |
|                         EfiPciIoAttributeOperationEnable,
 | |
|                         Supports,
 | |
|                         NULL
 | |
|                         );
 | |
|     }
 | |
|     PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     InterruptPin = PciConfigHeader.Device.InterruptPin;
 | |
| 
 | |
|     if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {
 | |
|       PciIo->GetLocation (
 | |
|                PciIo,
 | |
|                &PciSegment,
 | |
|                &PciBus,
 | |
|                &PciDevice,
 | |
|                &PciFunction
 | |
|                );
 | |
|       //
 | |
|       // Translate PIRQ index back thru busses to slot bus with InterruptPin
 | |
|       // zero based
 | |
|       //
 | |
|       InterruptPin -= 1;
 | |
| 
 | |
|       Status = GetBaseBus (
 | |
|                  Private,
 | |
|                  PciBus,
 | |
|                  PciDevice,
 | |
|                  RoutingTable,
 | |
|                  RoutingTableEntries
 | |
|                  );
 | |
| 
 | |
|       if (Status == EFI_NOT_FOUND) {
 | |
|         TranslateBusPirq (
 | |
|           Private,
 | |
|           &PciBus,
 | |
|           &PciDevice,
 | |
|           &PciFunction,
 | |
|           &InterruptPin
 | |
|           );
 | |
|       }
 | |
|       //
 | |
|       // Translate InterruptPin(0-3) into PIRQ
 | |
|       //
 | |
|       Status = LegacyBiosPlatform->TranslatePirq (
 | |
|                                      LegacyBiosPlatform,
 | |
|                                      PciBus,
 | |
|                                      (PciDevice << 3),
 | |
|                                      PciFunction,
 | |
|                                      &InterruptPin,
 | |
|                                      &PciIrq
 | |
|                                      );
 | |
|       //
 | |
|       // TranslatePirq() should never fail or we are in trouble
 | |
|       // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
 | |
|       //
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       LegacyInterrupt->WritePirq (
 | |
|                          LegacyInterrupt,
 | |
|                          InterruptPin,
 | |
|                          PciIrq
 | |
|                          );
 | |
| 
 | |
|       //
 | |
|       // Check if device has an OPROM associated with it.
 | |
|       // If not invoke special 16-bit function, to allow 16-bit
 | |
|       // code to install an interrupt handler.
 | |
|       //
 | |
|       Status = LegacyBiosCheckPciRom (
 | |
|                  &Private->LegacyBios,
 | |
|                  HandleBuffer[Index],
 | |
|                  NULL,
 | |
|                  NULL,
 | |
|                  &Flags
 | |
|                  );
 | |
|       if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {
 | |
|         //
 | |
|         // Device has no OPROM associated with it and is a mass storage
 | |
|         // device. It needs to have an PCI IRQ handler installed. To
 | |
|         // correctly install the handler we need to insure device is
 | |
|         // connected. The device may just have register itself but not
 | |
|         // been connected. Re-read PCI config space after as it can
 | |
|         // change
 | |
|         //
 | |
|         //
 | |
|         // Get IDE Handle. If matches handle then skip ConnectController
 | |
|         // since ConnectController may force native mode and we don't
 | |
|         // want that for primary IDE controller
 | |
|         //
 | |
|         MassStorageHandleCount = 0;
 | |
|         MassStorageHandleBuffer = NULL;
 | |
|         LegacyBiosPlatform->GetPlatformHandle (
 | |
|                               Private->LegacyBiosPlatform,
 | |
|                               EfiGetPlatformIdeHandle,
 | |
|                               0,
 | |
|                               &MassStorageHandleBuffer,
 | |
|                               &MassStorageHandleCount,
 | |
|                               NULL
 | |
|                               );
 | |
| 
 | |
|         HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
 | |
| 
 | |
|         LegacyBiosBuildIdeData (Private, &HddInfo, 0);
 | |
|         PciIo->Pci.Read (
 | |
|                      PciIo,
 | |
|                      EfiPciIoWidthUint32,
 | |
|                      0,
 | |
|                      sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                      &PciConfigHeader
 | |
|                      );
 | |
| 
 | |
|         for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {
 | |
|           if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {
 | |
|             //
 | |
|             // InstallLegacyIrqHandler according to Platform requirement
 | |
|             //
 | |
|             InstallLegacyIrqHandler (
 | |
|               Private,
 | |
|               PciIo,
 | |
|               PciIrq,
 | |
|               &PciConfigHeader
 | |
|               );
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // Write InterruptPin and enable 8259.
 | |
|       //
 | |
|       PciIo->Pci.Write (
 | |
|                    PciIo,
 | |
|                    EfiPciIoWidthUint8,
 | |
|                    0x3c,
 | |
|                    1,
 | |
|                    &PciIrq
 | |
|                    );
 | |
|       Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));
 | |
| 
 | |
|       Legacy8259->GetMask (
 | |
|                     Legacy8259,
 | |
|                     &LegMask,
 | |
|                     &LegEdgeLevel,
 | |
|                     NULL,
 | |
|                     NULL
 | |
|                     );
 | |
| 
 | |
|       LegMask       = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));
 | |
|       LegEdgeLevel  = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));
 | |
|       Legacy8259->SetMask (
 | |
|                     Legacy8259,
 | |
|                     &LegMask,
 | |
|                     &LegEdgeLevel,
 | |
|                     NULL,
 | |
|                     NULL
 | |
|                     );
 | |
|     }
 | |
|   }
 | |
|   FreePool (HandleBuffer);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find & verify PnP Expansion header in ROM image
 | |
| 
 | |
|   @param  Private                Protocol instance pointer.
 | |
|   @param  FirstHeader            1 = Find first header, 0 = Find successive headers
 | |
|   @param  PnpPtr                 Input Rom start if FirstHeader =1, Current Header
 | |
|                                  otherwise Output Next header, if it exists
 | |
| 
 | |
|   @retval EFI_SUCCESS            Next Header found at BasePnpPtr
 | |
|   @retval EFI_NOT_FOUND          No more headers
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindNextPnpExpansionHeader (
 | |
|   IN  LEGACY_BIOS_INSTANCE             *Private,
 | |
|   IN BOOLEAN                           FirstHeader,
 | |
|   IN OUT LEGACY_PNP_EXPANSION_HEADER   **PnpPtr
 | |
| 
 | |
|   )
 | |
| {
 | |
|   UINTN                       TempData;
 | |
|   LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;
 | |
|   LocalPnpPtr = *PnpPtr;
 | |
|   if (FirstHeader == FIRST_INSTANCE) {
 | |
|     mBasePnpPtr     = LocalPnpPtr;
 | |
|     mBbsRomSegment  = (UINT16) ((UINTN) mBasePnpPtr >> 4);
 | |
|     //
 | |
|     // Offset 0x1a gives offset to PnP expansion header for the first
 | |
|     // instance, there after the structure gives the offset to the next
 | |
|     // structure
 | |
|     //
 | |
|     LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);
 | |
|     TempData    = (*((UINT16 *) LocalPnpPtr));
 | |
|   } else {
 | |
|     TempData = (UINT16) LocalPnpPtr->NextHeader;
 | |
|   }
 | |
| 
 | |
|   LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));
 | |
| 
 | |
|   //
 | |
|   // Search for PnP table in Shadowed ROM
 | |
|   //
 | |
|   *PnpPtr = LocalPnpPtr;
 | |
|   if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Update list of Bev or BCV table entries.
 | |
| 
 | |
|   @param  Private                Protocol instance pointer.
 | |
|   @param  RomStart               Table of ROM start address in RAM/ROM. PciIo  _
 | |
|                                  Handle to PCI IO for this device
 | |
|   @param  PciIo                  Instance of PCI I/O Protocol
 | |
| 
 | |
|   @retval EFI_SUCCESS            Always should succeed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UpdateBevBcvTable (
 | |
|   IN  LEGACY_BIOS_INSTANCE             *Private,
 | |
|   IN  EFI_LEGACY_EXPANSION_ROM_HEADER  *RomStart,
 | |
|   IN  EFI_PCI_IO_PROTOCOL              *PciIo
 | |
|   )
 | |
| {
 | |
|   VOID                            *RomEnd;
 | |
|   BBS_TABLE                       *BbsTable;
 | |
|   UINTN                           BbsIndex;
 | |
|   EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;
 | |
|   LEGACY_PNP_EXPANSION_HEADER     *PnpPtr;
 | |
|   BOOLEAN                         Instance;
 | |
|   EFI_STATUS                      Status;
 | |
|   UINTN                           Segment;
 | |
|   UINTN                           Bus;
 | |
|   UINTN                           Device;
 | |
|   UINTN                           Function;
 | |
|   UINT8                           Class;
 | |
|   UINT16                          DeviceType;
 | |
|   Segment     = 0;
 | |
|   Bus         = 0;
 | |
|   Device      = 0;
 | |
|   Function    = 0;
 | |
|   Class       = 0;
 | |
|   DeviceType  = BBS_UNKNOWN;
 | |
| 
 | |
|   //
 | |
|   // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
 | |
|   // controller).
 | |
|   //
 | |
|   BbsIndex  = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
 | |
| 
 | |
|   BbsTable  = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;
 | |
|   PnpPtr    = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;
 | |
|   PciPtr    = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;
 | |
| 
 | |
|   RomEnd    = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);
 | |
|   Instance  = FIRST_INSTANCE;
 | |
|   //
 | |
|   // OPROMs like PXE may not be tied to a piece of hardware and thus
 | |
|   // don't have a PciIo associated with them
 | |
|   //
 | |
|   if (PciIo != NULL) {
 | |
|     PciIo->GetLocation (
 | |
|              PciIo,
 | |
|              &Segment,
 | |
|              &Bus,
 | |
|              &Device,
 | |
|              &Function
 | |
|              );
 | |
|     PciIo->Pci.Read (
 | |
|                  PciIo,
 | |
|                  EfiPciIoWidthUint8,
 | |
|                  0x0b,
 | |
|                  1,
 | |
|                  &Class
 | |
|                  );
 | |
| 
 | |
|     if (Class == PCI_CLASS_MASS_STORAGE) {
 | |
|       DeviceType = BBS_HARDDISK;
 | |
|     } else {
 | |
|       if (Class == PCI_CLASS_NETWORK) {
 | |
|         DeviceType = BBS_EMBED_NETWORK;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   while (TRUE) {
 | |
|     Status    = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);
 | |
|     Instance  = NOT_FIRST_INSTANCE;
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // There can be additional $PnP headers within the OPROM.
 | |
|     // Example: SCSI can have one per drive.
 | |
|     //
 | |
|     BbsTable[BbsIndex].BootPriority             = BBS_UNPRIORITIZED_ENTRY;
 | |
|     BbsTable[BbsIndex].DeviceType               = DeviceType;
 | |
|     BbsTable[BbsIndex].Bus                      = (UINT32) Bus;
 | |
|     BbsTable[BbsIndex].Device                   = (UINT32) Device;
 | |
|     BbsTable[BbsIndex].Function                 = (UINT32) Function;
 | |
|     BbsTable[BbsIndex].StatusFlags.OldPosition  = 0;
 | |
|     BbsTable[BbsIndex].StatusFlags.Reserved1    = 0;
 | |
|     BbsTable[BbsIndex].StatusFlags.Enabled      = 0;
 | |
|     BbsTable[BbsIndex].StatusFlags.Failed       = 0;
 | |
|     BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;
 | |
|     BbsTable[BbsIndex].StatusFlags.Reserved2    = 0;
 | |
|     BbsTable[BbsIndex].Class                    = PnpPtr->Class;
 | |
|     BbsTable[BbsIndex].SubClass                 = PnpPtr->SubClass;
 | |
|     BbsTable[BbsIndex].DescStringOffset         = PnpPtr->ProductNamePointer;
 | |
|     BbsTable[BbsIndex].DescStringSegment        = mBbsRomSegment;
 | |
|     BbsTable[BbsIndex].MfgStringOffset          = PnpPtr->MfgPointer;
 | |
|     BbsTable[BbsIndex].MfgStringSegment         = mBbsRomSegment;
 | |
|     BbsTable[BbsIndex].BootHandlerSegment       = mBbsRomSegment;
 | |
| 
 | |
|     //
 | |
|     // Have seen case where PXE base code have PnP expansion ROM
 | |
|     // header but no Bcv or Bev vectors.
 | |
|     //
 | |
|     if (PnpPtr->Bcv != 0) {
 | |
|       BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;
 | |
|       ++BbsIndex;
 | |
|     }
 | |
| 
 | |
|     if (PnpPtr->Bev != 0) {
 | |
|       BbsTable[BbsIndex].BootHandlerOffset  = PnpPtr->Bev;
 | |
|       BbsTable[BbsIndex].DeviceType         = BBS_BEV_DEVICE;
 | |
|       ++BbsIndex;
 | |
|     }
 | |
| 
 | |
|     if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;
 | |
|   Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
 | |
|   to chose the order. Skip any devices that have already have legacy
 | |
|   BIOS run.
 | |
| 
 | |
|   @param  Private                Protocol instance pointer.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Succeed.
 | |
|   @retval EFI_UNSUPPORTED        Cannot get VGA device handle.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PciShadowRoms (
 | |
|   IN  LEGACY_BIOS_INSTANCE      *Private
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_PCI_IO_PROTOCOL               *PciIo;
 | |
|   PCI_TYPE00                        Pci;
 | |
|   UINTN                             Index;
 | |
|   UINTN                             HandleCount;
 | |
|   EFI_HANDLE                        *HandleBuffer;
 | |
|   EFI_HANDLE                        VgaHandle;
 | |
|   EFI_HANDLE                        FirstHandle;
 | |
|   VOID                              **RomStart;
 | |
|   UINTN                             Flags;
 | |
|   PCI_TYPE00                        PciConfigHeader;
 | |
|   UINT16                            *Command;
 | |
|   UINT64                            Supports;
 | |
| 
 | |
|   //
 | |
|   // Make the VGA device first
 | |
|   //
 | |
|   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiGetPlatformVgaHandle,
 | |
|                                           0,
 | |
|                                           &HandleBuffer,
 | |
|                                           &HandleCount,
 | |
|                                           NULL
 | |
|                                           );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   VgaHandle = HandleBuffer[0];
 | |
| 
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Place the VGA handle as first.
 | |
|   //
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
|     if (HandleBuffer[Index] == VgaHandle) {
 | |
|       FirstHandle         = HandleBuffer[0];
 | |
|       HandleBuffer[0]     = HandleBuffer[Index];
 | |
|       HandleBuffer[Index] = FirstHandle;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Allocate memory to save Command WORD from each device. We do this
 | |
|   // to restore devices to same state as EFI after switching to legacy.
 | |
|   //
 | |
|   Command = (UINT16 *) AllocatePool (
 | |
|                          sizeof (UINT16) * (HandleCount + 1)
 | |
|                          );
 | |
|   if (NULL == Command) {
 | |
|     FreePool (HandleBuffer);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Disconnect all EFI devices first. This covers cases where alegacy BIOS
 | |
|   // may control multiple PCI devices.
 | |
|   //
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
| 
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     (VOID **) &PciIo
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     //
 | |
|     // Save command register for "connect" loop
 | |
|     //
 | |
|     PciIo->Pci.Read (
 | |
|                  PciIo,
 | |
|                  EfiPciIoWidthUint32,
 | |
|                  0,
 | |
|                  sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                  &PciConfigHeader
 | |
|                  );
 | |
|     Command[Index] = PciConfigHeader.Hdr.Command;
 | |
|     //
 | |
|     // Skip any device that already has a legacy ROM run
 | |
|     //
 | |
|     Status = IsLegacyRom (HandleBuffer[Index]);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Stop EFI Drivers with oprom.
 | |
|     //
 | |
|     gBS->DisconnectController (
 | |
|            HandleBuffer[Index],
 | |
|            NULL,
 | |
|            NULL
 | |
|            );
 | |
|   }
 | |
|   //
 | |
|   // For every device that has not had a legacy ROM started. Start a legacy ROM.
 | |
|   //
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
| 
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     (VOID **) &PciIo
 | |
|                     );
 | |
| 
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     //
 | |
|     // Here make sure if one VGA have been shadowed,
 | |
|     // then wil not shadowed another one.
 | |
|     //
 | |
|     PciIo->Pci.Read (
 | |
|                  PciIo,
 | |
|                  EfiPciIoWidthUint32,
 | |
|                  0,
 | |
|                  sizeof (Pci) / sizeof (UINT32),
 | |
|                  &Pci
 | |
|                  );
 | |
| 
 | |
|     //
 | |
|     // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
 | |
|     // one will work in legacy mode (OPROM will be given control) and
 | |
|     // other Video devices will work in native mode (OS driver will handle these devices).
 | |
|     //
 | |
|     if (IS_PCI_DISPLAY (&Pci) && Index != 0) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Skip any device that already has a legacy ROM run
 | |
|     //
 | |
|     Status = IsLegacyRom (HandleBuffer[Index]);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
 | |
|     //
 | |
|     if (IS_PCI_DISPLAY (&Pci) && Index == 0) {
 | |
|       Status = LegacyBiosInstallVgaRom (Private);
 | |
|       //
 | |
|       // A return status of EFI_NOT_FOUND is considered valid (No EFI
 | |
|       // driver is controlling video).
 | |
|       //
 | |
|       ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Install legacy ROM
 | |
|     //
 | |
|     Status = LegacyBiosInstallPciRom (
 | |
|                &Private->LegacyBios,
 | |
|                HandleBuffer[Index],
 | |
|                NULL,
 | |
|                &Flags,
 | |
|                NULL,
 | |
|                NULL,
 | |
|                (VOID **) &RomStart,
 | |
|                NULL
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Restore Command register so legacy has same devices enabled or disabled
 | |
|     // as EFI.
 | |
|     // If Flags = NO_ROM use command register as is. This covers the
 | |
|     //            following cases:
 | |
|     //              Device has no ROMs associated with it.
 | |
|     //              Device has ROM associated with it but was already
 | |
|     //              installed.
 | |
|     //          = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
 | |
|     //          = ROM_FOUND and VALID_LEGACY_ROM, enable it.
 | |
|     //
 | |
|     if ((Flags & ROM_FOUND) == ROM_FOUND) {
 | |
|       if ((Flags & VALID_LEGACY_ROM) == 0) {
 | |
|         Command[Index] = 0;
 | |
|       } else {
 | |
|         //
 | |
|         // For several VGAs, only one of them can be enabled.
 | |
|         //
 | |
|         Status = PciIo->Attributes (
 | |
|                           PciIo,
 | |
|                           EfiPciIoAttributeOperationSupported,
 | |
|                           0,
 | |
|                           &Supports
 | |
|                           );
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
 | |
|           Status = PciIo->Attributes (
 | |
|                             PciIo,
 | |
|                             EfiPciIoAttributeOperationEnable,
 | |
|                             Supports,
 | |
|                             NULL
 | |
|                             );
 | |
|         }
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           Command[Index] = 0x1f;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     PciIo->Pci.Write (
 | |
|                  PciIo,
 | |
|                  EfiPciIoWidthUint16,
 | |
|                  0x04,
 | |
|                  1,
 | |
|                  &Command[Index]
 | |
|                  );
 | |
|   }
 | |
| 
 | |
|   FreePool (Command);
 | |
|   FreePool (HandleBuffer);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Test to see if a legacy PCI ROM exists for this device. Optionally return
 | |
|   the Legacy ROM instance for this PCI device.
 | |
| 
 | |
|   @param  This                   Protocol instance pointer.
 | |
|   @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
 | |
|                                  be loaded
 | |
|   @param  RomImage               Return the legacy PCI ROM for this device
 | |
|   @param  RomSize                Size of ROM Image
 | |
|   @param  Flags                  Indicates if ROM found and if PC-AT.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Legacy Option ROM available for this device
 | |
|   @retval EFI_UNSUPPORTED        Legacy Option ROM not supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosCheckPciRom (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
 | |
|   IN  EFI_HANDLE                        PciHandle,
 | |
|   OUT VOID                              **RomImage, OPTIONAL
 | |
|   OUT UINTN                             *RomSize, OPTIONAL
 | |
|   OUT UINTN                             *Flags
 | |
|   )
 | |
| {
 | |
|   return LegacyBiosCheckPciRomEx (
 | |
|            This,
 | |
|            PciHandle,
 | |
|            RomImage,
 | |
|            RomSize,
 | |
|            NULL,
 | |
|            Flags,
 | |
|            NULL,
 | |
|            NULL
 | |
|            );
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Routine Description:
 | |
|     Test to see if a legacy PCI ROM exists for this device. Optionally return
 | |
|     the Legacy ROM instance for this PCI device.
 | |
| 
 | |
|     @param[in] This          Protocol instance pointer.
 | |
|     @param[in] PciHandle               The PCI PC-AT OPROM from this devices ROM BAR will be loaded
 | |
|     @param[out] RomImage               Return the legacy PCI ROM for this device
 | |
|     @param[out] RomSize                Size of ROM Image
 | |
|     @param[out] RuntimeImageLength     Runtime size of ROM Image
 | |
|     @param[out] Flags                  Indicates if ROM found and if PC-AT.
 | |
|     @param[out] OpromRevision          Revision of the PCI Rom
 | |
|     @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
 | |
| 
 | |
|     @return EFI_SUCCESS            Legacy Option ROM available for this device
 | |
|     @return EFI_ALREADY_STARTED    This device is already managed by its Oprom
 | |
|     @return EFI_UNSUPPORTED        Legacy Option ROM not supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LegacyBiosCheckPciRomEx (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
 | |
|   IN  EFI_HANDLE                        PciHandle,
 | |
|   OUT VOID                              **RomImage, OPTIONAL
 | |
|   OUT UINTN                             *RomSize, OPTIONAL
 | |
|   OUT UINTN                             *RuntimeImageLength, OPTIONAL
 | |
|   OUT UINTN                             *Flags, OPTIONAL
 | |
|   OUT UINT8                             *OpromRevision, OPTIONAL
 | |
|   OUT VOID                              **ConfigUtilityCodeHeader OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   LEGACY_BIOS_INSTANCE            *Private;
 | |
|   EFI_PCI_IO_PROTOCOL             *PciIo;
 | |
|   UINTN                           LocalRomSize;
 | |
|   VOID                            *LocalRomImage;
 | |
|   PCI_TYPE00                      PciConfigHeader;
 | |
|   VOID                            *LocalConfigUtilityCodeHeader;
 | |
| 
 | |
|   LocalConfigUtilityCodeHeader = NULL;
 | |
|   *Flags = NO_ROM;
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   PciHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // See if the option ROM for PciHandle has already been executed
 | |
|   //
 | |
|   Status = IsLegacyRom (PciHandle);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     *Flags |= (UINTN)(ROM_FOUND | VALID_LEGACY_ROM);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Check for PCI ROM Bar
 | |
|   //
 | |
|   LocalRomSize  = (UINTN) PciIo->RomSize;
 | |
|   LocalRomImage = PciIo->RomImage;
 | |
|   if (LocalRomSize != 0) {
 | |
|     *Flags |= ROM_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // PCI specification states you should check VendorId and Device Id.
 | |
|   //
 | |
|   PciIo->Pci.Read (
 | |
|                PciIo,
 | |
|                EfiPciIoWidthUint32,
 | |
|                0,
 | |
|                sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                &PciConfigHeader
 | |
|                );
 | |
| 
 | |
|   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
|   Status = GetPciLegacyRom (
 | |
|              Private->Csm16PciInterfaceVersion,
 | |
|              PciConfigHeader.Hdr.VendorId,
 | |
|              PciConfigHeader.Hdr.DeviceId,
 | |
|              &LocalRomImage,
 | |
|              &LocalRomSize,
 | |
|              RuntimeImageLength,
 | |
|              OpromRevision,
 | |
|              &LocalConfigUtilityCodeHeader
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   *Flags |= VALID_LEGACY_ROM;
 | |
| 
 | |
|   //
 | |
|   // See if Configuration Utility Code Header valid
 | |
|   //
 | |
|   if (LocalConfigUtilityCodeHeader != NULL) {
 | |
|     *Flags |= ROM_WITH_CONFIG;
 | |
|   }
 | |
| 
 | |
|   if (ConfigUtilityCodeHeader != NULL) {
 | |
|     *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;
 | |
|   }
 | |
| 
 | |
|   if (RomImage != NULL) {
 | |
|     *RomImage = LocalRomImage;
 | |
|   }
 | |
| 
 | |
|   if (RomSize != NULL) {
 | |
|     *RomSize = LocalRomSize;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Load a legacy PC-AT OPROM on the PciHandle device. Return information
 | |
|   about how many disks were added by the OPROM and the shadow address and
 | |
|   size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
 | |
| 
 | |
|   @retval EFI_SUCCESS   Legacy ROM loaded for this device
 | |
|   @retval EFI_NOT_FOUND No PS2 Keyboard found
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EnablePs2Keyboard (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_HANDLE                          *HandleBuffer;
 | |
|   UINTN                               HandleCount;
 | |
|   EFI_ISA_IO_PROTOCOL                 *IsaIo;
 | |
|   UINTN                               Index;
 | |
| 
 | |
|   //
 | |
|   // Get SimpleTextIn and find PS2 controller
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiSimpleTextInProtocolGuid,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
|     //
 | |
|     // Open the IO Abstraction(s) needed to perform the supported test
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiIsaIoProtocolGuid,
 | |
|                     (VOID **) &IsaIo,
 | |
|                     NULL,
 | |
|                     HandleBuffer[Index],
 | |
|                     EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
 | |
|                     );
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Use the ISA I/O Protocol to see if Controller is the Keyboard
 | |
|       // controller
 | |
|       //
 | |
|       if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|       }
 | |
| 
 | |
|       gBS->CloseProtocol (
 | |
|              HandleBuffer[Index],
 | |
|              &gEfiIsaIoProtocolGuid,
 | |
|              NULL,
 | |
|              HandleBuffer[Index]
 | |
|              );
 | |
|     }
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
 | |
|     }
 | |
|   }
 | |
|   FreePool (HandleBuffer);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Load a legacy PC-AT OpROM for VGA controller.
 | |
| 
 | |
|   @param  Private                Driver private data.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Legacy ROM successfully installed for this device.
 | |
|   @retval EFI_DEVICE_ERROR       No VGA device handle found, or native EFI video
 | |
|                                  driver cannot be successfully disconnected, or VGA
 | |
|                                  thunk driver cannot be successfully connected.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LegacyBiosInstallVgaRom (
 | |
|   IN  LEGACY_BIOS_INSTANCE            *Private
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                           Status;
 | |
|   EFI_HANDLE                           VgaHandle;
 | |
|   UINTN                                HandleCount;
 | |
|   EFI_HANDLE                           *HandleBuffer;
 | |
|   EFI_HANDLE                           *ConnectHandleBuffer;
 | |
|   EFI_PCI_IO_PROTOCOL                  *PciIo;
 | |
|   PCI_TYPE00                           PciConfigHeader;
 | |
|   UINT64                               Supports;
 | |
|   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
 | |
|   UINTN                                EntryCount;
 | |
|   UINTN                                Index;
 | |
|   VOID                                 *Interface;
 | |
| 
 | |
|   //
 | |
|   // EfiLegacyBiosGuild attached to a device implies that there is a legacy
 | |
|   // BIOS associated with that device.
 | |
|   //
 | |
|   // There are 3 cases to consider.
 | |
|   //   Case 1: No EFI driver is controlling the video.
 | |
|   //     Action: Return EFI_SUCCESS from DisconnectController, search
 | |
|   //             video thunk driver, and connect it.
 | |
|   //   Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
 | |
|   //           not on the image handle.
 | |
|   //     Action: Disconnect EFI driver.
 | |
|   //             ConnectController for video thunk
 | |
|   //   Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
 | |
|   //           on the image handle.
 | |
|   //     Action: Do nothing and set Private->VgaInstalled = TRUE.
 | |
|   //             Then this routine is not called any more.
 | |
|   //
 | |
|   //
 | |
|   // Get the VGA device.
 | |
|   //
 | |
|   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiGetPlatformVgaHandle,
 | |
|                                           0,
 | |
|                                           &HandleBuffer,
 | |
|                                           &HandleCount,
 | |
|                                           NULL
 | |
|                                           );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   VgaHandle = HandleBuffer[0];
 | |
| 
 | |
|   //
 | |
|   // Check whether video thunk driver already starts.
 | |
|   //
 | |
|   Status = gBS->OpenProtocolInformation (
 | |
|                   VgaHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   &OpenInfoBuffer,
 | |
|                   &EntryCount
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < EntryCount; Index++) {
 | |
|     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
 | |
|       Status = gBS->HandleProtocol (
 | |
|                       OpenInfoBuffer[Index].AgentHandle,
 | |
|                       &gEfiLegacyBiosGuid,
 | |
|                       (VOID **) &Interface
 | |
|                       );
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         //
 | |
|         // This should be video thunk driver which is managing video device
 | |
|         // So it need not start again
 | |
|         //
 | |
|         DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));
 | |
|         Private->VgaInstalled = TRUE;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Kick off the native EFI driver
 | |
|   //
 | |
|   Status = gBS->DisconnectController (
 | |
|                   VgaHandle,
 | |
|                   NULL,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Status != EFI_NOT_FOUND) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     } else {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Find all the Thunk Driver
 | |
|   //
 | |
|   HandleBuffer = NULL;
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiLegacyBiosGuid,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));
 | |
|   ASSERT (ConnectHandleBuffer != NULL);
 | |
| 
 | |
|   CopyMem (
 | |
|     ConnectHandleBuffer,
 | |
|     HandleBuffer,
 | |
|     sizeof (EFI_HANDLE) * HandleCount
 | |
|     );
 | |
|   ConnectHandleBuffer[HandleCount] = NULL;
 | |
| 
 | |
|   FreePool (HandleBuffer);
 | |
| 
 | |
|   //
 | |
|   // Enable the device and make sure VGA cycles are being forwarded to this VGA device
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   VgaHandle,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   PciIo->Pci.Read (
 | |
|                PciIo,
 | |
|                EfiPciIoWidthUint32,
 | |
|                0,
 | |
|                sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                &PciConfigHeader
 | |
|                );
 | |
| 
 | |
|   Status = PciIo->Attributes (
 | |
|                     PciIo,
 | |
|                     EfiPciIoAttributeOperationSupported,
 | |
|                     0,
 | |
|                     &Supports
 | |
|                     );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Supports &= (UINT64)(EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \
 | |
|                          EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
 | |
|     Status = PciIo->Attributes (
 | |
|                       PciIo,
 | |
|                       EfiPciIoAttributeOperationEnable,
 | |
|                       Supports,
 | |
|                       NULL
 | |
|                       );
 | |
|   }
 | |
| 
 | |
|   if (Status == EFI_SUCCESS) {
 | |
|     Private->VgaInstalled = TRUE;
 | |
| 
 | |
|     //
 | |
|     // Attach the VGA thunk driver.
 | |
|     // Assume the video is installed. This prevents potential of infinite recursion.
 | |
|     //
 | |
|     Status = gBS->ConnectController (
 | |
|                     VgaHandle,
 | |
|                     ConnectHandleBuffer,
 | |
|                     NULL,
 | |
|                     TRUE
 | |
|                     );
 | |
|   }
 | |
| 
 | |
|   FreePool (ConnectHandleBuffer);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     Private->VgaInstalled = FALSE;
 | |
| 
 | |
|     //
 | |
|     // Reconnect the EFI VGA driver.
 | |
|     //
 | |
|     gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Load a legacy PC-AT OpROM.
 | |
| 
 | |
|   @param  This                              Protocol instance pointer.
 | |
|   @param  Private                          Driver's private data.
 | |
|   @param  PciHandle                      The EFI handle for the PCI device. It could be
 | |
|                                                     NULL if the  OpROM image is not associated with
 | |
|                                                     any device.
 | |
|   @param  OpromRevision              The revision of PCI PC-AT ROM image.
 | |
|   @param  RomImage                    Pointer to PCI PC-AT ROM image header. It must not
 | |
|                                                     be NULL.
 | |
|   @param  ImageSize                     Size of the PCI PC-AT ROM image.
 | |
|   @param  RuntimeImageLength      On input is the max runtime image length indicated by the PCIR structure
 | |
|                                                     On output is the actual runtime image length
 | |
|   @param  DiskStart                       Disk number of first device hooked by the ROM. If
 | |
|                                                     DiskStart is the same as DiskEnd no disked were
 | |
|                                                     hooked.
 | |
|   @param  DiskEnd                         Disk number of the last device hooked by the ROM.
 | |
|   @param  RomShadowAddress       Shadow address of PC-AT ROM
 | |
| 
 | |
|   @retval EFI_SUCCESS            Legacy ROM loaded for this device
 | |
|   @retval EFI_OUT_OF_RESOURCES   No more space for this ROM
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosInstallRom (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
 | |
|   IN LEGACY_BIOS_INSTANCE               *Private,
 | |
|   IN EFI_HANDLE                         PciHandle,
 | |
|   IN UINT8                              OpromRevision,
 | |
|   IN VOID                               *RomImage,
 | |
|   IN UINTN                              ImageSize,
 | |
|   IN OUT UINTN                          *RuntimeImageLength,
 | |
|   OUT UINT8                             *DiskStart, OPTIONAL
 | |
|   OUT UINT8                             *DiskEnd, OPTIONAL
 | |
|   OUT VOID                              **RomShadowAddress OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_STATUS            PciEnableStatus;
 | |
|   EFI_PCI_IO_PROTOCOL   *PciIo;
 | |
|   UINT8                 LocalDiskStart;
 | |
|   UINT8                 LocalDiskEnd;
 | |
|   UINTN                 Segment;
 | |
|   UINTN                 Bus;
 | |
|   UINTN                 Device;
 | |
|   UINTN                 Function;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   UINT8                 VideoMode;
 | |
|   UINT8                 OldVideoMode;
 | |
|   EFI_TIME              BootTime;
 | |
|   UINT32                *BdaPtr;
 | |
|   UINT32                LocalTime;
 | |
|   UINT32                StartBbsIndex;
 | |
|   UINT32                EndBbsIndex;
 | |
|   UINT32                MaxRomAddr;
 | |
|   UINTN                 TempData;
 | |
|   UINTN                 InitAddress;
 | |
|   UINTN                 RuntimeAddress;
 | |
|   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
 | |
|   UINT32                Granularity;
 | |
| 
 | |
|   PciIo           = NULL;
 | |
|   LocalDiskStart  = 0;
 | |
|   LocalDiskEnd    = 0;
 | |
|   Segment         = 0;
 | |
|   Bus             = 0;
 | |
|   Device          = 0;
 | |
|   Function        = 0;
 | |
|   VideoMode       = 0;
 | |
|   OldVideoMode    = 0;
 | |
|   PhysicalAddress = 0;
 | |
|   MaxRomAddr      = PcdGet32 (PcdEndOpromShadowAddress);
 | |
| 
 | |
|   if ((Private->Legacy16Table->TableLength >= OFFSET_OF(EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
 | |
|       (Private->Legacy16Table->UmaAddress != 0) &&
 | |
|       (Private->Legacy16Table->UmaSize != 0) &&
 | |
|       (MaxRomAddr > (Private->Legacy16Table->UmaAddress))) {
 | |
|     MaxRomAddr = Private->Legacy16Table->UmaAddress;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   PciProgramAllInterruptLineRegisters (Private);
 | |
| 
 | |
|   if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {
 | |
|     //
 | |
|     // CSM16 3.0 meets PCI 3.0 OpROM
 | |
|     //   first test if there is enough space for its INIT code
 | |
|     //
 | |
|     PhysicalAddress = CONVENTIONAL_MEMORY_TOP;
 | |
|     Status = gBS->AllocatePages (
 | |
|                     AllocateMaxAddress,
 | |
|                     EfiBootServicesCode,
 | |
|                     EFI_SIZE_TO_PAGES (ImageSize),
 | |
|                     &PhysicalAddress
 | |
|                     );
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
 | |
|       //
 | |
|       // Report Status Code to indicate that there is no enough space for OpROM
 | |
|       //
 | |
|       REPORT_STATUS_CODE (
 | |
|         EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
 | |
|         );
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     InitAddress = (UINTN) PhysicalAddress;
 | |
|     //
 | |
|     //   then test if there is enough space for its RT code
 | |
|     //
 | |
|     RuntimeAddress = Private->OptionRom;
 | |
|     if (RuntimeAddress + *RuntimeImageLength > MaxRomAddr) {
 | |
|       DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
 | |
|       gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
 | |
|       //
 | |
|       // Report Status Code to indicate that there is no enough space for OpROM
 | |
|       //
 | |
|       REPORT_STATUS_CODE (
 | |
|         EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
 | |
|         );
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   } else {
 | |
|     // CSM16 3.0 meets PCI 2.x OpROM
 | |
|     // CSM16 2.x meets PCI 2.x/3.0 OpROM
 | |
|     //   test if there is enough space for its INIT code
 | |
|     //
 | |
|     InitAddress    = PCI_START_ADDRESS (Private->OptionRom);
 | |
|     if (InitAddress + ImageSize > MaxRomAddr) {
 | |
|       DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
 | |
|       //
 | |
|       // Report Status Code to indicate that there is no enough space for OpROM
 | |
|       //
 | |
|       REPORT_STATUS_CODE (
 | |
|         EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
 | |
|         );
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     RuntimeAddress = InitAddress;
 | |
|   }
 | |
| 
 | |
|   Private->LegacyRegion->UnLock (
 | |
|                            Private->LegacyRegion,
 | |
|                            0xE0000,
 | |
|                            0x20000,
 | |
|                            &Granularity
 | |
|                            );
 | |
| 
 | |
|   Private->LegacyRegion->UnLock (
 | |
|                            Private->LegacyRegion,
 | |
|                            (UINT32) RuntimeAddress,
 | |
|                            (UINT32) ImageSize,
 | |
|                            &Granularity
 | |
|                            );
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));
 | |
| 
 | |
|   CopyMem ((VOID *) InitAddress, RomImage, ImageSize);
 | |
| 
 | |
|   //
 | |
|   // Read the highest disk number "installed: and assume a new disk will
 | |
|   // show up on the first drive past the current value.
 | |
|   // There are several considerations here:
 | |
|   // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
 | |
|   //    the change until boot selection time frame.
 | |
|   // 2. BBS compliants drives will not change 40:75 until boot time.
 | |
|   // 3. Onboard IDE controllers will change 40:75
 | |
|   //
 | |
|   ACCESS_PAGE0_CODE (
 | |
|     LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
 | |
|     if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
 | |
|       //
 | |
|       // Update table since onboard IDE drives found
 | |
|       //
 | |
|       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = 0xff;
 | |
|       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = 0xff;
 | |
|       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = 0xff;
 | |
|       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = 0xff;
 | |
|       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = (UINT8) (Private->Disk4075 + 0x80);
 | |
|       Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber    = LocalDiskStart;
 | |
|       Private->LegacyEfiHddTableIndex ++;
 | |
|       Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);
 | |
|       Private->DiskEnd  = LocalDiskStart;
 | |
|     }
 | |
| 
 | |
|     if (PciHandle != mVgaHandle) {
 | |
| 
 | |
|       EnablePs2Keyboard ();
 | |
| 
 | |
|       //
 | |
|       // Store current mode settings since PrepareToScanRom may change mode.
 | |
|       //
 | |
|       VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // Notify the platform that we are about to scan the ROM
 | |
|   //
 | |
|   Status = Private->LegacyBiosPlatform->PlatformHooks (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiPlatformHookPrepareToScanRom,
 | |
|                                           0,
 | |
|                                           PciHandle,
 | |
|                                           &InitAddress,
 | |
|                                           NULL,
 | |
|                                           NULL
 | |
|                                           );
 | |
| 
 | |
|   //
 | |
|   // If Status returned is EFI_UNSUPPORTED then abort due to platform
 | |
|   // policy.
 | |
|   //
 | |
|   if (Status == EFI_UNSUPPORTED) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Report corresponding status code
 | |
|   //
 | |
|   REPORT_STATUS_CODE (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Generate number of ticks since midnight for BDA. Some OPROMs require
 | |
|   // this. Place result in 40:6C-6F
 | |
|   //
 | |
|   gRT->GetTime (&BootTime, NULL);
 | |
|   LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
 | |
| 
 | |
|   //
 | |
|   // Multiply result by 18.2 for number of ticks since midnight.
 | |
|   // Use 182/10 to avoid floating point math.
 | |
|   //
 | |
|   ACCESS_PAGE0_CODE (
 | |
|     LocalTime = (LocalTime * 182) / 10;
 | |
|     BdaPtr    = (UINT32 *) ((UINTN) 0x46C);
 | |
|     *BdaPtr   = LocalTime;
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // Pass in handoff data
 | |
|   //
 | |
|   PciEnableStatus = EFI_UNSUPPORTED;
 | |
|   ZeroMem (&Regs, sizeof (Regs));
 | |
|   if (PciHandle != NULL) {
 | |
| 
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     PciHandle,
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     (VOID **) &PciIo
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     //
 | |
|     // Enable command register.
 | |
|     //
 | |
|     PciEnableStatus = PciIo->Attributes (
 | |
|                                PciIo,
 | |
|                                EfiPciIoAttributeOperationEnable,
 | |
|                                EFI_PCI_DEVICE_ENABLE,
 | |
|                                NULL
 | |
|                                );
 | |
| 
 | |
|     PciIo->GetLocation (
 | |
|              PciIo,
 | |
|              &Segment,
 | |
|              &Bus,
 | |
|              &Device,
 | |
|              &Function
 | |
|              );
 | |
|     DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));
 | |
|   }
 | |
| 
 | |
|   mIgnoreBbsUpdateFlag  = FALSE;
 | |
|   Regs.X.AX             = Legacy16DispatchOprom;
 | |
| 
 | |
|   //
 | |
|   // Generate DispatchOpRomTable data
 | |
|   //
 | |
|   Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;
 | |
|   Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset  = Private->Legacy16Table->PnPInstallationCheckOffset;
 | |
|   Private->IntThunk->DispatchOpromTable.OpromSegment                = (UINT16) (InitAddress >> 4);
 | |
|   Private->IntThunk->DispatchOpromTable.PciBus                      = (UINT8) Bus;
 | |
|   Private->IntThunk->DispatchOpromTable.PciDeviceFunction           = (UINT8) ((Device << 3) | Function);
 | |
|   Private->IntThunk->DispatchOpromTable.NumberBbsEntries            = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
 | |
|   Private->IntThunk->DispatchOpromTable.BbsTablePointer             = (UINT32) (UINTN) Private->BbsTablePtr;
 | |
|   Private->IntThunk->DispatchOpromTable.RuntimeSegment              = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));
 | |
|   TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;
 | |
|   Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
 | |
|   Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
 | |
|   //
 | |
|   // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
 | |
|   // Otherwise, it may cause the system to hang in some cases
 | |
|   //
 | |
|   if (!EFI_ERROR (PciEnableStatus)) {
 | |
|     DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));
 | |
|     Private->LegacyBios.FarCall86 (
 | |
|       &Private->LegacyBios,
 | |
|       Private->Legacy16CallSegment,
 | |
|       Private->Legacy16CallOffset,
 | |
|       &Regs,
 | |
|       NULL,
 | |
|       0
 | |
|       );
 | |
|   } else {
 | |
|     Regs.X.BX = 0;
 | |
|   }
 | |
| 
 | |
|   if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {
 | |
|     Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries  = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;
 | |
|     mIgnoreBbsUpdateFlag = TRUE;
 | |
|   }
 | |
|   //
 | |
|   // Check if non-BBS compliant drives found
 | |
|   //
 | |
|   if (Regs.X.BX != 0) {
 | |
|     LocalDiskEnd  = (UINT8) (LocalDiskStart + Regs.H.BL);
 | |
|     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;
 | |
|     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;
 | |
|     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;
 | |
|     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;
 | |
|     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;
 | |
|     Private->DiskEnd = LocalDiskEnd;
 | |
|     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
 | |
|     Private->LegacyEfiHddTableIndex += 1;
 | |
|   }
 | |
|   //
 | |
|   // Skip video mode set, if installing VGA
 | |
|   //
 | |
|   if (PciHandle != mVgaHandle) {
 | |
|     //
 | |
|     // Set mode settings since PrepareToScanRom may change mode
 | |
|     //
 | |
|     ACCESS_PAGE0_CODE ({
 | |
|       OldVideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
 | |
|     });
 | |
| 
 | |
|     if (VideoMode != OldVideoMode) {
 | |
|       //
 | |
|       // The active video mode is changed, restore it to original mode.
 | |
|       //
 | |
|       Regs.H.AH = 0x00;
 | |
|       Regs.H.AL = VideoMode;
 | |
|       Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Regs.X.AX from the adapter initializion is ignored since some adapters
 | |
|   // do not follow the standard of setting AX = 0 on success.
 | |
|   //
 | |
|   //
 | |
|   // The ROM could have updated it's size so we need to read again.
 | |
|   //
 | |
|   if (((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
 | |
|     //
 | |
|     // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.
 | |
|     // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.
 | |
|     //
 | |
|     *RuntimeImageLength = 0;
 | |
|   } else {
 | |
|     *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Size512 * 512;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));
 | |
| 
 | |
|   //
 | |
|   // If OpROM runs in 2.0 mode
 | |
|   //
 | |
|   if (PhysicalAddress == 0) {
 | |
|     if (*RuntimeImageLength < ImageSize) {
 | |
|       //
 | |
|       // Make area from end of shadowed rom to end of original rom all ffs
 | |
|       //
 | |
|       gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ACCESS_PAGE0_CODE (
 | |
|     LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // Allow platform to perform any required actions after the
 | |
|   // OPROM has been initialized.
 | |
|   //
 | |
|   Status = Private->LegacyBiosPlatform->PlatformHooks (
 | |
|                                           Private->LegacyBiosPlatform,
 | |
|                                           EfiPlatformHookAfterRomInit,
 | |
|                                           0,
 | |
|                                           PciHandle,
 | |
|                                           &RuntimeAddress,
 | |
|                                           NULL,
 | |
|                                           NULL
 | |
|                                           );
 | |
|   if (PciHandle != NULL) {
 | |
|     //
 | |
|     // If no PCI Handle then no header or Bevs.
 | |
|     //
 | |
|     if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {
 | |
|       StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
 | |
|       TempData      = RuntimeAddress;
 | |
|       UpdateBevBcvTable (
 | |
|         Private,
 | |
|         (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,
 | |
|         PciIo
 | |
|         );
 | |
|       EndBbsIndex   = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
 | |
|       LocalDiskEnd  = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));
 | |
|       if (LocalDiskEnd != LocalDiskStart) {
 | |
|         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;
 | |
|         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;
 | |
|         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;
 | |
|         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;
 | |
|         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;
 | |
|         Private->DiskEnd = LocalDiskEnd;
 | |
|         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
 | |
|         Private->LegacyEfiHddTableIndex += 1;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Mark PCI device as having a legacy BIOS ROM loaded.
 | |
|     //
 | |
|     RomShadow (
 | |
|       PciHandle,
 | |
|       (UINT32) RuntimeAddress,
 | |
|       (UINT32) *RuntimeImageLength,
 | |
|       LocalDiskStart,
 | |
|       LocalDiskEnd
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Stuff caller's OPTIONAL return parameters.
 | |
|   //
 | |
|   if (RomShadowAddress != NULL) {
 | |
|     *RomShadowAddress = (VOID *) RuntimeAddress;
 | |
|   }
 | |
| 
 | |
|   if (DiskStart != NULL) {
 | |
|     *DiskStart = LocalDiskStart;
 | |
|   }
 | |
| 
 | |
|   if (DiskEnd != NULL) {
 | |
|     *DiskEnd = LocalDiskEnd;
 | |
|   }
 | |
| 
 | |
|   Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
| Done:
 | |
|   if (PhysicalAddress != 0) {
 | |
|     //
 | |
|     // Free pages when OpROM is 3.0
 | |
|     //
 | |
|     gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Insure all shadowed  areas are locked
 | |
|   //
 | |
|   Private->LegacyRegion->Lock (
 | |
|                            Private->LegacyRegion,
 | |
|                            0xC0000,
 | |
|                            0x40000,
 | |
|                            &Granularity
 | |
|                            );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Let IOMMU grant DMA access for the PCI device.
 | |
| 
 | |
|   @param  PciHandle             The EFI handle for the PCI device.
 | |
|   @param  HostAddress           The system memory address to map to the PCI controller.
 | |
|   @param  NumberOfBytes         The number of bytes to map.
 | |
| 
 | |
|   @retval EFI_SUCCESS  The DMA access is granted.
 | |
| **/
 | |
| EFI_STATUS
 | |
| IoMmuGrantAccess (
 | |
|   IN  EFI_HANDLE                        PciHandle,
 | |
|   IN  EFI_PHYSICAL_ADDRESS              HostAddress,
 | |
|   IN  UINTN                             NumberOfBytes
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS            DeviceAddress;
 | |
|   VOID                            *Mapping;
 | |
|   EFI_STATUS                      Status;
 | |
| 
 | |
|   if (PciHandle == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   if (mIoMmu == NULL) {
 | |
|     gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);
 | |
|   }
 | |
|   if (mIoMmu != NULL) {
 | |
|     Status = mIoMmu->Map (
 | |
|                        mIoMmu,
 | |
|                        EdkiiIoMmuOperationBusMasterCommonBuffer,
 | |
|                        (VOID *)(UINTN)HostAddress,
 | |
|                        &NumberOfBytes,
 | |
|                        &DeviceAddress,
 | |
|                        &Mapping
 | |
|                        );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuMap - %r\n", Status));
 | |
|     } else {
 | |
|       ASSERT (DeviceAddress == HostAddress);
 | |
|       Status = mIoMmu->SetAttribute (
 | |
|                          mIoMmu,
 | |
|                          PciHandle,
 | |
|                          Mapping,
 | |
|                          EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
 | |
|                          );
 | |
|       if (EFI_ERROR(Status)) {
 | |
|         DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuSetAttribute - %r\n", Status));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Load a legacy PC-AT OPROM on the PciHandle device. Return information
 | |
|   about how many disks were added by the OPROM and the shadow address and
 | |
|   size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
 | |
| 
 | |
|   @param  This                   Protocol instance pointer.
 | |
|   @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
 | |
|                                  be loaded. This value is NULL if RomImage is
 | |
|                                  non-NULL. This is the normal case.
 | |
|   @param  RomImage               A PCI PC-AT ROM image. This argument is non-NULL
 | |
|                                  if there is no hardware associated with the ROM
 | |
|                                  and thus no PciHandle, otherwise is must be NULL.
 | |
|                                  Example is PXE base code.
 | |
|   @param  Flags                  Indicates if ROM found and if PC-AT.
 | |
|   @param  DiskStart              Disk number of first device hooked by the ROM. If
 | |
|                                  DiskStart is the same as DiskEnd no disked were
 | |
|                                  hooked.
 | |
|   @param  DiskEnd                Disk number of the last device hooked by the ROM.
 | |
|   @param  RomShadowAddress       Shadow address of PC-AT ROM
 | |
|   @param  RomShadowedSize        Size of RomShadowAddress in bytes
 | |
| 
 | |
|   @retval EFI_SUCCESS            Legacy ROM loaded for this device
 | |
|   @retval EFI_INVALID_PARAMETER  PciHandle not found
 | |
|   @retval EFI_UNSUPPORTED        There is no PCI ROM in the ROM BAR or no onboard
 | |
|                                  ROM
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LegacyBiosInstallPciRom (
 | |
|   IN EFI_LEGACY_BIOS_PROTOCOL           * This,
 | |
|   IN  EFI_HANDLE                        PciHandle,
 | |
|   IN  VOID                              **RomImage,
 | |
|   OUT UINTN                             *Flags,
 | |
|   OUT UINT8                             *DiskStart, OPTIONAL
 | |
|   OUT UINT8                             *DiskEnd, OPTIONAL
 | |
|   OUT VOID                              **RomShadowAddress, OPTIONAL
 | |
|   OUT UINT32                            *RomShadowedSize OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   LEGACY_BIOS_INSTANCE            *Private;
 | |
|   VOID                            *LocalRomImage;
 | |
|   UINTN                           ImageSize;
 | |
|   UINTN                           RuntimeImageLength;
 | |
|   EFI_PCI_IO_PROTOCOL             *PciIo;
 | |
|   PCI_TYPE01                      PciConfigHeader;
 | |
|   UINTN                           HandleCount;
 | |
|   EFI_HANDLE                      *HandleBuffer;
 | |
|   UINTN                           PciSegment;
 | |
|   UINTN                           PciBus;
 | |
|   UINTN                           PciDevice;
 | |
|   UINTN                           PciFunction;
 | |
|   UINTN                           LastBus;
 | |
|   UINTN                           Index;
 | |
|   UINT8                           OpromRevision;
 | |
|   UINT32                          Granularity;
 | |
|   PCI_3_0_DATA_STRUCTURE          *Pcir;
 | |
| 
 | |
|   OpromRevision = 0;
 | |
| 
 | |
|   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
 | |
|   if (Private->Legacy16Table->LastPciBus == 0) {
 | |
|     //
 | |
|     // Get last bus number if not already found
 | |
|     //
 | |
|     Status = gBS->LocateHandleBuffer (
 | |
|                     ByProtocol,
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     NULL,
 | |
|                     &HandleCount,
 | |
|                     &HandleBuffer
 | |
|                     );
 | |
| 
 | |
|     LastBus = 0;
 | |
|     for (Index = 0; Index < HandleCount; Index++) {
 | |
|       Status = gBS->HandleProtocol (
 | |
|                       HandleBuffer[Index],
 | |
|                       &gEfiPciIoProtocolGuid,
 | |
|                       (VOID **) &PciIo
 | |
|                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       Status = PciIo->GetLocation (
 | |
|                         PciIo,
 | |
|                         &PciSegment,
 | |
|                         &PciBus,
 | |
|                         &PciDevice,
 | |
|                         &PciFunction
 | |
|                         );
 | |
|       if (PciBus > LastBus) {
 | |
|         LastBus = PciBus;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Private->LegacyRegion->UnLock (
 | |
|                              Private->LegacyRegion,
 | |
|                              0xE0000,
 | |
|                              0x20000,
 | |
|                              &Granularity
 | |
|                              );
 | |
|     Private->Legacy16Table->LastPciBus = (UINT8) LastBus;
 | |
|     Private->LegacyRegion->Lock (
 | |
|                              Private->LegacyRegion,
 | |
|                              0xE0000,
 | |
|                              0x20000,
 | |
|                              &Granularity
 | |
|                              );
 | |
|   }
 | |
| 
 | |
|   *Flags = 0;
 | |
|   if ((PciHandle != NULL) && (RomImage == NULL)) {
 | |
|     //
 | |
|     // If PciHandle has OpRom to Execute
 | |
|     // and OpRom are all associated with Hardware
 | |
|     //
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     PciHandle,
 | |
|                     &gEfiPciIoProtocolGuid,
 | |
|                     (VOID **) &PciIo
 | |
|                     );
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       PciIo->Pci.Read (
 | |
|                    PciIo,
 | |
|                    EfiPciIoWidthUint32,
 | |
|                    0,
 | |
|                    sizeof (PciConfigHeader) / sizeof (UINT32),
 | |
|                    &PciConfigHeader
 | |
|                    );
 | |
| 
 | |
|       //
 | |
|       // if video installed & OPROM is video return
 | |
|       //
 | |
|       if (
 | |
|           (
 | |
|            ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&
 | |
|             (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))
 | |
|            ||
 | |
|            ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&
 | |
|             (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))
 | |
|           )
 | |
|           &&
 | |
|           (!Private->VgaInstalled)
 | |
|          ) {
 | |
|         mVgaInstallationInProgress = TRUE;
 | |
| 
 | |
|         //
 | |
|         //      return EFI_UNSUPPORTED;
 | |
|         //
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // To run any legacy image, the VGA needs to be installed first.
 | |
|     // if installing the video, then don't need the thunk as already installed.
 | |
|     //
 | |
|     Status = Private->LegacyBiosPlatform->GetPlatformHandle (
 | |
|                                             Private->LegacyBiosPlatform,
 | |
|                                             EfiGetPlatformVgaHandle,
 | |
|                                             0,
 | |
|                                             &HandleBuffer,
 | |
|                                             &HandleCount,
 | |
|                                             NULL
 | |
|                                             );
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       mVgaHandle = HandleBuffer[0];
 | |
|       if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {
 | |
|         //
 | |
|         // A return status of EFI_NOT_FOUND is considered valid (No EFI
 | |
|         // driver is controlling video.
 | |
|         //
 | |
|         mVgaInstallationInProgress  = TRUE;
 | |
|         Status                      = LegacyBiosInstallVgaRom (Private);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           if (Status != EFI_NOT_FOUND) {
 | |
|             mVgaInstallationInProgress = FALSE;
 | |
|             return Status;
 | |
|           }
 | |
|         } else {
 | |
|           mVgaInstallationInProgress = FALSE;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // See if the option ROM for PciHandle has already been executed
 | |
|     //
 | |
|     Status = IsLegacyRom (PciHandle);
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       mVgaInstallationInProgress = FALSE;
 | |
|       GetShadowedRomParameters (
 | |
|         PciHandle,
 | |
|         DiskStart,
 | |
|         DiskEnd,
 | |
|         RomShadowAddress,
 | |
|         (UINTN *) RomShadowedSize
 | |
|         );
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Status = LegacyBiosCheckPciRomEx (
 | |
|                &Private->LegacyBios,
 | |
|                PciHandle,
 | |
|                &LocalRomImage,
 | |
|                &ImageSize,
 | |
|                &RuntimeImageLength,
 | |
|                Flags,
 | |
|                &OpromRevision,
 | |
|                NULL
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // There is no PCI ROM in the ROM BAR or no onboard ROM
 | |
|       //
 | |
|       mVgaInstallationInProgress = FALSE;
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
|   } else {
 | |
|     if ((RomImage == NULL) || (*RomImage == NULL)) {
 | |
|       //
 | |
|       // If PciHandle is NULL, and no OpRom is to be associated
 | |
|       //
 | |
|       mVgaInstallationInProgress = FALSE;
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     Status = Private->LegacyBiosPlatform->GetPlatformHandle (
 | |
|                                             Private->LegacyBiosPlatform,
 | |
|                                             EfiGetPlatformVgaHandle,
 | |
|                                             0,
 | |
|                                             &HandleBuffer,
 | |
|                                             &HandleCount,
 | |
|                                             NULL
 | |
|                                             );
 | |
|     if ((!EFI_ERROR (Status)) && (!Private->VgaInstalled)) {
 | |
|       //
 | |
|       // A return status of EFI_NOT_FOUND is considered valid (No EFI
 | |
|       // driver is controlling video.
 | |
|       //
 | |
|       mVgaInstallationInProgress  = TRUE;
 | |
|       Status                      = LegacyBiosInstallVgaRom (Private);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         if (Status != EFI_NOT_FOUND) {
 | |
|           mVgaInstallationInProgress = FALSE;
 | |
|           return Status;
 | |
|         }
 | |
|       } else {
 | |
|         mVgaInstallationInProgress = FALSE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     LocalRomImage = *RomImage;
 | |
|     if (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE ||
 | |
|         ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset == 0 ||
 | |
|         (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset & 3 ) != 0) {
 | |
|       mVgaInstallationInProgress = FALSE;
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     Pcir = (PCI_3_0_DATA_STRUCTURE *)
 | |
|            ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);
 | |
| 
 | |
|     if ((Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) || (Pcir->CodeType != PCI_CODE_TYPE_PCAT_IMAGE)) {
 | |
|       mVgaInstallationInProgress = FALSE;
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     ImageSize = Pcir->ImageLength * 512;
 | |
|     if (Pcir->Length >= 0x1C) {
 | |
|       OpromRevision = Pcir->Revision;
 | |
|     } else {
 | |
|       OpromRevision = 0;
 | |
|     }
 | |
|     if (Pcir->Revision < 3) {
 | |
|       RuntimeImageLength = 0;
 | |
|     } else {
 | |
|       RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Grant access for below 1M
 | |
|   // BDA/EBDA/LowPMM and scratch memory for OPROM.
 | |
|   //
 | |
|   IoMmuGrantAccess (PciHandle, 0, SIZE_1MB);
 | |
|   //
 | |
|   // Grant access for HiPmm
 | |
|   //
 | |
|   IoMmuGrantAccess (
 | |
|     PciHandle,
 | |
|     Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemory,
 | |
|     Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemorySizeInBytes
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Shadow and initialize the OpROM.
 | |
|   //
 | |
|   ASSERT (Private->TraceIndex < 0x200);
 | |
|   Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;
 | |
|   Private->TraceIndex ++;
 | |
|   Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);
 | |
|   Status = LegacyBiosInstallRom (
 | |
|              This,
 | |
|              Private,
 | |
|              PciHandle,
 | |
|              OpromRevision,
 | |
|              LocalRomImage,
 | |
|              ImageSize,
 | |
|              &RuntimeImageLength,
 | |
|              DiskStart,
 | |
|              DiskEnd,
 | |
|              RomShadowAddress
 | |
|              );
 | |
|   if (RomShadowedSize != NULL) {
 | |
|     *RomShadowedSize = (UINT32) RuntimeImageLength;
 | |
|   }
 | |
| 
 | |
|   mVgaInstallationInProgress = FALSE;
 | |
|   return Status;
 | |
| }
 | |
| 
 |