Home | History | Annotate | Download | only in LegacyBiosDxe
      1 /** @file
      2 
      3 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      4 
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions
      7 of the BSD License which accompanies this distribution.  The
      8 full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "LegacyBiosInterface.h"
     17 #include <IndustryStandard/Pci30.h>
     18 
     19 #define PCI_START_ADDRESS(x)   (((x) + 0x7ff) & ~0x7ff)
     20 
     21 #define MAX_BRIDGE_INDEX  0x20
     22 typedef struct {
     23   UINTN PciSegment;
     24   UINTN PciBus;
     25   UINTN PciDevice;
     26   UINTN PciFunction;
     27   UINT8 PrimaryBus;
     28   UINT8 SecondaryBus;
     29   UINT8 SubordinateBus;
     30 } BRIDGE_TABLE;
     31 
     32 #define ROM_MAX_ENTRIES 24
     33 BRIDGE_TABLE                        Bridges[MAX_BRIDGE_INDEX];
     34 UINTN                               SortedBridgeIndex[MAX_BRIDGE_INDEX];
     35 UINTN                               NumberOfBridges;
     36 LEGACY_PNP_EXPANSION_HEADER  *mBasePnpPtr;
     37 UINT16                              mBbsRomSegment;
     38 UINTN                               mHandleCount;
     39 EFI_HANDLE                          mVgaHandle;
     40 BOOLEAN                             mIgnoreBbsUpdateFlag;
     41 BOOLEAN                             mVgaInstallationInProgress  = FALSE;
     42 UINT32                              mRomCount                   = 0x00;
     43 ROM_INSTANCE_ENTRY                  mRomEntry[ROM_MAX_ENTRIES];
     44 
     45 
     46 /**
     47   Query shadowed legacy ROM parameters registered by RomShadow() previously.
     48 
     49   @param  PciHandle        PCI device whos ROM has been shadowed
     50   @param  DiskStart        DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
     51   @param  DiskEnd          DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
     52   @param  RomShadowAddress Address where ROM was shadowed
     53   @param  ShadowedSize     Runtime size of ROM
     54 
     55   @retval EFI_SUCCESS      Query Logging successful.
     56   @retval EFI_NOT_FOUND    No logged data found about PciHandle.
     57 
     58 **/
     59 EFI_STATUS
     60 GetShadowedRomParameters (
     61   IN EFI_HANDLE                         PciHandle,
     62   OUT UINT8                             *DiskStart,         OPTIONAL
     63   OUT UINT8                             *DiskEnd,           OPTIONAL
     64   OUT VOID                              **RomShadowAddress, OPTIONAL
     65   OUT UINTN                             *ShadowedSize       OPTIONAL
     66   )
     67 {
     68   EFI_STATUS          Status;
     69   EFI_PCI_IO_PROTOCOL *PciIo;
     70   UINTN               Index;
     71   UINTN               PciSegment;
     72   UINTN               PciBus;
     73   UINTN               PciDevice;
     74   UINTN               PciFunction;
     75 
     76   //
     77   // Get the PCI I/O Protocol on PciHandle
     78   //
     79   Status = gBS->HandleProtocol (
     80                   PciHandle,
     81                   &gEfiPciIoProtocolGuid,
     82                   (VOID **) &PciIo
     83                   );
     84   if (EFI_ERROR (Status)) {
     85     return Status;
     86   }
     87 
     88   //
     89   // Get the location of the PCI device
     90   //
     91   PciIo->GetLocation (
     92            PciIo,
     93            &PciSegment,
     94            &PciBus,
     95            &PciDevice,
     96            &PciFunction
     97            );
     98 
     99   for(Index = 0; Index < mRomCount; Index++) {
    100     if ((mRomEntry[Index].PciSegment == PciSegment) &&
    101         (mRomEntry[Index].PciBus == PciBus)         &&
    102         (mRomEntry[Index].PciDevice == PciDevice)   &&
    103         (mRomEntry[Index].PciFunction == PciFunction)) {
    104       break;
    105     }
    106   }
    107 
    108   if (Index == mRomCount) {
    109     return EFI_NOT_FOUND;
    110   }
    111 
    112   if (DiskStart != NULL) {
    113     *DiskStart = mRomEntry[Index].DiskStart;
    114   }
    115 
    116   if (DiskEnd != NULL) {
    117     *DiskEnd = mRomEntry[Index].DiskEnd;
    118   }
    119 
    120   if (RomShadowAddress != NULL) {
    121     *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;
    122   }
    123 
    124   if (ShadowedSize != NULL) {
    125     *ShadowedSize = mRomEntry[Index].ShadowedSize;
    126   }
    127 
    128   return EFI_SUCCESS;
    129 }
    130 
    131 /**
    132   Every legacy ROM that is shadowed by the Legacy BIOS driver will be
    133   registered into this API so that the policy code can know what has
    134   happend
    135 
    136   @param  PciHandle              PCI device whos ROM is being shadowed
    137   @param  ShadowAddress          Address that ROM was shadowed
    138   @param  ShadowedSize           Runtime size of ROM
    139   @param  DiskStart              DiskStart value from
    140                                  EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
    141   @param  DiskEnd                DiskEnd value from
    142                                  EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
    143 
    144   @retval EFI_SUCCESS            Logging successful.
    145   @retval EFI_OUT_OF_RESOURCES   No remaining room for registering another option
    146                                  ROM.
    147 
    148 **/
    149 EFI_STATUS
    150 RomShadow (
    151   IN  EFI_HANDLE                                  PciHandle,
    152   IN  UINT32                                      ShadowAddress,
    153   IN  UINT32                                      ShadowedSize,
    154   IN  UINT8                                       DiskStart,
    155   IN  UINT8                                       DiskEnd
    156   )
    157 {
    158   EFI_STATUS          Status;
    159   EFI_PCI_IO_PROTOCOL *PciIo;
    160 
    161   //
    162   // See if there is room to register another option ROM
    163   //
    164   if (mRomCount >= ROM_MAX_ENTRIES) {
    165     return EFI_OUT_OF_RESOURCES;
    166   }
    167   //
    168   // Get the PCI I/O Protocol on PciHandle
    169   //
    170   Status = gBS->HandleProtocol (
    171                   PciHandle,
    172                   &gEfiPciIoProtocolGuid,
    173                   (VOID **) &PciIo
    174                   );
    175   if (EFI_ERROR (Status)) {
    176     return Status;
    177   }
    178   //
    179   // Get the location of the PCI device
    180   //
    181   PciIo->GetLocation (
    182            PciIo,
    183            &mRomEntry[mRomCount].PciSegment,
    184            &mRomEntry[mRomCount].PciBus,
    185            &mRomEntry[mRomCount].PciDevice,
    186            &mRomEntry[mRomCount].PciFunction
    187            );
    188   mRomEntry[mRomCount].ShadowAddress = ShadowAddress;
    189   mRomEntry[mRomCount].ShadowedSize  = ShadowedSize;
    190   mRomEntry[mRomCount].DiskStart     = DiskStart;
    191   mRomEntry[mRomCount].DiskEnd       = DiskEnd;
    192 
    193   mRomCount++;
    194 
    195   return EFI_SUCCESS;
    196 }
    197 
    198 
    199 /**
    200   Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
    201   information represents every call to RomShadow ()
    202 
    203   @param  PciHandle              PCI device to get status for
    204 
    205   @retval EFI_SUCCESS            Legacy ROM loaded for this device
    206   @retval EFI_NOT_FOUND          No Legacy ROM loaded for this device
    207 
    208 **/
    209 EFI_STATUS
    210 IsLegacyRom (
    211   IN  EFI_HANDLE                PciHandle
    212   )
    213 {
    214   EFI_STATUS          Status;
    215   EFI_PCI_IO_PROTOCOL *PciIo;
    216   UINTN               Index;
    217   UINTN               Segment;
    218   UINTN               Bus;
    219   UINTN               Device;
    220   UINTN               Function;
    221 
    222   //
    223   // Get the PCI I/O Protocol on PciHandle
    224   //
    225   Status = gBS->HandleProtocol (
    226                   PciHandle,
    227                   &gEfiPciIoProtocolGuid,
    228                   (VOID **) &PciIo
    229                   );
    230   if (EFI_ERROR (Status)) {
    231     return Status;
    232   }
    233   //
    234   // Get the location of the PCI device
    235   //
    236   PciIo->GetLocation (
    237            PciIo,
    238            &Segment,
    239            &Bus,
    240            &Device,
    241            &Function
    242            );
    243 
    244   //
    245   // See if the option ROM from PciHandle has been previously posted
    246   //
    247   for (Index = 0; Index < mRomCount; Index++) {
    248     if (mRomEntry[Index].PciSegment == Segment &&
    249         mRomEntry[Index].PciBus == Bus &&
    250         mRomEntry[Index].PciDevice == Device &&
    251         mRomEntry[Index].PciFunction == Function
    252         ) {
    253       return EFI_SUCCESS;
    254     }
    255   }
    256 
    257   return EFI_NOT_FOUND;
    258 }
    259 
    260 /**
    261   Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
    262   related information from the header.
    263 
    264   @param  Csm16Revision           The PCI interface version of underlying CSM16
    265   @param  VendorId                Vendor ID of the PCI device
    266   @param  DeviceId                Device ID of the PCI device
    267   @param  Rom                     On input pointing to beginning of the raw PCI OpROM
    268                                   On output pointing to the first legacy PCI OpROM
    269   @param  ImageSize               On input is the size of Raw PCI Rom
    270                                   On output is the size of the first legacy PCI ROM
    271   @param  MaxRuntimeImageLength   The max runtime image length only valid if OpRomRevision >= 3
    272   @param  OpRomRevision           Revision of the PCI Rom
    273   @param  ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
    274 
    275   @retval EFI_SUCCESS             Successfully find the legacy PCI ROM
    276   @retval EFI_NOT_FOUND           Failed to find the legacy PCI ROM
    277 
    278 **/
    279 EFI_STATUS
    280 GetPciLegacyRom (
    281   IN     UINT16 Csm16Revision,
    282   IN     UINT16 VendorId,
    283   IN     UINT16 DeviceId,
    284   IN OUT VOID   **Rom,
    285   IN OUT UINTN  *ImageSize,
    286   OUT    UINTN  *MaxRuntimeImageLength,   OPTIONAL
    287   OUT    UINT8  *OpRomRevision,           OPTIONAL
    288   OUT    VOID   **ConfigUtilityCodeHeader OPTIONAL
    289   )
    290 {
    291   BOOLEAN                 Match;
    292   UINT16                  *DeviceIdList;
    293   EFI_PCI_ROM_HEADER      RomHeader;
    294   PCI_3_0_DATA_STRUCTURE  *Pcir;
    295   VOID                    *BackupImage;
    296   VOID                    *BestImage;
    297 
    298 
    299   if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {
    300     return EFI_NOT_FOUND;
    301   }
    302 
    303   BestImage     = NULL;
    304   BackupImage   = NULL;
    305   RomHeader.Raw = *Rom;
    306   while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
    307     if (RomHeader.Generic->PcirOffset == 0 ||
    308         (RomHeader.Generic->PcirOffset & 3) !=0 ||
    309         *ImageSize < RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)) {
    310       break;
    311     }
    312 
    313     Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
    314     //
    315     // Check signature in the PCI Data Structure.
    316     //
    317     if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
    318       break;
    319     }
    320 
    321     if ((UINTN)(RomHeader.Raw - (UINT8 *) *Rom) + Pcir->ImageLength * 512 > *ImageSize) {
    322       break;
    323     }
    324 
    325     if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
    326       Match = FALSE;
    327       if (Pcir->VendorId == VendorId) {
    328         if (Pcir->DeviceId == DeviceId) {
    329           Match = TRUE;
    330         } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {
    331           DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);
    332           //
    333           // Checking the device list
    334           //
    335           while (*DeviceIdList != 0) {
    336             if (*DeviceIdList == DeviceId) {
    337               Match = TRUE;
    338               break;
    339             }
    340             DeviceIdList ++;
    341           }
    342         }
    343       }
    344 
    345       if (Match) {
    346         if (Csm16Revision >= 0x0300) {
    347           //
    348           // Case 1: CSM16 3.0
    349           //
    350           if (Pcir->Revision >= 3) {
    351             //
    352             // case 1.1: meets OpRom 3.0
    353             //           Perfect!!!
    354             //
    355             BestImage  = RomHeader.Raw;
    356             break;
    357           } else {
    358             //
    359             // case 1.2: meets OpRom 2.x
    360             //           Store it and try to find the OpRom 3.0
    361             //
    362             BackupImage = RomHeader.Raw;
    363           }
    364         } else {
    365           //
    366           // Case 2: CSM16 2.x
    367           //
    368           if (Pcir->Revision >= 3) {
    369             //
    370             // case 2.1: meets OpRom 3.0
    371             //           Store it and try to find the OpRom 2.x
    372             //
    373             BackupImage = RomHeader.Raw;
    374           } else {
    375             //
    376             // case 2.2: meets OpRom 2.x
    377             //           Perfect!!!
    378             //
    379             BestImage   = RomHeader.Raw;
    380             break;
    381           }
    382         }
    383       } else {
    384         DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));
    385       }
    386     }
    387 
    388     if ((Pcir->Indicator & 0x80) == 0x80) {
    389       break;
    390     } else {
    391       RomHeader.Raw += 512 * Pcir->ImageLength;
    392     }
    393   }
    394 
    395   if (BestImage == NULL) {
    396     if (BackupImage == NULL) {
    397       return EFI_NOT_FOUND;
    398     }
    399     //
    400     // The versions of CSM16 and OpRom don't match exactly
    401     //
    402     BestImage = BackupImage;
    403   }
    404   RomHeader.Raw = BestImage;
    405   Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
    406   *Rom       = BestImage;
    407   *ImageSize = Pcir->ImageLength * 512;
    408 
    409   if (MaxRuntimeImageLength != NULL) {
    410     if (Pcir->Revision < 3) {
    411       *MaxRuntimeImageLength = 0;
    412     } else {
    413       *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
    414     }
    415   }
    416 
    417   if (OpRomRevision != NULL) {
    418     //
    419     // Optional return PCI Data Structure revision
    420     //
    421     if (Pcir->Length >= 0x1C) {
    422       *OpRomRevision = Pcir->Revision;
    423     } else {
    424       *OpRomRevision = 0;
    425     }
    426   }
    427 
    428   if (ConfigUtilityCodeHeader != NULL) {
    429     //
    430     // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
    431     //
    432     if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {
    433       *ConfigUtilityCodeHeader = NULL;
    434     } else {
    435       *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;
    436     }
    437   }
    438 
    439   return EFI_SUCCESS;
    440 }
    441 
    442 /**
    443   Build a table of bridge info for PIRQ translation.
    444 
    445   @param  RoutingTable         RoutingTable obtained from Platform.
    446   @param  RoutingTableEntries  Number of RoutingTable entries.
    447 
    448   @retval EFI_SUCCESS          New Subordinate bus.
    449   @retval EFI_NOT_FOUND        No more Subordinate busses.
    450 
    451 **/
    452 EFI_STATUS
    453 CreateBridgeTable (
    454   IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,
    455   IN UINTN                                RoutingTableEntries
    456   )
    457 {
    458   EFI_STATUS          Status;
    459   UINTN               HandleCount;
    460   EFI_HANDLE          *HandleBuffer;
    461   UINTN               BridgeIndex;
    462   UINTN               Index;
    463   UINTN               Index1;
    464   EFI_PCI_IO_PROTOCOL *PciIo;
    465   PCI_TYPE01          PciConfigHeader;
    466   BRIDGE_TABLE        SlotBridges[MAX_BRIDGE_INDEX];
    467   UINTN               SlotBridgeIndex;
    468 
    469   BridgeIndex = 0x00;
    470   SlotBridgeIndex = 0x00;
    471 
    472   //
    473   // Assumption is table is built from low bus to high bus numbers.
    474   //
    475   Status = gBS->LocateHandleBuffer (
    476                   ByProtocol,
    477                   &gEfiPciIoProtocolGuid,
    478                   NULL,
    479                   &HandleCount,
    480                   &HandleBuffer
    481                   );
    482   if (EFI_ERROR (Status)) {
    483     return EFI_NOT_FOUND;
    484   }
    485   for (Index = 0; Index < HandleCount; Index++) {
    486     Status = gBS->HandleProtocol (
    487                     HandleBuffer[Index],
    488                     &gEfiPciIoProtocolGuid,
    489                     (VOID **) &PciIo
    490                     );
    491     if (EFI_ERROR (Status)) {
    492       continue;
    493     }
    494 
    495     PciIo->Pci.Read (
    496                  PciIo,
    497                  EfiPciIoWidthUint32,
    498                  0,
    499                  sizeof (PciConfigHeader) / sizeof (UINT32),
    500                  &PciConfigHeader
    501                  );
    502 
    503     if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {
    504       PciIo->GetLocation (
    505                PciIo,
    506                &Bridges[BridgeIndex].PciSegment,
    507                &Bridges[BridgeIndex].PciBus,
    508                &Bridges[BridgeIndex].PciDevice,
    509                &Bridges[BridgeIndex].PciFunction
    510                );
    511 
    512       Bridges[BridgeIndex].PrimaryBus     = PciConfigHeader.Bridge.PrimaryBus;
    513 
    514       Bridges[BridgeIndex].SecondaryBus   = PciConfigHeader.Bridge.SecondaryBus;
    515 
    516       Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;
    517 
    518       for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){
    519         //
    520         // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
    521         // Once we find one, store it in the SlotBridges[]
    522         //
    523         if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)
    524            && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {
    525           CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));
    526           SlotBridgeIndex++;
    527 
    528           break;
    529         }
    530       }
    531 
    532       ++BridgeIndex;
    533     }
    534   }
    535 
    536   //
    537   // Pack up Bridges by removing those useless ones
    538   //
    539   for (Index = 0; Index < BridgeIndex;){
    540     for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {
    541       if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||
    542         ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {
    543         //
    544         // We have found one that meets our criteria
    545         //
    546         Index++;
    547         break;
    548       }
    549     }
    550 
    551     //
    552     // This one doesn't meet criteria, pack it
    553     //
    554     if (Index1 >= SlotBridgeIndex) {
    555       for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {
    556         CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));
    557       }
    558 
    559       BridgeIndex--;
    560     }
    561   }
    562 
    563   NumberOfBridges = BridgeIndex;
    564 
    565   //
    566   // Sort bridges low to high by Secondary bus followed by subordinate bus
    567   //
    568   if (NumberOfBridges > 1) {
    569     Index = 0;
    570     do {
    571       SortedBridgeIndex[Index] = Index;
    572       ++Index;
    573     } while (Index < NumberOfBridges);
    574 
    575     for (Index = 0; Index < NumberOfBridges - 1; Index++) {
    576       for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {
    577         if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {
    578           SortedBridgeIndex[Index]  = Index1;
    579           SortedBridgeIndex[Index1] = Index;
    580         }
    581 
    582         if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&
    583             (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)
    584             ) {
    585           SortedBridgeIndex[Index]  = Index1;
    586           SortedBridgeIndex[Index1] = Index;
    587         }
    588       }
    589     }
    590   }
    591   FreePool (HandleBuffer);
    592   return EFI_SUCCESS;
    593 }
    594 
    595 
    596 /**
    597   Find base Bridge for device.
    598 
    599   @param  Private                Legacy  BIOS Instance data
    600   @param  PciBus                 Input = Bus of device.
    601   @param  PciDevice              Input = Device.
    602   @param  RoutingTable           The platform specific routing table
    603   @param  RoutingTableEntries    Number of entries in table
    604 
    605   @retval EFI_SUCCESS            At base bus.
    606   @retval EFI_NOT_FOUND          Behind a bridge.
    607 
    608 **/
    609 EFI_STATUS
    610 GetBaseBus (
    611   IN  LEGACY_BIOS_INSTANCE        *Private,
    612   IN UINTN                        PciBus,
    613   IN UINTN                        PciDevice,
    614   IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
    615   IN UINTN                        RoutingTableEntries
    616   )
    617 {
    618   UINTN Index;
    619   for (Index = 0; Index < RoutingTableEntries; Index++) {
    620     if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {
    621       return EFI_SUCCESS;
    622     }
    623   }
    624 
    625   return EFI_NOT_FOUND;
    626 }
    627 
    628 /**
    629   Translate PIRQ through busses
    630 
    631   @param  Private              Legacy  BIOS Instance data
    632   @param  PciBus               Input = Bus of device. Output = Translated Bus
    633   @param  PciDevice            Input = Device. Output = Translated Device
    634   @param  PciFunction          Input = Function. Output = Translated Function
    635   @param  PirqIndex            Input = Original PIRQ index. If single function
    636                                   device then 0, otherwise 0-3.
    637                                Output = Translated Index
    638 
    639   @retval EFI_SUCCESS          Pirq successfully translated.
    640   @retval EFI_NOT_FOUND        The device is not behind any known bridge.
    641 
    642 **/
    643 EFI_STATUS
    644 TranslateBusPirq (
    645   IN  LEGACY_BIOS_INSTANCE            *Private,
    646   IN OUT UINTN                        *PciBus,
    647   IN OUT UINTN                        *PciDevice,
    648   IN OUT UINTN                        *PciFunction,
    649   IN OUT UINT8                        *PirqIndex
    650   )
    651 {
    652   /*
    653   This routine traverses the PCI busses from base slot
    654   and translates the PIRQ register to the appropriate one.
    655 
    656   Example:
    657 
    658   Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
    659     Primary bus# = 0
    660     Secondary bus # = 1
    661     Subordinate bus # is highest bus # behind this bus
    662        Bus 1, Device 0 is Slot 0 and is not a bridge.
    663        Bus 1, Device 1 is Slot 1 and is a bridge.
    664          Slot PIRQ routing is A,B,C,D.
    665          Primary bus # = 1
    666          Secondary bus # = 2
    667          Subordinate bus # = 5
    668             Bus 2, Device 6 is a bridge. It has no bridges behind it.
    669               Primary bus # = 2
    670               Secondary bus # = 3
    671               Subordinate bus # = 3
    672               Bridge PIRQ routing is C,D,A,B
    673             Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
    674               Primary bus # = 2
    675               Secondary bus = 4   Device 6 takes bus 2.
    676               Subordinate bus = 5.
    677               Bridge PIRQ routing is D,A,B,C
    678                  Bus 4, Device 2 is a bridge. It has no bridges behind it.
    679                    Primary bus # = 4
    680                    Secondary bus # = 5
    681                    Subordinate bus = 5
    682                    Bridge PIRQ routing is B,C,D,A
    683                       Bus 5, Device 1 is to be programmed.
    684                          Device PIRQ routing is C,D,A,B
    685 
    686 
    687 Search busses starting from slot bus for final bus >= Secondary bus and
    688 final bus <= Suborninate bus. Assumption is bus entries increase in bus
    689 number.
    690 Starting PIRQ is A,B,C,D.
    691 Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
    692   7 modulo 4 giving (D,A,B,C).
    693 Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
    694   (B,C,D,A).
    695 No other busses match criteria. Device to be programmed is Bus 5, Device 1.
    696 Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
    697 
    698 */
    699   UINTN LocalBus;
    700   UINTN LocalDevice;
    701   UINTN BaseBus;
    702   UINTN BaseDevice;
    703   UINTN BaseFunction;
    704   UINT8 LocalPirqIndex;
    705   BOOLEAN BaseIndexFlag;
    706   UINTN BridgeIndex;
    707   UINTN SBridgeIndex;
    708   BaseIndexFlag   = FALSE;
    709   BridgeIndex     = 0x00;
    710 
    711   LocalPirqIndex  = *PirqIndex;
    712   LocalBus        = *PciBus;
    713   LocalDevice     = *PciDevice;
    714   BaseBus         = *PciBus;
    715   BaseDevice      = *PciDevice;
    716   BaseFunction    = *PciFunction;
    717 
    718   //
    719   // LocalPirqIndex list PIRQs in rotated fashion
    720   // = 0  A,B,C,D
    721   // = 1  B,C,D,A
    722   // = 2  C,D,A,B
    723   // = 3  D,A,B,C
    724   //
    725 
    726   for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {
    727     SBridgeIndex = SortedBridgeIndex[BridgeIndex];
    728     //
    729     // Check if device behind this bridge
    730     //
    731     if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {
    732       //
    733       // If BaseIndexFlag = FALSE then have found base bridge, i.e
    734       // bridge in slot. Save info for use by IRQ routing table.
    735       //
    736       if (!BaseIndexFlag) {
    737         BaseBus       = Bridges[SBridgeIndex].PciBus;
    738         BaseDevice    = Bridges[SBridgeIndex].PciDevice;
    739         BaseFunction  = Bridges[SBridgeIndex].PciFunction;
    740         BaseIndexFlag = TRUE;
    741       } else {
    742         LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);
    743       }
    744 
    745       //
    746       // Check if at device. If not get new PCI location & PIRQ
    747       //
    748       if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {
    749         //
    750         // Translate PIRQ
    751         //
    752         LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);
    753         break;
    754       }
    755     }
    756   }
    757 
    758   //
    759   // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
    760   //
    761   if(BridgeIndex >= NumberOfBridges){
    762     DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));
    763   }
    764 
    765   *PirqIndex    = LocalPirqIndex;
    766   *PciBus       = BaseBus;
    767   *PciDevice    = BaseDevice;
    768   *PciFunction  = BaseFunction;
    769 
    770   return EFI_SUCCESS;
    771 }
    772 
    773 
    774 /**
    775   Copy the $PIR table as required.
    776 
    777   @param  Private                Legacy  BIOS Instance data
    778   @param  RoutingTable           Pointer to IRQ routing table
    779   @param  RoutingTableEntries    IRQ routing table entries
    780   @param  PirqTable              Pointer to $PIR table
    781   @param  PirqTableSize          Length of table
    782 
    783 **/
    784 VOID
    785 CopyPirqTable (
    786   IN  LEGACY_BIOS_INSTANCE                *Private,
    787   IN EFI_LEGACY_IRQ_ROUTING_ENTRY         *RoutingTable,
    788   IN UINTN                                RoutingTableEntries,
    789   IN EFI_LEGACY_PIRQ_TABLE_HEADER         *PirqTable,
    790   IN UINTN                                PirqTableSize
    791   )
    792 {
    793   EFI_IA32_REGISTER_SET Regs;
    794   UINT32                Granularity;
    795 
    796   //
    797   // Copy $PIR table, if it exists.
    798   //
    799   if (PirqTable != NULL) {
    800     Private->LegacyRegion->UnLock (
    801                             Private->LegacyRegion,
    802                             0xE0000,
    803                             0x20000,
    804                             &Granularity
    805                             );
    806 
    807     Private->InternalIrqRoutingTable  = RoutingTable;
    808     Private->NumberIrqRoutingEntries  = (UINT16) (RoutingTableEntries);
    809     ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    810 
    811     Regs.X.AX = Legacy16GetTableAddress;
    812     Regs.X.CX = (UINT16) PirqTableSize;
    813     //
    814     // Allocate at F segment according to PCI IRQ Routing Table Specification
    815     //
    816     Regs.X.BX = (UINT16) 0x1;
    817     //
    818     // 16-byte boundary alignment requirement according to
    819     // PCI IRQ Routing Table Specification
    820     //
    821     Regs.X.DX = 0x10;
    822     Private->LegacyBios.FarCall86 (
    823       &Private->LegacyBios,
    824       Private->Legacy16CallSegment,
    825       Private->Legacy16CallOffset,
    826       &Regs,
    827       NULL,
    828       0
    829       );
    830 
    831     Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
    832     if (Regs.X.AX != 0) {
    833       DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));
    834     } else {
    835       DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));
    836       Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;
    837       CopyMem (
    838         (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,
    839         PirqTable,
    840         PirqTableSize
    841         );
    842     }
    843 
    844     Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
    845     Private->LegacyRegion->Lock (
    846                              Private->LegacyRegion,
    847                              0xE0000,
    848                              0x20000,
    849                              &Granularity
    850                              );
    851   }
    852 
    853   Private->PciInterruptLine = TRUE;
    854   mHandleCount              = 0;
    855 }
    856 
    857 /**
    858   Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
    859 
    860   @param  PciHandle               The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
    861 
    862 **/
    863 VOID
    864 DumpPciHandle (
    865   IN EFI_LEGACY_INSTALL_PCI_HANDLER  *PciHandle
    866   )
    867 {
    868   DEBUG ((EFI_D_INFO, "PciBus             - %02x\n", (UINTN)PciHandle->PciBus));
    869   DEBUG ((EFI_D_INFO, "PciDeviceFun       - %02x\n", (UINTN)PciHandle->PciDeviceFun));
    870   DEBUG ((EFI_D_INFO, "PciSegment         - %02x\n", (UINTN)PciHandle->PciSegment));
    871   DEBUG ((EFI_D_INFO, "PciClass           - %02x\n", (UINTN)PciHandle->PciClass));
    872   DEBUG ((EFI_D_INFO, "PciSubclass        - %02x\n", (UINTN)PciHandle->PciSubclass));
    873   DEBUG ((EFI_D_INFO, "PciInterface       - %02x\n", (UINTN)PciHandle->PciInterface));
    874 
    875   DEBUG ((EFI_D_INFO, "PrimaryIrq         - %02x\n", (UINTN)PciHandle->PrimaryIrq));
    876   DEBUG ((EFI_D_INFO, "PrimaryReserved    - %02x\n", (UINTN)PciHandle->PrimaryReserved));
    877   DEBUG ((EFI_D_INFO, "PrimaryControl     - %04x\n", (UINTN)PciHandle->PrimaryControl));
    878   DEBUG ((EFI_D_INFO, "PrimaryBase        - %04x\n", (UINTN)PciHandle->PrimaryBase));
    879   DEBUG ((EFI_D_INFO, "PrimaryBusMaster   - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));
    880 
    881   DEBUG ((EFI_D_INFO, "SecondaryIrq       - %02x\n", (UINTN)PciHandle->SecondaryIrq));
    882   DEBUG ((EFI_D_INFO, "SecondaryReserved  - %02x\n", (UINTN)PciHandle->SecondaryReserved));
    883   DEBUG ((EFI_D_INFO, "SecondaryControl   - %04x\n", (UINTN)PciHandle->SecondaryControl));
    884   DEBUG ((EFI_D_INFO, "SecondaryBase      - %04x\n", (UINTN)PciHandle->SecondaryBase));
    885   DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));
    886   return;
    887 }
    888 
    889 /**
    890   Copy the $PIR table as required.
    891 
    892   @param  Private                Legacy  BIOS Instance data
    893   @param  PciIo                  Pointer to PCI_IO protocol
    894   @param  PciIrq                 Pci IRQ number
    895   @param  PciConfigHeader        Type00 Pci configuration header
    896 
    897 **/
    898 VOID
    899 InstallLegacyIrqHandler (
    900   IN LEGACY_BIOS_INSTANCE       *Private,
    901   IN EFI_PCI_IO_PROTOCOL        *PciIo,
    902   IN UINT8                      PciIrq,
    903   IN PCI_TYPE00                 *PciConfigHeader
    904   )
    905 {
    906   EFI_IA32_REGISTER_SET     Regs;
    907   UINT16                    LegMask;
    908   UINTN                     PciSegment;
    909   UINTN                     PciBus;
    910   UINTN                     PciDevice;
    911   UINTN                     PciFunction;
    912   EFI_LEGACY_8259_PROTOCOL  *Legacy8259;
    913   UINT16                    PrimaryMaster;
    914   UINT16                    SecondaryMaster;
    915   UINTN                     TempData;
    916   UINTN                     RegisterAddress;
    917   UINT32                    Granularity;
    918 
    919   PrimaryMaster   = 0;
    920   SecondaryMaster = 0;
    921   Legacy8259      = Private->Legacy8259;
    922   //
    923   // Disable interrupt in PIC, in case shared, to prevent an
    924   // interrupt from occuring.
    925   //
    926   Legacy8259->GetMask (
    927                 Legacy8259,
    928                 &LegMask,
    929                 NULL,
    930                 NULL,
    931                 NULL
    932                 );
    933 
    934   LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));
    935 
    936   Legacy8259->SetMask (
    937                 Legacy8259,
    938                 &LegMask,
    939                 NULL,
    940                 NULL,
    941                 NULL
    942                 );
    943 
    944   PciIo->GetLocation (
    945           PciIo,
    946           &PciSegment,
    947           &PciBus,
    948           &PciDevice,
    949           &PciFunction
    950           );
    951   Private->IntThunk->PciHandler.PciBus              = (UINT8) PciBus;
    952   Private->IntThunk->PciHandler.PciDeviceFun        = (UINT8) ((PciDevice << 3) + PciFunction);
    953   Private->IntThunk->PciHandler.PciSegment          = (UINT8) PciSegment;
    954   Private->IntThunk->PciHandler.PciClass            = PciConfigHeader->Hdr.ClassCode[2];
    955   Private->IntThunk->PciHandler.PciSubclass         = PciConfigHeader->Hdr.ClassCode[1];
    956   Private->IntThunk->PciHandler.PciInterface        = PciConfigHeader->Hdr.ClassCode[0];
    957 
    958   //
    959   // Use native mode base address registers in two cases:
    960   // 1. Programming Interface (PI) register indicates Primary Controller is
    961   // in native mode OR
    962   // 2. PCI device Sub Class Code is not IDE
    963   //
    964   Private->IntThunk->PciHandler.PrimaryBusMaster  = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);
    965   if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
    966     Private->IntThunk->PciHandler.PrimaryIrq      = PciIrq;
    967     Private->IntThunk->PciHandler.PrimaryBase     = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);
    968     Private->IntThunk->PciHandler.PrimaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);
    969   } else {
    970     Private->IntThunk->PciHandler.PrimaryIrq      = 14;
    971     Private->IntThunk->PciHandler.PrimaryBase     = 0x1f0;
    972     Private->IntThunk->PciHandler.PrimaryControl  = 0x3f6;
    973   }
    974   //
    975   // Secondary controller data
    976   //
    977   if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {
    978     Private->IntThunk->PciHandler.SecondaryBusMaster  = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);
    979     PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);
    980     SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);
    981 
    982     //
    983     // Clear pending interrupts in Bus Master registers
    984     //
    985     IoWrite16 (PrimaryMaster, 0x04);
    986     IoWrite16 (SecondaryMaster, 0x04);
    987 
    988   }
    989 
    990   //
    991   // Use native mode base address registers in two cases:
    992   // 1. Programming Interface (PI) register indicates Secondary Controller is
    993   // in native mode OR
    994   // 2. PCI device Sub Class Code is not IDE
    995   //
    996   if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
    997     Private->IntThunk->PciHandler.SecondaryIrq      = PciIrq;
    998     Private->IntThunk->PciHandler.SecondaryBase     = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);
    999     Private->IntThunk->PciHandler.SecondaryControl  = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);
   1000   } else {
   1001 
   1002     Private->IntThunk->PciHandler.SecondaryIrq      = 15;
   1003     Private->IntThunk->PciHandler.SecondaryBase     = 0x170;
   1004     Private->IntThunk->PciHandler.SecondaryControl  = 0x376;
   1005   }
   1006 
   1007   //
   1008   // Clear pending interrupts in IDE Command Block Status reg before we
   1009   // Thunk to CSM16 below.  Don't want a pending Interrupt before we
   1010   // install the handlers as wierd corruption would occur and hang system.
   1011   //
   1012   //
   1013   // Read IDE CMD blk status reg to clear out any pending interrupts.
   1014   // Do here for Primary and Secondary IDE channels
   1015   //
   1016   RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;
   1017   IoRead8 (RegisterAddress);
   1018   RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;
   1019   IoRead8 (RegisterAddress);
   1020 
   1021   Private->IntThunk->PciHandler.PrimaryReserved   = 0;
   1022   Private->IntThunk->PciHandler.SecondaryReserved = 0;
   1023   Private->LegacyRegion->UnLock (
   1024                            Private->LegacyRegion,
   1025                            0xE0000,
   1026                            0x20000,
   1027                            &Granularity
   1028                            );
   1029 
   1030   Regs.X.AX = Legacy16InstallPciHandler;
   1031   TempData  = (UINTN) &Private->IntThunk->PciHandler;
   1032   Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
   1033   Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
   1034 
   1035   DumpPciHandle (&Private->IntThunk->PciHandler);
   1036 
   1037   Private->LegacyBios.FarCall86 (
   1038     &Private->LegacyBios,
   1039     Private->Legacy16CallSegment,
   1040     Private->Legacy16CallOffset,
   1041     &Regs,
   1042     NULL,
   1043     0
   1044     );
   1045 
   1046   Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
   1047   Private->LegacyRegion->Lock (
   1048                            Private->LegacyRegion,
   1049                            0xE0000,
   1050                            0x20000,
   1051                            &Granularity
   1052                            );
   1053 
   1054 }
   1055 
   1056 
   1057 /**
   1058   Program the interrupt routing register in all the PCI devices. On a PC AT system
   1059   this register contains the 8259 IRQ vector that matches it's PCI interrupt.
   1060 
   1061   @param  Private                Legacy  BIOS Instance data
   1062 
   1063   @retval EFI_SUCCESS            Succeed.
   1064   @retval EFI_ALREADY_STARTED    All PCI devices have been processed.
   1065 
   1066 **/
   1067 EFI_STATUS
   1068 PciProgramAllInterruptLineRegisters (
   1069   IN  LEGACY_BIOS_INSTANCE      *Private
   1070   )
   1071 {
   1072   EFI_STATUS                        Status;
   1073   EFI_PCI_IO_PROTOCOL               *PciIo;
   1074   EFI_LEGACY_8259_PROTOCOL          *Legacy8259;
   1075   EFI_LEGACY_INTERRUPT_PROTOCOL     *LegacyInterrupt;
   1076   EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
   1077   UINT8                             InterruptPin;
   1078   UINTN                             Index;
   1079   UINTN                             HandleCount;
   1080   EFI_HANDLE                        *HandleBuffer;
   1081   UINTN                             MassStorageHandleCount;
   1082   EFI_HANDLE                        *MassStorageHandleBuffer;
   1083   UINTN                             MassStorageHandleIndex;
   1084   UINT8                             PciIrq;
   1085   UINT16                            Command;
   1086   UINTN                             PciSegment;
   1087   UINTN                             PciBus;
   1088   UINTN                             PciDevice;
   1089   UINTN                             PciFunction;
   1090   EFI_LEGACY_IRQ_ROUTING_ENTRY      *RoutingTable;
   1091   UINTN                             RoutingTableEntries;
   1092   UINT16                            LegMask;
   1093   UINT16                            LegEdgeLevel;
   1094   PCI_TYPE00                        PciConfigHeader;
   1095   EFI_LEGACY_PIRQ_TABLE_HEADER      *PirqTable;
   1096   UINTN                             PirqTableSize;
   1097   UINTN                             Flags;
   1098   HDD_INFO                          *HddInfo;
   1099   UINT64                            Supports;
   1100 
   1101   //
   1102   // Note - This routine use to return immediately if Private->PciInterruptLine
   1103   //        was true. Routine changed since resets etc can cause not all
   1104   //        PciIo protocols to be registered the first time through.
   1105   // New algorithm is to do the copy $PIR table on first pass and save
   1106   // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
   1107   // a larger handle count then proceed with body of function else return
   1108   // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
   1109   // If zero then function unprogrammed else skip function.
   1110   //
   1111   Legacy8259          = Private->Legacy8259;
   1112   LegacyInterrupt     = Private->LegacyInterrupt;
   1113   LegacyBiosPlatform  = Private->LegacyBiosPlatform;
   1114 
   1115   LegacyBiosPlatform->GetRoutingTable (
   1116                         Private->LegacyBiosPlatform,
   1117                         (VOID *) &RoutingTable,
   1118                         &RoutingTableEntries,
   1119                         (VOID *) &PirqTable,
   1120                         &PirqTableSize,
   1121                         NULL,
   1122                         NULL
   1123                         );
   1124   CreateBridgeTable (RoutingTable, RoutingTableEntries);
   1125 
   1126   if (!Private->PciInterruptLine) {
   1127     CopyPirqTable (
   1128       Private,
   1129       RoutingTable,
   1130       RoutingTableEntries,
   1131       PirqTable,
   1132       PirqTableSize
   1133       );
   1134   }
   1135 
   1136   Status = gBS->LocateHandleBuffer (
   1137                   ByProtocol,
   1138                   &gEfiPciIoProtocolGuid,
   1139                   NULL,
   1140                   &HandleCount,
   1141                   &HandleBuffer
   1142                   );
   1143   if (EFI_ERROR (Status)) {
   1144     return EFI_NOT_FOUND;
   1145   }
   1146   if (HandleCount == mHandleCount) {
   1147     FreePool (HandleBuffer);
   1148     return EFI_ALREADY_STARTED;
   1149   }
   1150 
   1151   if (mHandleCount == 0x00) {
   1152     mHandleCount = HandleCount;
   1153   }
   1154 
   1155   for (Index = 0; Index < HandleCount; Index++) {
   1156     //
   1157     // If VGA then only do VGA to allow drives fore time to spin up
   1158     // otherwise assign PCI IRQs to all potential devices.
   1159     //
   1160     if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {
   1161       continue;
   1162     } else {
   1163       //
   1164       // Force code to go through all handles next time called if video.
   1165       // This will catch case where HandleCount doesn't change but want
   1166       //  to get drive info etc.
   1167       //
   1168       mHandleCount = 0x00;
   1169     }
   1170 
   1171     Status = gBS->HandleProtocol (
   1172                     HandleBuffer[Index],
   1173                     &gEfiPciIoProtocolGuid,
   1174                     (VOID **) &PciIo
   1175                     );
   1176     ASSERT_EFI_ERROR (Status);
   1177 
   1178     //
   1179     // Test whether the device can be enabled or not.
   1180     // If it can't be enabled, then just skip it to avoid further operation.
   1181     //
   1182     PciIo->Pci.Read (
   1183                  PciIo,
   1184                  EfiPciIoWidthUint32,
   1185                  0,
   1186                  sizeof (PciConfigHeader) / sizeof (UINT32),
   1187                  &PciConfigHeader
   1188                  );
   1189     Command = PciConfigHeader.Hdr.Command;
   1190 
   1191     //
   1192     // Note PciIo->Attributes does not program the PCI command register
   1193     //
   1194     Status = PciIo->Attributes (
   1195                       PciIo,
   1196                       EfiPciIoAttributeOperationSupported,
   1197                       0,
   1198                       &Supports
   1199                       );
   1200     if (!EFI_ERROR (Status)) {
   1201       Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
   1202       Status = PciIo->Attributes (
   1203                         PciIo,
   1204                         EfiPciIoAttributeOperationEnable,
   1205                         Supports,
   1206                         NULL
   1207                         );
   1208     }
   1209     PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);
   1210 
   1211     if (EFI_ERROR (Status)) {
   1212       continue;
   1213     }
   1214 
   1215     InterruptPin = PciConfigHeader.Device.InterruptPin;
   1216 
   1217     if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {
   1218       PciIo->GetLocation (
   1219                PciIo,
   1220                &PciSegment,
   1221                &PciBus,
   1222                &PciDevice,
   1223                &PciFunction
   1224                );
   1225       //
   1226       // Translate PIRQ index back thru busses to slot bus with InterruptPin
   1227       // zero based
   1228       //
   1229       InterruptPin -= 1;
   1230 
   1231       Status = GetBaseBus (
   1232                  Private,
   1233                  PciBus,
   1234                  PciDevice,
   1235                  RoutingTable,
   1236                  RoutingTableEntries
   1237                  );
   1238 
   1239       if (Status == EFI_NOT_FOUND) {
   1240         TranslateBusPirq (
   1241           Private,
   1242           &PciBus,
   1243           &PciDevice,
   1244           &PciFunction,
   1245           &InterruptPin
   1246           );
   1247       }
   1248       //
   1249       // Translate InterruptPin(0-3) into PIRQ
   1250       //
   1251       Status = LegacyBiosPlatform->TranslatePirq (
   1252                                      LegacyBiosPlatform,
   1253                                      PciBus,
   1254                                      (PciDevice << 3),
   1255                                      PciFunction,
   1256                                      &InterruptPin,
   1257                                      &PciIrq
   1258                                      );
   1259       //
   1260       // TranslatePirq() should never fail or we are in trouble
   1261       // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
   1262       //
   1263       if (EFI_ERROR (Status)) {
   1264         DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));
   1265         continue;
   1266       }
   1267 
   1268       LegacyInterrupt->WritePirq (
   1269                          LegacyInterrupt,
   1270                          InterruptPin,
   1271                          PciIrq
   1272                          );
   1273 
   1274       //
   1275       // Check if device has an OPROM associated with it.
   1276       // If not invoke special 16-bit function, to allow 16-bit
   1277       // code to install an interrupt handler.
   1278       //
   1279       Status = LegacyBiosCheckPciRom (
   1280                  &Private->LegacyBios,
   1281                  HandleBuffer[Index],
   1282                  NULL,
   1283                  NULL,
   1284                  &Flags
   1285                  );
   1286       if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {
   1287         //
   1288         // Device has no OPROM associated with it and is a mass storage
   1289         // device. It needs to have an PCI IRQ handler installed. To
   1290         // correctly install the handler we need to insure device is
   1291         // connected. The device may just have register itself but not
   1292         // been connected. Re-read PCI config space after as it can
   1293         // change
   1294         //
   1295         //
   1296         // Get IDE Handle. If matches handle then skip ConnectController
   1297         // since ConnectController may force native mode and we don't
   1298         // want that for primary IDE controller
   1299         //
   1300         MassStorageHandleCount = 0;
   1301         MassStorageHandleBuffer = NULL;
   1302         LegacyBiosPlatform->GetPlatformHandle (
   1303                               Private->LegacyBiosPlatform,
   1304                               EfiGetPlatformIdeHandle,
   1305                               0,
   1306                               &MassStorageHandleBuffer,
   1307                               &MassStorageHandleCount,
   1308                               NULL
   1309                               );
   1310 
   1311         HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
   1312 
   1313         LegacyBiosBuildIdeData (Private, &HddInfo, 0);
   1314         PciIo->Pci.Read (
   1315                      PciIo,
   1316                      EfiPciIoWidthUint32,
   1317                      0,
   1318                      sizeof (PciConfigHeader) / sizeof (UINT32),
   1319                      &PciConfigHeader
   1320                      );
   1321 
   1322         for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {
   1323           if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {
   1324             //
   1325             // InstallLegacyIrqHandler according to Platform requirement
   1326             //
   1327             InstallLegacyIrqHandler (
   1328               Private,
   1329               PciIo,
   1330               PciIrq,
   1331               &PciConfigHeader
   1332               );
   1333             break;
   1334           }
   1335         }
   1336       }
   1337       //
   1338       // Write InterruptPin and enable 8259.
   1339       //
   1340       PciIo->Pci.Write (
   1341                    PciIo,
   1342                    EfiPciIoWidthUint8,
   1343                    0x3c,
   1344                    1,
   1345                    &PciIrq
   1346                    );
   1347       Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));
   1348 
   1349       Legacy8259->GetMask (
   1350                     Legacy8259,
   1351                     &LegMask,
   1352                     &LegEdgeLevel,
   1353                     NULL,
   1354                     NULL
   1355                     );
   1356 
   1357       LegMask       = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));
   1358       LegEdgeLevel  = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));
   1359       Legacy8259->SetMask (
   1360                     Legacy8259,
   1361                     &LegMask,
   1362                     &LegEdgeLevel,
   1363                     NULL,
   1364                     NULL
   1365                     );
   1366     }
   1367   }
   1368   FreePool (HandleBuffer);
   1369   return EFI_SUCCESS;
   1370 }
   1371 
   1372 
   1373 /**
   1374   Find & verify PnP Expansion header in ROM image
   1375 
   1376   @param  Private                Protocol instance pointer.
   1377   @param  FirstHeader            1 = Find first header, 0 = Find successive headers
   1378   @param  PnpPtr                 Input Rom start if FirstHeader =1, Current Header
   1379                                  otherwise Output Next header, if it exists
   1380 
   1381   @retval EFI_SUCCESS            Next Header found at BasePnpPtr
   1382   @retval EFI_NOT_FOUND          No more headers
   1383 
   1384 **/
   1385 EFI_STATUS
   1386 FindNextPnpExpansionHeader (
   1387   IN  LEGACY_BIOS_INSTANCE             *Private,
   1388   IN BOOLEAN                           FirstHeader,
   1389   IN OUT LEGACY_PNP_EXPANSION_HEADER   **PnpPtr
   1390 
   1391   )
   1392 {
   1393   UINTN                       TempData;
   1394   LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;
   1395   LocalPnpPtr = *PnpPtr;
   1396   if (FirstHeader == FIRST_INSTANCE) {
   1397     mBasePnpPtr     = LocalPnpPtr;
   1398     mBbsRomSegment  = (UINT16) ((UINTN) mBasePnpPtr >> 4);
   1399     //
   1400     // Offset 0x1a gives offset to PnP expansion header for the first
   1401     // instance, there after the structure gives the offset to the next
   1402     // structure
   1403     //
   1404     LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);
   1405     TempData    = (*((UINT16 *) LocalPnpPtr));
   1406   } else {
   1407     TempData = (UINT16) LocalPnpPtr->NextHeader;
   1408   }
   1409 
   1410   LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));
   1411 
   1412   //
   1413   // Search for PnP table in Shadowed ROM
   1414   //
   1415   *PnpPtr = LocalPnpPtr;
   1416   if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {
   1417     return EFI_SUCCESS;
   1418   } else {
   1419     return EFI_NOT_FOUND;
   1420   }
   1421 }
   1422 
   1423 
   1424 /**
   1425   Update list of Bev or BCV table entries.
   1426 
   1427   @param  Private                Protocol instance pointer.
   1428   @param  RomStart               Table of ROM start address in RAM/ROM. PciIo  _
   1429                                  Handle to PCI IO for this device
   1430   @param  PciIo                  Instance of PCI I/O Protocol
   1431 
   1432   @retval EFI_SUCCESS            Always should succeed.
   1433 
   1434 **/
   1435 EFI_STATUS
   1436 UpdateBevBcvTable (
   1437   IN  LEGACY_BIOS_INSTANCE             *Private,
   1438   IN  EFI_LEGACY_EXPANSION_ROM_HEADER  *RomStart,
   1439   IN  EFI_PCI_IO_PROTOCOL              *PciIo
   1440   )
   1441 {
   1442   VOID                            *RomEnd;
   1443   BBS_TABLE                       *BbsTable;
   1444   UINTN                           BbsIndex;
   1445   EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;
   1446   LEGACY_PNP_EXPANSION_HEADER     *PnpPtr;
   1447   BOOLEAN                         Instance;
   1448   EFI_STATUS                      Status;
   1449   UINTN                           Segment;
   1450   UINTN                           Bus;
   1451   UINTN                           Device;
   1452   UINTN                           Function;
   1453   UINT8                           Class;
   1454   UINT16                          DeviceType;
   1455   Segment     = 0;
   1456   Bus         = 0;
   1457   Device      = 0;
   1458   Function    = 0;
   1459   Class       = 0;
   1460   DeviceType  = BBS_UNKNOWN;
   1461 
   1462   //
   1463   // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
   1464   // controller).
   1465   //
   1466   BbsIndex  = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
   1467 
   1468   BbsTable  = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;
   1469   PnpPtr    = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;
   1470   PciPtr    = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;
   1471 
   1472   RomEnd    = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);
   1473   Instance  = FIRST_INSTANCE;
   1474   //
   1475   // OPROMs like PXE may not be tied to a piece of hardware and thus
   1476   // don't have a PciIo associated with them
   1477   //
   1478   if (PciIo != NULL) {
   1479     PciIo->GetLocation (
   1480              PciIo,
   1481              &Segment,
   1482              &Bus,
   1483              &Device,
   1484              &Function
   1485              );
   1486     PciIo->Pci.Read (
   1487                  PciIo,
   1488                  EfiPciIoWidthUint8,
   1489                  0x0b,
   1490                  1,
   1491                  &Class
   1492                  );
   1493 
   1494     if (Class == PCI_CLASS_MASS_STORAGE) {
   1495       DeviceType = BBS_HARDDISK;
   1496     } else {
   1497       if (Class == PCI_CLASS_NETWORK) {
   1498         DeviceType = BBS_EMBED_NETWORK;
   1499       }
   1500     }
   1501   }
   1502 
   1503   while (TRUE) {
   1504     Status    = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);
   1505     Instance  = NOT_FIRST_INSTANCE;
   1506     if (EFI_ERROR (Status)) {
   1507       break;
   1508     }
   1509     //
   1510     // There can be additional $PnP headers within the OPROM.
   1511     // Example: SCSI can have one per drive.
   1512     //
   1513     BbsTable[BbsIndex].BootPriority             = BBS_UNPRIORITIZED_ENTRY;
   1514     BbsTable[BbsIndex].DeviceType               = DeviceType;
   1515     BbsTable[BbsIndex].Bus                      = (UINT32) Bus;
   1516     BbsTable[BbsIndex].Device                   = (UINT32) Device;
   1517     BbsTable[BbsIndex].Function                 = (UINT32) Function;
   1518     BbsTable[BbsIndex].StatusFlags.OldPosition  = 0;
   1519     BbsTable[BbsIndex].StatusFlags.Reserved1    = 0;
   1520     BbsTable[BbsIndex].StatusFlags.Enabled      = 0;
   1521     BbsTable[BbsIndex].StatusFlags.Failed       = 0;
   1522     BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;
   1523     BbsTable[BbsIndex].StatusFlags.Reserved2    = 0;
   1524     BbsTable[BbsIndex].Class                    = PnpPtr->Class;
   1525     BbsTable[BbsIndex].SubClass                 = PnpPtr->SubClass;
   1526     BbsTable[BbsIndex].DescStringOffset         = PnpPtr->ProductNamePointer;
   1527     BbsTable[BbsIndex].DescStringSegment        = mBbsRomSegment;
   1528     BbsTable[BbsIndex].MfgStringOffset          = PnpPtr->MfgPointer;
   1529     BbsTable[BbsIndex].MfgStringSegment         = mBbsRomSegment;
   1530     BbsTable[BbsIndex].BootHandlerSegment       = mBbsRomSegment;
   1531 
   1532     //
   1533     // Have seen case where PXE base code have PnP expansion ROM
   1534     // header but no Bcv or Bev vectors.
   1535     //
   1536     if (PnpPtr->Bcv != 0) {
   1537       BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;
   1538       ++BbsIndex;
   1539     }
   1540 
   1541     if (PnpPtr->Bev != 0) {
   1542       BbsTable[BbsIndex].BootHandlerOffset  = PnpPtr->Bev;
   1543       BbsTable[BbsIndex].DeviceType         = BBS_BEV_DEVICE;
   1544       ++BbsIndex;
   1545     }
   1546 
   1547     if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {
   1548       break;
   1549     }
   1550   }
   1551 
   1552   BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;
   1553   Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;
   1554   return EFI_SUCCESS;
   1555 }
   1556 
   1557 
   1558 /**
   1559   Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
   1560   to chose the order. Skip any devices that have already have legacy
   1561   BIOS run.
   1562 
   1563   @param  Private                Protocol instance pointer.
   1564 
   1565   @retval EFI_SUCCESS            Succeed.
   1566   @retval EFI_UNSUPPORTED        Cannot get VGA device handle.
   1567 
   1568 **/
   1569 EFI_STATUS
   1570 PciShadowRoms (
   1571   IN  LEGACY_BIOS_INSTANCE      *Private
   1572   )
   1573 {
   1574   EFI_STATUS                        Status;
   1575   EFI_PCI_IO_PROTOCOL               *PciIo;
   1576   PCI_TYPE00                        Pci;
   1577   UINTN                             Index;
   1578   UINTN                             HandleCount;
   1579   EFI_HANDLE                        *HandleBuffer;
   1580   EFI_HANDLE                        VgaHandle;
   1581   EFI_HANDLE                        FirstHandle;
   1582   VOID                              **RomStart;
   1583   UINTN                             Flags;
   1584   PCI_TYPE00                        PciConfigHeader;
   1585   UINT16                            *Command;
   1586   UINT64                            Supports;
   1587 
   1588   //
   1589   // Make the VGA device first
   1590   //
   1591   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
   1592                                           Private->LegacyBiosPlatform,
   1593                                           EfiGetPlatformVgaHandle,
   1594                                           0,
   1595                                           &HandleBuffer,
   1596                                           &HandleCount,
   1597                                           NULL
   1598                                           );
   1599   if (EFI_ERROR (Status)) {
   1600     return EFI_UNSUPPORTED;
   1601   }
   1602 
   1603   VgaHandle = HandleBuffer[0];
   1604 
   1605   Status = gBS->LocateHandleBuffer (
   1606                   ByProtocol,
   1607                   &gEfiPciIoProtocolGuid,
   1608                   NULL,
   1609                   &HandleCount,
   1610                   &HandleBuffer
   1611                   );
   1612 
   1613   if (EFI_ERROR (Status)) {
   1614     return Status;
   1615   }
   1616   //
   1617   // Place the VGA handle as first.
   1618   //
   1619   for (Index = 0; Index < HandleCount; Index++) {
   1620     if (HandleBuffer[Index] == VgaHandle) {
   1621       FirstHandle         = HandleBuffer[0];
   1622       HandleBuffer[0]     = HandleBuffer[Index];
   1623       HandleBuffer[Index] = FirstHandle;
   1624       break;
   1625     }
   1626   }
   1627   //
   1628   // Allocate memory to save Command WORD from each device. We do this
   1629   // to restore devices to same state as EFI after switching to legacy.
   1630   //
   1631   Command = (UINT16 *) AllocatePool (
   1632                          sizeof (UINT16) * (HandleCount + 1)
   1633                          );
   1634   if (NULL == Command) {
   1635     FreePool (HandleBuffer);
   1636     return EFI_OUT_OF_RESOURCES;
   1637   }
   1638   //
   1639   // Disconnect all EFI devices first. This covers cases where alegacy BIOS
   1640   // may control multiple PCI devices.
   1641   //
   1642   for (Index = 0; Index < HandleCount; Index++) {
   1643 
   1644     Status = gBS->HandleProtocol (
   1645                     HandleBuffer[Index],
   1646                     &gEfiPciIoProtocolGuid,
   1647                     (VOID **) &PciIo
   1648                     );
   1649     ASSERT_EFI_ERROR (Status);
   1650 
   1651     //
   1652     // Save command register for "connect" loop
   1653     //
   1654     PciIo->Pci.Read (
   1655                  PciIo,
   1656                  EfiPciIoWidthUint32,
   1657                  0,
   1658                  sizeof (PciConfigHeader) / sizeof (UINT32),
   1659                  &PciConfigHeader
   1660                  );
   1661     Command[Index] = PciConfigHeader.Hdr.Command;
   1662     //
   1663     // Skip any device that already has a legacy ROM run
   1664     //
   1665     Status = IsLegacyRom (HandleBuffer[Index]);
   1666     if (!EFI_ERROR (Status)) {
   1667       continue;
   1668     }
   1669     //
   1670     // Stop EFI Drivers with oprom.
   1671     //
   1672     gBS->DisconnectController (
   1673            HandleBuffer[Index],
   1674            NULL,
   1675            NULL
   1676            );
   1677   }
   1678   //
   1679   // For every device that has not had a legacy ROM started. Start a legacy ROM.
   1680   //
   1681   for (Index = 0; Index < HandleCount; Index++) {
   1682 
   1683     Status = gBS->HandleProtocol (
   1684                     HandleBuffer[Index],
   1685                     &gEfiPciIoProtocolGuid,
   1686                     (VOID **) &PciIo
   1687                     );
   1688 
   1689     ASSERT_EFI_ERROR (Status);
   1690 
   1691     //
   1692     // Here make sure if one VGA have been shadowed,
   1693     // then wil not shadowed another one.
   1694     //
   1695     PciIo->Pci.Read (
   1696                  PciIo,
   1697                  EfiPciIoWidthUint32,
   1698                  0,
   1699                  sizeof (Pci) / sizeof (UINT32),
   1700                  &Pci
   1701                  );
   1702 
   1703     //
   1704     // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
   1705     // one will work in legacy mode (OPROM will be given control) and
   1706     // other Video devices will work in native mode (OS driver will handle these devices).
   1707     //
   1708     if (IS_PCI_DISPLAY (&Pci) && Index != 0) {
   1709       continue;
   1710     }
   1711     //
   1712     // Skip any device that already has a legacy ROM run
   1713     //
   1714     Status = IsLegacyRom (HandleBuffer[Index]);
   1715     if (!EFI_ERROR (Status)) {
   1716       continue;
   1717     }
   1718 
   1719     //
   1720     // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
   1721     //
   1722     if (IS_PCI_DISPLAY (&Pci) && Index == 0) {
   1723       Status = LegacyBiosInstallVgaRom (Private);
   1724       //
   1725       // A return status of EFI_NOT_FOUND is considered valid (No EFI
   1726       // driver is controlling video).
   1727       //
   1728       ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND));
   1729       continue;
   1730     }
   1731 
   1732     //
   1733     // Install legacy ROM
   1734     //
   1735     Status = LegacyBiosInstallPciRom (
   1736                &Private->LegacyBios,
   1737                HandleBuffer[Index],
   1738                NULL,
   1739                &Flags,
   1740                NULL,
   1741                NULL,
   1742                (VOID **) &RomStart,
   1743                NULL
   1744                );
   1745     if (EFI_ERROR (Status)) {
   1746       if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {
   1747         continue;
   1748       }
   1749     }
   1750     //
   1751     // Restore Command register so legacy has same devices enabled or disabled
   1752     // as EFI.
   1753     // If Flags = NO_ROM use command register as is. This covers the
   1754     //            following cases:
   1755     //              Device has no ROMs associated with it.
   1756     //              Device has ROM associated with it but was already
   1757     //              installed.
   1758     //          = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
   1759     //          = ROM_FOUND and VALID_LEGACY_ROM, enable it.
   1760     //
   1761     if ((Flags & ROM_FOUND) == ROM_FOUND) {
   1762       if ((Flags & VALID_LEGACY_ROM) == 0) {
   1763         Command[Index] = 0;
   1764       } else {
   1765         //
   1766         // For several VGAs, only one of them can be enabled.
   1767         //
   1768         Status = PciIo->Attributes (
   1769                           PciIo,
   1770                           EfiPciIoAttributeOperationSupported,
   1771                           0,
   1772                           &Supports
   1773                           );
   1774         if (!EFI_ERROR (Status)) {
   1775           Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
   1776           Status = PciIo->Attributes (
   1777                             PciIo,
   1778                             EfiPciIoAttributeOperationEnable,
   1779                             Supports,
   1780                             NULL
   1781                             );
   1782         }
   1783         if (!EFI_ERROR (Status)) {
   1784           Command[Index] = 0x1f;
   1785         }
   1786       }
   1787     }
   1788 
   1789     PciIo->Pci.Write (
   1790                  PciIo,
   1791                  EfiPciIoWidthUint16,
   1792                  0x04,
   1793                  1,
   1794                  &Command[Index]
   1795                  );
   1796   }
   1797 
   1798   FreePool (Command);
   1799   FreePool (HandleBuffer);
   1800   return EFI_SUCCESS;
   1801 }
   1802 
   1803 
   1804 /**
   1805   Test to see if a legacy PCI ROM exists for this device. Optionally return
   1806   the Legacy ROM instance for this PCI device.
   1807 
   1808   @param  This                   Protocol instance pointer.
   1809   @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
   1810                                  be loaded
   1811   @param  RomImage               Return the legacy PCI ROM for this device
   1812   @param  RomSize                Size of ROM Image
   1813   @param  Flags                  Indicates if ROM found and if PC-AT.
   1814 
   1815   @retval EFI_SUCCESS            Legacy Option ROM availible for this device
   1816   @retval EFI_UNSUPPORTED        Legacy Option ROM not supported.
   1817 
   1818 **/
   1819 EFI_STATUS
   1820 EFIAPI
   1821 LegacyBiosCheckPciRom (
   1822   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
   1823   IN  EFI_HANDLE                        PciHandle,
   1824   OUT VOID                              **RomImage, OPTIONAL
   1825   OUT UINTN                             *RomSize, OPTIONAL
   1826   OUT UINTN                             *Flags
   1827   )
   1828 {
   1829   return LegacyBiosCheckPciRomEx (
   1830            This,
   1831            PciHandle,
   1832            RomImage,
   1833            RomSize,
   1834            NULL,
   1835            Flags,
   1836            NULL,
   1837            NULL
   1838            );
   1839 
   1840 }
   1841 
   1842 /**
   1843 
   1844   Routine Description:
   1845     Test to see if a legacy PCI ROM exists for this device. Optionally return
   1846     the Legacy ROM instance for this PCI device.
   1847 
   1848     @param[in] This          Protocol instance pointer.
   1849     @param[in] PciHandle               The PCI PC-AT OPROM from this devices ROM BAR will be loaded
   1850     @param[out] RomImage               Return the legacy PCI ROM for this device
   1851     @param[out] RomSize                Size of ROM Image
   1852     @param[out] RuntimeImageLength     Runtime size of ROM Image
   1853     @param[out] Flags                  Indicates if ROM found and if PC-AT.
   1854     @param[out] OpromRevision          Revision of the PCI Rom
   1855     @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
   1856 
   1857     @return EFI_SUCCESS            Legacy Option ROM availible for this device
   1858     @return EFI_ALREADY_STARTED    This device is already managed by its Oprom
   1859     @return EFI_UNSUPPORTED        Legacy Option ROM not supported.
   1860 
   1861 **/
   1862 EFI_STATUS
   1863 LegacyBiosCheckPciRomEx (
   1864   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
   1865   IN  EFI_HANDLE                        PciHandle,
   1866   OUT VOID                              **RomImage, OPTIONAL
   1867   OUT UINTN                             *RomSize, OPTIONAL
   1868   OUT UINTN                             *RuntimeImageLength, OPTIONAL
   1869   OUT UINTN                             *Flags, OPTIONAL
   1870   OUT UINT8                             *OpromRevision, OPTIONAL
   1871   OUT VOID                              **ConfigUtilityCodeHeader OPTIONAL
   1872   )
   1873 {
   1874   EFI_STATUS                      Status;
   1875   LEGACY_BIOS_INSTANCE            *Private;
   1876   EFI_PCI_IO_PROTOCOL             *PciIo;
   1877   UINTN                           LocalRomSize;
   1878   VOID                            *LocalRomImage;
   1879   PCI_TYPE00                      PciConfigHeader;
   1880   VOID                            *LocalConfigUtilityCodeHeader;
   1881 
   1882   LocalConfigUtilityCodeHeader = NULL;
   1883   *Flags = NO_ROM;
   1884   Status = gBS->HandleProtocol (
   1885                   PciHandle,
   1886                   &gEfiPciIoProtocolGuid,
   1887                   (VOID **) &PciIo
   1888                   );
   1889   if (EFI_ERROR (Status)) {
   1890     return EFI_UNSUPPORTED;
   1891   }
   1892 
   1893   //
   1894   // See if the option ROM for PciHandle has already been executed
   1895   //
   1896   Status = IsLegacyRom (PciHandle);
   1897   if (!EFI_ERROR (Status)) {
   1898     *Flags |= (UINTN)(ROM_FOUND | VALID_LEGACY_ROM);
   1899     return EFI_SUCCESS;
   1900   }
   1901   //
   1902   // Check for PCI ROM Bar
   1903   //
   1904   LocalRomSize  = (UINTN) PciIo->RomSize;
   1905   LocalRomImage = PciIo->RomImage;
   1906   if (LocalRomSize != 0) {
   1907     *Flags |= ROM_FOUND;
   1908   }
   1909 
   1910   //
   1911   // PCI specification states you should check VendorId and Device Id.
   1912   //
   1913   PciIo->Pci.Read (
   1914                PciIo,
   1915                EfiPciIoWidthUint32,
   1916                0,
   1917                sizeof (PciConfigHeader) / sizeof (UINT32),
   1918                &PciConfigHeader
   1919                );
   1920 
   1921   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
   1922   Status = GetPciLegacyRom (
   1923              Private->Csm16PciInterfaceVersion,
   1924              PciConfigHeader.Hdr.VendorId,
   1925              PciConfigHeader.Hdr.DeviceId,
   1926              &LocalRomImage,
   1927              &LocalRomSize,
   1928              RuntimeImageLength,
   1929              OpromRevision,
   1930              &LocalConfigUtilityCodeHeader
   1931              );
   1932   if (EFI_ERROR (Status)) {
   1933     return EFI_UNSUPPORTED;
   1934   }
   1935 
   1936   *Flags |= VALID_LEGACY_ROM;
   1937 
   1938   //
   1939   // See if Configuration Utility Code Header valid
   1940   //
   1941   if (LocalConfigUtilityCodeHeader != NULL) {
   1942     *Flags |= ROM_WITH_CONFIG;
   1943   }
   1944 
   1945   if (ConfigUtilityCodeHeader != NULL) {
   1946     *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;
   1947   }
   1948 
   1949   if (RomImage != NULL) {
   1950     *RomImage = LocalRomImage;
   1951   }
   1952 
   1953   if (RomSize != NULL) {
   1954     *RomSize = LocalRomSize;
   1955   }
   1956 
   1957   return EFI_SUCCESS;
   1958 }
   1959 
   1960 /**
   1961   Load a legacy PC-AT OPROM on the PciHandle device. Return information
   1962   about how many disks were added by the OPROM and the shadow address and
   1963   size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
   1964 
   1965   @retval EFI_SUCCESS   Legacy ROM loaded for this device
   1966   @retval EFI_NOT_FOUND No PS2 Keyboard found
   1967 
   1968 **/
   1969 EFI_STATUS
   1970 EnablePs2Keyboard (
   1971   VOID
   1972   )
   1973 {
   1974   EFI_STATUS                          Status;
   1975   EFI_HANDLE                          *HandleBuffer;
   1976   UINTN                               HandleCount;
   1977   EFI_ISA_IO_PROTOCOL                 *IsaIo;
   1978   UINTN                               Index;
   1979 
   1980   //
   1981   // Get SimpleTextIn and find PS2 controller
   1982   //
   1983   Status = gBS->LocateHandleBuffer (
   1984                   ByProtocol,
   1985                   &gEfiSimpleTextInProtocolGuid,
   1986                   NULL,
   1987                   &HandleCount,
   1988                   &HandleBuffer
   1989                   );
   1990   if (EFI_ERROR (Status)) {
   1991     return EFI_NOT_FOUND;
   1992   }
   1993   for (Index = 0; Index < HandleCount; Index++) {
   1994     //
   1995     // Open the IO Abstraction(s) needed to perform the supported test
   1996     //
   1997     Status = gBS->OpenProtocol (
   1998                     HandleBuffer[Index],
   1999                     &gEfiIsaIoProtocolGuid,
   2000                     (VOID **) &IsaIo,
   2001                     NULL,
   2002                     HandleBuffer[Index],
   2003                     EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
   2004                     );
   2005 
   2006     if (!EFI_ERROR (Status)) {
   2007       //
   2008       // Use the ISA I/O Protocol to see if Controller is the Keyboard
   2009       // controller
   2010       //
   2011       if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
   2012         Status = EFI_UNSUPPORTED;
   2013       }
   2014 
   2015       gBS->CloseProtocol (
   2016              HandleBuffer[Index],
   2017              &gEfiIsaIoProtocolGuid,
   2018              NULL,
   2019              HandleBuffer[Index]
   2020              );
   2021     }
   2022 
   2023     if (!EFI_ERROR (Status)) {
   2024       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
   2025     }
   2026   }
   2027   FreePool (HandleBuffer);
   2028   return EFI_SUCCESS;
   2029 }
   2030 
   2031 
   2032 /**
   2033   Load a legacy PC-AT OpROM for VGA controller.
   2034 
   2035   @param  Private                Driver private data.
   2036 
   2037   @retval EFI_SUCCESS            Legacy ROM successfully installed for this device.
   2038   @retval EFI_DEVICE_ERROR       No VGA device handle found, or native EFI video
   2039                                  driver cannot be successfully disconnected, or VGA
   2040                                  thunk driver cannot be successfully connected.
   2041 
   2042 **/
   2043 EFI_STATUS
   2044 LegacyBiosInstallVgaRom (
   2045   IN  LEGACY_BIOS_INSTANCE            *Private
   2046   )
   2047 {
   2048   EFI_STATUS                           Status;
   2049   EFI_HANDLE                           VgaHandle;
   2050   UINTN                                HandleCount;
   2051   EFI_HANDLE                           *HandleBuffer;
   2052   EFI_HANDLE                           *ConnectHandleBuffer;
   2053   EFI_PCI_IO_PROTOCOL                  *PciIo;
   2054   PCI_TYPE00                           PciConfigHeader;
   2055   UINT64                               Supports;
   2056   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
   2057   UINTN                                EntryCount;
   2058   UINTN                                Index;
   2059   VOID                                 *Interface;
   2060 
   2061   //
   2062   // EfiLegacyBiosGuild attached to a device implies that there is a legacy
   2063   // BIOS associated with that device.
   2064   //
   2065   // There are 3 cases to consider.
   2066   //   Case 1: No EFI driver is controlling the video.
   2067   //     Action: Return EFI_SUCCESS from DisconnectController, search
   2068   //             video thunk driver, and connect it.
   2069   //   Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
   2070   //           not on the image handle.
   2071   //     Action: Disconnect EFI driver.
   2072   //             ConnectController for video thunk
   2073   //   Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
   2074   //           on the image handle.
   2075   //     Action: Do nothing and set Private->VgaInstalled = TRUE.
   2076   //             Then this routine is not called any more.
   2077   //
   2078   //
   2079   // Get the VGA device.
   2080   //
   2081   Status = Private->LegacyBiosPlatform->GetPlatformHandle (
   2082                                           Private->LegacyBiosPlatform,
   2083                                           EfiGetPlatformVgaHandle,
   2084                                           0,
   2085                                           &HandleBuffer,
   2086                                           &HandleCount,
   2087                                           NULL
   2088                                           );
   2089   if (EFI_ERROR (Status)) {
   2090     return EFI_DEVICE_ERROR;
   2091   }
   2092 
   2093   VgaHandle = HandleBuffer[0];
   2094 
   2095   //
   2096   // Check whether video thunk driver already starts.
   2097   //
   2098   Status = gBS->OpenProtocolInformation (
   2099                   VgaHandle,
   2100                   &gEfiPciIoProtocolGuid,
   2101                   &OpenInfoBuffer,
   2102                   &EntryCount
   2103                   );
   2104   if (EFI_ERROR (Status)) {
   2105     return Status;
   2106   }
   2107 
   2108   for (Index = 0; Index < EntryCount; Index++) {
   2109     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
   2110       Status = gBS->HandleProtocol (
   2111                       OpenInfoBuffer[Index].AgentHandle,
   2112                       &gEfiLegacyBiosGuid,
   2113                       (VOID **) &Interface
   2114                       );
   2115       if (!EFI_ERROR (Status)) {
   2116         //
   2117         // This should be video thunk driver which is managing video device
   2118         // So it need not start again
   2119         //
   2120         DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));
   2121         Private->VgaInstalled = TRUE;
   2122         return EFI_SUCCESS;
   2123       }
   2124     }
   2125   }
   2126 
   2127   //
   2128   // Kick off the native EFI driver
   2129   //
   2130   Status = gBS->DisconnectController (
   2131                   VgaHandle,
   2132                   NULL,
   2133                   NULL
   2134                   );
   2135   if (EFI_ERROR (Status)) {
   2136     if (Status != EFI_NOT_FOUND) {
   2137       return EFI_DEVICE_ERROR;
   2138     } else {
   2139       return Status;
   2140     }
   2141   }
   2142   //
   2143   // Find all the Thunk Driver
   2144   //
   2145   HandleBuffer = NULL;
   2146   Status = gBS->LocateHandleBuffer (
   2147                   ByProtocol,
   2148                   &gEfiLegacyBiosGuid,
   2149                   NULL,
   2150                   &HandleCount,
   2151                   &HandleBuffer
   2152                   );
   2153   ASSERT_EFI_ERROR (Status);
   2154   ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));
   2155   ASSERT (ConnectHandleBuffer != NULL);
   2156 
   2157   CopyMem (
   2158     ConnectHandleBuffer,
   2159     HandleBuffer,
   2160     sizeof (EFI_HANDLE) * HandleCount
   2161     );
   2162   ConnectHandleBuffer[HandleCount] = NULL;
   2163 
   2164   FreePool (HandleBuffer);
   2165 
   2166   //
   2167   // Enable the device and make sure VGA cycles are being forwarded to this VGA device
   2168   //
   2169   Status = gBS->HandleProtocol (
   2170                   VgaHandle,
   2171                   &gEfiPciIoProtocolGuid,
   2172                   (VOID **) &PciIo
   2173                   );
   2174   ASSERT_EFI_ERROR (Status);
   2175   PciIo->Pci.Read (
   2176                PciIo,
   2177                EfiPciIoWidthUint32,
   2178                0,
   2179                sizeof (PciConfigHeader) / sizeof (UINT32),
   2180                &PciConfigHeader
   2181                );
   2182 
   2183   Status = PciIo->Attributes (
   2184                     PciIo,
   2185                     EfiPciIoAttributeOperationSupported,
   2186                     0,
   2187                     &Supports
   2188                     );
   2189   if (!EFI_ERROR (Status)) {
   2190     Supports &= (UINT64)(EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \
   2191                          EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
   2192     Status = PciIo->Attributes (
   2193                       PciIo,
   2194                       EfiPciIoAttributeOperationEnable,
   2195                       Supports,
   2196                       NULL
   2197                       );
   2198   }
   2199 
   2200   if (Status == EFI_SUCCESS) {
   2201     Private->VgaInstalled = TRUE;
   2202 
   2203     //
   2204     // Attach the VGA thunk driver.
   2205     // Assume the video is installed. This prevents potential of infinite recursion.
   2206     //
   2207     Status = gBS->ConnectController (
   2208                     VgaHandle,
   2209                     ConnectHandleBuffer,
   2210                     NULL,
   2211                     TRUE
   2212                     );
   2213   }
   2214 
   2215   FreePool (ConnectHandleBuffer);
   2216 
   2217   if (EFI_ERROR (Status)) {
   2218 
   2219     Private->VgaInstalled = FALSE;
   2220 
   2221     //
   2222     // Reconnect the EFI VGA driver.
   2223     //
   2224     gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);
   2225     return EFI_DEVICE_ERROR;
   2226   }
   2227 
   2228   return EFI_SUCCESS;
   2229 }
   2230 
   2231 
   2232 /**
   2233   Load a legacy PC-AT OpROM.
   2234 
   2235   @param  This                              Protocol instance pointer.
   2236   @param  Private                          Driver's private data.
   2237   @param  PciHandle                      The EFI handle for the PCI device. It could be
   2238                                                     NULL if the  OpROM image is not associated with
   2239                                                     any device.
   2240   @param  OpromRevision              The revision of PCI PC-AT ROM image.
   2241   @param  RomImage                    Pointer to PCI PC-AT ROM image header. It must not
   2242                                                     be NULL.
   2243   @param  ImageSize                     Size of the PCI PC-AT ROM image.
   2244   @param  RuntimeImageLength      On input is the max runtime image length indicated by the PCIR structure
   2245                                                     On output is the actual runtime image length
   2246   @param  DiskStart                       Disk number of first device hooked by the ROM. If
   2247                                                     DiskStart is the same as DiskEnd no disked were
   2248                                                     hooked.
   2249   @param  DiskEnd                         Disk number of the last device hooked by the ROM.
   2250   @param  RomShadowAddress       Shadow address of PC-AT ROM
   2251 
   2252   @retval EFI_SUCCESS            Legacy ROM loaded for this device
   2253   @retval EFI_OUT_OF_RESOURCES   No more space for this ROM
   2254 
   2255 **/
   2256 EFI_STATUS
   2257 EFIAPI
   2258 LegacyBiosInstallRom (
   2259   IN EFI_LEGACY_BIOS_PROTOCOL           *This,
   2260   IN LEGACY_BIOS_INSTANCE               *Private,
   2261   IN EFI_HANDLE                         PciHandle,
   2262   IN UINT8                              OpromRevision,
   2263   IN VOID                               *RomImage,
   2264   IN UINTN                              ImageSize,
   2265   IN OUT UINTN                          *RuntimeImageLength,
   2266   OUT UINT8                             *DiskStart, OPTIONAL
   2267   OUT UINT8                             *DiskEnd, OPTIONAL
   2268   OUT VOID                              **RomShadowAddress OPTIONAL
   2269   )
   2270 {
   2271   EFI_STATUS            Status;
   2272   EFI_STATUS            PciEnableStatus;
   2273   EFI_PCI_IO_PROTOCOL   *PciIo;
   2274   UINT8                 LocalDiskStart;
   2275   UINT8                 LocalDiskEnd;
   2276   UINTN                 Segment;
   2277   UINTN                 Bus;
   2278   UINTN                 Device;
   2279   UINTN                 Function;
   2280   EFI_IA32_REGISTER_SET Regs;
   2281   UINT8                 VideoMode;
   2282   EFI_TIME              BootTime;
   2283   UINT32                *BdaPtr;
   2284   UINT32                LocalTime;
   2285   UINT32                StartBbsIndex;
   2286   UINT32                EndBbsIndex;
   2287   UINT32                MaxRomAddr;
   2288   UINTN                 TempData;
   2289   UINTN                 InitAddress;
   2290   UINTN                 RuntimeAddress;
   2291   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
   2292   UINT32                Granularity;
   2293 
   2294   PciIo           = NULL;
   2295   LocalDiskStart  = 0;
   2296   LocalDiskEnd    = 0;
   2297   Segment         = 0;
   2298   Bus             = 0;
   2299   Device          = 0;
   2300   Function        = 0;
   2301   VideoMode       = 0;
   2302   PhysicalAddress = 0;
   2303   MaxRomAddr      = PcdGet32 (PcdEndOpromShadowAddress);
   2304 
   2305   if ((Private->Legacy16Table->TableLength >= OFFSET_OF(EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
   2306       (Private->Legacy16Table->UmaAddress != 0) &&
   2307       (Private->Legacy16Table->UmaSize != 0) &&
   2308       (MaxRomAddr > (Private->Legacy16Table->UmaAddress))) {
   2309     MaxRomAddr = Private->Legacy16Table->UmaAddress;
   2310   }
   2311 
   2312 
   2313   PciProgramAllInterruptLineRegisters (Private);
   2314 
   2315   if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {
   2316     //
   2317     // CSM16 3.0 meets PCI 3.0 OpROM
   2318     //   first test if there is enough space for its INIT code
   2319     //
   2320     PhysicalAddress = CONVENTIONAL_MEMORY_TOP;
   2321     Status = gBS->AllocatePages (
   2322                     AllocateMaxAddress,
   2323                     EfiBootServicesCode,
   2324                     EFI_SIZE_TO_PAGES (ImageSize),
   2325                     &PhysicalAddress
   2326                     );
   2327 
   2328     if (EFI_ERROR (Status)) {
   2329       DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
   2330       //
   2331       // Report Status Code to indicate that there is no enough space for OpROM
   2332       //
   2333       REPORT_STATUS_CODE (
   2334         EFI_ERROR_CODE | EFI_ERROR_MINOR,
   2335         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
   2336         );
   2337       return EFI_OUT_OF_RESOURCES;
   2338     }
   2339     InitAddress = (UINTN) PhysicalAddress;
   2340     //
   2341     //   then test if there is enough space for its RT code
   2342     //
   2343     RuntimeAddress = Private->OptionRom;
   2344     if (RuntimeAddress + *RuntimeImageLength > MaxRomAddr) {
   2345       DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
   2346       gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
   2347       //
   2348       // Report Status Code to indicate that there is no enough space for OpROM
   2349       //
   2350       REPORT_STATUS_CODE (
   2351         EFI_ERROR_CODE | EFI_ERROR_MINOR,
   2352         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
   2353         );
   2354       return EFI_OUT_OF_RESOURCES;
   2355     }
   2356   } else {
   2357     // CSM16 3.0 meets PCI 2.x OpROM
   2358     // CSM16 2.x meets PCI 2.x/3.0 OpROM
   2359     //   test if there is enough space for its INIT code
   2360     //
   2361     InitAddress    = PCI_START_ADDRESS (Private->OptionRom);
   2362     if (InitAddress + ImageSize > MaxRomAddr) {
   2363       DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
   2364       //
   2365       // Report Status Code to indicate that there is no enough space for OpROM
   2366       //
   2367       REPORT_STATUS_CODE (
   2368         EFI_ERROR_CODE | EFI_ERROR_MINOR,
   2369         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
   2370         );
   2371       return EFI_OUT_OF_RESOURCES;
   2372     }
   2373 
   2374     RuntimeAddress = InitAddress;
   2375   }
   2376 
   2377   Private->LegacyRegion->UnLock (
   2378                            Private->LegacyRegion,
   2379                            0xE0000,
   2380                            0x20000,
   2381                            &Granularity
   2382                            );
   2383 
   2384   Private->LegacyRegion->UnLock (
   2385                            Private->LegacyRegion,
   2386                            (UINT32) RuntimeAddress,
   2387                            (UINT32) ImageSize,
   2388                            &Granularity
   2389                            );
   2390 
   2391   DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));
   2392 
   2393   CopyMem ((VOID *) InitAddress, RomImage, ImageSize);
   2394 
   2395   //
   2396   // Read the highest disk number "installed: and assume a new disk will
   2397   // show up on the first drive past the current value.
   2398   // There are several considerations here:
   2399   // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
   2400   //    the change until boot selection time frame.
   2401   // 2. BBS compliants drives will not change 40:75 until boot time.
   2402   // 3. Onboard IDE controllers will change 40:75
   2403   //
   2404   LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
   2405   if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
   2406     //
   2407     // Update table since onboard IDE drives found
   2408     //
   2409     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = 0xff;
   2410     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = 0xff;
   2411     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = 0xff;
   2412     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = 0xff;
   2413     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = (UINT8) (Private->Disk4075 + 0x80);
   2414     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber    = LocalDiskStart;
   2415     Private->LegacyEfiHddTableIndex ++;
   2416     Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);
   2417     Private->DiskEnd  = LocalDiskStart;
   2418   }
   2419 
   2420   if (PciHandle != mVgaHandle) {
   2421 
   2422     EnablePs2Keyboard ();
   2423 
   2424     //
   2425     // Store current mode settings since PrepareToScanRom may change mode.
   2426     //
   2427     VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
   2428   }
   2429   //
   2430   // Notify the platform that we are about to scan the ROM
   2431   //
   2432   Status = Private->LegacyBiosPlatform->PlatformHooks (
   2433                                           Private->LegacyBiosPlatform,
   2434                                           EfiPlatformHookPrepareToScanRom,
   2435                                           0,
   2436                                           PciHandle,
   2437                                           &InitAddress,
   2438                                           NULL,
   2439                                           NULL
   2440                                           );
   2441 
   2442   //
   2443   // If Status returned is EFI_UNSUPPORTED then abort due to platform
   2444   // policy.
   2445   //
   2446   if (Status == EFI_UNSUPPORTED) {
   2447     goto Done;
   2448   }
   2449 
   2450   //
   2451   // Report corresponding status code
   2452   //
   2453   REPORT_STATUS_CODE (
   2454     EFI_PROGRESS_CODE,
   2455     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)
   2456     );
   2457 
   2458   //
   2459   // Generate number of ticks since midnight for BDA. Some OPROMs require
   2460   // this. Place result in 40:6C-6F
   2461   //
   2462   gRT->GetTime (&BootTime, NULL);
   2463   LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
   2464 
   2465   //
   2466   // Multiply result by 18.2 for number of ticks since midnight.
   2467   // Use 182/10 to avoid floating point math.
   2468   //
   2469   LocalTime = (LocalTime * 182) / 10;
   2470   BdaPtr    = (UINT32 *) ((UINTN) 0x46C);
   2471   *BdaPtr   = LocalTime;
   2472 
   2473   //
   2474   // Pass in handoff data
   2475   //
   2476   PciEnableStatus = EFI_UNSUPPORTED;
   2477   ZeroMem (&Regs, sizeof (Regs));
   2478   if (PciHandle != NULL) {
   2479 
   2480     Status = gBS->HandleProtocol (
   2481                     PciHandle,
   2482                     &gEfiPciIoProtocolGuid,
   2483                     (VOID **) &PciIo
   2484                     );
   2485     ASSERT_EFI_ERROR (Status);
   2486 
   2487     //
   2488     // Enable command register.
   2489     //
   2490     PciEnableStatus = PciIo->Attributes (
   2491                                PciIo,
   2492                                EfiPciIoAttributeOperationEnable,
   2493                                EFI_PCI_DEVICE_ENABLE,
   2494                                NULL
   2495                                );
   2496 
   2497     PciIo->GetLocation (
   2498              PciIo,
   2499              &Segment,
   2500              &Bus,
   2501              &Device,
   2502              &Function
   2503              );
   2504     DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));
   2505   }
   2506 
   2507   mIgnoreBbsUpdateFlag  = FALSE;
   2508   Regs.X.AX             = Legacy16DispatchOprom;
   2509 
   2510   //
   2511   // Generate DispatchOpRomTable data
   2512   //
   2513   Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;
   2514   Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset  = Private->Legacy16Table->PnPInstallationCheckOffset;
   2515   Private->IntThunk->DispatchOpromTable.OpromSegment                = (UINT16) (InitAddress >> 4);
   2516   Private->IntThunk->DispatchOpromTable.PciBus                      = (UINT8) Bus;
   2517   Private->IntThunk->DispatchOpromTable.PciDeviceFunction           = (UINT8) ((Device << 3) | Function);
   2518   Private->IntThunk->DispatchOpromTable.NumberBbsEntries            = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
   2519   Private->IntThunk->DispatchOpromTable.BbsTablePointer             = (UINT32) (UINTN) Private->BbsTablePtr;
   2520   Private->IntThunk->DispatchOpromTable.RuntimeSegment              = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));
   2521   TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;
   2522   Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
   2523   Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
   2524   //
   2525   // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
   2526   // Otherwise, it may cause the system to hang in some cases
   2527   //
   2528   if (!EFI_ERROR (PciEnableStatus)) {
   2529     DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));
   2530     Private->LegacyBios.FarCall86 (
   2531       &Private->LegacyBios,
   2532       Private->Legacy16CallSegment,
   2533       Private->Legacy16CallOffset,
   2534       &Regs,
   2535       NULL,
   2536       0
   2537       );
   2538   } else {
   2539     Regs.X.BX = 0;
   2540   }
   2541 
   2542   if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {
   2543     Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries  = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;
   2544     mIgnoreBbsUpdateFlag = TRUE;
   2545   }
   2546   //
   2547   // Check if non-BBS compliant drives found
   2548   //
   2549   if (Regs.X.BX != 0) {
   2550     LocalDiskEnd  = (UINT8) (LocalDiskStart + Regs.H.BL);
   2551     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;
   2552     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;
   2553     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;
   2554     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;
   2555     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;
   2556     Private->DiskEnd = LocalDiskEnd;
   2557     Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
   2558     Private->LegacyEfiHddTableIndex += 1;
   2559   }
   2560   //
   2561   // Skip video mode set, if installing VGA
   2562   //
   2563   if (PciHandle != mVgaHandle) {
   2564     //
   2565     // Set mode settings since PrepareToScanRom may change mode
   2566     //
   2567     if (VideoMode != *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE))) {
   2568       //
   2569       // The active video mode is changed, restore it to original mode.
   2570       //
   2571       Regs.H.AH = 0x00;
   2572       Regs.H.AL = VideoMode;
   2573       Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);
   2574     }
   2575   }
   2576   //
   2577   // Regs.X.AX from the adapter initializion is ignored since some adapters
   2578   // do not follow the standard of setting AX = 0 on success.
   2579   //
   2580   //
   2581   // The ROM could have updated it's size so we need to read again.
   2582   //
   2583   if (((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
   2584     //
   2585     // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.
   2586     // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.
   2587     //
   2588     *RuntimeImageLength = 0;
   2589   } else {
   2590     *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Size512 * 512;
   2591   }
   2592 
   2593   DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));
   2594 
   2595   //
   2596   // If OpROM runs in 2.0 mode
   2597   //
   2598   if (PhysicalAddress == 0) {
   2599     if (*RuntimeImageLength < ImageSize) {
   2600       //
   2601       // Make area from end of shadowed rom to end of original rom all ffs
   2602       //
   2603       gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);
   2604     }
   2605   }
   2606 
   2607   LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
   2608 
   2609   //
   2610   // Allow platform to perform any required actions after the
   2611   // OPROM has been initialized.
   2612   //
   2613   Status = Private->LegacyBiosPlatform->PlatformHooks (
   2614                                           Private->LegacyBiosPlatform,
   2615                                           EfiPlatformHookAfterRomInit,
   2616                                           0,
   2617                                           PciHandle,
   2618                                           &RuntimeAddress,
   2619                                           NULL,
   2620                                           NULL
   2621                                           );
   2622   if (PciHandle != NULL) {
   2623     //
   2624     // If no PCI Handle then no header or Bevs.
   2625     //
   2626     if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {
   2627       StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
   2628       TempData      = RuntimeAddress;
   2629       UpdateBevBcvTable (
   2630         Private,
   2631         (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,
   2632         PciIo
   2633         );
   2634       EndBbsIndex   = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
   2635       LocalDiskEnd  = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));
   2636       if (LocalDiskEnd != LocalDiskStart) {
   2637         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment        = (UINT8) Segment;
   2638         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus            = (UINT8) Bus;
   2639         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice         = (UINT8) Device;
   2640         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction       = (UINT8) Function;
   2641         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber  = Private->DiskEnd;
   2642         Private->DiskEnd = LocalDiskEnd;
   2643         Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
   2644         Private->LegacyEfiHddTableIndex += 1;
   2645       }
   2646     }
   2647     //
   2648     // Mark PCI device as having a legacy BIOS ROM loaded.
   2649     //
   2650     RomShadow (
   2651       PciHandle,
   2652       (UINT32) RuntimeAddress,
   2653       (UINT32) *RuntimeImageLength,
   2654       LocalDiskStart,
   2655       LocalDiskEnd
   2656       );
   2657   }
   2658 
   2659   //
   2660   // Stuff caller's OPTIONAL return parameters.
   2661   //
   2662   if (RomShadowAddress != NULL) {
   2663     *RomShadowAddress = (VOID *) RuntimeAddress;
   2664   }
   2665 
   2666   if (DiskStart != NULL) {
   2667     *DiskStart = LocalDiskStart;
   2668   }
   2669 
   2670   if (DiskEnd != NULL) {
   2671     *DiskEnd = LocalDiskEnd;
   2672   }
   2673 
   2674   Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);
   2675 
   2676   Status = EFI_SUCCESS;
   2677 
   2678 Done:
   2679   if (PhysicalAddress != 0) {
   2680     //
   2681     // Free pages when OpROM is 3.0
   2682     //
   2683     gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
   2684   }
   2685 
   2686   //
   2687   // Insure all shadowed  areas are locked
   2688   //
   2689   Private->LegacyRegion->Lock (
   2690                            Private->LegacyRegion,
   2691                            0xC0000,
   2692                            0x40000,
   2693                            &Granularity
   2694                            );
   2695 
   2696   return Status;
   2697 }
   2698 
   2699 /**
   2700   Load a legacy PC-AT OPROM on the PciHandle device. Return information
   2701   about how many disks were added by the OPROM and the shadow address and
   2702   size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
   2703 
   2704   @param  This                   Protocol instance pointer.
   2705   @param  PciHandle              The PCI PC-AT OPROM from this devices ROM BAR will
   2706                                  be loaded. This value is NULL if RomImage is
   2707                                  non-NULL. This is the normal case.
   2708   @param  RomImage               A PCI PC-AT ROM image. This argument is non-NULL
   2709                                  if there is no hardware associated with the ROM
   2710                                  and thus no PciHandle, otherwise is must be NULL.
   2711                                  Example is PXE base code.
   2712   @param  Flags                  Indicates if ROM found and if PC-AT.
   2713   @param  DiskStart              Disk number of first device hooked by the ROM. If
   2714                                  DiskStart is the same as DiskEnd no disked were
   2715                                  hooked.
   2716   @param  DiskEnd                Disk number of the last device hooked by the ROM.
   2717   @param  RomShadowAddress       Shadow address of PC-AT ROM
   2718   @param  RomShadowedSize        Size of RomShadowAddress in bytes
   2719 
   2720   @retval EFI_SUCCESS            Legacy ROM loaded for this device
   2721   @retval EFI_INVALID_PARAMETER  PciHandle not found
   2722   @retval EFI_UNSUPPORTED        There is no PCI ROM in the ROM BAR or no onboard
   2723                                  ROM
   2724 
   2725 **/
   2726 EFI_STATUS
   2727 EFIAPI
   2728 LegacyBiosInstallPciRom (
   2729   IN EFI_LEGACY_BIOS_PROTOCOL           * This,
   2730   IN  EFI_HANDLE                        PciHandle,
   2731   IN  VOID                              **RomImage,
   2732   OUT UINTN                             *Flags,
   2733   OUT UINT8                             *DiskStart, OPTIONAL
   2734   OUT UINT8                             *DiskEnd, OPTIONAL
   2735   OUT VOID                              **RomShadowAddress, OPTIONAL
   2736   OUT UINT32                            *RomShadowedSize OPTIONAL
   2737   )
   2738 {
   2739   EFI_STATUS                      Status;
   2740   LEGACY_BIOS_INSTANCE            *Private;
   2741   VOID                            *LocalRomImage;
   2742   UINTN                           ImageSize;
   2743   UINTN                           RuntimeImageLength;
   2744   EFI_PCI_IO_PROTOCOL             *PciIo;
   2745   PCI_TYPE01                      PciConfigHeader;
   2746   UINTN                           HandleCount;
   2747   EFI_HANDLE                      *HandleBuffer;
   2748   UINTN                           PciSegment;
   2749   UINTN                           PciBus;
   2750   UINTN                           PciDevice;
   2751   UINTN                           PciFunction;
   2752   UINTN                           LastBus;
   2753   UINTN                           Index;
   2754   UINT8                           OpromRevision;
   2755   UINT32                          Granularity;
   2756   PCI_3_0_DATA_STRUCTURE          *Pcir;
   2757 
   2758   OpromRevision = 0;
   2759 
   2760   Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
   2761   if (Private->Legacy16Table->LastPciBus == 0) {
   2762     //
   2763     // Get last bus number if not already found
   2764     //
   2765     Status = gBS->LocateHandleBuffer (
   2766                     ByProtocol,
   2767                     &gEfiPciIoProtocolGuid,
   2768                     NULL,
   2769                     &HandleCount,
   2770                     &HandleBuffer
   2771                     );
   2772 
   2773     LastBus = 0;
   2774     for (Index = 0; Index < HandleCount; Index++) {
   2775       Status = gBS->HandleProtocol (
   2776                       HandleBuffer[Index],
   2777                       &gEfiPciIoProtocolGuid,
   2778                       (VOID **) &PciIo
   2779                       );
   2780       if (EFI_ERROR (Status)) {
   2781         continue;
   2782       }
   2783 
   2784       Status = PciIo->GetLocation (
   2785                         PciIo,
   2786                         &PciSegment,
   2787                         &PciBus,
   2788                         &PciDevice,
   2789                         &PciFunction
   2790                         );
   2791       if (PciBus > LastBus) {
   2792         LastBus = PciBus;
   2793       }
   2794     }
   2795 
   2796     Private->LegacyRegion->UnLock (
   2797                              Private->LegacyRegion,
   2798                              0xE0000,
   2799                              0x20000,
   2800                              &Granularity
   2801                              );
   2802     Private->Legacy16Table->LastPciBus = (UINT8) LastBus;
   2803     Private->LegacyRegion->Lock (
   2804                              Private->LegacyRegion,
   2805                              0xE0000,
   2806                              0x20000,
   2807                              &Granularity
   2808                              );
   2809   }
   2810 
   2811   *Flags = 0;
   2812   if ((PciHandle != NULL) && (RomImage == NULL)) {
   2813     //
   2814     // If PciHandle has OpRom to Execute
   2815     // and OpRom are all associated with Hardware
   2816     //
   2817     Status = gBS->HandleProtocol (
   2818                     PciHandle,
   2819                     &gEfiPciIoProtocolGuid,
   2820                     (VOID **) &PciIo
   2821                     );
   2822 
   2823     if (!EFI_ERROR (Status)) {
   2824       PciIo->Pci.Read (
   2825                    PciIo,
   2826                    EfiPciIoWidthUint32,
   2827                    0,
   2828                    sizeof (PciConfigHeader) / sizeof (UINT32),
   2829                    &PciConfigHeader
   2830                    );
   2831 
   2832       //
   2833       // if video installed & OPROM is video return
   2834       //
   2835       if (
   2836           (
   2837            ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&
   2838             (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))
   2839            ||
   2840            ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&
   2841             (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))
   2842           )
   2843           &&
   2844           (!Private->VgaInstalled)
   2845          ) {
   2846         mVgaInstallationInProgress = TRUE;
   2847 
   2848         //
   2849         //      return EFI_UNSUPPORTED;
   2850         //
   2851       }
   2852     }
   2853     //
   2854     // To run any legacy image, the VGA needs to be installed first.
   2855     // if installing the video, then don't need the thunk as already installed.
   2856     //
   2857     Status = Private->LegacyBiosPlatform->GetPlatformHandle (
   2858                                             Private->LegacyBiosPlatform,
   2859                                             EfiGetPlatformVgaHandle,
   2860                                             0,
   2861                                             &HandleBuffer,
   2862                                             &HandleCount,
   2863                                             NULL
   2864                                             );
   2865 
   2866     if (!EFI_ERROR (Status)) {
   2867       mVgaHandle = HandleBuffer[0];
   2868       if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {
   2869         //
   2870         // A return status of EFI_NOT_FOUND is considered valid (No EFI
   2871         // driver is controlling video.
   2872         //
   2873         mVgaInstallationInProgress  = TRUE;
   2874         Status                      = LegacyBiosInstallVgaRom (Private);
   2875         if (EFI_ERROR (Status)) {
   2876           if (Status != EFI_NOT_FOUND) {
   2877             mVgaInstallationInProgress = FALSE;
   2878             return Status;
   2879           }
   2880         } else {
   2881           mVgaInstallationInProgress = FALSE;
   2882         }
   2883       }
   2884     }
   2885     //
   2886     // See if the option ROM for PciHandle has already been executed
   2887     //
   2888     Status = IsLegacyRom (PciHandle);
   2889 
   2890     if (!EFI_ERROR (Status)) {
   2891       mVgaInstallationInProgress = FALSE;
   2892       GetShadowedRomParameters (
   2893         PciHandle,
   2894         DiskStart,
   2895         DiskEnd,
   2896         RomShadowAddress,
   2897         (UINTN *) RomShadowedSize
   2898         );
   2899       return EFI_SUCCESS;
   2900     }
   2901 
   2902     Status = LegacyBiosCheckPciRomEx (
   2903                &Private->LegacyBios,
   2904                PciHandle,
   2905                &LocalRomImage,
   2906                &ImageSize,
   2907                &RuntimeImageLength,
   2908                Flags,
   2909                &OpromRevision,
   2910                NULL
   2911                );
   2912     if (EFI_ERROR (Status)) {
   2913       //
   2914       // There is no PCI ROM in the ROM BAR or no onboard ROM
   2915       //
   2916       mVgaInstallationInProgress = FALSE;
   2917       return EFI_UNSUPPORTED;
   2918     }
   2919   } else {
   2920     if ((RomImage == NULL) || (*RomImage == NULL)) {
   2921       //
   2922       // If PciHandle is NULL, and no OpRom is to be associated
   2923       //
   2924       mVgaInstallationInProgress = FALSE;
   2925       return EFI_UNSUPPORTED;
   2926     }
   2927 
   2928     Status = Private->LegacyBiosPlatform->GetPlatformHandle (
   2929                                             Private->LegacyBiosPlatform,
   2930                                             EfiGetPlatformVgaHandle,
   2931                                             0,
   2932                                             &HandleBuffer,
   2933                                             &HandleCount,
   2934                                             NULL
   2935                                             );
   2936     if ((!EFI_ERROR (Status)) && (!Private->VgaInstalled)) {
   2937       //
   2938       // A return status of EFI_NOT_FOUND is considered valid (No EFI
   2939       // driver is controlling video.
   2940       //
   2941       mVgaInstallationInProgress  = TRUE;
   2942       Status                      = LegacyBiosInstallVgaRom (Private);
   2943       if (EFI_ERROR (Status)) {
   2944         if (Status != EFI_NOT_FOUND) {
   2945           mVgaInstallationInProgress = FALSE;
   2946           return Status;
   2947         }
   2948       } else {
   2949         mVgaInstallationInProgress = FALSE;
   2950       }
   2951     }
   2952 
   2953     LocalRomImage = *RomImage;
   2954     if (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE ||
   2955         ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset == 0 ||
   2956         (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset & 3 ) != 0) {
   2957       mVgaInstallationInProgress = FALSE;
   2958       return EFI_UNSUPPORTED;
   2959     }
   2960 
   2961     Pcir = (PCI_3_0_DATA_STRUCTURE *)
   2962            ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);
   2963 
   2964     if ((Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) || (Pcir->CodeType != PCI_CODE_TYPE_PCAT_IMAGE)) {
   2965       mVgaInstallationInProgress = FALSE;
   2966       return EFI_UNSUPPORTED;
   2967     }
   2968 
   2969     ImageSize = Pcir->ImageLength * 512;
   2970     if (Pcir->Length >= 0x1C) {
   2971       OpromRevision = Pcir->Revision;
   2972     } else {
   2973       OpromRevision = 0;
   2974     }
   2975     if (Pcir->Revision < 3) {
   2976       RuntimeImageLength = 0;
   2977     } else {
   2978       RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
   2979     }
   2980   }
   2981   //
   2982   // Shadow and initialize the OpROM.
   2983   //
   2984   ASSERT (Private->TraceIndex < 0x200);
   2985   Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;
   2986   Private->TraceIndex ++;
   2987   Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);
   2988   Status = LegacyBiosInstallRom (
   2989              This,
   2990              Private,
   2991              PciHandle,
   2992              OpromRevision,
   2993              LocalRomImage,
   2994              ImageSize,
   2995              &RuntimeImageLength,
   2996              DiskStart,
   2997              DiskEnd,
   2998              RomShadowAddress
   2999              );
   3000   if (RomShadowedSize != NULL) {
   3001     *RomShadowedSize = (UINT32) RuntimeImageLength;
   3002   }
   3003 
   3004   mVgaInstallationInProgress = FALSE;
   3005   return Status;
   3006 }
   3007 
   3008