]> git.proxmox.com Git - mirror_edk2.git/blobdiff - DuetPkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c
Renamed remotely
[mirror_edk2.git] / DuetPkg / PciRootBridgeNoEnumerationDxe / X64 / PcatIo.c
diff --git a/DuetPkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c b/DuetPkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c
new file mode 100644 (file)
index 0000000..0a786f8
--- /dev/null
@@ -0,0 +1,732 @@
+/*++\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+    PcatPciRootBridgeIo.c\r
+    \r
+Abstract:\r
+\r
+    EFI PC AT PCI Root Bridge Io Protocol\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "PcatPciRootBridge.h"\r
+\r
+static BOOLEAN                  mPciOptionRomTableInstalled = FALSE;\r
+static EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable          = {0, NULL};\r
+\r
+EFI_STATUS\r
+PcatRootBridgeIoIoRead (\r
+  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,\r
+  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
+  IN     UINT64                                 UserAddress,\r
+  IN     UINTN                                  Count,\r
+  IN OUT VOID                                   *UserBuffer\r
+  )\r
+{\r
+  return gCpuIo->Io.Read (\r
+                      gCpuIo,\r
+                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+                      UserAddress,\r
+                      Count,\r
+                      UserBuffer\r
+                      );\r
+}\r
+\r
+EFI_STATUS\r
+PcatRootBridgeIoIoWrite (\r
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,\r
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
+  IN UINT64                                 UserAddress,\r
+  IN UINTN                                  Count,\r
+  IN OUT VOID                               *UserBuffer\r
+  )\r
+{\r
+  return gCpuIo->Io.Write (\r
+                      gCpuIo,\r
+                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+                      UserAddress,\r
+                      Count,\r
+                      UserBuffer\r
+                      );\r
+\r
+}\r
+\r
+EFI_STATUS\r
+PcatRootBridgeIoGetIoPortMapping (\r
+  OUT EFI_PHYSICAL_ADDRESS  *IoPortMapping,\r
+  OUT EFI_PHYSICAL_ADDRESS  *MemoryPortMapping\r
+  )\r
+/*++\r
+\r
+  Get the IO Port Mapping.  For IA-32 it is always 0.\r
+  \r
+--*/\r
+{\r
+  *IoPortMapping = 0;\r
+  *MemoryPortMapping = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PcatRootBridgeIoPciRW (\r
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,\r
+  IN BOOLEAN                                Write,\r
+  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,\r
+  IN UINT64                                 UserAddress,\r
+  IN UINTN                                  Count,\r
+  IN OUT VOID                               *UserBuffer\r
+  )\r
+{\r
+  PCI_CONFIG_ACCESS_CF8             Pci;\r
+  PCI_CONFIG_ACCESS_CF8             PciAligned;\r
+  UINT32                            InStride;\r
+  UINT32                            OutStride;\r
+  UINTN                             PciData;\r
+  UINTN                             PciDataStride;\r
+  PCAT_PCI_ROOT_BRIDGE_INSTANCE     *PrivateData;\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS  PciAddress;\r
+  UINT64                            PciExpressRegAddr;\r
+  BOOLEAN                           UsePciExpressAccess;\r
+\r
+  if (Width < 0 || Width >= EfiPciWidthMaximum) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if ((Width & 0x03) >= EfiPciWidthUint64) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);\r
+\r
+  InStride    = 1 << (Width & 0x03);\r
+  OutStride   = InStride;\r
+  if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {\r
+    InStride = 0;\r
+  }\r
+\r
+  if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {\r
+    OutStride = 0;\r
+  }\r
+\r
+  UsePciExpressAccess = FALSE;\r
+\r
+  CopyMem (&PciAddress, &UserAddress, sizeof(UINT64));\r
+\r
+  if (PciAddress.ExtendedRegister > 0xFF) {\r
+    //\r
+    // Check PciExpressBaseAddress\r
+    //\r
+    if ((PrivateData->PciExpressBaseAddress == 0) ||\r
+        (PrivateData->PciExpressBaseAddress >= EFI_MAX_ADDRESS)) {\r
+      return EFI_UNSUPPORTED;\r
+    } else {\r
+      UsePciExpressAccess = TRUE;\r
+    }\r
+  } else {\r
+    if (PciAddress.ExtendedRegister != 0) {\r
+      Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF;\r
+    } else {\r
+      Pci.Bits.Reg = PciAddress.Register;\r
+    }\r
+    //\r
+    // Note: We can also use PciExpress access here, if wanted.\r
+    //\r
+  }\r
+\r
+  if (!UsePciExpressAccess) {\r
+    Pci.Bits.Func     = PciAddress.Function;\r
+    Pci.Bits.Dev      = PciAddress.Device;\r
+    Pci.Bits.Bus      = PciAddress.Bus;\r
+    Pci.Bits.Reserved = 0;\r
+    Pci.Bits.Enable   = 1;\r
+\r
+    //\r
+    // PCI Config access are all 32-bit alligned, but by accessing the\r
+    //  CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types\r
+    //  are possible on PCI.\r
+    //\r
+    // To read a byte of PCI config space you load 0xcf8 and \r
+    //  read 0xcfc, 0xcfd, 0xcfe, 0xcff\r
+    //\r
+    PciDataStride = Pci.Bits.Reg & 0x03;\r
+\r
+    while (Count) {\r
+      PciAligned = Pci;\r
+      PciAligned.Bits.Reg &= 0xfc;\r
+      PciData = (UINTN)PrivateData->PciData + PciDataStride;\r
+      EfiAcquireLock(&PrivateData->PciLock);\r
+      This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned);\r
+      if (Write) {\r
+        This->Io.Write (This, Width, PciData, 1, UserBuffer);\r
+      } else {\r
+        This->Io.Read (This, Width, PciData, 1, UserBuffer);\r
+      }\r
+      EfiReleaseLock(&PrivateData->PciLock);\r
+      UserBuffer = ((UINT8 *)UserBuffer) + OutStride;\r
+      PciDataStride = (PciDataStride + InStride) % 4;\r
+      Pci.Bits.Reg += InStride;\r
+      Count -= 1;\r
+    }\r
+  } else {\r
+    //\r
+    // Access PCI-Express space by using memory mapped method.\r
+    //\r
+    PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) |\r
+                        (PciAddress.Bus      << 20) |\r
+                        (PciAddress.Device   << 15) |\r
+                        (PciAddress.Function << 12);\r
+    if (PciAddress.ExtendedRegister != 0) {\r
+      PciExpressRegAddr += PciAddress.ExtendedRegister;\r
+    } else {\r
+      PciExpressRegAddr += PciAddress.Register;\r
+    }\r
+    while (Count) {\r
+      if (Write) {\r
+        This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer);\r
+      } else {\r
+        This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer);\r
+      }\r
+\r
+      UserBuffer = ((UINT8 *) UserBuffer) + OutStride;\r
+      PciExpressRegAddr += InStride;\r
+      Count -= 1;\r
+    }\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+static\r
+VOID\r
+ScanPciBus(\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev,\r
+  UINT16                           MinBus,\r
+  UINT16                           MaxBus,\r
+  UINT16                           MinDevice,\r
+  UINT16                           MaxDevice,\r
+  UINT16                           MinFunc,\r
+  UINT16                           MaxFunc,\r
+  EFI_PCI_BUS_SCAN_CALLBACK        Callback,\r
+  VOID                             *Context\r
+  )\r
+  \r
+{\r
+  UINT16      Bus;\r
+  UINT16      Device;\r
+  UINT16      Func;\r
+  UINT64      Address;\r
+  PCI_TYPE00  PciHeader;\r
+\r
+  //\r
+  // Loop through all busses\r
+  //\r
+  for (Bus = MinBus; Bus <= MaxBus; Bus++) {\r
+    //  \r
+    // Loop 32 devices per bus\r
+    //\r
+    for (Device = MinDevice; Device <= MaxDevice; Device++) {\r
+      //\r
+      // Loop through 8 functions per device\r
+      //\r
+      for (Func = MinFunc; Func <= MaxFunc; Func++) {\r
+\r
+        //\r
+        // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device\r
+        //\r
+        Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
+\r
+        //\r
+        // Read the VendorID from this PCI Device's Confioguration Header\r
+        //\r
+        IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId);\r
+    \r
+        //\r
+        // If VendorId = 0xffff, there does not exist a device at this \r
+        // location. For each device, if there is any function on it, \r
+        // there must be 1 function at Function 0. So if Func = 0, there\r
+        // will be no more functions in the same device, so we can break\r
+        // loop to deal with the next device.\r
+        //  \r
+        if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) {\r
+          break;\r
+        }\r
+        \r
+        if (PciHeader.Hdr.VendorId != 0xffff) {\r
+\r
+          //\r
+          // Read the HeaderType to determine if this is a multi-function device\r
+          //\r
+          IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType);\r
+\r
+          //\r
+          // Call the callback function for the device that was found\r
+          //\r
+          Callback(\r
+            IoDev, \r
+            MinBus, MaxBus,\r
+            MinDevice, MaxDevice,\r
+            MinFunc, MaxFunc,\r
+            Bus,\r
+            Device,\r
+            Func,\r
+            Context\r
+            );\r
+\r
+          //\r
+          // If this is not a multi-function device, we can leave the loop \r
+          // to deal with the next device.\r
+          //\r
+          if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) {\r
+            break;\r
+          }\r
+        }  \r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+static\r
+VOID\r
+CheckForRom (\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev,\r
+  UINT16                           MinBus,\r
+  UINT16                           MaxBus,\r
+  UINT16                           MinDevice,\r
+  UINT16                           MaxDevice,\r
+  UINT16                           MinFunc,\r
+  UINT16                           MaxFunc,\r
+  UINT16                           Bus,\r
+  UINT16                           Device,\r
+  UINT16                           Func,\r
+  IN VOID                          *VoidContext\r
+  )\r
+{\r
+  EFI_STATUS                                 Status;\r
+  PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT  *Context;\r
+  UINT64                                     Address;\r
+  PCI_TYPE00                                 PciHeader;\r
+  PCI_TYPE01                                 *PciBridgeHeader;\r
+  UINT32                                     Register;\r
+  UINT32                                     RomBar;\r
+  UINT32                                     RomBarSize;\r
+  EFI_PHYSICAL_ADDRESS                       RomBuffer;\r
+  UINT32                                     MaxRomSize;\r
+  EFI_PCI_EXPANSION_ROM_HEADER               EfiRomHeader;\r
+  PCI_DATA_STRUCTURE                         Pcir;\r
+  EFI_PCI_OPTION_ROM_DESCRIPTOR              *TempPciOptionRomDescriptors;\r
+  BOOLEAN                                    LastImage;\r
+\r
+  Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;\r
+\r
+  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
+\r
+  //\r
+  // Save the contents of the PCI Configuration Header\r
+  //\r
+  IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);\r
+\r
+  if (IS_PCI_BRIDGE(&PciHeader)) {\r
+\r
+    PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader);\r
+\r
+    //\r
+    // See if the PCI-PCI Bridge has its secondary interface enabled.\r
+    //\r
+    if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) {\r
+\r
+      //\r
+      // Disable the Prefetchable Memory Window\r
+      //\r
+      Register = 0x00000000;\r
+      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register);\r
+      IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register);\r
+      Register = 0xffffffff;\r
+      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register);\r
+      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register);\r
+\r
+      //\r
+      // Program Memory Window to the PCI Root Bridge Memory Window\r
+      //\r
+      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow);\r
+\r
+      //\r
+      // Enable the Memory decode for the PCI-PCI Bridge\r
+      //\r
+      IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
+      Register |= 0x02;\r
+      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
+\r
+      //\r
+      // Recurse on the Secondary Bus Number\r
+      //\r
+      ScanPciBus(\r
+        IoDev,\r
+        PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, \r
+        0, PCI_MAX_DEVICE, \r
+        0, PCI_MAX_FUNC, \r
+        CheckForRom, Context\r
+        );\r
+    }\r
+  } else {\r
+\r
+    //\r
+    // Check if an Option ROM Register is present and save the Option ROM Window Register\r
+    //\r
+    RomBar = 0xffffffff;\r
+    IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
+    IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
+\r
+    RomBarSize = (~(RomBar & 0xfffff800)) + 1;\r
+\r
+    //\r
+    // Make sure the size of the ROM is between 0 and 16 MB\r
+    //\r
+    if (RomBarSize > 0 && RomBarSize <= 0x01000000) {\r
+\r
+      //\r
+      // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window\r
+      //\r
+      RomBar = (Context->PpbMemoryWindow & 0xffff) << 16;\r
+      RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize;\r
+      if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) {\r
+        MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar;\r
+        RomBar = RomBar + 1;\r
+        IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
+        IoDev->Pci.Read  (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);\r
+        RomBar = RomBar - 1;\r
+\r
+        //\r
+        // Enable the Memory decode for the PCI Device\r
+        //\r
+        IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
+        Register |= 0x02;\r
+        IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
+\r
+        //\r
+        // Follow the chain of images to determine the size of the Option ROM present\r
+        // Keep going until the last image is found by looking at the Indicator field\r
+        // or the size of an image is 0, or the size of all the images is bigger than the\r
+        // size of the window programmed into the PPB.\r
+        //\r
+        RomBarSize = 0;\r
+        do {\r
+\r
+          LastImage = TRUE;\r
+\r
+          ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader));\r
+          IoDev->Mem.Read (\r
+            IoDev, \r
+            EfiPciWidthUint8, \r
+            RomBar + RomBarSize, \r
+            sizeof(EfiRomHeader),\r
+            &EfiRomHeader\r
+            );\r
+\r
+          Pcir.ImageLength = 0;\r
+\r
+          if (EfiRomHeader.Signature == 0xaa55) {\r
+\r
+            ZeroMem (&Pcir, sizeof(Pcir));\r
+            IoDev->Mem.Read (\r
+              IoDev, \r
+              EfiPciWidthUint8, \r
+              RomBar + RomBarSize + EfiRomHeader.PcirOffset, \r
+              sizeof(Pcir),\r
+              &Pcir\r
+              );\r
+\r
+            if ((Pcir.Indicator & 0x80) == 0x00) {\r
+              LastImage = FALSE;\r
+            }\r
+\r
+            RomBarSize += Pcir.ImageLength * 512;\r
+          }\r
+        } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);\r
+\r
+        if (RomBarSize > 0) {\r
+\r
+          //\r
+          // Allocate a memory buffer for the Option ROM contents.\r
+          //\r
+          Status = gBS->AllocatePages(\r
+                          AllocateAnyPages,\r
+                          EfiBootServicesData,\r
+                          EFI_SIZE_TO_PAGES(RomBarSize),\r
+                          &RomBuffer\r
+                          );\r
+\r
+          if (!EFI_ERROR (Status)) {\r
+\r
+            //\r
+            // Copy the contents of the Option ROM to the memory buffer\r
+            //\r
+            IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);\r
+\r
+            Status = gBS->AllocatePool(\r
+                            EfiBootServicesData,\r
+                            ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),\r
+                            &TempPciOptionRomDescriptors\r
+                            );\r
+            if (mPciOptionRomTable.PciOptionRomCount > 0) {\r
+              CopyMem(\r
+                TempPciOptionRomDescriptors, \r
+                mPciOptionRomTable.PciOptionRomDescriptors, \r
+                (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)\r
+                );\r
+\r
+              gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);\r
+            }\r
+\r
+            mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; \r
+\r
+            TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);\r
+\r
+            TempPciOptionRomDescriptors->RomAddress              = RomBuffer;\r
+            TempPciOptionRomDescriptors->MemoryType              = EfiBootServicesData;\r
+            TempPciOptionRomDescriptors->RomLength               = RomBarSize;\r
+            TempPciOptionRomDescriptors->Seg                     = (UINT32)IoDev->SegmentNumber;\r
+            TempPciOptionRomDescriptors->Bus                     = (UINT8)Bus;\r
+            TempPciOptionRomDescriptors->Dev                     = (UINT8)Device;\r
+            TempPciOptionRomDescriptors->Func                    = (UINT8)Func;\r
+            TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;\r
+            TempPciOptionRomDescriptors->DontLoadEfiRom          = FALSE;\r
+\r
+            mPciOptionRomTable.PciOptionRomCount++;\r
+          }\r
+        }\r
+\r
+        //\r
+        // Disable the Memory decode for the PCI-PCI Bridge\r
+        //\r
+        IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
+        Register &= (~0x02);\r
+        IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Restore the PCI Configuration Header \r
+  //\r
+  IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);\r
+}\r
+\r
+static\r
+VOID\r
+SaveCommandRegister (\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev,\r
+  UINT16                           MinBus,\r
+  UINT16                           MaxBus,\r
+  UINT16                           MinDevice,\r
+  UINT16                           MaxDevice,\r
+  UINT16                           MinFunc,\r
+  UINT16                           MaxFunc,\r
+  UINT16                           Bus,\r
+  UINT16                           Device,\r
+  UINT16                           Func,\r
+  IN VOID                          *VoidContext\r
+  )\r
+\r
+{\r
+  PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT  *Context;\r
+  UINT64  Address;\r
+  UINTN   Index;\r
+  UINT16  Command;\r
+\r
+  Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;\r
+\r
+  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);\r
+\r
+  Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;\r
+\r
+  IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);\r
+\r
+  //\r
+  // Clear the memory enable bit\r
+  //\r
+  Command = Context->CommandRegisterBuffer[Index] & (~0x02);\r
+\r
+  IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command);\r
+}\r
+\r
+static\r
+VOID\r
+RestoreCommandRegister (\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev,\r
+  UINT16                           MinBus,\r
+  UINT16                           MaxBus,\r
+  UINT16                           MinDevice,\r
+  UINT16                           MaxDevice,\r
+  UINT16                           MinFunc,\r
+  UINT16                           MaxFunc,\r
+  UINT16                           Bus,\r
+  UINT16                           Device,\r
+  UINT16                           Func,\r
+  IN VOID                          *VoidContext\r
+  )\r
+\r
+{\r
+  PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT  *Context;\r
+  UINT64                                     Address;\r
+  UINTN                                      Index;\r
+\r
+  Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;\r
+\r
+  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4);\r
+\r
+  Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func;\r
+\r
+  IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]);\r
+}\r
+\r
+EFI_STATUS\r
+ScanPciRootBridgeForRoms(\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev\r
+  )\r
+  \r
+{\r
+  EFI_STATUS                                 Status;\r
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR          *Descriptors; \r
+  UINT16                                     MinBus;\r
+  UINT16                                     MaxBus;\r
+  UINT64                                     RootWindowBase;\r
+  UINT64                                     RootWindowLimit;\r
+  PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT  Context;\r
+\r
+  if (mPciOptionRomTableInstalled == FALSE) {\r
+    gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);\r
+    mPciOptionRomTableInstalled = TRUE;\r
+  }\r
+\r
+  Status = IoDev->Configuration(IoDev, &Descriptors);\r
+  if (EFI_ERROR (Status) || Descriptors == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  MinBus = 0xffff;\r
+  MaxBus = 0xffff;\r
+  RootWindowBase  = 0;\r
+  RootWindowLimit = 0;\r
+  while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
+    //\r
+    // Find bus range\r
+    //\r
+    if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
+      MinBus = (UINT16)Descriptors->AddrRangeMin;\r
+      MaxBus = (UINT16)Descriptors->AddrRangeMax;\r
+    }\r
+    //\r
+    // Find memory descriptors that are not prefetchable\r
+    //\r
+    if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {\r
+      //\r
+      // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices\r
+      //\r
+      if (Descriptors->AddrRangeMax < 0x100000000) {\r
+        //\r
+        // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB\r
+        //\r
+        if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {\r
+          RootWindowBase  = Descriptors->AddrRangeMin;\r
+          RootWindowLimit = Descriptors->AddrRangeMax;\r
+        }\r
+      }\r
+    }\r
+    Descriptors ++;\r
+  }\r
+\r
+  //\r
+  // Make sure a bus range was found\r
+  //\r
+  if (MinBus == 0xffff || MaxBus == 0xffff) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Make sure a non-prefetchable memory region was found\r
+  //\r
+  if (RootWindowBase == 0 && RootWindowLimit == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Round the Base and Limit values to 1 MB boudaries\r
+  //\r
+  RootWindowBase  = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;\r
+  RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;\r
+\r
+  //\r
+  // Make sure that the size of the rounded window is greater than zero\r
+  //\r
+  if (RootWindowLimit <= RootWindowBase) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer to save the Command register from all the PCI devices\r
+  //\r
+  Context.CommandRegisterBuffer = NULL;\r
+  Status = gBS->AllocatePool(\r
+                  EfiBootServicesData,\r
+                  sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),\r
+                  &Context.CommandRegisterBuffer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Context.PpbMemoryWindow   = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);\r
+\r
+  //\r
+  // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits\r
+  //\r
+  ScanPciBus(\r
+    IoDev,\r
+    MinBus, MaxBus, \r
+    0, PCI_MAX_DEVICE, \r
+    0, PCI_MAX_FUNC, \r
+    SaveCommandRegister, &Context\r
+    );\r
+\r
+  //\r
+  // Recursively scan all the busses for PCI Option ROMs\r
+  //\r
+  ScanPciBus(\r
+    IoDev,\r
+    MinBus, MinBus, \r
+    0, PCI_MAX_DEVICE, \r
+    0, PCI_MAX_FUNC, \r
+    CheckForRom, &Context\r
+    );\r
+\r
+  //\r
+  // Restore the Command register in all the PCI devices\r
+  //\r
+  ScanPciBus(\r
+    IoDev,\r
+    MinBus, MaxBus, \r
+    0, PCI_MAX_DEVICE, \r
+    0, PCI_MAX_FUNC, \r
+    RestoreCommandRegister, &Context\r
+    );\r
+\r
+  //\r
+  // Free the buffer used to save all the Command register values\r
+  //\r
+  gBS->FreePool(Context.CommandRegisterBuffer);\r
+\r
+  return EFI_SUCCESS;\r
+}\r