[edk2-devel] [edk2-platforms] [PATCH V1 2/2] PurleyOpenBoardPkg : Override generic PciBus Driver with Platform specific instance of PciBus driver.

Nate DeSimone nathaniel.l.desimone at intel.com
Thu Jul 29 02:10:56 UTC 2021


Reviewed-by: Nate DeSimone <nathaniel.l.desimone at intel.com>

> -----Original Message-----
> From: manickavasakam karpagavinayagam <manickavasakamk at ami.com>
> Sent: Wednesday, June 16, 2021 2:48 PM
> To: devel at edk2.groups.io
> Cc: Oram, Isaac W <isaac.w.oram at intel.com>; Desimone, Nathaniel L
> <nathaniel.l.desimone at intel.com>; Felixp at ami.com; DOPPALAPUDI,
> HARIKRISHNA <harikrishnad at ami.com>; Jha, Manish <manishj at ami.com>;
> Bobroff, Zachary <zacharyb at ami.com>; KARPAGAVINAYAGAM,
> MANICKAVASAKAM <manickavasakamk at ami.com>
> Subject: [edk2-platforms] [PATCH V1 2/2] PurleyOpenBoardPkg : Override
> generic PciBus Driver with Platform specific instance of PciBus driver.
> 
> Overriden generic PciBus Driver with Platform specific instance of PciBus
> driver
> To skip SPI controller initialization during PCI enumeration to avoid SET
> variable
> assert issue during POST
> To skip executing a specific MLX card UEFI OPROM
> Move
> PurleyOpenBoardPkg/Override/edk2/MdeModulePkg/Bus/Pci/PciBusDxe to
> PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/PciBusDxe
> ---
>  .../BoardTiogaPass/CoreDxeInclude.dsc         |    5 +-
>  .../BoardTiogaPass/CoreUefiBootInclude.fdf    |    5 +-
>  .../Bus/Pci/PciBusDxe/ComponentName.c         |  170 +
>  .../Bus/Pci/PciBusDxe/ComponentName.h         |  146 +
>  .../MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.c   |  460 +++
>  .../MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h   |  396 +++
>  .../Bus/Pci/PciBusDxe/PciBusDxe.inf           |  112 +
>  .../Bus/Pci/PciBusDxe/PciBusDxe.uni           |   16 +
>  .../Bus/Pci/PciBusDxe/PciBusDxeExtra.uni      |   14 +
>  .../Bus/Pci/PciBusDxe/PciCommand.c            |  267 ++
>  .../Bus/Pci/PciBusDxe/PciCommand.h            |  232 ++
>  .../Bus/Pci/PciBusDxe/PciDeviceSupport.c      | 1056 ++++++
>  .../Bus/Pci/PciBusDxe/PciDeviceSupport.h      |  266 ++
>  .../Bus/Pci/PciBusDxe/PciDriverOverride.c     |  188 ++
>  .../Bus/Pci/PciBusDxe/PciDriverOverride.h     |   83 +
>  .../Bus/Pci/PciBusDxe/PciEnumerator.c         | 2210 +++++++++++++
>  .../Bus/Pci/PciBusDxe/PciEnumerator.h         |  515 +++
>  .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.c  | 2885
> +++++++++++++++++
>  .../Bus/Pci/PciBusDxe/PciEnumeratorSupport.h  |  480 +++
>  .../Bus/Pci/PciBusDxe/PciHotPlugSupport.c     |  484 +++
>  .../Bus/Pci/PciBusDxe/PciHotPlugSupport.h     |  205 ++
>  .../MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c    | 2087 ++++++++++++
>  .../MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.h    |  660 ++++
>  .../MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c   | 1809 +++++++++++
>  .../MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.h   |  179 +
>  .../Bus/Pci/PciBusDxe/PciOptionRomSupport.c   |  776 +++++
>  .../Bus/Pci/PciBusDxe/PciOptionRomSupport.h   |  136 +
>  .../Bus/Pci/PciBusDxe/PciPowerManagement.c    |   82 +
>  .../Bus/Pci/PciBusDxe/PciPowerManagement.h    |   28 +
>  .../Bus/Pci/PciBusDxe/PciResourceSupport.c    | 2292 +++++++++++++
>  .../Bus/Pci/PciBusDxe/PciResourceSupport.h    |  456 +++
>  .../Bus/Pci/PciBusDxe/PciRomTable.c           |  135 +
>  .../Bus/Pci/PciBusDxe/PciRomTable.h           |   48 +
>  33 files changed, 18881 insertions(+), 2 deletions(-)
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/ComponentName.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/ComponentName.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBus.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBus.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBusDxe.inf
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBusDxe.uni
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciBusDxeExtra.uni
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciCommand.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciCommand.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDeviceSupport.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDeviceSupport.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDriverOverride.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciDriverOverride.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumerator.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumerator.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumeratorSupport.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciEnumeratorSupport.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciHotPlugSupport.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciHotPlugSupport.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciIo.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciIo.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciLib.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciLib.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciOptionRomSupport.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciOptionRomSupport.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciPowerManagement.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciPowerManagement.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciResourceSupport.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciResourceSupport.h
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciRomTable.c
>  create mode 100644
> Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/Pci
> BusDxe/PciRomTable.h
> 
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> index 7dcb892dd5..b0660d72dd 100644
> ---
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreDxeInclude.dsc
> @@ -78,7 +78,10 @@
>    PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf
> 
>    #MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> -  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +#TiogaPass Override START :Skip  OPROM for specific Mellanox card & SPI
> Controller
> +  #MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +
> $(PLATFORM_BOARD_PACKAGE)/Override/MdeModulePkg/Bus/Pci/PciBus
> Dxe/PciBusDxe.inf
> +#TiogaPass Override END
> 
>    MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
>    MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> index 478a818546..141ce5dda3 100644
> ---
> a/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/BoardTiogaPass/CoreUefiBootInclud
> e.fdf
> @@ -42,7 +42,10 @@ INF
> MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntime
> Dxe.inf
>  INF  PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf
> 
>  #INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> -INF  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +#TiogaPass Override START :Skip OPROM for specific Mellanox card & SPI
> Controller
> + #INF  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> + INF
> $(PLATFORM_BOARD_PACKAGE)/Override/MdeModulePkg/Bus/Pci/PciBus
> Dxe/PciBusDxe.inf
> +#TiogaPass Override END
> 
>  INF  MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
>  INF  MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.c
> new file mode 100644
> index 0000000000..f3554507e2
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.c
> @@ -0,0 +1,170 @@
> +/** @file
> +  EFI Component Name functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// EFI Component Name Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME_PROTOCOL  gPciBusComponentName = {
> +  PciBusComponentNameGetDriverName,
> +  PciBusComponentNameGetControllerName,
> +  "eng"
> +};
> +
> +//
> +// EFI Component Name 2 Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)
> PciBusComponentNameGetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)
> PciBusComponentNameGetControllerName,
> +  "en"
> +};
> +
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> mPciBusDriverNameTable[] = {
> +  { "eng;en", (CHAR16 *) L"PCI Bus Driver" },
> +  { NULL , NULL }
> +};
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the driver.
> +
> +  This function retrieves the user readable name of a driver in the form of a
> +  Unicode string. If the driver specified by This has a user readable name in
> +  the language specified by Language, then a pointer to the driver name is
> +  returned in DriverName, and EFI_SUCCESS is returned. If the driver
> specified
> +  by This does not support the language specified by Language,
> +  then EFI_UNSUPPORTED is returned.
> +
> +  @param  This[in]              A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> +  @param  Language[in]          A pointer to a Null-terminated ASCII string
> +                                array indicating the language. This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified
> +                                in RFC 4646 or ISO 639-2 language code format.
> +
> +  @param  DriverName[out]       A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                driver specified by This in the language
> +                                specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> +                                This and the language specified by Language was
> +                                returned in DriverName.
> +
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  )
> +{
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           mPciBusDriverNameTable,
> +           DriverName,
> +           (BOOLEAN)(This == &gPciBusComponentName)
> +           );
> +}
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the controller
> +  that is being managed by a driver.
> +
> +  This function retrieves the user readable name of the controller specified
> by
> +  ControllerHandle and ChildHandle in the form of a Unicode string. If the
> +  driver specified by This has a user readable name in the language specified
> by
> +  Language, then a pointer to the controller name is returned in
> ControllerName,
> +  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
> +  managing the controller specified by ControllerHandle and ChildHandle,
> +  then EFI_UNSUPPORTED is returned.  If the driver specified by This does
> not
> +  support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> +  @param  This[in]              A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> +  @param  ControllerHandle[in]  The handle of a controller that the driver
> +                                specified by This is managing.  This handle
> +                                specifies the controller whose name is to be
> +                                returned.
> +
> +  @param  ChildHandle[in]       The handle of the child controller to retrieve
> +                                the name of.  This is an optional parameter that
> +                                may be NULL.  It will be NULL for device
> +                                drivers.  It will also be NULL for a bus drivers
> +                                that wish to retrieve the name of the bus
> +                                controller.  It will not be NULL for a bus
> +                                driver that wishes to retrieve the name of a
> +                                child controller.
> +
> +  @param  Language[in]          A pointer to a Null-terminated ASCII string
> +                                array indicating the language.  This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified in
> +                                RFC 4646 or ISO 639-2 language code format.
> +
> +  @param  ControllerName[out]   A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                controller specified by ControllerHandle and
> +                                ChildHandle in the language specified by
> +                                Language from the point of view of the driver
> +                                specified by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the user readable name
> in
> +                                the language specified by Language for the
> +                                driver specified by This was returned in
> +                                DriverName.
> +
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> +                                EFI_HANDLE.
> +
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> +                                managing the controller specified by
> +                                ControllerHandle and ChildHandle.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> +  IN  EFI_HANDLE                                      ControllerHandle,
> +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> +  IN  CHAR8                                           *Language,
> +  OUT CHAR16                                          **ControllerName
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.h
> new file mode 100644
> index 0000000000..fc3c672760
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/ComponentName.h
> @@ -0,0 +1,146 @@
> +/** @file
> +  EFI Component Name functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#ifndef _EFI_PCI_BUS_COMPONENT_NAME_H_
> +#define _EFI_PCI_BUS_COMPONENT_NAME_H_
> +
> +extern EFI_COMPONENT_NAME_PROTOCOL   gPciBusComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL  gPciBusComponentName2;
> +
> +//
> +// EFI Component Name Functions
> +//
> +/**
> +  Retrieves a Unicode string that is the user readable name of the driver.
> +
> +  This function retrieves the user readable name of a driver in the form of a
> +  Unicode string. If the driver specified by This has a user readable name in
> +  the language specified by Language, then a pointer to the driver name is
> +  returned in DriverName, and EFI_SUCCESS is returned. If the driver
> specified
> +  by This does not support the language specified by Language,
> +  then EFI_UNSUPPORTED is returned.
> +
> +  @param  This[in]              A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> +  @param  Language[in]          A pointer to a Null-terminated ASCII string
> +                                array indicating the language. This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified
> +                                in RFC 4646 or ISO 639-2 language code format.
> +
> +  @param  DriverName[out]       A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                driver specified by This in the language
> +                                specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> +                                This and the language specified by Language was
> +                                returned in DriverName.
> +
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  );
> +
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the controller
> +  that is being managed by a driver.
> +
> +  This function retrieves the user readable name of the controller specified
> by
> +  ControllerHandle and ChildHandle in the form of a Unicode string. If the
> +  driver specified by This has a user readable name in the language specified
> by
> +  Language, then a pointer to the controller name is returned in
> ControllerName,
> +  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
> +  managing the controller specified by ControllerHandle and ChildHandle,
> +  then EFI_UNSUPPORTED is returned.  If the driver specified by This does
> not
> +  support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> +  @param  This[in]              A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> +  @param  ControllerHandle[in]  The handle of a controller that the driver
> +                                specified by This is managing.  This handle
> +                                specifies the controller whose name is to be
> +                                returned.
> +
> +  @param  ChildHandle[in]       The handle of the child controller to retrieve
> +                                the name of.  This is an optional parameter that
> +                                may be NULL.  It will be NULL for device
> +                                drivers.  It will also be NULL for a bus drivers
> +                                that wish to retrieve the name of the bus
> +                                controller.  It will not be NULL for a bus
> +                                driver that wishes to retrieve the name of a
> +                                child controller.
> +
> +  @param  Language[in]          A pointer to a Null-terminated ASCII string
> +                                array indicating the language.  This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified in
> +                                RFC 4646 or ISO 639-2 language code format.
> +
> +  @param  ControllerName[out]   A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                controller specified by ControllerHandle and
> +                                ChildHandle in the language specified by
> +                                Language from the point of view of the driver
> +                                specified by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the user readable name
> in
> +                                the language specified by Language for the
> +                                driver specified by This was returned in
> +                                DriverName.
> +
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> +                                EFI_HANDLE.
> +
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> +                                managing the controller specified by
> +                                ControllerHandle and ChildHandle.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> +  IN  EFI_HANDLE                                      ControllerHandle,
> +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> +  IN  CHAR8                                           *Language,
> +  OUT CHAR16                                          **ControllerName
> +  );
> +
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.c
> new file mode 100644
> index 0000000000..682b2dac38
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.c
> @@ -0,0 +1,460 @@
> +/** @file
> +  Driver Binding functions for PCI Bus module.
> +
> +  Single PCI bus driver instance will manager all PCI Root Bridges in one EFI
> based firmware,
> +  since all PCI Root Bridges' resources need to be managed together.
> +  Supported() function will try to get PCI Root Bridge IO Protocol.
> +  Start() function will get PCI Host Bridge Resource Allocation Protocol to
> manage all
> +  PCI Root Bridges. So it means platform needs install PCI Root Bridge IO
> protocol for each
> +  PCI Root Bus and install PCI Host Bridge Resource Allocation Protocol.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// PCI Bus Driver Global Variables
> +//
> +EFI_DRIVER_BINDING_PROTOCOL                   gPciBusDriverBinding = {
> +  PciBusDriverBindingSupported,
> +  PciBusDriverBindingStart,
> +  PciBusDriverBindingStop,
> +  0xa,
> +  NULL,
> +  NULL
> +};
> +
> +EFI_HANDLE
> gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
> +EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL
> *gIncompatiblePciDeviceSupport = NULL;
> +UINTN                                         gPciHostBridgeNumber = 0;
> +BOOLEAN                                       gFullEnumeration     = TRUE;
> +UINT64                                        gAllOne              = 0xFFFFFFFFFFFFFFFFULL;
> +UINT64                                        gAllZero             = 0;
> +
> +EFI_PCI_PLATFORM_PROTOCOL                     *gPciPlatformProtocol;
> +EFI_PCI_OVERRIDE_PROTOCOL                     *gPciOverrideProtocol;
> +EDKII_IOMMU_PROTOCOL                          *mIoMmuProtocol;
> +EDKII_DEVICE_SECURITY_PROTOCOL                *mDeviceSecurityProtocol;
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_PCI_HOTPLUG_REQUEST_PROTOCOL mPciHotPlugRequest = {
> +  PciHotPlugRequestNotify
> +};
> +
> +/**
> +  The Entry Point for PCI Bus module. The user code starts with this function.
> +
> +  Installs driver module protocols and. Creates virtual device handles for
> ConIn,
> +  ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex
> protocol,
> +  Simple Pointer protocol, Absolute Pointer protocol on those virtual
> handlers.
> +  Installs Graphics Output protocol and/or UGA Draw protocol if needed.
> +
> +  @param[in] ImageHandle    The firmware allocated handle for the EFI
> image.
> +  @param[in] SystemTable    A pointer to the EFI System Table.
> +
> +  @retval EFI_SUCCESS       The entry point is executed successfully.
> +  @retval other             Some error occurred when executing this entry point.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusEntryPoint (
> +  IN EFI_HANDLE         ImageHandle,
> +  IN EFI_SYSTEM_TABLE   *SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  EFI_HANDLE  Handle;
> +
> +  //
> +  // Initializes PCI devices pool
> +  //
> +  InitializePciDevicePool ();
> +
> +  //
> +  // Install driver model protocol(s).
> +  //
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> +             ImageHandle,
> +             SystemTable,
> +             &gPciBusDriverBinding,
> +             ImageHandle,
> +             &gPciBusComponentName,
> +             &gPciBusComponentName2
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +    //
> +    // If Hot Plug is supported, install EFI PCI Hot Plug Request protocol.
> +    //
> +    Handle = NULL;
> +    Status = gBS->InstallProtocolInterface (
> +                    &Handle,
> +                    &gEfiPciHotPlugRequestProtocolGuid,
> +                    EFI_NATIVE_INTERFACE,
> +                    &mPciHotPlugRequest
> +                    );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Test to see if this driver supports ControllerHandle. Any ControllerHandle
> +  than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be
> supported.
> +
> +  @param  This                Protocol instance pointer.
> +  @param  Controller          Handle of device to test.
> +  @param  RemainingDevicePath Optional parameter use to pick a specific
> child
> +                              device to start.
> +
> +  @retval EFI_SUCCESS         This driver supports this device.
> +  @retval EFI_ALREADY_STARTED This driver is already running on this
> device.
> +  @retval other               This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> +  IN EFI_HANDLE                     Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +  EFI_DEV_PATH_PTR                Node;
> +
> +  //
> +  // Check RemainingDevicePath validation
> +  //
> +  if (RemainingDevicePath != NULL) {
> +    //
> +    // Check if RemainingDevicePath is the End of Device Path Node,
> +    // if yes, go on checking other conditions
> +    //
> +    if (!IsDevicePathEnd (RemainingDevicePath)) {
> +      //
> +      // If RemainingDevicePath isn't the End of Device Path Node,
> +      // check its validation
> +      //
> +      Node.DevPath = RemainingDevicePath;
> +      if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
> +          Node.DevPath->SubType != HW_PCI_DP         ||
> +          DevicePathNodeLength(Node.DevPath) != sizeof(PCI_DEVICE_PATH))
> {
> +        return EFI_UNSUPPORTED;
> +      }
> +    }
> +  }
> +
> +  //
> +  // Check if Pci Root Bridge IO protocol is installed by platform
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  (VOID **) &PciRootBridgeIo,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (Status == EFI_ALREADY_STARTED) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Close the I/O Abstraction(s) used to perform the supported test
> +  //
> +  gBS->CloseProtocol (
> +        Controller,
> +        &gEfiPciRootBridgeIoProtocolGuid,
> +        This->DriverBindingHandle,
> +        Controller
> +        );
> +
> +  //
> +  // Open the EFI Device Path protocol needed to perform the supported
> test
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiDevicePathProtocolGuid,
> +                  (VOID **) &ParentDevicePath,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (Status == EFI_ALREADY_STARTED) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Close protocol, don't use device path protocol in the Support() function
> +  //
> +  gBS->CloseProtocol (
> +        Controller,
> +        &gEfiDevicePathProtocolGuid,
> +        This->DriverBindingHandle,
> +        Controller
> +        );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Start this driver on ControllerHandle and enumerate Pci bus and start
> +  all device under PCI bus.
> +
> +  @param  This                 Protocol instance pointer.
> +  @param  Controller           Handle of device to bind driver to.
> +  @param  RemainingDevicePath  Optional parameter use to pick a specific
> child
> +                               device to start.
> +
> +  @retval EFI_SUCCESS          This driver is added to ControllerHandle.
> +  @retval EFI_ALREADY_STARTED  This driver is already running on
> ControllerHandle.
> +  @retval other                This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE                   Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  //
> +  // Initialize PciRootBridgeIo to suppress incorrect compiler warning.
> +  //
> +  PciRootBridgeIo = NULL;
> +
> +  //
> +  // Check RemainingDevicePath validation
> +  //
> +  if (RemainingDevicePath != NULL) {
> +    //
> +    // Check if RemainingDevicePath is the End of Device Path Node,
> +    // if yes, return EFI_SUCCESS
> +    //
> +    if (IsDevicePathEnd (RemainingDevicePath)) {
> +      return EFI_SUCCESS;
> +    }
> +  }
> +
> +  gBS->LocateProtocol (
> +         &gEfiIncompatiblePciDeviceSupportProtocolGuid,
> +         NULL,
> +         (VOID **) &gIncompatiblePciDeviceSupport
> +         );
> +
> +  //
> +  // If PCI Platform protocol is available, get it now.
> +  // If the platform implements this, it must be installed before BDS phase
> +  //
> +  gPciPlatformProtocol = NULL;
> +  gBS->LocateProtocol (
> +        &gEfiPciPlatformProtocolGuid,
> +        NULL,
> +        (VOID **) &gPciPlatformProtocol
> +        );
> +
> +  //
> +  // If PCI Platform protocol doesn't exist, try to Pci Override Protocol.
> +  //
> +  if (gPciPlatformProtocol == NULL) {
> +    gPciOverrideProtocol = NULL;
> +    gBS->LocateProtocol (
> +          &gEfiPciOverrideProtocolGuid,
> +          NULL,
> +          (VOID **) &gPciOverrideProtocol
> +          );
> +  }
> +
> +  if (mIoMmuProtocol == NULL) {
> +    gBS->LocateProtocol (
> +          &gEdkiiIoMmuProtocolGuid,
> +          NULL,
> +          (VOID **) &mIoMmuProtocol
> +          );
> +  }
> +
> +  if (mDeviceSecurityProtocol == NULL) {
> +    gBS->LocateProtocol (
> +          &gEdkiiDeviceSecurityProtocolGuid,
> +          NULL,
> +          (VOID **) &mDeviceSecurityProtocol
> +          );
> +  }
> +
> +  if (PcdGetBool (PcdPciDisableBusEnumeration)) {
> +    gFullEnumeration = FALSE;
> +  } else {
> +    gFullEnumeration = (BOOLEAN) ((SearchHostBridgeHandle (Controller) ?
> FALSE : TRUE));
> +  }
> +
> +  //
> +  // Open Device Path Protocol for PCI root bridge
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiDevicePathProtocolGuid,
> +                  (VOID **) &ParentDevicePath,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Report Status Code to indicate PCI bus starts
> +  //
> +  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +    EFI_PROGRESS_CODE,
> +    (EFI_IO_BUS_PCI | EFI_IOB_PC_INIT),
> +    ParentDevicePath
> +    );
> +
> +  Status = EFI_SUCCESS;
> +  //
> +  // Enumerate the entire host bridge
> +  // After enumeration, a database that records all the device information
> will be created
> +  //
> +  //
> +  if (gFullEnumeration) {
> +    //
> +    // Get the rootbridge Io protocol to find the host bridge handle
> +    //
> +    Status = gBS->OpenProtocol (
> +                    Controller,
> +                    &gEfiPciRootBridgeIoProtocolGuid,
> +                    (VOID **) &PciRootBridgeIo,
> +                    gPciBusDriverBinding.DriverBindingHandle,
> +                    Controller,
> +                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                    );
> +
> +    if (!EFI_ERROR (Status)) {
> +      Status = PciEnumerator (Controller, PciRootBridgeIo->ParentHandle);
> +    }
> +  } else {
> +    //
> +    // If PCI bus has already done the full enumeration, never do it again
> +    //
> +    Status = PciEnumeratorLight (Controller);
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Start all the devices under the entire host bridge.
> +  //
> +  StartPciDevices (Controller);
> +
> +  if (gFullEnumeration) {
> +    gFullEnumeration = FALSE;
> +
> +    Status = gBS->InstallProtocolInterface (
> +                    &PciRootBridgeIo->ParentHandle,
> +                    &gEfiPciEnumerationCompleteProtocolGuid,
> +                    EFI_NATIVE_INTERFACE,
> +                    NULL
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Stop this driver on ControllerHandle. Support stopping any child handles
> +  created by this driver.
> +
> +  @param  This              Protocol instance pointer.
> +  @param  Controller        Handle of device to stop driver on.
> +  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If
> number of
> +                            children is zero stop the entire bus driver.
> +  @param  ChildHandleBuffer List of Child Handles to Stop.
> +
> +  @retval EFI_SUCCESS       This driver is removed ControllerHandle.
> +  @retval other             This driver was not removed from this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusDriverBindingStop (
> +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> +  IN  EFI_HANDLE                    Controller,
> +  IN  UINTN                         NumberOfChildren,
> +  IN  EFI_HANDLE                    *ChildHandleBuffer
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINTN       Index;
> +  BOOLEAN     AllChildrenStopped;
> +
> +  if (NumberOfChildren == 0) {
> +    //
> +    // Close the bus driver
> +    //
> +    gBS->CloseProtocol (
> +          Controller,
> +          &gEfiDevicePathProtocolGuid,
> +          This->DriverBindingHandle,
> +          Controller
> +          );
> +    gBS->CloseProtocol (
> +          Controller,
> +          &gEfiPciRootBridgeIoProtocolGuid,
> +          This->DriverBindingHandle,
> +          Controller
> +          );
> +
> +    DestroyRootBridgeByHandle (
> +      Controller
> +      );
> +
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Stop all the children
> +  //
> +
> +  AllChildrenStopped = TRUE;
> +
> +  for (Index = 0; Index < NumberOfChildren; Index++) {
> +
> +    //
> +    // De register all the pci device
> +    //
> +    Status = DeRegisterPciDevice (Controller, ChildHandleBuffer[Index]);
> +
> +    if (EFI_ERROR (Status)) {
> +      AllChildrenStopped = FALSE;
> +    }
> +  }
> +
> +  if (!AllChildrenStopped) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.h
> new file mode 100644
> index 0000000000..967933e278
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBus.h
> @@ -0,0 +1,396 @@
> +/** @file
> +  Header files and data structures needed by PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#ifndef _EFI_PCI_BUS_H_
> +#define _EFI_PCI_BUS_H_
> +
> +#include <PiDxe.h>
> +
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/PciHostBridgeResourceAllocation.h>
> +#include <Protocol/PciIo.h>
> +#include <Protocol/LoadFile2.h>
> +#include <Protocol/PciRootBridgeIo.h>
> +#include <Protocol/PciHotPlugRequest.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/PciPlatform.h>
> +#include <Protocol/PciHotPlugInit.h>
> +#include <Protocol/Decompress.h>
> +#include <Protocol/BusSpecificDriverOverride.h>
> +#include <Protocol/IncompatiblePciDeviceSupport.h>
> +#include <Protocol/PciOverride.h>
> +#include <Protocol/PciEnumerationComplete.h>
> +#include <Protocol/IoMmu.h>
> +#include <Protocol/DeviceSecurity.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/BaseLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/PcdLib.h>
> +
> +#include <IndustryStandard/Pci.h>
> +#include <IndustryStandard/PeImage.h>
> +#include <IndustryStandard/Acpi.h>
> +
> +typedef struct _PCI_IO_DEVICE              PCI_IO_DEVICE;
> +typedef struct _PCI_BAR                    PCI_BAR;
> +
> +#define EFI_PCI_RID(Bus, Device, Function)  (((UINT32)Bus << 8) +
> ((UINT32)Device << 3) + (UINT32)Function)
> +#define EFI_PCI_BUS_OF_RID(RID)             ((UINT32)RID >> 8)
> +
> +#define     EFI_PCI_IOV_POLICY_ARI           0x0001
> +#define     EFI_PCI_IOV_POLICY_SRIOV         0x0002
> +#define     EFI_PCI_IOV_POLICY_MRIOV         0x0004
> +
> +typedef enum {
> +  PciBarTypeUnknown = 0,
> +  PciBarTypeIo16,
> +  PciBarTypeIo32,
> +  PciBarTypeMem32,
> +  PciBarTypePMem32,
> +  PciBarTypeMem64,
> +  PciBarTypePMem64,
> +  PciBarTypeOpRom,
> +  PciBarTypeIo,
> +  PciBarTypeMem,
> +  PciBarTypeMaxType
> +} PCI_BAR_TYPE;
> +
> +#include "ComponentName.h"
> +#include "PciIo.h"
> +#include "PciCommand.h"
> +#include "PciDeviceSupport.h"
> +#include "PciEnumerator.h"
> +#include "PciEnumeratorSupport.h"
> +#include "PciDriverOverride.h"
> +#include "PciRomTable.h"
> +#include "PciOptionRomSupport.h"
> +#include "PciPowerManagement.h"
> +#include "PciHotPlugSupport.h"
> +#include "PciLib.h"
> +
> +#define VGABASE1  0x3B0
> +#define VGALIMIT1 0x3BB
> +
> +#define VGABASE2  0x3C0
> +#define VGALIMIT2 0x3DF
> +
> +#define ISABASE   0x100
> +#define ISALIMIT  0x3FF
> +
> +//
> +// PCI BAR parameters
> +//
> +struct _PCI_BAR {
> +  UINT64        BaseAddress;
> +  UINT64        Length;
> +  UINT64        Alignment;
> +  PCI_BAR_TYPE  BarType;
> +  BOOLEAN       BarTypeFixed;
> +  UINT16        Offset;
> +};
> +
> +//
> +// defined in PCI Card Specification, 8.0
> +//
> +#define PCI_CARD_MEMORY_BASE_0                0x1C
> +#define PCI_CARD_MEMORY_LIMIT_0               0x20
> +#define PCI_CARD_MEMORY_BASE_1                0x24
> +#define PCI_CARD_MEMORY_LIMIT_1               0x28
> +#define PCI_CARD_IO_BASE_0_LOWER              0x2C
> +#define PCI_CARD_IO_BASE_0_UPPER              0x2E
> +#define PCI_CARD_IO_LIMIT_0_LOWER             0x30
> +#define PCI_CARD_IO_LIMIT_0_UPPER             0x32
> +#define PCI_CARD_IO_BASE_1_LOWER              0x34
> +#define PCI_CARD_IO_BASE_1_UPPER              0x36
> +#define PCI_CARD_IO_LIMIT_1_LOWER             0x38
> +#define PCI_CARD_IO_LIMIT_1_UPPER             0x3A
> +#define PCI_CARD_BRIDGE_CONTROL               0x3E
> +
> +#define PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE BIT8
> +#define PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE BIT9
> +
> +#define RB_IO_RANGE                           1
> +#define RB_MEM32_RANGE                        2
> +#define RB_PMEM32_RANGE                       3
> +#define RB_MEM64_RANGE                        4
> +#define RB_PMEM64_RANGE                       5
> +
> +#define PPB_BAR_0                             0
> +#define PPB_BAR_1                             1
> +#define PPB_IO_RANGE                          2
> +#define PPB_MEM32_RANGE                       3
> +#define PPB_PMEM32_RANGE                      4
> +#define PPB_PMEM64_RANGE                      5
> +#define PPB_MEM64_RANGE                       0xFF
> +
> +#define P2C_BAR_0                             0
> +#define P2C_MEM_1                             1
> +#define P2C_MEM_2                             2
> +#define P2C_IO_1                              3
> +#define P2C_IO_2                              4
> +
> +#define EFI_BRIDGE_IO32_DECODE_SUPPORTED      0x0001
> +#define EFI_BRIDGE_PMEM32_DECODE_SUPPORTED    0x0002
> +#define EFI_BRIDGE_PMEM64_DECODE_SUPPORTED    0x0004
> +#define EFI_BRIDGE_IO16_DECODE_SUPPORTED      0x0008
> +#define EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED 0x0010
> +#define EFI_BRIDGE_MEM64_DECODE_SUPPORTED     0x0020
> +#define EFI_BRIDGE_MEM32_DECODE_SUPPORTED     0x0040
> +
> +#define PCI_MAX_HOST_BRIDGE_NUM               0x0010
> +
> +//
> +// Define option for attribute
> +//
> +#define EFI_SET_SUPPORTS    0
> +#define EFI_SET_ATTRIBUTES  1
> +
> +#define PCI_IO_DEVICE_SIGNATURE               SIGNATURE_32 ('p', 'c', 'i', 'o')
> +
> +struct _PCI_IO_DEVICE {
> +  UINT32                                    Signature;
> +  EFI_HANDLE                                Handle;
> +  EFI_PCI_IO_PROTOCOL                       PciIo;
> +  LIST_ENTRY                                Link;
> +
> +  EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL PciDriverOverride;
> +  EFI_DEVICE_PATH_PROTOCOL                  *DevicePath;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *PciRootBridgeIo;
> +  EFI_LOAD_FILE2_PROTOCOL                   LoadFile2;
> +
> +  //
> +  // PCI configuration space header type
> +  //
> +  PCI_TYPE00                                Pci;
> +
> +  //
> +  // Bus number, Device number, Function number
> +  //
> +  UINT8                                     BusNumber;
> +  UINT8                                     DeviceNumber;
> +  UINT8                                     FunctionNumber;
> +
> +  //
> +  // BAR for this PCI Device
> +  //
> +  PCI_BAR                                   PciBar[PCI_MAX_BAR];
> +
> +  //
> +  // The bridge device this pci device is subject to
> +  //
> +  PCI_IO_DEVICE                             *Parent;
> +
> +  //
> +  // A linked list for children Pci Device if it is bridge device
> +  //
> +  LIST_ENTRY                                ChildList;
> +
> +  //
> +  // TRUE if the PCI bus driver creates the handle for this PCI device
> +  //
> +  BOOLEAN                                   Registered;
> +
> +  //
> +  // TRUE if the PCI bus driver successfully allocates the resource required by
> +  // this PCI device
> +  //
> +  BOOLEAN                                   Allocated;
> +
> +  //
> +  // The attribute this PCI device currently set
> +  //
> +  UINT64                                    Attributes;
> +
> +  //
> +  // The attributes this PCI device actually supports
> +  //
> +  UINT64                                    Supports;
> +
> +  //
> +  // The resource decode the bridge supports
> +  //
> +  UINT32                                    Decodes;
> +
> +  //
> +  // TRUE if the ROM image is from the PCI Option ROM BAR
> +  //
> +  BOOLEAN                                   EmbeddedRom;
> +
> +  //
> +  // The OptionRom Size
> +  //
> +  UINT32                                    RomSize;
> +
> +  //
> +  // TRUE if all OpROM (in device or in platform specific position) have been
> processed
> +  //
> +  BOOLEAN                                   AllOpRomProcessed;
> +
> +  //
> +  // TRUE if there is any EFI driver in the OptionRom
> +  //
> +  BOOLEAN                                   BusOverride;
> +
> +  //
> +  // A list tracking reserved resource on a bridge device
> +  //
> +  LIST_ENTRY                                ReservedResourceList;
> +
> +  //
> +  // A list tracking image handle of platform specific overriding driver
> +  //
> +  LIST_ENTRY                                OptionRomDriverList;
> +
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
> *ResourcePaddingDescriptors;
> +  EFI_HPC_PADDING_ATTRIBUTES                PaddingAttributes;
> +
> +  //
> +  // Bus number ranges for a PCI Root Bridge device
> +  //
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR         *BusNumberRanges;
> +
> +  BOOLEAN                                   IsPciExp;
> +  //
> +  // For SR-IOV
> +  //
> +  UINT8                                     PciExpressCapabilityOffset;
> +  UINT32                                    AriCapabilityOffset;
> +  UINT32                                    SrIovCapabilityOffset;
> +  UINT32                                    MrIovCapabilityOffset;
> +  PCI_BAR                                   VfPciBar[PCI_MAX_BAR];
> +  UINT32                                    SystemPageSize;
> +  UINT16                                    InitialVFs;
> +  UINT16                                    ReservedBusNum;
> +  //
> +  // Per PCI to PCI Bridge spec, I/O window is 4K aligned,
> +  // but some chipsets support non-standard I/O window alignments less
> than 4K.
> +  // This field is used to support this case.
> +  //
> +  UINT16                                    BridgeIoAlignment;
> +  UINT32                                    ResizableBarOffset;
> +  UINT32                                    ResizableBarNumber;
> +};
> +
> +#define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \
> +  CR (a, PCI_IO_DEVICE, PciIo, PCI_IO_DEVICE_SIGNATURE)
> +
> +#define PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS(a) \
> +  CR (a, PCI_IO_DEVICE, PciDriverOverride, PCI_IO_DEVICE_SIGNATURE)
> +
> +#define PCI_IO_DEVICE_FROM_LINK(a) \
> +  CR (a, PCI_IO_DEVICE, Link, PCI_IO_DEVICE_SIGNATURE)
> +
> +#define PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS(a) \
> +  CR (a, PCI_IO_DEVICE, LoadFile2, PCI_IO_DEVICE_SIGNATURE)
> +
> +
> +
> +//
> +// Global Variables
> +//
> +extern EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL
> *gIncompatiblePciDeviceSupport;
> +extern EFI_DRIVER_BINDING_PROTOCOL                  gPciBusDriverBinding;
> +extern EFI_COMPONENT_NAME_PROTOCOL
> gPciBusComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL
> gPciBusComponentName2;
> +extern BOOLEAN                                      gFullEnumeration;
> +extern UINTN                                        gPciHostBridgeNumber;
> +extern EFI_HANDLE
> gPciHostBrigeHandles[PCI_MAX_HOST_BRIDGE_NUM];
> +extern UINT64                                       gAllOne;
> +extern UINT64                                       gAllZero;
> +extern EFI_PCI_PLATFORM_PROTOCOL                    *gPciPlatformProtocol;
> +extern EFI_PCI_OVERRIDE_PROTOCOL                    *gPciOverrideProtocol;
> +extern BOOLEAN                                      mReserveIsaAliases;
> +extern BOOLEAN                                      mReserveVgaAliases;
> +
> +/**
> +  Macro that checks whether device is a GFX device.
> +
> +  @param  _p      Specified device.
> +
> +  @retval TRUE    Device is a GFX device.
> +  @retval FALSE   Device is not a GFX device.
> +
> +**/
> +#define IS_PCI_GFX(_p)     IS_CLASS2 (_p, PCI_CLASS_DISPLAY,
> PCI_CLASS_DISPLAY_OTHER)
> +
> +/**
> +  Test to see if this driver supports ControllerHandle. Any ControllerHandle
> +  than contains a gEfiPciRootBridgeIoProtocolGuid protocol can be
> supported.
> +
> +  @param  This                Protocol instance pointer.
> +  @param  Controller          Handle of device to test.
> +  @param  RemainingDevicePath Optional parameter use to pick a specific
> child
> +                              device to start.
> +
> +  @retval EFI_SUCCESS         This driver supports this device.
> +  @retval EFI_ALREADY_STARTED This driver is already running on this
> device.
> +  @retval other               This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> +  IN EFI_HANDLE                     Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> +  );
> +
> +/**
> +  Start this driver on ControllerHandle and enumerate Pci bus and start
> +  all device under PCI bus.
> +
> +  @param  This                 Protocol instance pointer.
> +  @param  Controller           Handle of device to bind driver to.
> +  @param  RemainingDevicePath  Optional parameter use to pick a specific
> child
> +                               device to start.
> +
> +  @retval EFI_SUCCESS          This driver is added to ControllerHandle.
> +  @retval EFI_ALREADY_STARTED  This driver is already running on
> ControllerHandle.
> +  @retval other                This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> +  IN EFI_HANDLE                     Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> +  );
> +
> +/**
> +  Stop this driver on ControllerHandle. Support stopping any child handles
> +  created by this driver.
> +
> +  @param  This              Protocol instance pointer.
> +  @param  Controller        Handle of device to stop driver on.
> +  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If
> number of
> +                            children is zero stop the entire bus driver.
> +  @param  ChildHandleBuffer List of Child Handles to Stop.
> +
> +  @retval EFI_SUCCESS       This driver is removed ControllerHandle.
> +  @retval other             This driver was not removed from this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciBusDriverBindingStop (
> +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> +  IN  EFI_HANDLE                    Controller,
> +  IN  UINTN                         NumberOfChildren,
> +  IN  EFI_HANDLE                    *ChildHandleBuffer
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.inf
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.inf
> new file mode 100644
> index 0000000000..9d999f973b
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.inf
> @@ -0,0 +1,112 @@
> +## @file
> +#  The PCI bus driver will probe all PCI devices and allocate MMIO and IO
> space for these devices.
> +#  Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable
> hot plug supporting.
> +#
> +#  Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PciBusDxe
> +  MODULE_UNI_FILE                = PciBusDxe.uni
> +  FILE_GUID                      = 93B80004-9FB3-11d4-9A3A-0090273FC14D
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = PciBusEntryPoint
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 EBC ARM AARCH64
> +#
> +#  DRIVER_BINDING                =  gPciBusDriverBinding
> +#  COMPONENT_NAME                =  gPciBusComponentName
> +#  COMPONENT_NAME2               =  gPciBusComponentName2
> +#
> +
> +[Sources]
> +  PciLib.c
> +  PciIo.c
> +  PciBus.c
> +  PciDeviceSupport.c
> +  ComponentName.c
> +  ComponentName.h
> +  PciCommand.c
> +  PciResourceSupport.c
> +  PciEnumeratorSupport.c
> +  PciEnumerator.c
> +  PciOptionRomSupport.c
> +  PciDriverOverride.c
> +  PciPowerManagement.c
> +  PciPowerManagement.h
> +  PciDriverOverride.h
> +  PciRomTable.c
> +  PciHotPlugSupport.c
> +  PciLib.h
> +  PciHotPlugSupport.h
> +  PciRomTable.h
> +  PciOptionRomSupport.h
> +  PciEnumeratorSupport.h
> +  PciEnumerator.h
> +  PciResourceSupport.h
> +  PciDeviceSupport.h
> +  PciCommand.h
> +  PciIo.h
> +  PciBus.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  PcdLib
> +  DevicePathLib
> +  UefiBootServicesTableLib
> +  MemoryAllocationLib
> +  ReportStatusCodeLib
> +  BaseMemoryLib
> +  UefiLib
> +  BaseLib
> +  UefiDriverEntryPoint
> +  DebugLib
> +
> +[Protocols]
> +  gEfiPciHotPlugRequestProtocolGuid               ## SOMETIMES_PRODUCES
> +  gEfiPciIoProtocolGuid                           ## BY_START
> +  gEfiDevicePathProtocolGuid                      ## BY_START
> +  gEfiBusSpecificDriverOverrideProtocolGuid       ## BY_START
> +  gEfiLoadedImageProtocolGuid                     ## SOMETIMES_CONSUMES
> +  gEfiDecompressProtocolGuid                      ## SOMETIMES_CONSUMES
> +  gEfiPciHotPlugInitProtocolGuid                  ## SOMETIMES_CONSUMES
> +  gEfiPciHostBridgeResourceAllocationProtocolGuid ## TO_START
> +  gEfiPciPlatformProtocolGuid                     ## SOMETIMES_CONSUMES
> +  gEfiPciOverrideProtocolGuid                     ## SOMETIMES_CONSUMES
> +  gEfiPciEnumerationCompleteProtocolGuid          ## PRODUCES
> +  gEfiPciRootBridgeIoProtocolGuid                 ## TO_START
> +  gEfiIncompatiblePciDeviceSupportProtocolGuid    ##
> SOMETIMES_CONSUMES
> +  gEfiLoadFile2ProtocolGuid                       ## SOMETIMES_PRODUCES
> +  gEdkiiIoMmuProtocolGuid                         ## SOMETIMES_CONSUMES
> +  gEdkiiDeviceSecurityProtocolGuid                ## SOMETIMES_CONSUMES
> +  gEdkiiDeviceIdentifierTypePciGuid               ## SOMETIMES_CONSUMES
> +  gEfiLoadedImageDevicePathProtocolGuid           ## CONSUMES
> +
> +[FeaturePcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport
> ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPciBridgeIoAlignmentProbe       ##
> CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdUnalignedPciIoEnable            ##
> CONSUMES
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom
> ## CONSUMES
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize         ##
> SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSupport                ##
> CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport                  ##
> CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport                ##
> CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration    ##
> SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarSupport     ##
> CONSUMES
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  PciBusDxeExtra.uni
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.uni
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.uni
> new file mode 100644
> index 0000000000..81bfc2c9ef
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxe.uni
> @@ -0,0 +1,16 @@
> +// /** @file
> +// The PCI bus driver will probe all PCI devices and allocate MMIO and IO
> space for these devices.
> +//
> +// Please use PCD feature flag PcdPciBusHotplugDeviceSupport to enable
> hot plug supporting.
> +//
> +// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "Probes all PCI
> devices and allocate MMIO and IO space for these devices"
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "Please use PCD
> feature flag PcdPciBusHotplugDeviceSupport to enable hot plug supporting."
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxeExtra.uni
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxeExtra.uni
> new file mode 100644
> index 0000000000..f6a7cdae00
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciBusDxeExtra.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// PciBusDxe Localized Strings and Content
> +//
> +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"PCI Bus DXE Driver"
> +
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.c
> new file mode 100644
> index 0000000000..3111448643
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.c
> @@ -0,0 +1,267 @@
> +/** @file
> +  PCI command register operations supporting functions implementation for
> PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +/**
> +  Operate the PCI register via PciIo function interface.
> +
> +  @param PciIoDevice    Pointer to instance of PCI_IO_DEVICE.
> +  @param Command        Operator command.
> +  @param Offset         The address within the PCI configuration space for the
> PCI controller.
> +  @param Operation      Type of Operation.
> +  @param PtrCommand     Return buffer holding old PCI command, if
> operation is not EFI_SET_REGISTER.
> +
> +  @return Status of PciIo operation.
> +
> +**/
> +EFI_STATUS
> +PciOperateRegister (
> +  IN  PCI_IO_DEVICE *PciIoDevice,
> +  IN  UINT16        Command,
> +  IN  UINT8         Offset,
> +  IN  UINT8         Operation,
> +  OUT UINT16        *PtrCommand
> +  )
> +{
> +  UINT16              OldCommand;
> +  EFI_STATUS          Status;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +
> +  OldCommand  = 0;
> +  PciIo       = &PciIoDevice->PciIo;
> +
> +  if (Operation != EFI_SET_REGISTER) {
> +    Status = PciIo->Pci.Read (
> +                          PciIo,
> +                          EfiPciIoWidthUint16,
> +                          Offset,
> +                          1,
> +                          &OldCommand
> +                          );
> +
> +    if (Operation == EFI_GET_REGISTER) {
> +      *PtrCommand = OldCommand;
> +      return Status;
> +    }
> +  }
> +
> +  if (Operation == EFI_ENABLE_REGISTER) {
> +    OldCommand = (UINT16) (OldCommand | Command);
> +  } else if (Operation == EFI_DISABLE_REGISTER) {
> +    OldCommand = (UINT16) (OldCommand & ~(Command));
> +  } else {
> +    OldCommand = Command;
> +  }
> +
> +  return PciIo->Pci.Write (
> +                      PciIo,
> +                      EfiPciIoWidthUint16,
> +                      Offset,
> +                      1,
> +                      &OldCommand
> +                      );
> +}
> +
> +/**
> +  Check the capability supporting by given device.
> +
> +  @param PciIoDevice   Pointer to instance of PCI_IO_DEVICE.
> +
> +  @retval TRUE         Capability supported.
> +  @retval FALSE        Capability not supported.
> +
> +**/
> +BOOLEAN
> +PciCapabilitySupport (
> +  IN PCI_IO_DEVICE  *PciIoDevice
> +  )
> +{
> +  if ((PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Locate capability register block per capability ID.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param CapId             The capability ID.
> +  @param Offset            A pointer to the offset returned.
> +  @param NextRegBlock      A pointer to the next block returned.
> +
> +  @retval EFI_SUCCESS      Successfully located capability register block.
> +  @retval EFI_UNSUPPORTED  Pci device does not support capability.
> +  @retval EFI_NOT_FOUND    Pci device support but can not find register
> block.
> +
> +**/
> +EFI_STATUS
> +LocateCapabilityRegBlock (
> +  IN PCI_IO_DEVICE  *PciIoDevice,
> +  IN UINT8          CapId,
> +  IN OUT UINT8      *Offset,
> +  OUT UINT8         *NextRegBlock OPTIONAL
> +  )
> +{
> +  UINT8   CapabilityPtr;
> +  UINT16  CapabilityEntry;
> +  UINT8   CapabilityID;
> +
> +  //
> +  // To check the capability of this device supports
> +  //
> +  if (!PciCapabilitySupport (PciIoDevice)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (*Offset != 0) {
> +    CapabilityPtr = *Offset;
> +  } else {
> +
> +    CapabilityPtr = 0;
> +    if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
> +
> +      PciIoDevice->PciIo.Pci.Read (
> +                               &PciIoDevice->PciIo,
> +                               EfiPciIoWidthUint8,
> +                               EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR,
> +                               1,
> +                               &CapabilityPtr
> +                               );
> +    } else {
> +
> +      PciIoDevice->PciIo.Pci.Read (
> +                               &PciIoDevice->PciIo,
> +                               EfiPciIoWidthUint8,
> +                               PCI_CAPBILITY_POINTER_OFFSET,
> +                               1,
> +                               &CapabilityPtr
> +                               );
> +    }
> +  }
> +
> +  while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) {
> +    PciIoDevice->PciIo.Pci.Read (
> +                             &PciIoDevice->PciIo,
> +                             EfiPciIoWidthUint16,
> +                             CapabilityPtr,
> +                             1,
> +                             &CapabilityEntry
> +                             );
> +
> +    CapabilityID = (UINT8) CapabilityEntry;
> +
> +    if (CapabilityID == CapId) {
> +      *Offset = CapabilityPtr;
> +      if (NextRegBlock != NULL) {
> +        *NextRegBlock = (UINT8) (CapabilityEntry >> 8);
> +      }
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    //
> +    // Certain PCI device may incorrectly have capability pointing to itself,
> +    // break to avoid dead loop.
> +    //
> +    if (CapabilityPtr == (UINT8) (CapabilityEntry >> 8)) {
> +      break;
> +    }
> +
> +    CapabilityPtr = (UINT8) (CapabilityEntry >> 8);
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Locate PciExpress capability register block per capability ID.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param CapId             The capability ID.
> +  @param Offset            A pointer to the offset returned.
> +  @param NextRegBlock      A pointer to the next block returned.
> +
> +  @retval EFI_SUCCESS      Successfully located capability register block.
> +  @retval EFI_UNSUPPORTED  Pci device does not support capability.
> +  @retval EFI_NOT_FOUND    Pci device support but can not find register
> block.
> +
> +**/
> +EFI_STATUS
> +LocatePciExpressCapabilityRegBlock (
> +  IN     PCI_IO_DEVICE *PciIoDevice,
> +  IN     UINT16        CapId,
> +  IN OUT UINT32        *Offset,
> +     OUT UINT32        *NextRegBlock OPTIONAL
> +  )
> +{
> +  EFI_STATUS           Status;
> +  UINT32               CapabilityPtr;
> +  UINT32               CapabilityEntry;
> +  UINT16               CapabilityID;
> +
> +  //
> +  // To check the capability of this device supports
> +  //
> +  if (!PciIoDevice->IsPciExp) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (*Offset != 0) {
> +    CapabilityPtr = *Offset;
> +  } else {
> +    CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET;
> +  }
> +
> +  while (CapabilityPtr != 0) {
> +    //
> +    // Mask it to DWORD alignment per PCI spec
> +    //
> +    CapabilityPtr &= 0xFFC;
> +    Status = PciIoDevice->PciIo.Pci.Read (
> +                                      &PciIoDevice->PciIo,
> +                                      EfiPciIoWidthUint32,
> +                                      CapabilityPtr,
> +                                      1,
> +                                      &CapabilityEntry
> +                                      );
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    if (CapabilityEntry == MAX_UINT32) {
> +      DEBUG ((
> +        DEBUG_WARN,
> +        "%a: [%02x|%02x|%02x] failed to access config space at offset 0x%x\n",
> +        __FUNCTION__,
> +        PciIoDevice->BusNumber,
> +        PciIoDevice->DeviceNumber,
> +        PciIoDevice->FunctionNumber,
> +        CapabilityPtr
> +        ));
> +      break;
> +    }
> +
> +    CapabilityID = (UINT16) CapabilityEntry;
> +
> +    if (CapabilityID == CapId) {
> +      *Offset = CapabilityPtr;
> +      if (NextRegBlock != NULL) {
> +        *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF;
> +      }
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.h
> new file mode 100644
> index 0000000000..5eabd56bf2
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciCommand.h
> @@ -0,0 +1,232 @@
> +/** @file
> +  PCI command register operations supporting functions declaration for PCI
> Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#ifndef _EFI_PCI_COMMAND_H_
> +#define _EFI_PCI_COMMAND_H_
> +
> +//
> +// The PCI Command register bits owned by PCI Bus driver.
> +//
> +// They should be cleared at the beginning. The other registers
> +// are owned by chipset, we should not touch them.
> +//
> +#define EFI_PCI_COMMAND_BITS_OWNED                          ( \
> +                EFI_PCI_COMMAND_IO_SPACE                    | \
> +                EFI_PCI_COMMAND_MEMORY_SPACE                | \
> +                EFI_PCI_COMMAND_BUS_MASTER                  | \
> +                EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE | \
> +                EFI_PCI_COMMAND_VGA_PALETTE_SNOOP           | \
> +                EFI_PCI_COMMAND_FAST_BACK_TO_BACK             \
> +                )
> +
> +//
> +// The PCI Bridge Control register bits owned by PCI Bus driver.
> +//
> +// They should be cleared at the beginning. The other registers
> +// are owned by chipset, we should not touch them.
> +//
> +#define EFI_PCI_BRIDGE_CONTROL_BITS_OWNED                   ( \
> +                EFI_PCI_BRIDGE_CONTROL_ISA                  | \
> +                EFI_PCI_BRIDGE_CONTROL_VGA                  | \
> +                EFI_PCI_BRIDGE_CONTROL_VGA_16               | \
> +                EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK      \
> +                )
> +
> +//
> +// The PCCard Bridge Control register bits owned by PCI Bus driver.
> +//
> +// They should be cleared at the beginning. The other registers
> +// are owned by chipset, we should not touch them.
> +//
> +#define EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED                ( \
> +                EFI_PCI_BRIDGE_CONTROL_ISA                  | \
> +                EFI_PCI_BRIDGE_CONTROL_VGA                  | \
> +                EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK      \
> +                )
> +
> +
> +#define EFI_GET_REGISTER      1
> +#define EFI_SET_REGISTER      2
> +#define EFI_ENABLE_REGISTER   3
> +#define EFI_DISABLE_REGISTER  4
> +
> +/**
> +  Operate the PCI register via PciIo function interface.
> +
> +  @param PciIoDevice    Pointer to instance of PCI_IO_DEVICE.
> +  @param Command        Operator command.
> +  @param Offset         The address within the PCI configuration space for the
> PCI controller.
> +  @param Operation      Type of Operation.
> +  @param PtrCommand     Return buffer holding old PCI command, if
> operation is not EFI_SET_REGISTER.
> +
> +  @return Status of PciIo operation.
> +
> +**/
> +EFI_STATUS
> +PciOperateRegister (
> +  IN  PCI_IO_DEVICE *PciIoDevice,
> +  IN  UINT16        Command,
> +  IN  UINT8         Offset,
> +  IN  UINT8         Operation,
> +  OUT UINT16        *PtrCommand
> +  );
> +
> +/**
> +  Check the capability supporting by given device.
> +
> +  @param PciIoDevice   Pointer to instance of PCI_IO_DEVICE.
> +
> +  @retval TRUE         Capability supported.
> +  @retval FALSE        Capability not supported.
> +
> +**/
> +BOOLEAN
> +PciCapabilitySupport (
> +  IN PCI_IO_DEVICE  *PciIoDevice
> +  );
> +
> +/**
> +  Locate capability register block per capability ID.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param CapId             The capability ID.
> +  @param Offset            A pointer to the offset returned.
> +  @param NextRegBlock      A pointer to the next block returned.
> +
> +  @retval EFI_SUCCESS      Successfully located capability register block.
> +  @retval EFI_UNSUPPORTED  Pci device does not support capability.
> +  @retval EFI_NOT_FOUND    Pci device support but can not find register
> block.
> +
> +**/
> +EFI_STATUS
> +LocateCapabilityRegBlock (
> +  IN PCI_IO_DEVICE  *PciIoDevice,
> +  IN UINT8          CapId,
> +  IN OUT UINT8      *Offset,
> +  OUT UINT8         *NextRegBlock OPTIONAL
> +  );
> +
> +/**
> +  Locate PciExpress capability register block per capability ID.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param CapId             The capability ID.
> +  @param Offset            A pointer to the offset returned.
> +  @param NextRegBlock      A pointer to the next block returned.
> +
> +  @retval EFI_SUCCESS      Successfully located capability register block.
> +  @retval EFI_UNSUPPORTED  Pci device does not support capability.
> +  @retval EFI_NOT_FOUND    Pci device support but can not find register
> block.
> +
> +**/
> +EFI_STATUS
> +LocatePciExpressCapabilityRegBlock (
> +  IN     PCI_IO_DEVICE *PciIoDevice,
> +  IN     UINT16        CapId,
> +  IN OUT UINT32        *Offset,
> +     OUT UINT32        *NextRegBlock OPTIONAL
> +  );
> +
> +/**
> +  Macro that reads command register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[out]           Pointer to the 16-bit value read from command
> register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_READ_COMMAND_REGISTER(a,b) \
> +        PciOperateRegister (a, 0, PCI_COMMAND_OFFSET, EFI_GET_REGISTER,
> b)
> +
> +/**
> +  Macro that writes command register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[in]            The 16-bit value written into command register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_SET_COMMAND_REGISTER(a,b) \
> +        PciOperateRegister (a, b, PCI_COMMAND_OFFSET, EFI_SET_REGISTER,
> NULL)
> +
> +/**
> +  Macro that enables command register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[in]            The enabled value written into command register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_ENABLE_COMMAND_REGISTER(a,b) \
> +        PciOperateRegister (a, b, PCI_COMMAND_OFFSET,
> EFI_ENABLE_REGISTER, NULL)
> +
> +/**
> +  Macro that disables command register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[in]            The disabled value written into command register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_DISABLE_COMMAND_REGISTER(a,b) \
> +        PciOperateRegister (a, b, PCI_COMMAND_OFFSET,
> EFI_DISABLE_REGISTER, NULL)
> +
> +/**
> +  Macro that reads PCI bridge control register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[out]           The 16-bit value read from control register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_READ_BRIDGE_CONTROL_REGISTER(a,b) \
> +        PciOperateRegister (a, 0, PCI_BRIDGE_CONTROL_REGISTER_OFFSET,
> EFI_GET_REGISTER, b)
> +
> +/**
> +  Macro that writes PCI bridge control register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[in]            The 16-bit value written into control register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_SET_BRIDGE_CONTROL_REGISTER(a,b) \
> +        PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET,
> EFI_SET_REGISTER, NULL)
> +
> +/**
> +  Macro that enables PCI bridge control register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[in]            The enabled value written into command register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_ENABLE_BRIDGE_CONTROL_REGISTER(a,b) \
> +        PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET,
> EFI_ENABLE_REGISTER, NULL)
> +
> +/**
> + Macro that disables PCI bridge control register.
> +
> +  @param a[in]            Pointer to instance of PCI_IO_DEVICE.
> +  @param b[in]            The disabled value written into command register.
> +
> +  @return status of PciIo operation
> +
> +**/
> +#define PCI_DISABLE_BRIDGE_CONTROL_REGISTER(a,b) \
> +        PciOperateRegister (a, b, PCI_BRIDGE_CONTROL_REGISTER_OFFSET,
> EFI_DISABLE_REGISTER, NULL)
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.c
> new file mode 100644
> index 0000000000..7effbd5053
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.c
> @@ -0,0 +1,1056 @@
> +/** @file
> +  Supporting functions implementation for PCI devices management.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// This device structure is serviced as a header.
> +// Its next field points to the first root bridge device node.
> +//
> +LIST_ENTRY  mPciDevicePool;
> +
> +/**
> +  Initialize the PCI devices pool.
> +
> +**/
> +VOID
> +InitializePciDevicePool (
> +  VOID
> +  )
> +{
> +  InitializeListHead (&mPciDevicePool);
> +}
> +
> +/**
> +  Insert a root bridge into PCI device pool.
> +
> +  @param RootBridge     A pointer to the PCI_IO_DEVICE.
> +
> +**/
> +VOID
> +InsertRootBridge (
> +  IN PCI_IO_DEVICE      *RootBridge
> +  )
> +{
> +  InsertTailList (&mPciDevicePool, &(RootBridge->Link));
> +}
> +
> +/**
> +  This function is used to insert a PCI device node under
> +  a bridge.
> +
> +  @param Bridge         The PCI bridge.
> +  @param PciDeviceNode  The PCI device needs inserting.
> +
> +**/
> +VOID
> +InsertPciDevice (
> +  IN PCI_IO_DEVICE      *Bridge,
> +  IN PCI_IO_DEVICE      *PciDeviceNode
> +  )
> +{
> +  InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
> +  PciDeviceNode->Parent = Bridge;
> +}
> +
> +/**
> +  Destroy root bridge and remove it from device tree.
> +
> +  @param RootBridge     The bridge want to be removed.
> +
> +**/
> +VOID
> +DestroyRootBridge (
> +  IN PCI_IO_DEVICE      *RootBridge
> +  )
> +{
> +  DestroyPciDeviceTree (RootBridge);
> +
> +  FreePciDevice (RootBridge);
> +}
> +
> +/**
> +  Destroy a pci device node.
> +
> +  All direct or indirect allocated resource for this node will be freed.
> +
> +  @param PciIoDevice  A pointer to the PCI_IO_DEVICE to be destroyed.
> +
> +**/
> +VOID
> +FreePciDevice (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +  ASSERT (PciIoDevice != NULL);
> +  //
> +  // Assume all children have been removed underneath this device
> +  //
> +  if (PciIoDevice->ResourcePaddingDescriptors != NULL) {
> +    FreePool (PciIoDevice->ResourcePaddingDescriptors);
> +  }
> +
> +  if (PciIoDevice->DevicePath != NULL) {
> +    FreePool (PciIoDevice->DevicePath);
> +  }
> +
> +  if (PciIoDevice->BusNumberRanges != NULL) {
> +    FreePool (PciIoDevice->BusNumberRanges);
> +  }
> +
> +  FreePool (PciIoDevice);
> +}
> +
> +/**
> +  Destroy all the pci device node under the bridge.
> +  Bridge itself is not included.
> +
> +  @param Bridge      A pointer to the PCI_IO_DEVICE.
> +
> +**/
> +VOID
> +DestroyPciDeviceTree (
> +  IN PCI_IO_DEVICE      *Bridge
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *Temp;
> +
> +  while (!IsListEmpty (&Bridge->ChildList)) {
> +
> +    CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +    //
> +    // Remove this node from the linked list
> +    //
> +    RemoveEntryList (CurrentLink);
> +
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +      DestroyPciDeviceTree (Temp);
> +    }
> +
> +    FreePciDevice (Temp);
> +  }
> +}
> +
> +/**
> +  Destroy all device nodes under the root bridge
> +  specified by Controller.
> +
> +  The root bridge itself is also included.
> +
> +  @param  Controller    Root bridge handle.
> +
> +  @retval EFI_SUCCESS   Destroy all device nodes successfully.
> +  @retval EFI_NOT_FOUND Cannot find any PCI device under specified
> +                        root bridge.
> +
> +**/
> +EFI_STATUS
> +DestroyRootBridgeByHandle (
> +  IN EFI_HANDLE        Controller
> +  )
> +{
> +
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *Temp;
> +
> +  CurrentLink = mPciDevicePool.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (Temp->Handle == Controller) {
> +
> +      RemoveEntryList (CurrentLink);
> +
> +      DestroyPciDeviceTree (Temp);
> +
> +      FreePciDevice (Temp);
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This function registers the PCI IO device.
> +
> +  It creates a handle for this PCI IO device (if the handle does not exist),
> attaches
> +  appropriate protocols onto the handle, does necessary initialization, and
> sets up
> +  parent/child relationship with its bus controller.
> +
> +  @param Controller     An EFI handle for the PCI bus controller.
> +  @param PciIoDevice    A PCI_IO_DEVICE pointer to the PCI IO device to be
> registered.
> +  @param Handle         A pointer to hold the returned EFI handle for the PCI
> IO device.
> +
> +  @retval EFI_SUCCESS   The PCI device is successfully registered.
> +  @retval other         An error occurred when registering the PCI device.
> +
> +**/
> +EFI_STATUS
> +RegisterPciDevice (
> +  IN  EFI_HANDLE          Controller,
> +  IN  PCI_IO_DEVICE       *PciIoDevice,
> +  OUT EFI_HANDLE          *Handle      OPTIONAL
> +  )
> +{
> +  EFI_STATUS          Status;
> +  VOID                *PlatformOpRomBuffer;
> +  UINTN               PlatformOpRomSize;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT8               Data8;
> +  BOOLEAN             HasEfiImage;
> +
> +  //
> +  // Install the pciio protocol, device path protocol
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &PciIoDevice->Handle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  PciIoDevice->DevicePath,
> +                  &gEfiPciIoProtocolGuid,
> +                  &PciIoDevice->PciIo,
> +                  NULL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Force Interrupt line to "Unknown" or "No Connection"
> +  //
> +  PciIo = &(PciIoDevice->PciIo);
> +  Data8 = PCI_INT_LINE_UNKNOWN;
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
> +
> +  //
> +  // Process OpRom
> +  //
> +  if (!PciIoDevice->AllOpRomProcessed) {
> +
> +    //
> +    // Get the OpRom provided by platform
> +    //
> +    if (gPciPlatformProtocol != NULL) {
> +      Status = gPciPlatformProtocol->GetPciRom (
> +                                       gPciPlatformProtocol,
> +                                       PciIoDevice->Handle,
> +                                       &PlatformOpRomBuffer,
> +                                       &PlatformOpRomSize
> +                                       );
> +      if (!EFI_ERROR (Status)) {
> +        PciIoDevice->EmbeddedRom    = FALSE;
> +        PciIoDevice->RomSize        = (UINT32) PlatformOpRomSize;
> +        PciIoDevice->PciIo.RomSize  = PlatformOpRomSize;
> +        PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
> +        //
> +        // For OpROM read from gPciPlatformProtocol:
> +        // Add the Rom Image to internal database for later PCI light
> enumeration
> +        //
> +        PciRomAddImageMapping (
> +          NULL,
> +          PciIoDevice->PciRootBridgeIo->SegmentNumber,
> +          PciIoDevice->BusNumber,
> +          PciIoDevice->DeviceNumber,
> +          PciIoDevice->FunctionNumber,
> +          PciIoDevice->PciIo.RomImage,
> +          PciIoDevice->PciIo.RomSize
> +          );
> +      }
> +    } else if (gPciOverrideProtocol != NULL) {
> +      Status = gPciOverrideProtocol->GetPciRom (
> +                                       gPciOverrideProtocol,
> +                                       PciIoDevice->Handle,
> +                                       &PlatformOpRomBuffer,
> +                                       &PlatformOpRomSize
> +                                       );
> +      if (!EFI_ERROR (Status)) {
> +        PciIoDevice->EmbeddedRom    = FALSE;
> +        PciIoDevice->RomSize        = (UINT32) PlatformOpRomSize;
> +        PciIoDevice->PciIo.RomSize  = PlatformOpRomSize;
> +        PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
> +        //
> +        // For OpROM read from gPciOverrideProtocol:
> +        // Add the Rom Image to internal database for later PCI light
> enumeration
> +        //
> +        PciRomAddImageMapping (
> +          NULL,
> +          PciIoDevice->PciRootBridgeIo->SegmentNumber,
> +          PciIoDevice->BusNumber,
> +          PciIoDevice->DeviceNumber,
> +          PciIoDevice->FunctionNumber,
> +          PciIoDevice->PciIo.RomImage,
> +          PciIoDevice->PciIo.RomSize
> +          );
> +      }
> +    }
> +  }
> +
> +  //
> +  // Determine if there are EFI images in the option rom
> +  //
> +  HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage,
> PciIoDevice->PciIo.RomSize);
> +
> +  if (HasEfiImage) {
> +    Status = gBS->InstallMultipleProtocolInterfaces (
> +                    &PciIoDevice->Handle,
> +                    &gEfiLoadFile2ProtocolGuid,
> +                    &PciIoDevice->LoadFile2,
> +                    NULL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      gBS->UninstallMultipleProtocolInterfaces (
> +             PciIoDevice->Handle,
> +             &gEfiDevicePathProtocolGuid,
> +             PciIoDevice->DevicePath,
> +             &gEfiPciIoProtocolGuid,
> +             &PciIoDevice->PciIo,
> +             NULL
> +             );
> +      return Status;
> +    }
> +  }
> +
> +
> +  if (!PciIoDevice->AllOpRomProcessed) {
> +
> +    PciIoDevice->AllOpRomProcessed = TRUE;
> +
> +    //
> +    // Dispatch the EFI OpRom for the PCI device.
> +    // The OpRom is got from platform in the above code
> +    // or loaded from device in the previous round of bus enumeration
> +    //
> +    if (HasEfiImage) {
> +      ProcessOpRomImage (PciIoDevice);
> +    }
> +  }
> +
> +  if (PciIoDevice->BusOverride) {
> +    //
> +    // Install Bus Specific Driver Override Protocol
> +    //
> +    Status = gBS->InstallMultipleProtocolInterfaces (
> +                    &PciIoDevice->Handle,
> +                    &gEfiBusSpecificDriverOverrideProtocolGuid,
> +                    &PciIoDevice->PciDriverOverride,
> +                    NULL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      gBS->UninstallMultipleProtocolInterfaces (
> +             PciIoDevice->Handle,
> +             &gEfiDevicePathProtocolGuid,
> +             PciIoDevice->DevicePath,
> +             &gEfiPciIoProtocolGuid,
> +             &PciIoDevice->PciIo,
> +             NULL
> +             );
> +      if (HasEfiImage) {
> +        gBS->UninstallMultipleProtocolInterfaces (
> +               PciIoDevice->Handle,
> +               &gEfiLoadFile2ProtocolGuid,
> +               &PciIoDevice->LoadFile2,
> +               NULL
> +               );
> +      }
> +
> +      return Status;
> +    }
> +  }
> +
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  (VOID **) &(PciIoDevice->PciRootBridgeIo),
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  PciIoDevice->Handle,
> +                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (Handle != NULL) {
> +    *Handle = PciIoDevice->Handle;
> +  }
> +
> +  //
> +  // Indicate the pci device is registered
> +  //
> +  PciIoDevice->Registered = TRUE;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function is used to remove the whole PCI devices on the specified
> bridge from
> +  the root bridge.
> +
> +  @param RootBridgeHandle   The root bridge device handle.
> +  @param Bridge             The bridge device to be removed.
> +
> +**/
> +VOID
> +RemoveAllPciDeviceOnBridge (
> +  EFI_HANDLE               RootBridgeHandle,
> +  PCI_IO_DEVICE            *Bridge
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *Temp;
> +
> +  while (!IsListEmpty (&Bridge->ChildList)) {
> +
> +    CurrentLink = Bridge->ChildList.ForwardLink;
> +    Temp        = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    //
> +    // Check if the current node has been deregistered before
> +    // If it is not, then deregister it
> +    //
> +    if (Temp->Registered) {
> +      DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
> +    }
> +
> +    //
> +    // Remove this node from the linked list
> +    //
> +    RemoveEntryList (CurrentLink);
> +
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +      RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
> +    }
> +
> +    FreePciDevice (Temp);
> +  }
> +}
> +
> +/**
> +  This function is used to de-register the PCI IO device.
> +
> +  That includes un-installing PciIo protocol from the specified PCI
> +  device handle.
> +
> +  @param Controller    An EFI handle for the PCI bus controller.
> +  @param Handle        PCI device handle.
> +
> +  @retval EFI_SUCCESS  The PCI device is successfully de-registered.
> +  @retval other        An error occurred when de-registering the PCI device.
> +
> +**/
> +EFI_STATUS
> +DeRegisterPciDevice (
> +  IN  EFI_HANDLE                     Controller,
> +  IN  EFI_HANDLE                     Handle
> +  )
> +
> +{
> +  EFI_PCI_IO_PROTOCOL             *PciIo;
> +  EFI_STATUS                      Status;
> +  PCI_IO_DEVICE                   *PciIoDevice;
> +  PCI_IO_DEVICE                   *Node;
> +  LIST_ENTRY                      *CurrentLink;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  Status = gBS->OpenProtocol (
> +                  Handle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **) &PciIo,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +    PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
> +
> +    //
> +    // If it is already de-registered
> +    //
> +    if (!PciIoDevice->Registered) {
> +      return EFI_SUCCESS;
> +    }
> +
> +    //
> +    // If it is PPB, first de-register its children
> +    //
> +
> +    if (!IsListEmpty (&PciIoDevice->ChildList)) {
> +
> +      CurrentLink = PciIoDevice->ChildList.ForwardLink;
> +
> +      while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
> +        Node    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +        Status  = DeRegisterPciDevice (Controller, Node->Handle);
> +
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +
> +        CurrentLink = CurrentLink->ForwardLink;
> +      }
> +    }
> +
> +    //
> +    // Close the child handle
> +    //
> +    Status = gBS->CloseProtocol (
> +                    Controller,
> +                    &gEfiPciRootBridgeIoProtocolGuid,
> +                    gPciBusDriverBinding.DriverBindingHandle,
> +                    Handle
> +                    );
> +
> +    //
> +    // Un-install the Device Path protocol and PCI I/O protocol
> +    // and Bus Specific Driver Override protocol if needed.
> +    //
> +    if (PciIoDevice->BusOverride) {
> +      Status = gBS->UninstallMultipleProtocolInterfaces (
> +                      Handle,
> +                      &gEfiDevicePathProtocolGuid,
> +                      PciIoDevice->DevicePath,
> +                      &gEfiPciIoProtocolGuid,
> +                      &PciIoDevice->PciIo,
> +                      &gEfiBusSpecificDriverOverrideProtocolGuid,
> +                      &PciIoDevice->PciDriverOverride,
> +                      NULL
> +                      );
> +    } else {
> +      Status = gBS->UninstallMultipleProtocolInterfaces (
> +                      Handle,
> +                      &gEfiDevicePathProtocolGuid,
> +                      PciIoDevice->DevicePath,
> +                      &gEfiPciIoProtocolGuid,
> +                      &PciIoDevice->PciIo,
> +                      NULL
> +                      );
> +    }
> +
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Try to uninstall LoadFile2 protocol if exists
> +      //
> +      Status = gBS->OpenProtocol (
> +                      Handle,
> +                      &gEfiLoadFile2ProtocolGuid,
> +                      NULL,
> +                      gPciBusDriverBinding.DriverBindingHandle,
> +                      Controller,
> +                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> +                      );
> +      if (!EFI_ERROR (Status)) {
> +        Status = gBS->UninstallMultipleProtocolInterfaces (
> +                        Handle,
> +                        &gEfiLoadFile2ProtocolGuid,
> +                        &PciIoDevice->LoadFile2,
> +                        NULL
> +                        );
> +      }
> +      //
> +      // Restore Status
> +      //
> +      Status = EFI_SUCCESS;
> +    }
> +
> +
> +    if (EFI_ERROR (Status)) {
> +      gBS->OpenProtocol (
> +            Controller,
> +            &gEfiPciRootBridgeIoProtocolGuid,
> +            (VOID **) &PciRootBridgeIo,
> +            gPciBusDriverBinding.DriverBindingHandle,
> +            Handle,
> +            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> +            );
> +      return Status;
> +    }
> +
> +    //
> +    // The Device Driver should disable this device after disconnect
> +    // so the Pci Bus driver will not touch this device any more.
> +    // Restore the register field to the original value
> +    //
> +    PciIoDevice->Registered = FALSE;
> +    PciIoDevice->Handle     = NULL;
> +  } else {
> +
> +    //
> +    // Handle may be closed before
> +    //
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Start to manage the PCI device on the specified root bridge or PCI-PCI
> Bridge.
> +
> +  @param Controller          The root bridge handle.
> +  @param RootBridge          A pointer to the PCI_IO_DEVICE.
> +  @param RemainingDevicePath A pointer to the
> EFI_DEVICE_PATH_PROTOCOL.
> +  @param NumberOfChildren    Children number.
> +  @param ChildHandleBuffer   A pointer to the child handle buffer.
> +
> +  @retval EFI_NOT_READY   Device is not allocated.
> +  @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
> +  @retval EFI_NOT_FOUND   Can not find the specific device.
> +  @retval EFI_SUCCESS     Success to start Pci devices on bridge.
> +
> +**/
> +EFI_STATUS
> +StartPciDevicesOnBridge (
> +  IN EFI_HANDLE                          Controller,
> +  IN PCI_IO_DEVICE                       *RootBridge,
> +  IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath,
> +  IN OUT UINT8                           *NumberOfChildren,
> +  IN OUT EFI_HANDLE                      *ChildHandleBuffer
> +  )
> +
> +{
> +  PCI_IO_DEVICE             *PciIoDevice;
> +  EFI_DEV_PATH_PTR          Node;
> +  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
> +  EFI_STATUS                Status;
> +  LIST_ENTRY                *CurrentLink;
> +  UINT64                    Supports;
> +
> +  PciIoDevice = NULL;
> +  CurrentLink = RootBridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
> +
> +    PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    if (RemainingDevicePath != NULL) {
> +
> +      Node.DevPath = RemainingDevicePath;
> +
> +      if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
> +          Node.Pci->Function != PciIoDevice->FunctionNumber) {
> +        CurrentLink = CurrentLink->ForwardLink;
> +        continue;
> +      }
> +
> +      //
> +      // Check if the device has been assigned with required resource
> +      //
> +      if (!PciIoDevice->Allocated) {
> +        return EFI_NOT_READY;
> +      }
> +
> +      //
> +      // Check if the current node has been registered before
> +      // If it is not, register it
> +      //
> +      if (!PciIoDevice->Registered) {
> +        Status = RegisterPciDevice (
> +                   Controller,
> +                   PciIoDevice,
> +                   NULL
> +                   );
> +
> +      }
> +
> +      if (NumberOfChildren != NULL && ChildHandleBuffer != NULL &&
> PciIoDevice->Registered) {
> +        ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
> +        (*NumberOfChildren)++;
> +      }
> +
> +      //
> +      // Get the next device path
> +      //
> +      CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
> +      if (IsDevicePathEnd (CurrentDevicePath)) {
> +        return EFI_SUCCESS;
> +      }
> +
> +      //
> +      // If it is a PPB
> +      //
> +      if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +        Status = StartPciDevicesOnBridge (
> +                   Controller,
> +                   PciIoDevice,
> +                   CurrentDevicePath,
> +                   NumberOfChildren,
> +                   ChildHandleBuffer
> +                   );
> +
> +        PciIoDevice->PciIo.Attributes (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoAttributeOperationSupported,
> +                             0,
> +                             &Supports
> +                             );
> +        Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
> +        PciIoDevice->PciIo.Attributes (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoAttributeOperationEnable,
> +                             Supports,
> +                             NULL
> +                             );
> +
> +        return Status;
> +      } else {
> +
> +        //
> +        // Currently, the PCI bus driver only support PCI-PCI bridge
> +        //
> +        return EFI_UNSUPPORTED;
> +      }
> +
> +    } else {
> +
> +      //
> +      // If remaining device path is NULL,
> +      // try to enable all the pci devices under this bridge
> +      //
> +      if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
> +        Status = RegisterPciDevice (
> +                   Controller,
> +                   PciIoDevice,
> +                   NULL
> +                   );
> +
> +      }
> +
> +      if (NumberOfChildren != NULL && ChildHandleBuffer != NULL &&
> PciIoDevice->Registered) {
> +        ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
> +        (*NumberOfChildren)++;
> +      }
> +
> +      if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +        Status = StartPciDevicesOnBridge (
> +                   Controller,
> +                   PciIoDevice,
> +                   RemainingDevicePath,
> +                   NumberOfChildren,
> +                   ChildHandleBuffer
> +                   );
> +
> +        PciIoDevice->PciIo.Attributes (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoAttributeOperationSupported,
> +                             0,
> +                             &Supports
> +                             );
> +        Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
> +        PciIoDevice->PciIo.Attributes (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoAttributeOperationEnable,
> +                             Supports,
> +                             NULL
> +                             );
> +
> +      }
> +
> +      CurrentLink = CurrentLink->ForwardLink;
> +    }
> +  }
> +
> +  if (PciIoDevice == NULL) {
> +    return EFI_NOT_FOUND;
> +  } else {
> +    return EFI_SUCCESS;
> +  }
> +}
> +
> +/**
> +  Start to manage all the PCI devices it found previously under
> +  the entire host bridge.
> +
> +  @param Controller          The root bridge handle.
> +
> +  @retval EFI_NOT_READY   Device is not allocated.
> +  @retval EFI_SUCCESS     Success to start Pci device on host bridge.
> +
> +**/
> +EFI_STATUS
> +StartPciDevices (
> +  IN EFI_HANDLE                         Controller
> +  )
> +{
> +  PCI_IO_DEVICE     *RootBridge;
> +  EFI_HANDLE        ThisHostBridge;
> +  LIST_ENTRY        *CurrentLink;
> +
> +  RootBridge = GetRootBridgeByHandle (Controller);
> +  ASSERT (RootBridge != NULL);
> +  ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
> +
> +  CurrentLink = mPciDevicePool.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
> +
> +    RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    //
> +    // Locate the right root bridge to start
> +    //
> +    if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
> +      StartPciDevicesOnBridge (
> +         RootBridge->Handle,
> +         RootBridge,
> +         NULL,
> +         NULL,
> +         NULL
> +         );
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Create root bridge device.
> +
> +  @param RootBridgeHandle    Specified root bridge handle.
> +
> +  @return The crated root bridge device instance, NULL means no
> +          root bridge device instance created.
> +
> +**/
> +PCI_IO_DEVICE *
> +CreateRootBridge (
> +  IN EFI_HANDLE                   RootBridgeHandle
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  PCI_IO_DEVICE                   *Dev;
> +  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
> +  if (Dev == NULL) {
> +    return NULL;
> +  }
> +
> +  Dev->Signature  = PCI_IO_DEVICE_SIGNATURE;
> +  Dev->Handle     = RootBridgeHandle;
> +  InitializeListHead (&Dev->ChildList);
> +
> +  Status = gBS->OpenProtocol (
> +                  RootBridgeHandle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  (VOID **) &ParentDevicePath,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  RootBridgeHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    FreePool (Dev);
> +    return NULL;
> +  }
> +
> +  //
> +  // Record the root bridge parent device path
> +  //
> +  Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
> +
> +  //
> +  // Get the pci root bridge io protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +                  RootBridgeHandle,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  (VOID **) &PciRootBridgeIo,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  RootBridgeHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    FreePciDevice (Dev);
> +    return NULL;
> +  }
> +
> +  Dev->PciRootBridgeIo = PciRootBridgeIo;
> +
> +  //
> +  // Initialize the PCI I/O instance structure
> +  //
> +  InitializePciIoInstance (Dev);
> +  InitializePciDriverOverrideInstance (Dev);
> +  InitializePciLoadFile2 (Dev);
> +
> +  //
> +  // Initialize reserved resource list and
> +  // option rom driver list
> +  //
> +  InitializeListHead (&Dev->ReservedResourceList);
> +  InitializeListHead (&Dev->OptionRomDriverList);
> +
> +  return Dev;
> +}
> +
> +/**
> +  Get root bridge device instance by specific root bridge handle.
> +
> +  @param RootBridgeHandle    Given root bridge handle.
> +
> +  @return The root bridge device instance, NULL means no root bridge
> +          device instance found.
> +
> +**/
> +PCI_IO_DEVICE *
> +GetRootBridgeByHandle (
> +  EFI_HANDLE RootBridgeHandle
> +  )
> +{
> +  PCI_IO_DEVICE   *RootBridgeDev;
> +  LIST_ENTRY      *CurrentLink;
> +
> +  CurrentLink = mPciDevicePool.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
> +
> +    RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    if (RootBridgeDev->Handle == RootBridgeHandle) {
> +      return RootBridgeDev;
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Judge whether Pci device existed.
> +
> +  @param Bridge       Parent bridge instance.
> +  @param PciIoDevice  Device instance.
> +
> +  @retval TRUE        Pci device existed.
> +  @retval FALSE       Pci device did not exist.
> +
> +**/
> +BOOLEAN
> +PciDeviceExisted (
> +  IN PCI_IO_DEVICE    *Bridge,
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +
> +  PCI_IO_DEVICE   *Temp;
> +  LIST_ENTRY      *CurrentLink;
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (Temp == PciIoDevice) {
> +      return TRUE;
> +    }
> +
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +      if (PciDeviceExisted (Temp, PciIoDevice)) {
> +        return TRUE;
> +      }
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Get the active VGA device on the specified Host Bridge.
> +
> +  @param HostBridgeHandle    Host Bridge handle.
> +
> +  @return The active VGA device on the specified Host Bridge.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDeviceOnHostBridge (
> +  IN EFI_HANDLE           HostBridgeHandle
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *PciIoDevice;
> +
> +  CurrentLink = mPciDevicePool.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
> +
> +    PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (PciIoDevice->PciRootBridgeIo->ParentHandle== HostBridgeHandle) {
> +
> +      PciIoDevice = LocateVgaDevice (PciIoDevice);
> +
> +      if (PciIoDevice != NULL) {
> +        return PciIoDevice;
> +      }
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Locate the active VGA device under the bridge.
> +
> +  @param Bridge  PCI IO instance for the bridge.
> +
> +  @return The active VGA device.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDevice (
> +  IN PCI_IO_DEVICE        *Bridge
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *PciIoDevice;
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +
> +    PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (IS_PCI_VGA(&PciIoDevice->Pci) &&
> +        (PciIoDevice->Attributes &
> +         (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
> +          EFI_PCI_IO_ATTRIBUTE_VGA_IO     |
> +          EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
> +      return PciIoDevice;
> +    }
> +
> +    if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +
> +      PciIoDevice = LocateVgaDevice (PciIoDevice);
> +
> +      if (PciIoDevice != NULL) {
> +        return PciIoDevice;
> +      }
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return NULL;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.h
> new file mode 100644
> index 0000000000..acc0edc0bb
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDeviceSupport.h
> @@ -0,0 +1,266 @@
> +/** @file
> +  Supporting functions declaration for PCI devices management.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_DEVICE_SUPPORT_H_
> +#define _EFI_PCI_DEVICE_SUPPORT_H_
> +
> +/**
> +  Initialize the PCI devices pool.
> +
> +**/
> +VOID
> +InitializePciDevicePool (
> +  VOID
> +  );
> +
> +/**
> +  Insert a root bridge into PCI device pool.
> +
> +  @param RootBridge     A pointer to the PCI_IO_DEVICE.
> +
> +**/
> +VOID
> +InsertRootBridge (
> +  IN PCI_IO_DEVICE      *RootBridge
> +  );
> +
> +/**
> +  This function is used to insert a PCI device node under
> +  a bridge.
> +
> +  @param Bridge         The PCI bridge.
> +  @param PciDeviceNode  The PCI device needs inserting.
> +
> +**/
> +VOID
> +InsertPciDevice (
> +  IN PCI_IO_DEVICE      *Bridge,
> +  IN PCI_IO_DEVICE      *PciDeviceNode
> +  );
> +
> +/**
> +  Destroy root bridge and remove it from device tree.
> +
> +  @param RootBridge     The bridge want to be removed.
> +
> +**/
> +VOID
> +DestroyRootBridge (
> +  IN PCI_IO_DEVICE      *RootBridge
> +  );
> +
> +/**
> +  Destroy all the pci device node under the bridge.
> +  Bridge itself is not included.
> +
> +  @param Bridge         A pointer to the PCI_IO_DEVICE.
> +
> +**/
> +VOID
> +DestroyPciDeviceTree (
> +  IN PCI_IO_DEVICE      *Bridge
> +  );
> +
> +/**
> +  Destroy all device nodes under the root bridge
> +  specified by Controller.
> +
> +  The root bridge itself is also included.
> +
> +  @param  Controller    Root bridge handle.
> +
> +  @retval EFI_SUCCESS   Destroy all device nodes successfully.
> +  @retval EFI_NOT_FOUND Cannot find any PCI device under specified
> +                        root bridge.
> +
> +**/
> +EFI_STATUS
> +DestroyRootBridgeByHandle (
> +  IN EFI_HANDLE        Controller
> +  );
> +
> +/**
> +  This function registers the PCI IO device.
> +
> +  It creates a handle for this PCI IO device (if the handle does not exist),
> attaches
> +  appropriate protocols onto the handle, does necessary initialization, and
> sets up
> +  parent/child relationship with its bus controller.
> +
> +  @param Controller     An EFI handle for the PCI bus controller.
> +  @param PciIoDevice    A PCI_IO_DEVICE pointer to the PCI IO device to be
> registered.
> +  @param Handle         A pointer to hold the returned EFI handle for the PCI
> IO device.
> +
> +  @retval EFI_SUCCESS   The PCI device is successfully registered.
> +  @retval other         An error occurred when registering the PCI device.
> +
> +**/
> +EFI_STATUS
> +RegisterPciDevice (
> +  IN  EFI_HANDLE          Controller,
> +  IN  PCI_IO_DEVICE       *PciIoDevice,
> +  OUT EFI_HANDLE          *Handle      OPTIONAL
> +  );
> +
> +/**
> +  This function is used to remove the whole PCI devices on the specified
> bridge from
> +  the root bridge.
> +
> +  @param RootBridgeHandle   The root bridge device handle.
> +  @param Bridge             The bridge device to be removed.
> +
> +**/
> +VOID
> +RemoveAllPciDeviceOnBridge (
> +  EFI_HANDLE               RootBridgeHandle,
> +  PCI_IO_DEVICE            *Bridge
> +  );
> +
> +/**
> +  This function is used to de-register the PCI IO device.
> +
> +  That includes un-installing PciIo protocol from the specified PCI
> +  device handle.
> +
> +  @param Controller    An EFI handle for the PCI bus controller.
> +  @param Handle        PCI device handle.
> +
> +  @retval EFI_SUCCESS  The PCI device is successfully de-registered.
> +  @retval other        An error occurred when de-registering the PCI device.
> +
> +**/
> +EFI_STATUS
> +DeRegisterPciDevice (
> +  IN  EFI_HANDLE                     Controller,
> +  IN  EFI_HANDLE                     Handle
> +  );
> +
> +/**
> +  Start to manage the PCI device on the specified root bridge or PCI-PCI
> Bridge.
> +
> +  @param Controller          The root bridge handle.
> +  @param RootBridge          A pointer to the PCI_IO_DEVICE.
> +  @param RemainingDevicePath A pointer to the
> EFI_DEVICE_PATH_PROTOCOL.
> +  @param NumberOfChildren    Children number.
> +  @param ChildHandleBuffer   A pointer to the child handle buffer.
> +
> +  @retval EFI_NOT_READY   Device is not allocated.
> +  @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
> +  @retval EFI_NOT_FOUND   Can not find the specific device.
> +  @retval EFI_SUCCESS     Success to start Pci devices on bridge.
> +
> +**/
> +EFI_STATUS
> +StartPciDevicesOnBridge (
> +  IN EFI_HANDLE                          Controller,
> +  IN PCI_IO_DEVICE                       *RootBridge,
> +  IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath,
> +  IN OUT UINT8                           *NumberOfChildren,
> +  IN OUT EFI_HANDLE                      *ChildHandleBuffer
> +  );
> +
> +/**
> +  Start to manage all the PCI devices it found previously under
> +  the entire host bridge.
> +
> +  @param Controller          The root bridge handle.
> +
> +  @retval EFI_NOT_READY   Device is not allocated.
> +  @retval EFI_SUCCESS     Success to start Pci device on host bridge.
> +
> +**/
> +EFI_STATUS
> +StartPciDevices (
> +  IN EFI_HANDLE                         Controller
> +  );
> +
> +/**
> +  Create root bridge device.
> +
> +  @param RootBridgeHandle    Specified root bridge handle.
> +
> +  @return The crated root bridge device instance, NULL means no
> +          root bridge device instance created.
> +
> +**/
> +PCI_IO_DEVICE *
> +CreateRootBridge (
> +  IN EFI_HANDLE                   RootBridgeHandle
> +  );
> +
> +/**
> +  Get root bridge device instance by specific root bridge handle.
> +
> +  @param RootBridgeHandle    Given root bridge handle.
> +
> +  @return The root bridge device instance, NULL means no root bridge
> +          device instance found.
> +
> +**/
> +PCI_IO_DEVICE *
> +GetRootBridgeByHandle (
> +  EFI_HANDLE RootBridgeHandle
> +  );
> +
> +
> +/**
> +  Judge whether Pci device existed.
> +
> +  @param Bridge       Parent bridge instance.
> +  @param PciIoDevice  Device instance.
> +
> +  @retval TRUE        Pci device existed.
> +  @retval FALSE       Pci device did not exist.
> +
> +**/
> +BOOLEAN
> +PciDeviceExisted (
> +  IN PCI_IO_DEVICE    *Bridge,
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +/**
> +  Get the active VGA device on the specified Host Bridge.
> +
> +  @param HostBridgeHandle    Host Bridge handle.
> +
> +  @return The active VGA device on the specified Host Bridge.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDeviceOnHostBridge (
> +  IN EFI_HANDLE           HostBridgeHandle
> +  );
> +
> +/**
> +  Locate the active VGA device under the bridge.
> +
> +  @param Bridge  PCI IO instance for the bridge.
> +
> +  @return The active VGA device.
> +
> +**/
> +PCI_IO_DEVICE *
> +LocateVgaDevice (
> +  IN PCI_IO_DEVICE        *Bridge
> +  );
> +
> +
> +/**
> +  Destroy a pci device node.
> +
> +  All direct or indirect allocated resource for this node will be freed.
> +
> +  @param PciIoDevice  A pointer to the PCI_IO_DEVICE to be destroyed.
> +
> +**/
> +VOID
> +FreePciDevice (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.c
> new file mode 100644
> index 0000000000..0c3f684c8c
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.c
> @@ -0,0 +1,188 @@
> +/** @file
> +  Functions implementation for Bus Specific Driver Override protocol.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +/**
> +  Initializes a PCI Driver Override Instance.
> +
> +  @param  PciIoDevice   PCI Device instance.
> +
> +**/
> +VOID
> +InitializePciDriverOverrideInstance (
> +  IN OUT PCI_IO_DEVICE          *PciIoDevice
> +  )
> +{
> +  PciIoDevice->PciDriverOverride.GetDriver = GetDriver;
> +}
> +
> +/**
> +  Find the image handle whose path equals to ImagePath.
> +
> +  @param ImagePath   Image path.
> +
> +  @return Image handle.
> +**/
> +EFI_HANDLE
> +LocateImageHandle (
> +  IN EFI_DEVICE_PATH_PROTOCOL   *ImagePath
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_HANDLE                    *Handles;
> +  UINTN                         Index;
> +  UINTN                         HandleNum;
> +  EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
> +  UINTN                         ImagePathSize;
> +  EFI_HANDLE                    ImageHandle;
> +
> +  Status = gBS->LocateHandleBuffer (
> +                  ByProtocol,
> +                  &gEfiLoadedImageDevicePathProtocolGuid,
> +                  NULL,
> +                  &HandleNum,
> +                  &Handles
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +
> +  ImageHandle   = NULL;
> +  ImagePathSize = GetDevicePathSize (ImagePath);
> +
> +  for (Index = 0; Index < HandleNum; Index++) {
> +    Status = gBS->HandleProtocol (Handles[Index],
> &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &DevicePath);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +    if ((ImagePathSize == GetDevicePathSize (DevicePath)) &&
> +        (CompareMem (ImagePath, DevicePath, ImagePathSize) == 0)
> +        ) {
> +      ImageHandle = Handles[Index];
> +      break;
> +    }
> +  }
> +
> +  FreePool (Handles);
> +  return ImageHandle;
> +}
> +
> +/**
> +  Uses a bus specific algorithm to retrieve a driver image handle for a
> controller.
> +
> +  @param  This                  A pointer to the
> EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance.
> +  @param  DriverImageHandle     On input, a pointer to the previous driver
> image handle returned
> +                                by GetDriver(). On output, a pointer to the next driver
> +                                image handle. Passing in a NULL, will return the first driver
> +                                image handle.
> +
> +  @retval EFI_SUCCESS           A bus specific override driver is returned in
> DriverImageHandle.
> +  @retval EFI_NOT_FOUND         The end of the list of override drivers was
> reached.
> +                                A bus specific override driver is not returned in
> DriverImageHandle.
> +  @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that
> was returned on a
> +                                previous call to GetDriver().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetDriver (
> +  IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL              *This,
> +  IN OUT EFI_HANDLE                                         *DriverImageHandle
> +  )
> +{
> +  PCI_IO_DEVICE             *PciIoDevice;
> +  LIST_ENTRY                *Link;
> +  PCI_DRIVER_OVERRIDE_LIST  *Override;
> +  BOOLEAN                   ReturnNext;
> +
> +  Override    = NULL;
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This);
> +  ReturnNext  = (BOOLEAN) (*DriverImageHandle == NULL);
> +  for ( Link = GetFirstNode (&PciIoDevice->OptionRomDriverList)
> +      ; !IsNull (&PciIoDevice->OptionRomDriverList, Link)
> +      ; Link = GetNextNode (&PciIoDevice->OptionRomDriverList, Link)
> +      ) {
> +
> +    Override = DRIVER_OVERRIDE_FROM_LINK (Link);
> +
> +    if (ReturnNext) {
> +      if (Override->DriverImageHandle == NULL) {
> +        Override->DriverImageHandle = LocateImageHandle (Override-
> >DriverImagePath);
> +      }
> +
> +      if (Override->DriverImageHandle == NULL) {
> +        //
> +        // The Option ROM identified by Override->DriverImagePath is not
> loaded.
> +        //
> +        continue;
> +      } else {
> +        *DriverImageHandle = Override->DriverImageHandle;
> +        return EFI_SUCCESS;
> +      }
> +    }
> +
> +    if (*DriverImageHandle == Override->DriverImageHandle) {
> +      ReturnNext = TRUE;
> +    }
> +  }
> +
> +  ASSERT (IsNull (&PciIoDevice->OptionRomDriverList, Link));
> +  //
> +  // ReturnNext indicates a handle match happens.
> +  // If all nodes are checked without handle match happening,
> +  // the DriverImageHandle should be a invalid handle.
> +  //
> +  if (ReturnNext) {
> +    return EFI_NOT_FOUND;
> +  } else {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +}
> +
> +/**
> +  Add an overriding driver image.
> +
> +  @param PciIoDevice        Instance of PciIo device.
> +  @param DriverImageHandle  Image handle of newly added driver image.
> +  @param DriverImagePath    Device path of newly added driver image.
> +
> +  @retval EFI_SUCCESS          Successfully added driver.
> +  @retval EFI_OUT_OF_RESOURCES No memory resource for new driver
> instance.
> +  @retval other                Some error occurred when locating
> gEfiLoadedImageProtocolGuid.
> +
> +**/
> +EFI_STATUS
> +AddDriver (
> +  IN PCI_IO_DEVICE            *PciIoDevice,
> +  IN EFI_HANDLE               DriverImageHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath
> +  )
> +{
> +  PCI_DRIVER_OVERRIDE_LIST      *Node;
> +
> +  //
> +  // Caller should pass in either Image Handle or Image Path, but not both.
> +  //
> +  ASSERT ((DriverImageHandle == NULL) || (DriverImagePath == NULL));
> +
> +  Node = AllocateZeroPool (sizeof (PCI_DRIVER_OVERRIDE_LIST));
> +  if (Node == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Node->Signature         = DRIVER_OVERRIDE_SIGNATURE;
> +  Node->DriverImageHandle = DriverImageHandle;
> +  Node->DriverImagePath   = DuplicateDevicePath (DriverImagePath);
> +
> +  InsertTailList (&PciIoDevice->OptionRomDriverList, &Node->Link);
> +
> +  PciIoDevice->BusOverride  = TRUE;
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.h
> new file mode 100644
> index 0000000000..ab058fa762
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciDriverOverride.h
> @@ -0,0 +1,83 @@
> +/** @file
> +  Functions declaration for Bus Specific Driver Override protocol.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +
> +#ifndef _EFI_PCI_DRIVER_OVERRRIDE_H_
> +#define _EFI_PCI_DRIVER_OVERRRIDE_H_
> +
> +#define DRIVER_OVERRIDE_SIGNATURE SIGNATURE_32 ('d', 'r', 'o', 'v')
> +
> +//
> +// PCI driver override driver image list
> +//
> +typedef struct {
> +  UINT32                   Signature;
> +  LIST_ENTRY               Link;
> +  EFI_HANDLE               DriverImageHandle;
> +  EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
> +} PCI_DRIVER_OVERRIDE_LIST;
> +
> +
> +#define DRIVER_OVERRIDE_FROM_LINK(a) \
> +  CR (a, PCI_DRIVER_OVERRIDE_LIST, Link, DRIVER_OVERRIDE_SIGNATURE)
> +
> +/**
> +  Initializes a PCI Driver Override Instance.
> +
> +  @param  PciIoDevice   PCI Device instance.
> +
> +**/
> +VOID
> +InitializePciDriverOverrideInstance (
> +  IN OUT PCI_IO_DEVICE          *PciIoDevice
> +  );
> +
> +/**
> +  Add an overriding driver image.
> +
> +  @param PciIoDevice        Instance of PciIo device.
> +  @param DriverImageHandle  Image handle of newly added driver image.
> +  @param DriverImagePath    Device path of newly added driver image.
> +
> +  @retval EFI_SUCCESS          Successfully added driver.
> +  @retval EFI_OUT_OF_RESOURCES No memory resource for new driver
> instance.
> +  @retval other                Some error occurred when locating
> gEfiLoadedImageProtocolGuid.
> +
> +**/
> +EFI_STATUS
> +AddDriver (
> +  IN PCI_IO_DEVICE            *PciIoDevice,
> +  IN EFI_HANDLE               DriverImageHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath
> +  );
> +
> +
> +/**
> +  Uses a bus specific algorithm to retrieve a driver image handle for a
> controller.
> +
> +  @param  This                  A pointer to the
> EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL instance.
> +  @param  DriverImageHandle     On input, a pointer to the previous driver
> image handle returned
> +                                by GetDriver(). On output, a pointer to the next driver
> +                                image handle. Passing in a NULL, will return the first driver
> +                                image handle.
> +
> +  @retval EFI_SUCCESS           A bus specific override driver is returned in
> DriverImageHandle.
> +  @retval EFI_NOT_FOUND         The end of the list of override drivers was
> reached.
> +                                A bus specific override driver is not returned in
> DriverImageHandle.
> +  @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that
> was returned on a
> +                                previous call to GetDriver().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetDriver (
> +  IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL              *This,
> +  IN OUT EFI_HANDLE                                         *DriverImageHandle
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.c
> new file mode 100644
> index 0000000000..4e1c328b7e
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.c
> @@ -0,0 +1,2210 @@
> +/** @file
> +  PCI eunmeration implementation on entire PCI bus system for PCI Bus
> module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +/**
> +  This routine is used to enumerate entire pci bus system
> +  in a given platform.
> +
> +  @param Controller          Parent controller handle.
> +  @param HostBridgeHandle    Host bridge handle.
> +
> +  @retval EFI_SUCCESS    PCI enumeration finished successfully.
> +  @retval other          Some error occurred when enumerating the pci bus
> system.
> +
> +**/
> +EFI_STATUS
> +PciEnumerator (
> +  IN EFI_HANDLE                    Controller,
> +  IN EFI_HANDLE                    HostBridgeHandle
> +  )
> +{
> +  EFI_STATUS                                        Status;
> +  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc;
> +
> +  //
> +  // Get the pci host bridge resource allocation protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +                  HostBridgeHandle,
> +                  &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +                  (VOID **) &PciResAlloc,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Notify the pci bus enumeration is about to begin
> +  //
> +  Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Start the bus allocation phase
> +  //
> +  Status = PciHostBridgeEnumerator (PciResAlloc);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Submit the resource request
> +  //
> +  Status = PciHostBridgeResourceAllocator (PciResAlloc);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Notify the pci bus enumeration is about to complete
> +  //
> +  Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndEnumeration);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Process P2C
> +  //
> +  Status = PciHostBridgeP2CProcess (PciResAlloc);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Process attributes for devices on this host bridge
> +  //
> +  Status = PciHostBridgeDeviceAttribute (PciResAlloc);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Enumerate PCI root bridge.
> +
> +  @param PciResAlloc   Pointer to protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +  @param RootBridgeDev Instance of root bridge device.
> +
> +  @retval EFI_SUCCESS  Successfully enumerated root bridge.
> +  @retval other        Failed to enumerate root bridge.
> +
> +**/
> +EFI_STATUS
> +PciRootBridgeEnumerator (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc,
> +  IN PCI_IO_DEVICE                                     *RootBridgeDev
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration1;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration2;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration3;
> +  UINT8                             SubBusNumber;
> +  UINT8                             StartBusNumber;
> +  UINT8                             PaddedBusRange;
> +  EFI_HANDLE                        RootBridgeHandle;
> +  UINT8                             Desc;
> +  UINT64                            AddrLen;
> +  UINT64                            AddrRangeMin;
> +
> +  SubBusNumber    = 0;
> +  StartBusNumber  = 0;
> +  PaddedBusRange  = 0;
> +
> +  //
> +  // Get the root bridge handle
> +  //
> +  RootBridgeHandle = RootBridgeDev->Handle;
> +
> +  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +    EFI_PROGRESS_CODE,
> +    EFI_IO_BUS_PCI | EFI_IOB_PCI_BUS_ENUM,
> +    RootBridgeDev->DevicePath
> +    );
> +
> +  //
> +  // Get the Bus information
> +  //
> +  Status = PciResAlloc->StartBusEnumeration (
> +                          PciResAlloc,
> +                          RootBridgeHandle,
> +                          (VOID **) &Configuration
> +                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (Configuration == NULL || Configuration->Desc ==
> ACPI_END_TAG_DESCRIPTOR) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  RootBridgeDev->BusNumberRanges = Configuration;
> +
> +  //
> +  // Sort the descriptors in ascending order
> +  //
> +  for (Configuration1 = Configuration; Configuration1->Desc !=
> ACPI_END_TAG_DESCRIPTOR; Configuration1++) {
> +    Configuration2 = Configuration1;
> +    for (Configuration3 = Configuration1 + 1; Configuration3->Desc !=
> ACPI_END_TAG_DESCRIPTOR; Configuration3++) {
> +      if (Configuration2->AddrRangeMin > Configuration3->AddrRangeMin) {
> +        Configuration2 = Configuration3;
> +      }
> +    }
> +    //
> +    // All other fields other than AddrRangeMin and AddrLen are ignored in a
> descriptor,
> +    // so only need to swap these two fields.
> +    //
> +    if (Configuration2 != Configuration1) {
> +      AddrRangeMin = Configuration1->AddrRangeMin;
> +      Configuration1->AddrRangeMin = Configuration2->AddrRangeMin;
> +      Configuration2->AddrRangeMin = AddrRangeMin;
> +
> +      AddrLen = Configuration1->AddrLen;
> +      Configuration1->AddrLen = Configuration2->AddrLen;
> +      Configuration2->AddrLen = AddrLen;
> +    }
> +  }
> +
> +  //
> +  // Get the bus number to start with
> +  //
> +  StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
> +
> +  //
> +  // Initialize the subordinate bus number
> +  //
> +  SubBusNumber = StartBusNumber;
> +
> +  //
> +  // Reset all assigned PCI bus number
> +  //
> +  ResetAllPpbBusNumber (
> +    RootBridgeDev,
> +    StartBusNumber
> +  );
> +
> +  //
> +  // Assign bus number
> +  //
> +  Status = PciScanBus (
> +            RootBridgeDev,
> +            StartBusNumber,
> +            &SubBusNumber,
> +            &PaddedBusRange
> +            );
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +
> +  //
> +  // Assign max bus number scanned
> +  //
> +
> +  Status = PciAllocateBusNumber (RootBridgeDev, SubBusNumber,
> PaddedBusRange, &SubBusNumber);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Find the bus range which contains the higest bus number, then returns
> the number of buses
> +  // that should be decoded.
> +  //
> +  while (Configuration->AddrRangeMin + Configuration->AddrLen - 1 <
> SubBusNumber) {
> +    Configuration++;
> +  }
> +  AddrLen = Configuration->AddrLen;
> +  Configuration->AddrLen = SubBusNumber - Configuration-
> >AddrRangeMin + 1;
> +
> +  //
> +  // Save the Desc field of the next descriptor. Mark the next descriptor as
> an END descriptor.
> +  //
> +  Configuration++;
> +  Desc = Configuration->Desc;
> +  Configuration->Desc = ACPI_END_TAG_DESCRIPTOR;
> +
> +  //
> +  // Set bus number
> +  //
> +  Status = PciResAlloc->SetBusNumbers (
> +                          PciResAlloc,
> +                          RootBridgeHandle,
> +                          RootBridgeDev->BusNumberRanges
> +                          );
> +
> +  //
> +  // Restore changed fields
> +  //
> +  Configuration->Desc = Desc;
> +  (Configuration - 1)->AddrLen = AddrLen;
> +
> +  return Status;
> +}
> +
> +/**
> +  This routine is used to process all PCI devices' Option Rom
> +  on a certain root bridge.
> +
> +  @param Bridge     Given parent's root bridge.
> +  @param RomBase    Base address of ROM driver loaded from.
> +  @param MaxLength  Maximum rom size.
> +
> +**/
> +VOID
> +ProcessOptionRom (
> +  IN PCI_IO_DEVICE *Bridge,
> +  IN UINT64        RomBase,
> +  IN UINT64        MaxLength
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *Temp;
> +
> +  //
> +  // Go through bridges to reach all devices
> +  //
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +
> +      //
> +      // Go further to process the option rom under this bridge
> +      //
> +      ProcessOptionRom (Temp, RomBase, MaxLength);
> +    }
> +
> +    if (Temp->RomSize != 0 && Temp->RomSize <= MaxLength) {
> +
> +      //
> +      // Load and process the option rom
> +      //
> +      LoadOpRomImage (Temp, RomBase);
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +}
> +
> +/**
> +  This routine is used to assign bus number to the given PCI bus system
> +
> +  @param Bridge             Parent root bridge instance.
> +  @param StartBusNumber     Number of beginning.
> +  @param SubBusNumber       The number of sub bus.
> +
> +  @retval EFI_SUCCESS       Successfully assigned bus number.
> +  @retval EFI_DEVICE_ERROR  Failed to assign bus number.
> +
> +**/
> +EFI_STATUS
> +PciAssignBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber,
> +  OUT UINT8                             *SubBusNumber
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  PCI_TYPE00                      Pci;
> +  UINT8                           Device;
> +  UINT8                           Func;
> +  UINT64                          Address;
> +  UINTN                           SecondBus;
> +  UINT16                          Register;
> +  UINT8                           Register8;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  PciRootBridgeIo = Bridge->PciRootBridgeIo;
> +
> +  SecondBus       = 0;
> +  Register        = 0;
> +
> +  *SubBusNumber = StartBusNumber;
> +
> +  //
> +  // First check to see whether the parent is ppb
> +  //
> +  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
> +    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
> +
> +      //
> +      // Check to see whether a pci device is present
> +      //
> +      Status = PciDevicePresent (
> +                PciRootBridgeIo,
> +                &Pci,
> +                StartBusNumber,
> +                Device,
> +                Func
> +                );
> +
> +      if (EFI_ERROR (Status) && Func == 0) {
> +        //
> +        // go to next device if there is no Function 0
> +        //
> +        break;
> +      }
> +
> +      if (!EFI_ERROR (Status)   &&
> +          (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
> +
> +        //
> +        // Reserved one bus for cardbus bridge
> +        //
> +        Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1,
> SubBusNumber);
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +        SecondBus = *SubBusNumber;
> +
> +        Register  = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
> +
> +        Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
> +
> +        Status = PciRootBridgeIo->Pci.Write (
> +                                        PciRootBridgeIo,
> +                                        EfiPciWidthUint16,
> +                                        Address,
> +                                        1,
> +                                        &Register
> +                                        );
> +
> +        //
> +        // Initialize SubBusNumber to SecondBus
> +        //
> +        Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
> +        Status = PciRootBridgeIo->Pci.Write (
> +                                        PciRootBridgeIo,
> +                                        EfiPciWidthUint8,
> +                                        Address,
> +                                        1,
> +                                        SubBusNumber
> +                                        );
> +        //
> +        // If it is PPB, resursively search down this bridge
> +        //
> +        if (IS_PCI_BRIDGE (&Pci)) {
> +
> +          Register8 = 0xFF;
> +          Status = PciRootBridgeIo->Pci.Write (
> +                                          PciRootBridgeIo,
> +                                          EfiPciWidthUint8,
> +                                          Address,
> +                                          1,
> +                                          &Register8
> +                                          );
> +
> +          Status = PciAssignBusNumber (
> +                    Bridge,
> +                    (UINT8) (SecondBus),
> +                    SubBusNumber
> +                    );
> +
> +          if (EFI_ERROR (Status)) {
> +            return EFI_DEVICE_ERROR;
> +          }
> +        }
> +
> +        //
> +        // Set the current maximum bus number under the PPB
> +        //
> +        Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
> +
> +        Status = PciRootBridgeIo->Pci.Write (
> +                                        PciRootBridgeIo,
> +                                        EfiPciWidthUint8,
> +                                        Address,
> +                                        1,
> +                                        SubBusNumber
> +                                        );
> +
> +      }
> +
> +      if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
> +
> +        //
> +        // Skip sub functions, this is not a multi function device
> +        //
> +        Func = PCI_MAX_FUNC;
> +      }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This routine is used to determine the root bridge attribute by interfacing
> +  the host bridge resource allocation protocol.
> +
> +  @param PciResAlloc    Protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +  @param RootBridgeDev  Root bridge instance
> +
> +  @retval EFI_SUCCESS  Successfully got root bridge's attribute.
> +  @retval other        Failed to get attribute.
> +
> +**/
> +EFI_STATUS
> +DetermineRootBridgeAttributes (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc,
> +  IN PCI_IO_DEVICE                                    *RootBridgeDev
> +  )
> +{
> +  UINT64      Attributes;
> +  EFI_STATUS  Status;
> +  EFI_HANDLE  RootBridgeHandle;
> +
> +  Attributes        = 0;
> +  RootBridgeHandle  = RootBridgeDev->Handle;
> +
> +  //
> +  // Get root bridge attribute by calling into pci host bridge resource
> allocation protocol
> +  //
> +  Status = PciResAlloc->GetAllocAttributes (
> +                          PciResAlloc,
> +                          RootBridgeHandle,
> +                          &Attributes
> +                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Here is the point where PCI bus driver calls HOST bridge allocation
> protocol
> +  // Currently we hardcoded for ea815
> +  //
> +  if ((Attributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {
> +    RootBridgeDev->Decodes |=
> EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED;
> +  }
> +
> +  if ((Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0) {
> +    RootBridgeDev->Decodes |= EFI_BRIDGE_MEM64_DECODE_SUPPORTED;
> +    RootBridgeDev->Decodes |=
> EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
> +  }
> +
> +  RootBridgeDev->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
> +  RootBridgeDev->Decodes |=
> EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
> +  RootBridgeDev->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get Max Option Rom size on specified bridge.
> +
> +  @param Bridge    Given bridge device instance.
> +
> +  @return Max size of option rom needed.
> +
> +**/
> +UINT32
> +GetMaxOptionRomSize (
> +  IN PCI_IO_DEVICE   *Bridge
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *Temp;
> +  UINT32          MaxOptionRomSize;
> +  UINT32          TempOptionRomSize;
> +
> +  MaxOptionRomSize = 0;
> +
> +  //
> +  // Go through bridges to reach all devices
> +  //
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +
> +      //
> +      // Get max option rom size under this bridge
> +      //
> +      TempOptionRomSize = GetMaxOptionRomSize (Temp);
> +
> +      //
> +      // Compare with the option rom size of the bridge
> +      // Get the larger one
> +      //
> +      if (Temp->RomSize > TempOptionRomSize) {
> +        TempOptionRomSize = Temp->RomSize;
> +      }
> +
> +    } else {
> +
> +      //
> +      // For devices get the rom size directly
> +      //
> +      TempOptionRomSize = Temp->RomSize;
> +    }
> +
> +    //
> +    // Get the largest rom size on this bridge
> +    //
> +    if (TempOptionRomSize > MaxOptionRomSize) {
> +      MaxOptionRomSize = TempOptionRomSize;
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return MaxOptionRomSize;
> +}
> +
> +/**
> +  Process attributes of devices on this host bridge
> +
> +  @param PciResAlloc Protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_SUCCESS   Successfully process attribute.
> +  @retval EFI_NOT_FOUND Can not find the specific root bridge device.
> +  @retval other         Failed to determine the root bridge device's attribute.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeDeviceAttribute (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  )
> +{
> +  EFI_HANDLE    RootBridgeHandle;
> +  PCI_IO_DEVICE *RootBridgeDev;
> +  EFI_STATUS    Status;
> +
> +  RootBridgeHandle = NULL;
> +
> +  while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle)
> == EFI_SUCCESS) {
> +
> +    //
> +    // Get RootBridg Device by handle
> +    //
> +    RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
> +
> +    if (RootBridgeDev == NULL) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    //
> +    // Set the attributes for devcies behind the Root Bridge
> +    //
> +    Status = DetermineDeviceAttribute (RootBridgeDev);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get resource allocation status from the ACPI resource descriptor.
> +
> +  @param AcpiConfig       Point to Acpi configuration table.
> +  @param IoResStatus      Return the status of I/O resource.
> +  @param Mem32ResStatus   Return the status of 32-bit Memory resource.
> +  @param PMem32ResStatus  Return the status of 32-bit Prefetchable
> Memory resource.
> +  @param Mem64ResStatus   Return the status of 64-bit Memory resource.
> +  @param PMem64ResStatus  Return the status of 64-bit Prefetchable
> Memory resource.
> +
> +**/
> +VOID
> +GetResourceAllocationStatus (
> +  VOID        *AcpiConfig,
> +  OUT UINT64  *IoResStatus,
> +  OUT UINT64  *Mem32ResStatus,
> +  OUT UINT64  *PMem32ResStatus,
> +  OUT UINT64  *Mem64ResStatus,
> +  OUT UINT64  *PMem64ResStatus
> +  )
> +{
> +  UINT8                             *Temp;
> +  UINT64                            ResStatus;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ACPIAddressDesc;
> +
> +  Temp = (UINT8 *) AcpiConfig;
> +
> +  while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> +
> +    ACPIAddressDesc       = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)
> Temp;
> +    ResStatus = ACPIAddressDesc->AddrTranslationOffset;
> +
> +    switch (ACPIAddressDesc->ResType) {
> +    case 0:
> +      if (ACPIAddressDesc->AddrSpaceGranularity == 32) {
> +        if (ACPIAddressDesc->SpecificFlag == 0x06) {
> +          //
> +          // Pmem32
> +          //
> +          *PMem32ResStatus = ResStatus;
> +        } else {
> +          //
> +          // Mem32
> +          //
> +          *Mem32ResStatus = ResStatus;
> +        }
> +      }
> +
> +      if (ACPIAddressDesc->AddrSpaceGranularity == 64) {
> +        if (ACPIAddressDesc->SpecificFlag == 0x06) {
> +          //
> +          // PMem64
> +          //
> +          *PMem64ResStatus = ResStatus;
> +        } else {
> +          //
> +          // Mem64
> +          //
> +          *Mem64ResStatus = ResStatus;
> +        }
> +      }
> +
> +      break;
> +
> +    case 1:
> +      //
> +      // Io
> +      //
> +      *IoResStatus = ResStatus;
> +      break;
> +
> +    default:
> +      break;
> +    }
> +
> +    Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
> +  }
> +}
> +
> +/**
> +  Remove a PCI device from device pool and mark its bar.
> +
> +  @param PciDevice Instance of Pci device.
> +
> +  @retval EFI_SUCCESS Successfully remove the PCI device.
> +  @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.
> +
> +**/
> +EFI_STATUS
> +RejectPciDevice (
> +  IN PCI_IO_DEVICE       *PciDevice
> +  )
> +{
> +  PCI_IO_DEVICE   *Bridge;
> +  PCI_IO_DEVICE   *Temp;
> +  LIST_ENTRY      *CurrentLink;
> +
> +  //
> +  // Remove the padding resource from a bridge
> +  //
> +  if ( IS_PCI_BRIDGE(&PciDevice->Pci) &&
> +       PciDevice->ResourcePaddingDescriptors != NULL ) {
> +    FreePool (PciDevice->ResourcePaddingDescriptors);
> +    PciDevice->ResourcePaddingDescriptors = NULL;
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Skip RB and PPB
> +  //
> +  if (IS_PCI_BRIDGE (&PciDevice->Pci) || (PciDevice->Parent == NULL)) {
> +    return EFI_ABORTED;
> +  }
> +
> +  if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) {
> +    //
> +    // Get the root bridge device
> +    //
> +    Bridge = PciDevice;
> +    while (Bridge->Parent != NULL) {
> +      Bridge = Bridge->Parent;
> +    }
> +
> +    RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice);
> +
> +    //
> +    // Mark its bar
> +    //
> +    InitializeP2C (PciDevice);
> +  }
> +
> +  //
> +  // Remove the device
> +  //
> +  Bridge      = PciDevice->Parent;
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    if (Temp == PciDevice) {
> +      InitializePciDevice (Temp);
> +      RemoveEntryList (CurrentLink);
> +      return EFI_SUCCESS;
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return EFI_ABORTED;
> +}
> +
> +/**
> +  Determine whethter a PCI device can be rejected.
> +
> +  @param  PciResNode Pointer to Pci resource node instance.
> +
> +  @retval TRUE  The PCI device can be rejected.
> +  @retval TRUE  The PCI device cannot be rejected.
> +
> +**/
> +BOOLEAN
> +IsRejectiveDevice (
> +  IN  PCI_RESOURCE_NODE   *PciResNode
> +  )
> +{
> +  PCI_IO_DEVICE *Temp;
> +
> +  Temp = PciResNode->PciDev;
> +
> +  //
> +  // Ensure the device is present
> +  //
> +  if (Temp == NULL) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // PPB and RB should go ahead
> +  //
> +  if (IS_PCI_BRIDGE (&Temp->Pci) || (Temp->Parent == NULL)) {
> +    return TRUE;
> +  }
> +
> +  //
> +  // Skip device on Bus0
> +  //
> +  if ((Temp->Parent != NULL) && (Temp->BusNumber == 0)) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Skip VGA
> +  //
> +  if (IS_PCI_VGA (&Temp->Pci)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Compare two resource nodes and get the larger resource consumer.
> +
> +  @param PciResNode1  resource node 1 want to be compared
> +  @param PciResNode2  resource node 2 want to be compared
> +
> +  @return Larger resource node.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +GetLargerConsumerDevice (
> +  IN  PCI_RESOURCE_NODE   *PciResNode1,
> +  IN  PCI_RESOURCE_NODE   *PciResNode2
> +  )
> +{
> +  if (PciResNode2 == NULL) {
> +    return PciResNode1;
> +  }
> +
> +  if ((IS_PCI_BRIDGE(&(PciResNode2->PciDev->Pci)) || (PciResNode2-
> >PciDev->Parent == NULL)) \
> +       && (PciResNode2->ResourceUsage != PciResUsagePadding) )
> +  {
> +    return PciResNode1;
> +  }
> +
> +  if (PciResNode1 == NULL) {
> +    return PciResNode2;
> +  }
> +
> +  if ((PciResNode1->Length) > (PciResNode2->Length)) {
> +    return PciResNode1;
> +  }
> +
> +  return PciResNode2;
> +}
> +
> +
> +/**
> +  Get the max resource consumer in the host resource pool.
> +
> +  @param ResPool  Pointer to resource pool node.
> +
> +  @return The max resource consumer in the host resource pool.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +GetMaxResourceConsumerDevice (
> +  IN  PCI_RESOURCE_NODE   *ResPool
> +  )
> +{
> +  PCI_RESOURCE_NODE *Temp;
> +  LIST_ENTRY        *CurrentLink;
> +  PCI_RESOURCE_NODE *PciResNode;
> +  PCI_RESOURCE_NODE *PPBResNode;
> +
> +  PciResNode  = NULL;
> +
> +  CurrentLink = ResPool->ChildList.ForwardLink;
> +  while (CurrentLink != NULL && CurrentLink != &ResPool->ChildList) {
> +
> +    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +
> +    if (!IsRejectiveDevice (Temp)) {
> +      CurrentLink = CurrentLink->ForwardLink;
> +      continue;
> +    }
> +
> +    if ((IS_PCI_BRIDGE (&(Temp->PciDev->Pci)) || (Temp->PciDev->Parent
> == NULL)) \
> +          && (Temp->ResourceUsage != PciResUsagePadding))
> +    {
> +      PPBResNode  = GetMaxResourceConsumerDevice (Temp);
> +      PciResNode  = GetLargerConsumerDevice (PciResNode, PPBResNode);
> +    } else {
> +      PciResNode = GetLargerConsumerDevice (PciResNode, Temp);
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return PciResNode;
> +}
> +
> +/**
> +  Adjust host bridge allocation so as to reduce resource requirement
> +
> +  @param IoPool           Pointer to instance of I/O resource Node.
> +  @param Mem32Pool        Pointer to instance of 32-bit memory resource
> Node.
> +  @param PMem32Pool       Pointer to instance of 32-bit Prefetchable
> memory resource node.
> +  @param Mem64Pool        Pointer to instance of 64-bit memory resource
> node.
> +  @param PMem64Pool       Pointer to instance of 64-bit Prefetchable
> memory resource node.
> +  @param IoResStatus      Status of I/O resource Node.
> +  @param Mem32ResStatus   Status of 32-bit memory resource Node.
> +  @param PMem32ResStatus  Status of 32-bit Prefetchable memory
> resource node.
> +  @param Mem64ResStatus   Status of 64-bit memory resource node.
> +  @param PMem64ResStatus  Status of 64-bit Prefetchable memory
> resource node.
> +
> +  @retval EFI_SUCCESS     Successfully adjusted resource on host bridge.
> +  @retval EFI_ABORTED     Host bridge hasn't this resource type or no
> resource be adjusted.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeAdjustAllocation (
> +  IN  PCI_RESOURCE_NODE   *IoPool,
> +  IN  PCI_RESOURCE_NODE   *Mem32Pool,
> +  IN  PCI_RESOURCE_NODE   *PMem32Pool,
> +  IN  PCI_RESOURCE_NODE   *Mem64Pool,
> +  IN  PCI_RESOURCE_NODE   *PMem64Pool,
> +  IN  UINT64              IoResStatus,
> +  IN  UINT64              Mem32ResStatus,
> +  IN  UINT64              PMem32ResStatus,
> +  IN  UINT64              Mem64ResStatus,
> +  IN  UINT64              PMem64ResStatus
> +  )
> +{
> +  BOOLEAN                               AllocationAjusted;
> +  PCI_RESOURCE_NODE                     *PciResNode;
> +  PCI_RESOURCE_NODE                     *ResPool[5];
> +  PCI_IO_DEVICE                         *RemovedPciDev[5];
> +  UINT64                                ResStatus[5];
> +  UINTN                                 RemovedPciDevNum;
> +  UINTN                                 DevIndex;
> +  UINTN                                 ResType;
> +  EFI_STATUS                            Status;
> +  EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD
> AllocFailExtendedData;
> +
> +  PciResNode = NULL;
> +  ZeroMem (RemovedPciDev, 5 * sizeof (PCI_IO_DEVICE *));
> +  RemovedPciDevNum  = 0;
> +
> +  ResPool[0]        = IoPool;
> +  ResPool[1]        = Mem32Pool;
> +  ResPool[2]        = PMem32Pool;
> +  ResPool[3]        = Mem64Pool;
> +  ResPool[4]        = PMem64Pool;
> +
> +  ResStatus[0]      = IoResStatus;
> +  ResStatus[1]      = Mem32ResStatus;
> +  ResStatus[2]      = PMem32ResStatus;
> +  ResStatus[3]      = Mem64ResStatus;
> +  ResStatus[4]      = PMem64ResStatus;
> +
> +  AllocationAjusted = FALSE;
> +
> +  for (ResType = 0; ResType < 5; ResType++) {
> +
> +    if (ResStatus[ResType] == EFI_RESOURCE_SATISFIED) {
> +      continue;
> +    }
> +
> +    if (ResStatus[ResType] == EFI_RESOURCE_NOT_SATISFIED) {
> +      //
> +      // Host bridge hasn't this resource type
> +      //
> +      return EFI_ABORTED;
> +    }
> +
> +    //
> +    // Hostbridge hasn't enough resource
> +    //
> +    PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]);
> +    if (PciResNode == NULL) {
> +      continue;
> +    }
> +
> +    //
> +    // Check if the device has been removed before
> +    //
> +    for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) {
> +      if (PciResNode->PciDev == RemovedPciDev[DevIndex]) {
> +        break;
> +      }
> +    }
> +
> +    if (DevIndex != RemovedPciDevNum) {
> +      continue;
> +    }
> +
> +    //
> +    // Remove the device if it isn't in the array
> +    //
> +    Status = RejectPciDevice (PciResNode->PciDev);
> +    if (Status == EFI_SUCCESS) {
> +      DEBUG ((
> +        EFI_D_ERROR,
> +        "PciBus: [%02x|%02x|%02x] was rejected due to resource
> confliction.\n",
> +        PciResNode->PciDev->BusNumber, PciResNode->PciDev-
> >DeviceNumber, PciResNode->PciDev->FunctionNumber
> +        ));
> +
> +      //
> +      // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
> +      //
> +      //
> +      // Have no way to get ReqRes, AllocRes & Bar here
> +      //
> +      ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
> +      AllocFailExtendedData.DevicePathSize = (UINT16) sizeof
> (EFI_DEVICE_PATH_PROTOCOL);
> +      AllocFailExtendedData.DevicePath     = (UINT8 *) PciResNode->PciDev-
> >DevicePath;
> +      AllocFailExtendedData.Bar            = PciResNode->Bar;
> +
> +      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> +            EFI_PROGRESS_CODE,
> +            EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
> +            (VOID *) &AllocFailExtendedData,
> +            sizeof (AllocFailExtendedData)
> +            );
> +
> +      //
> +      // Add it to the array and indicate at least a device has been rejected
> +      //
> +      RemovedPciDev[RemovedPciDevNum++] = PciResNode->PciDev;
> +      AllocationAjusted                 = TRUE;
> +    }
> +  }
> +  //
> +  // End for
> +  //
> +
> +  if (AllocationAjusted) {
> +    return EFI_SUCCESS;
> +  } else {
> +    return EFI_ABORTED;
> +  }
> +}
> +
> +/**
> +  Summary requests for all resource type, and construct ACPI resource
> +  requestor instance.
> +
> +  @param Bridge           detecting bridge
> +  @param IoNode           Pointer to instance of I/O resource Node
> +  @param Mem32Node        Pointer to instance of 32-bit memory resource
> Node
> +  @param PMem32Node       Pointer to instance of 32-bit Pmemory resource
> node
> +  @param Mem64Node        Pointer to instance of 64-bit memory resource
> node
> +  @param PMem64Node       Pointer to instance of 64-bit Pmemory resource
> node
> +  @param Config           Output buffer holding new constructed APCI resource
> requestor
> +
> +  @retval EFI_SUCCESS           Successfully constructed ACPI resource.
> +  @retval EFI_OUT_OF_RESOURCES  No memory available.
> +
> +**/
> +EFI_STATUS
> +ConstructAcpiResourceRequestor (
> +  IN PCI_IO_DEVICE      *Bridge,
> +  IN PCI_RESOURCE_NODE  *IoNode,
> +  IN PCI_RESOURCE_NODE  *Mem32Node,
> +  IN PCI_RESOURCE_NODE  *PMem32Node,
> +  IN PCI_RESOURCE_NODE  *Mem64Node,
> +  IN PCI_RESOURCE_NODE  *PMem64Node,
> +  OUT VOID              **Config
> +  )
> +{
> +  UINT8                             NumConfig;
> +  UINT8                             Aperture;
> +  UINT8                             *Configuration;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
> +  EFI_ACPI_END_TAG_DESCRIPTOR       *PtrEnd;
> +
> +  NumConfig = 0;
> +  Aperture  = 0;
> +
> +  *Config  = NULL;
> +
> +  //
> +  // if there is io request, add to the io aperture
> +  //
> +  if (ResourceRequestExisted (IoNode)) {
> +    NumConfig++;
> +    Aperture |= 0x01;
> +  }
> +
> +  //
> +  // if there is mem32 request, add to the mem32 aperture
> +  //
> +  if (ResourceRequestExisted (Mem32Node)) {
> +    NumConfig++;
> +    Aperture |= 0x02;
> +  }
> +
> +  //
> +  // if there is pmem32 request, add to the pmem32 aperture
> +  //
> +  if (ResourceRequestExisted (PMem32Node)) {
> +    NumConfig++;
> +    Aperture |= 0x04;
> +  }
> +
> +  //
> +  // if there is mem64 request, add to the mem64 aperture
> +  //
> +  if (ResourceRequestExisted (Mem64Node)) {
> +    NumConfig++;
> +    Aperture |= 0x08;
> +  }
> +
> +  //
> +  // if there is pmem64 request, add to the pmem64 aperture
> +  //
> +  if (ResourceRequestExisted (PMem64Node)) {
> +    NumConfig++;
> +    Aperture |= 0x10;
> +  }
> +
> +  if (NumConfig != 0) {
> +
> +    //
> +    // If there is at least one type of resource request,
> +    // allocate a acpi resource node
> +    //
> +    Configuration = AllocateZeroPool (sizeof
> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof
> (EFI_ACPI_END_TAG_DESCRIPTOR));
> +    if (Configuration == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
> +
> +    //
> +    // Deal with io aperture
> +    //
> +    if ((Aperture & 0x01) != 0) {
> +      Ptr->Desc     = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +      Ptr->Len      = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)
> - 3);
> +      //
> +      // Io
> +      //
> +      Ptr->ResType  = ACPI_ADDRESS_SPACE_TYPE_IO;
> +      //
> +      // non ISA range
> +      //
> +      Ptr->SpecificFlag = 1;
> +      Ptr->AddrLen      = IoNode->Length;
> +      Ptr->AddrRangeMax = IoNode->Alignment;
> +
> +      Ptr++;
> +    }
> +    //
> +    // Deal with mem32 aperture
> +    //
> +    if ((Aperture & 0x02) != 0) {
> +      Ptr->Desc     = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +      Ptr->Len      = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)
> - 3);
> +      //
> +      // Mem
> +      //
> +      Ptr->ResType  = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      //
> +      // Nonprefechable
> +      //
> +      Ptr->SpecificFlag = 0;
> +      //
> +      // 32 bit
> +      //
> +      Ptr->AddrSpaceGranularity = 32;
> +      Ptr->AddrLen      = Mem32Node->Length;
> +      Ptr->AddrRangeMax = Mem32Node->Alignment;
> +
> +      Ptr++;
> +    }
> +
> +    //
> +    // Deal with Pmem32 aperture
> +    //
> +    if ((Aperture & 0x04) != 0) {
> +      Ptr->Desc     = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +      Ptr->Len      = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)
> - 3);
> +      //
> +      // Mem
> +      //
> +      Ptr->ResType  = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      //
> +      // prefechable
> +      //
> +      Ptr->SpecificFlag = 0x6;
> +      //
> +      // 32 bit
> +      //
> +      Ptr->AddrSpaceGranularity = 32;
> +      Ptr->AddrLen      = PMem32Node->Length;
> +      Ptr->AddrRangeMax = PMem32Node->Alignment;
> +
> +      Ptr++;
> +    }
> +    //
> +    // Deal with mem64 aperture
> +    //
> +    if ((Aperture & 0x08) != 0) {
> +      Ptr->Desc     = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +      Ptr->Len      = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)
> - 3);
> +      //
> +      // Mem
> +      //
> +      Ptr->ResType  = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      //
> +      // nonprefechable
> +      //
> +      Ptr->SpecificFlag = 0;
> +      //
> +      // 64 bit
> +      //
> +      Ptr->AddrSpaceGranularity = 64;
> +      Ptr->AddrLen      = Mem64Node->Length;
> +      Ptr->AddrRangeMax = Mem64Node->Alignment;
> +
> +      Ptr++;
> +    }
> +    //
> +    // Deal with Pmem64 aperture
> +    //
> +    if ((Aperture & 0x10) != 0) {
> +      Ptr->Desc     = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +      Ptr->Len      = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)
> - 3);
> +      //
> +      // Mem
> +      //
> +      Ptr->ResType  = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      //
> +      // prefechable
> +      //
> +      Ptr->SpecificFlag = 0x06;
> +      //
> +      // 64 bit
> +      //
> +      Ptr->AddrSpaceGranularity = 64;
> +      Ptr->AddrLen      = PMem64Node->Length;
> +      Ptr->AddrRangeMax = PMem64Node->Alignment;
> +
> +      Ptr++;
> +    }
> +
> +    //
> +    // put the checksum
> +    //
> +    PtrEnd            = (EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr;
> +
> +    PtrEnd->Desc      = ACPI_END_TAG_DESCRIPTOR;
> +    PtrEnd->Checksum  = 0;
> +
> +  } else {
> +
> +    //
> +    // If there is no resource request
> +    //
> +    Configuration = AllocateZeroPool (sizeof
> (EFI_ACPI_END_TAG_DESCRIPTOR));
> +    if (Configuration == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    PtrEnd            = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Configuration);
> +    PtrEnd->Desc      = ACPI_END_TAG_DESCRIPTOR;
> +    PtrEnd->Checksum  = 0;
> +  }
> +
> +  *Config = Configuration;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get resource base from an acpi configuration descriptor.
> +
> +  @param Config       An acpi configuration descriptor.
> +  @param IoBase       Output of I/O resource base address.
> +  @param Mem32Base    Output of 32-bit memory base address.
> +  @param PMem32Base   Output of 32-bit prefetchable memory base
> address.
> +  @param Mem64Base    Output of 64-bit memory base address.
> +  @param PMem64Base   Output of 64-bit prefetchable memory base
> address.
> +
> +**/
> +VOID
> +GetResourceBase (
> +  IN VOID     *Config,
> +  OUT UINT64  *IoBase,
> +  OUT UINT64  *Mem32Base,
> +  OUT UINT64  *PMem32Base,
> +  OUT UINT64  *Mem64Base,
> +  OUT UINT64  *PMem64Base
> +  )
> +{
> +  UINT8                             *Temp;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
> +  UINT64                            ResStatus;
> +
> +  ASSERT (Config != NULL);
> +
> +  *IoBase     = 0xFFFFFFFFFFFFFFFFULL;
> +  *Mem32Base  = 0xFFFFFFFFFFFFFFFFULL;
> +  *PMem32Base = 0xFFFFFFFFFFFFFFFFULL;
> +  *Mem64Base  = 0xFFFFFFFFFFFFFFFFULL;
> +  *PMem64Base = 0xFFFFFFFFFFFFFFFFULL;
> +
> +  Temp        = (UINT8 *) Config;
> +
> +  while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> +
> +    Ptr       = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
> +    ResStatus = Ptr->AddrTranslationOffset;
> +
> +    if (ResStatus == EFI_RESOURCE_SATISFIED) {
> +
> +      switch (Ptr->ResType) {
> +
> +      //
> +      // Memory type aperture
> +      //
> +      case 0:
> +
> +        //
> +        // Check to see the granularity
> +        //
> +        if (Ptr->AddrSpaceGranularity == 32) {
> +          if ((Ptr->SpecificFlag & 0x06) != 0) {
> +            *PMem32Base = Ptr->AddrRangeMin;
> +          } else {
> +            *Mem32Base = Ptr->AddrRangeMin;
> +          }
> +        }
> +
> +        if (Ptr->AddrSpaceGranularity == 64) {
> +          if ((Ptr->SpecificFlag & 0x06) != 0) {
> +            *PMem64Base = Ptr->AddrRangeMin;
> +          } else {
> +            *Mem64Base = Ptr->AddrRangeMin;
> +          }
> +        }
> +        break;
> +
> +      case 1:
> +
> +        //
> +        // Io type aperture
> +        //
> +        *IoBase = Ptr->AddrRangeMin;
> +        break;
> +
> +      default:
> +        break;
> +
> +      }
> +      //
> +      // End switch
> +      //
> +    }
> +    //
> +    // End for
> +    //
> +    Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
> +  }
> +}
> +
> +/**
> +  Enumerate pci bridge, allocate resource and determine attribute
> +  for devices on this bridge.
> +
> +  @param BridgeDev    Pointer to instance of bridge device.
> +
> +  @retval EFI_SUCCESS Successfully enumerated PCI bridge.
> +  @retval other       Failed to enumerate.
> +
> +**/
> +EFI_STATUS
> +PciBridgeEnumerator (
> +  IN PCI_IO_DEVICE                                     *BridgeDev
> +  )
> +{
> +  UINT8               SubBusNumber;
> +  UINT8               StartBusNumber;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  EFI_STATUS          Status;
> +
> +  SubBusNumber    = 0;
> +  StartBusNumber  = 0;
> +  PciIo           = &(BridgeDev->PciIo);
> +  Status          = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1,
> &StartBusNumber);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = PciAssignBusNumber (
> +            BridgeDev,
> +            StartBusNumber,
> +            &SubBusNumber
> +            );
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = PciPciDeviceInfoCollector (BridgeDev, StartBusNumber);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = PciBridgeResourceAllocator (BridgeDev);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = DetermineDeviceAttribute (BridgeDev);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +}
> +
> +/**
> +  Allocate all kinds of resource for PCI bridge.
> +
> +  @param  Bridge      Pointer to bridge instance.
> +
> +  @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.
> +  @retval other       Failed to allocate resource for bridge.
> +
> +**/
> +EFI_STATUS
> +PciBridgeResourceAllocator (
> +  IN PCI_IO_DEVICE  *Bridge
> +  )
> +{
> +  PCI_RESOURCE_NODE *IoBridge;
> +  PCI_RESOURCE_NODE *Mem32Bridge;
> +  PCI_RESOURCE_NODE *PMem32Bridge;
> +  PCI_RESOURCE_NODE *Mem64Bridge;
> +  PCI_RESOURCE_NODE *PMem64Bridge;
> +  UINT64            IoBase;
> +  UINT64            Mem32Base;
> +  UINT64            PMem32Base;
> +  UINT64            Mem64Base;
> +  UINT64            PMem64Base;
> +  EFI_STATUS        Status;
> +
> +  IoBridge = CreateResourceNode (
> +               Bridge,
> +               0,
> +               Bridge->BridgeIoAlignment,
> +               0,
> +               PciBarTypeIo16,
> +               PciResUsageTypical
> +               );
> +
> +  Mem32Bridge = CreateResourceNode (
> +                  Bridge,
> +                  0,
> +                  0xFFFFF,
> +                  0,
> +                  PciBarTypeMem32,
> +                  PciResUsageTypical
> +                  );
> +
> +  PMem32Bridge = CreateResourceNode (
> +                   Bridge,
> +                   0,
> +                   0xFFFFF,
> +                   0,
> +                   PciBarTypePMem32,
> +                   PciResUsageTypical
> +                   );
> +
> +  Mem64Bridge = CreateResourceNode (
> +                  Bridge,
> +                  0,
> +                  0xFFFFF,
> +                  0,
> +                  PciBarTypeMem64,
> +                  PciResUsageTypical
> +                  );
> +
> +  PMem64Bridge = CreateResourceNode (
> +                   Bridge,
> +                   0,
> +                   0xFFFFF,
> +                   0,
> +                   PciBarTypePMem64,
> +                   PciResUsageTypical
> +                   );
> +
> +  //
> +  // Create resourcemap by going through all the devices subject to this root
> bridge
> +  //
> +  CreateResourceMap (
> +    Bridge,
> +    IoBridge,
> +    Mem32Bridge,
> +    PMem32Bridge,
> +    Mem64Bridge,
> +    PMem64Bridge
> +    );
> +
> +  Status = GetResourceBaseFromBridge (
> +             Bridge,
> +             &IoBase,
> +             &Mem32Base,
> +             &PMem32Base,
> +             &Mem64Base,
> +             &PMem64Base
> +             );
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Program IO resources
> +  //
> +  ProgramResource (
> +    IoBase,
> +    IoBridge
> +    );
> +
> +  //
> +  // Program Mem32 resources
> +  //
> +  ProgramResource (
> +    Mem32Base,
> +    Mem32Bridge
> +    );
> +
> +  //
> +  // Program PMem32 resources
> +  //
> +  ProgramResource (
> +    PMem32Base,
> +    PMem32Bridge
> +    );
> +
> +  //
> +  // Program Mem64 resources
> +  //
> +  ProgramResource (
> +    Mem64Base,
> +    Mem64Bridge
> +    );
> +
> +  //
> +  // Program PMem64 resources
> +  //
> +  ProgramResource (
> +    PMem64Base,
> +    PMem64Bridge
> +    );
> +
> +  DestroyResourceTree (IoBridge);
> +  DestroyResourceTree (Mem32Bridge);
> +  DestroyResourceTree (PMem32Bridge);
> +  DestroyResourceTree (PMem64Bridge);
> +  DestroyResourceTree (Mem64Bridge);
> +
> +  gBS->FreePool (IoBridge);
> +  gBS->FreePool (Mem32Bridge);
> +  gBS->FreePool (PMem32Bridge);
> +  gBS->FreePool (PMem64Bridge);
> +  gBS->FreePool (Mem64Bridge);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get resource base address for a pci bridge device.
> +
> +  @param Bridge     Given Pci driver instance.
> +  @param IoBase     Output for base address of I/O type resource.
> +  @param Mem32Base  Output for base address of 32-bit memory type
> resource.
> +  @param PMem32Base Ooutput for base address of 32-bit Pmemory type
> resource.
> +  @param Mem64Base  Output for base address of 64-bit memory type
> resource.
> +  @param PMem64Base Output for base address of 64-bit Pmemory type
> resource.
> +
> +  @retval EFI_SUCCESS           Successfully got resource base address.
> +  @retval EFI_OUT_OF_RESOURCES  PCI bridge is not available.
> +
> +**/
> +EFI_STATUS
> +GetResourceBaseFromBridge (
> +  IN  PCI_IO_DEVICE *Bridge,
> +  OUT UINT64        *IoBase,
> +  OUT UINT64        *Mem32Base,
> +  OUT UINT64        *PMem32Base,
> +  OUT UINT64        *Mem64Base,
> +  OUT UINT64        *PMem64Base
> +  )
> +{
> +  if (!Bridge->Allocated) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  *IoBase     = gAllOne;
> +  *Mem32Base  = gAllOne;
> +  *PMem32Base = gAllOne;
> +  *Mem64Base  = gAllOne;
> +  *PMem64Base = gAllOne;
> +
> +  if (IS_PCI_BRIDGE (&Bridge->Pci)) {
> +
> +    if (Bridge->PciBar[PPB_IO_RANGE].Length > 0) {
> +      *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress;
> +    }
> +
> +    if (Bridge->PciBar[PPB_MEM32_RANGE].Length > 0) {
> +      *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress;
> +    }
> +
> +    if (Bridge->PciBar[PPB_PMEM32_RANGE].Length > 0) {
> +      *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress;
> +    }
> +
> +    if (Bridge->PciBar[PPB_PMEM64_RANGE].Length > 0) {
> +      *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress;
> +    } else {
> +      *PMem64Base = gAllOne;
> +    }
> +
> +  }
> +
> +  if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) {
> +    if (Bridge->PciBar[P2C_IO_1].Length > 0) {
> +      *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress;
> +    } else {
> +      if (Bridge->PciBar[P2C_IO_2].Length > 0) {
> +        *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress;
> +      }
> +    }
> +
> +    if (Bridge->PciBar[P2C_MEM_1].Length > 0) {
> +      if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypePMem32) {
> +        *PMem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;
> +      }
> +
> +      if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypeMem32) {
> +        *Mem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;
> +      }
> +    }
> +
> +    if (Bridge->PciBar[P2C_MEM_2].Length > 0) {
> +      if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypePMem32) {
> +        *PMem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;
> +      }
> +
> +      if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypeMem32) {
> +        *Mem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;
> +      }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +   These are the notifications from the PCI bus driver that it is about to enter
> a certain
> +   phase of the PCI enumeration process.
> +
> +   This member function can be used to notify the host bridge driver to
> perform specific actions,
> +   including any chipset-specific initialization, so that the chipset is ready to
> enter the next phase.
> +   Eight notification points are defined at this time. See belows:
> +   EfiPciHostBridgeBeginEnumeration       Resets the host bridge PCI
> apertures and internal data
> +                                          structures. The PCI enumerator should issue this
> notification
> +                                          before starting a fresh enumeration process.
> Enumeration cannot
> +                                          be restarted after sending any other notification such
> as
> +                                          EfiPciHostBridgeBeginBusAllocation.
> +   EfiPciHostBridgeBeginBusAllocation     The bus allocation phase is about to
> begin. No specific action is
> +                                          required here. This notification can be used to perform
> any
> +                                          chipset-specific programming.
> +   EfiPciHostBridgeEndBusAllocation       The bus allocation and bus
> programming phase is complete. No
> +                                          specific action is required here. This notification can be
> used to
> +                                          perform any chipset-specific programming.
> +   EfiPciHostBridgeBeginResourceAllocation
> +                                          The resource allocation phase is about to begin. No
> specific
> +                                          action is required here. This notification can be used to
> perform
> +                                          any chipset-specific programming.
> +   EfiPciHostBridgeAllocateResources      Allocates resources per previously
> submitted requests for all the PCI
> +                                          root bridges. These resource settings are returned on
> the next call to
> +                                          GetProposedResources(). Before calling NotifyPhase()
> with a Phase of
> +                                          EfiPciHostBridgeAllocateResource, the PCI bus
> enumerator is responsible
> +                                          for gathering I/O and memory requests for
> +                                          all the PCI root bridges and submitting these requests
> using
> +                                          SubmitResources(). This function pads the resource
> amount
> +                                          to suit the root bridge hardware, takes care of
> dependencies between
> +                                          the PCI root bridges, and calls the Global Coherency
> Domain (GCD)
> +                                          with the allocation request. In the case of padding, the
> allocated range
> +                                          could be bigger than what was requested.
> +   EfiPciHostBridgeSetResources           Programs the host bridge hardware to
> decode previously allocated
> +                                          resources (proposed resources) for all the PCI root
> bridges. After the
> +                                          hardware is programmed, reassigning resources will
> not be supported.
> +                                          The bus settings are not affected.
> +   EfiPciHostBridgeFreeResources          Deallocates resources that were
> previously allocated for all the PCI
> +                                          root bridges and resets the I/O and memory apertures
> to their initial
> +                                          state. The bus settings are not affected. If the request
> to allocate
> +                                          resources fails, the PCI enumerator can use this
> notification to
> +                                          deallocate previous resources, adjust the requests,
> and retry
> +                                          allocation.
> +   EfiPciHostBridgeEndResourceAllocation  The resource allocation phase is
> completed. No specific action is
> +                                          required here. This notification can be used to perform
> any chipsetspecific
> +                                          programming.
> +
> +   @param[in] PciResAlloc         The instance pointer of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in] Phase               The phase during enumeration
> +
> +   @retval EFI_NOT_READY          This phase cannot be entered at this time.
> For example, this error
> +                                  is valid for a Phase of EfiPciHostBridgeAllocateResources if
> +                                  SubmitResources() has not been called for one or more
> +                                  PCI root bridges before this call
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware
> error. This error is valid
> +                                  for a Phase of EfiPciHostBridgeSetResources.
> +   @retval EFI_INVALID_PARAMETER  Invalid phase parameter
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed
> due to a lack of resources.
> +                                  This error is valid for a Phase of
> EfiPciHostBridgeAllocateResources if the
> +                                  previously submitted resource requests cannot be fulfilled
> or
> +                                  were only partially fulfilled.
> +   @retval EFI_SUCCESS            The notification was accepted without any
> errors.
> +
> +**/
> +EFI_STATUS
> +NotifyPhase (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc,
> +  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE       Phase
> +  )
> +{
> +  EFI_HANDLE                      HostBridgeHandle;
> +  EFI_HANDLE                      RootBridgeHandle;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +  EFI_STATUS                      Status;
> +
> +  HostBridgeHandle  = NULL;
> +  RootBridgeHandle  = NULL;
> +  if (gPciPlatformProtocol != NULL) {
> +    //
> +    // Get Host Bridge Handle.
> +    //
> +    PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);
> +
> +    //
> +    // Get the rootbridge Io protocol to find the host bridge handle
> +    //
> +    Status = gBS->HandleProtocol (
> +                    RootBridgeHandle,
> +                    &gEfiPciRootBridgeIoProtocolGuid,
> +                    (VOID **) &PciRootBridgeIo
> +                    );
> +
> +    if (EFI_ERROR (Status)) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    HostBridgeHandle = PciRootBridgeIo->ParentHandle;
> +
> +    //
> +    // Call PlatformPci::PlatformNotify() if the protocol is present.
> +    //
> +    gPciPlatformProtocol->PlatformNotify (
> +                            gPciPlatformProtocol,
> +                            HostBridgeHandle,
> +                            Phase,
> +                            ChipsetEntry
> +                            );
> +  } else if (gPciOverrideProtocol != NULL){
> +    //
> +    // Get Host Bridge Handle.
> +    //
> +    PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);
> +
> +    //
> +    // Get the rootbridge Io protocol to find the host bridge handle
> +    //
> +    Status = gBS->HandleProtocol (
> +                    RootBridgeHandle,
> +                    &gEfiPciRootBridgeIoProtocolGuid,
> +                    (VOID **) &PciRootBridgeIo
> +                    );
> +
> +    if (EFI_ERROR (Status)) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    HostBridgeHandle = PciRootBridgeIo->ParentHandle;
> +
> +    //
> +    // Call PlatformPci::PhaseNotify() if the protocol is present.
> +    //
> +    gPciOverrideProtocol->PlatformNotify (
> +                            gPciOverrideProtocol,
> +                            HostBridgeHandle,
> +                            Phase,
> +                            ChipsetEntry
> +                            );
> +  }
> +
> +  Status = PciResAlloc->NotifyPhase (
> +                          PciResAlloc,
> +                          Phase
> +                          );
> +
> +  if (gPciPlatformProtocol != NULL) {
> +    //
> +    // Call PlatformPci::PlatformNotify() if the protocol is present.
> +    //
> +    gPciPlatformProtocol->PlatformNotify (
> +                            gPciPlatformProtocol,
> +                            HostBridgeHandle,
> +                            Phase,
> +                            ChipsetExit
> +                            );
> +
> +  } else if (gPciOverrideProtocol != NULL) {
> +    //
> +    // Call PlatformPci::PhaseNotify() if the protocol is present.
> +    //
> +    gPciOverrideProtocol->PlatformNotify (
> +                            gPciOverrideProtocol,
> +                            HostBridgeHandle,
> +                            Phase,
> +                            ChipsetExit
> +                            );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Provides the hooks from the PCI bus driver to every PCI controller
> (device/function) at various
> +  stages of the PCI enumeration process that allow the host bridge driver to
> preinitialize individual
> +  PCI controllers before enumeration.
> +
> +  This function is called during the PCI enumeration process. No specific
> action is expected from this
> +  member function. It allows the host bridge driver to preinitialize individual
> PCI controllers before
> +  enumeration.
> +
> +  @param Bridge            Pointer to the
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +  @param Bus               The bus number of the pci device.
> +  @param Device            The device number of the pci device.
> +  @param Func              The function number of the pci device.
> +  @param Phase             The phase of the PCI device enumeration.
> +
> +  @retval EFI_SUCCESS              The requested parameters were returned.
> +  @retval EFI_INVALID_PARAMETER    RootBridgeHandle is not a valid root
> bridge handle.
> +  @retval EFI_INVALID_PARAMETER    Phase is not a valid phase that is
> defined in
> +                                   EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.
> +  @retval EFI_DEVICE_ERROR         Programming failed due to a hardware
> error. The PCI enumerator should
> +                                   not enumerate this device, including its child devices if it is
> a PCI-to-PCI
> +                                   bridge.
> +
> +**/
> +EFI_STATUS
> +PreprocessController (
> +  IN PCI_IO_DEVICE                                    *Bridge,
> +  IN UINT8                                            Bus,
> +  IN UINT8                                            Device,
> +  IN UINT8                                            Func,
> +  IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE     Phase
> +  )
> +{
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
> RootBridgePciAddress;
> +  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc;
> +  EFI_HANDLE                                        RootBridgeHandle;
> +  EFI_HANDLE                                        HostBridgeHandle;
> +  EFI_STATUS                                        Status;
> +
> +  //
> +  // Get the host bridge handle
> +  //
> +  HostBridgeHandle = Bridge->PciRootBridgeIo->ParentHandle;
> +
> +  //
> +  // Get the pci host bridge resource allocation protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +                  HostBridgeHandle,
> +                  &gEfiPciHostBridgeResourceAllocationProtocolGuid,
> +                  (VOID **) &PciResAlloc,
> +                  NULL,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Get Root Brige Handle
> +  //
> +  while (Bridge->Parent != NULL) {
> +    Bridge = Bridge->Parent;
> +  }
> +
> +  RootBridgeHandle                      = Bridge->Handle;
> +
> +  RootBridgePciAddress.Register         = 0;
> +  RootBridgePciAddress.Function         = Func;
> +  RootBridgePciAddress.Device           = Device;
> +  RootBridgePciAddress.Bus              = Bus;
> +  RootBridgePciAddress.ExtendedRegister = 0;
> +
> +  if (gPciPlatformProtocol != NULL) {
> +    //
> +    // Call PlatformPci::PrepController() if the protocol is present.
> +    //
> +    gPciPlatformProtocol->PlatformPrepController (
> +                            gPciPlatformProtocol,
> +                            HostBridgeHandle,
> +                            RootBridgeHandle,
> +                            RootBridgePciAddress,
> +                            Phase,
> +                            ChipsetEntry
> +                            );
> +  } else if (gPciOverrideProtocol != NULL) {
> +    //
> +    // Call PlatformPci::PrepController() if the protocol is present.
> +    //
> +    gPciOverrideProtocol->PlatformPrepController (
> +                            gPciOverrideProtocol,
> +                            HostBridgeHandle,
> +                            RootBridgeHandle,
> +                            RootBridgePciAddress,
> +                            Phase,
> +                            ChipsetEntry
> +                            );
> +  }
> +
> +  Status = PciResAlloc->PreprocessController (
> +                          PciResAlloc,
> +                          RootBridgeHandle,
> +                          RootBridgePciAddress,
> +                          Phase
> +                          );
> +
> +  if (gPciPlatformProtocol != NULL) {
> +    //
> +    // Call PlatformPci::PrepController() if the protocol is present.
> +    //
> +    gPciPlatformProtocol->PlatformPrepController (
> +                            gPciPlatformProtocol,
> +                            HostBridgeHandle,
> +                            RootBridgeHandle,
> +                            RootBridgePciAddress,
> +                            Phase,
> +                            ChipsetExit
> +                            );
> +  } else if (gPciOverrideProtocol != NULL) {
> +    //
> +    // Call PlatformPci::PrepController() if the protocol is present.
> +    //
> +    gPciOverrideProtocol->PlatformPrepController (
> +                            gPciOverrideProtocol,
> +                            HostBridgeHandle,
> +                            RootBridgeHandle,
> +                            RootBridgePciAddress,
> +                            Phase,
> +                            ChipsetExit
> +                            );
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function allows the PCI bus driver to be notified to act as requested
> when a hot-plug event has
> +  happened on the hot-plug controller. Currently, the operations include
> add operation and remove operation..
> +
> +  @param This                 A pointer to the hot plug request protocol.
> +  @param Operation            The operation the PCI bus driver is requested to
> make.
> +  @param Controller           The handle of the hot-plug controller.
> +  @param RemainingDevicePath  The remaining device path for the PCI-like
> hot-plug device.
> +  @param NumberOfChildren     The number of child handles.
> +                              For a add operation, it is an output parameter.
> +                              For a remove operation, it's an input parameter.
> +  @param ChildHandleBuffer    The buffer which contains the child handles.
> +
> +  @retval EFI_INVALID_PARAMETER  Operation is not a legal value.
> +                                 Controller is NULL or not a valid handle.
> +                                 NumberOfChildren is NULL.
> +                                 ChildHandleBuffer is NULL while Operation is add.
> +  @retval EFI_OUT_OF_RESOURCES   There are no enough resources to start
> the devices.
> +  @retval EFI_NOT_FOUND          Can not find bridge according to controller
> handle.
> +  @retval EFI_SUCCESS            The handles for the specified device have been
> created or destroyed
> +                                 as requested, and for an add operation, the new handles
> are
> +                                 returned in ChildHandleBuffer.
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciHotPlugRequestNotify (
> +  IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This,
> +  IN EFI_PCI_HOTPLUG_OPERATION        Operation,
> +  IN EFI_HANDLE                       Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL         * RemainingDevicePath OPTIONAL,
> +  IN OUT UINT8                        *NumberOfChildren,
> +  IN OUT EFI_HANDLE                   * ChildHandleBuffer
> +  )
> +{
> +  PCI_IO_DEVICE       *Bridge;
> +  PCI_IO_DEVICE       *Temp;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINTN               Index;
> +  EFI_HANDLE          RootBridgeHandle;
> +  EFI_STATUS          Status;
> +
> +  //
> +  // Check input parameter validity
> +  //
> +  if ((Controller == NULL) || (NumberOfChildren == NULL)){
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Operation != EfiPciHotPlugRequestAdd) && (Operation !=
> EfiPciHotplugRequestRemove)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Operation == EfiPciHotPlugRequestAdd){
> +    if (ChildHandleBuffer == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  } else if ((Operation == EfiPciHotplugRequestRemove) &&
> (*NumberOfChildren != 0)) {
> +    if (ChildHandleBuffer == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **) &PciIo,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Bridge = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
> +
> +  //
> +  // Get root bridge handle
> +  //
> +  Temp = Bridge;
> +  while (Temp->Parent != NULL) {
> +    Temp = Temp->Parent;
> +  }
> +
> +  RootBridgeHandle = Temp->Handle;
> +
> +  if (Operation == EfiPciHotPlugRequestAdd) {
> +    //
> +    // Report Status Code to indicate hot plug happens
> +    //
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_PROGRESS_CODE,
> +      (EFI_IO_BUS_PCI | EFI_IOB_PC_HOTPLUG),
> +      Temp->DevicePath
> +      );
> +
> +    if (NumberOfChildren != NULL) {
> +      *NumberOfChildren = 0;
> +    }
> +
> +    if (IsListEmpty (&Bridge->ChildList)) {
> +
> +      Status = PciBridgeEnumerator (Bridge);
> +
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +    }
> +
> +    Status = StartPciDevicesOnBridge (
> +              RootBridgeHandle,
> +              Bridge,
> +              RemainingDevicePath,
> +              NumberOfChildren,
> +              ChildHandleBuffer
> +              );
> +
> +    return Status;
> +  }
> +
> +  if (Operation == EfiPciHotplugRequestRemove) {
> +
> +    if (*NumberOfChildren == 0) {
> +      //
> +      // Remove all devices on the bridge
> +      //
> +      RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge);
> +      return EFI_SUCCESS;
> +
> +    }
> +
> +    for (Index = 0; Index < *NumberOfChildren; Index++) {
> +      //
> +      // De register all the pci device
> +      //
> +      Status = DeRegisterPciDevice (RootBridgeHandle,
> ChildHandleBuffer[Index]);
> +
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +
> +    }
> +    //
> +    // End for
> +    //
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Search hostbridge according to given handle
> +
> +  @param RootBridgeHandle  Host bridge handle.
> +
> +  @retval TRUE             Found host bridge handle.
> +  @retval FALSE            Not found hot bridge handle.
> +
> +**/
> +BOOLEAN
> +SearchHostBridgeHandle (
> +  IN EFI_HANDLE RootBridgeHandle
> +  )
> +{
> +  EFI_HANDLE                      HostBridgeHandle;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +  UINTN                           Index;
> +  EFI_STATUS                      Status;
> +
> +  //
> +  // Get the rootbridge Io protocol to find the host bridge handle
> +  //
> +  Status = gBS->OpenProtocol (
> +                  RootBridgeHandle,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  (VOID **) &PciRootBridgeIo,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  RootBridgeHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  HostBridgeHandle = PciRootBridgeIo->ParentHandle;
> +  for (Index = 0; Index < gPciHostBridgeNumber; Index++) {
> +    if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {
> +      return TRUE;
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Add host bridge handle to global variable for enumerating.
> +
> +  @param HostBridgeHandle   Host bridge handle.
> +
> +  @retval EFI_SUCCESS       Successfully added host bridge.
> +  @retval EFI_ABORTED       Host bridge is NULL, or given host bridge
> +                            has been in host bridge list.
> +
> +**/
> +EFI_STATUS
> +AddHostBridgeEnumerator (
> +  IN EFI_HANDLE HostBridgeHandle
> +  )
> +{
> +  UINTN Index;
> +
> +  if (HostBridgeHandle == NULL) {
> +    return EFI_ABORTED;
> +  }
> +
> +  for (Index = 0; Index < gPciHostBridgeNumber; Index++) {
> +    if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {
> +      return EFI_ABORTED;
> +    }
> +  }
> +
> +  if (Index < PCI_MAX_HOST_BRIDGE_NUM) {
> +    gPciHostBrigeHandles[Index] = HostBridgeHandle;
> +    gPciHostBridgeNumber++;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.h
> new file mode 100644
> index 0000000000..2a34c9043c
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumerator.h
> @@ -0,0 +1,515 @@
> +/** @file
> +  PCI bus enumeration logic function declaration for PCI bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_ENUMERATOR_H_
> +#define _EFI_PCI_ENUMERATOR_H_
> +
> +#include "PciResourceSupport.h"
> +
> +/**
> +  This routine is used to enumerate entire pci bus system
> +  in a given platform.
> +
> +  @param Controller          Parent controller handle.
> +  @param HostBridgeHandle    Host bridge handle.
> +
> +  @retval EFI_SUCCESS    PCI enumeration finished successfully.
> +  @retval other          Some error occurred when enumerating the pci bus
> system.
> +
> +**/
> +EFI_STATUS
> +PciEnumerator (
> +  IN EFI_HANDLE                    Controller,
> +  IN EFI_HANDLE                    HostBridgeHandle
> +  );
> +
> +/**
> +  Enumerate PCI root bridge.
> +
> +  @param PciResAlloc   Pointer to protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +  @param RootBridgeDev Instance of root bridge device.
> +
> +  @retval EFI_SUCCESS  Successfully enumerated root bridge.
> +  @retval other        Failed to enumerate root bridge.
> +
> +**/
> +EFI_STATUS
> +PciRootBridgeEnumerator (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc,
> +  IN PCI_IO_DEVICE                                     *RootBridgeDev
> +  );
> +
> +/**
> +  This routine is used to process all PCI devices' Option Rom
> +  on a certain root bridge.
> +
> +  @param Bridge     Given parent's root bridge.
> +  @param RomBase    Base address of ROM driver loaded from.
> +  @param MaxLength  Maximum rom size.
> +
> +**/
> +VOID
> +ProcessOptionRom (
> +  IN PCI_IO_DEVICE *Bridge,
> +  IN UINT64        RomBase,
> +  IN UINT64        MaxLength
> +  );
> +
> +/**
> +  This routine is used to assign bus number to the given PCI bus system
> +
> +  @param Bridge             Parent root bridge instance.
> +  @param StartBusNumber     Number of beginning.
> +  @param SubBusNumber       The number of sub bus.
> +
> +  @retval EFI_SUCCESS       Successfully assigned bus number.
> +  @retval EFI_DEVICE_ERROR  Failed to assign bus number.
> +
> +**/
> +EFI_STATUS
> +PciAssignBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber,
> +  OUT UINT8                             *SubBusNumber
> +  );
> +
> +/**
> +  This routine is used to determine the root bridge attribute by interfacing
> +  the host bridge resource allocation protocol.
> +
> +  @param PciResAlloc    Protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +  @param RootBridgeDev  Root bridge instance
> +
> +  @retval EFI_SUCCESS  Successfully got root bridge's attribute.
> +  @retval other        Failed to get attribute.
> +
> +**/
> +EFI_STATUS
> +DetermineRootBridgeAttributes (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc,
> +  IN PCI_IO_DEVICE                                    *RootBridgeDev
> +  );
> +
> +/**
> +  Get Max Option Rom size on specified bridge.
> +
> +  @param Bridge    Given bridge device instance.
> +
> +  @return Max size of option rom needed.
> +
> +**/
> +UINT32
> +GetMaxOptionRomSize (
> +  IN PCI_IO_DEVICE   *Bridge
> +  );
> +
> +/**
> +  Process attributes of devices on this host bridge
> +
> +  @param PciResAlloc Protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_SUCCESS   Successfully process attribute.
> +  @retval EFI_NOT_FOUND Can not find the specific root bridge device.
> +  @retval other         Failed to determine the root bridge device's attribute.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeDeviceAttribute (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  );
> +
> +/**
> +  Get resource allocation status from the ACPI resource descriptor.
> +
> +  @param AcpiConfig       Point to Acpi configuration table.
> +  @param IoResStatus      Return the status of I/O resource.
> +  @param Mem32ResStatus   Return the status of 32-bit Memory resource.
> +  @param PMem32ResStatus  Return the status of 32-bit Prefetchable
> Memory resource.
> +  @param Mem64ResStatus   Return the status of 64-bit Memory resource.
> +  @param PMem64ResStatus  Return the status of 64-bit Prefetchable
> Memory resource.
> +
> +**/
> +VOID
> +GetResourceAllocationStatus (
> +  VOID        *AcpiConfig,
> +  OUT UINT64  *IoResStatus,
> +  OUT UINT64  *Mem32ResStatus,
> +  OUT UINT64  *PMem32ResStatus,
> +  OUT UINT64  *Mem64ResStatus,
> +  OUT UINT64  *PMem64ResStatus
> +  );
> +
> +/**
> +  Remove a PCI device from device pool and mark its bar.
> +
> +  @param PciDevice Instance of Pci device.
> +
> +  @retval EFI_SUCCESS Successfully remove the PCI device.
> +  @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.
> +
> +**/
> +EFI_STATUS
> +RejectPciDevice (
> +  IN PCI_IO_DEVICE       *PciDevice
> +  );
> +
> +/**
> +  Determine whethter a PCI device can be rejected.
> +
> +  @param  PciResNode Pointer to Pci resource node instance.
> +
> +  @retval TRUE  The PCI device can be rejected.
> +  @retval TRUE  The PCI device cannot be rejected.
> +
> +**/
> +BOOLEAN
> +IsRejectiveDevice (
> +  IN  PCI_RESOURCE_NODE   *PciResNode
> +  );
> +
> +/**
> +  Compare two resource nodes and get the larger resource consumer.
> +
> +  @param PciResNode1  resource node 1 want to be compared
> +  @param PciResNode2  resource node 2 want to be compared
> +
> +  @return Larger resource node.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +GetLargerConsumerDevice (
> +  IN  PCI_RESOURCE_NODE   *PciResNode1,
> +  IN  PCI_RESOURCE_NODE   *PciResNode2
> +  );
> +
> +/**
> +  Get the max resource consumer in the host resource pool.
> +
> +  @param ResPool  Pointer to resource pool node.
> +
> +  @return The max resource consumer in the host resource pool.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +GetMaxResourceConsumerDevice (
> +  IN  PCI_RESOURCE_NODE   *ResPool
> +  );
> +
> +/**
> +  Adjust host bridge allocation so as to reduce resource requirement
> +
> +  @param IoPool           Pointer to instance of I/O resource Node.
> +  @param Mem32Pool        Pointer to instance of 32-bit memory resource
> Node.
> +  @param PMem32Pool       Pointer to instance of 32-bit Prefetchable
> memory resource node.
> +  @param Mem64Pool        Pointer to instance of 64-bit memory resource
> node.
> +  @param PMem64Pool       Pointer to instance of 64-bit Prefetchable
> memory resource node.
> +  @param IoResStatus      Status of I/O resource Node.
> +  @param Mem32ResStatus   Status of 32-bit memory resource Node.
> +  @param PMem32ResStatus  Status of 32-bit Prefetchable memory
> resource node.
> +  @param Mem64ResStatus   Status of 64-bit memory resource node.
> +  @param PMem64ResStatus  Status of 64-bit Prefetchable memory
> resource node.
> +
> +  @retval EFI_SUCCESS     Successfully adjusted resource on host bridge.
> +  @retval EFI_ABORTED     Host bridge hasn't this resource type or no
> resource be adjusted.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeAdjustAllocation (
> +  IN  PCI_RESOURCE_NODE   *IoPool,
> +  IN  PCI_RESOURCE_NODE   *Mem32Pool,
> +  IN  PCI_RESOURCE_NODE   *PMem32Pool,
> +  IN  PCI_RESOURCE_NODE   *Mem64Pool,
> +  IN  PCI_RESOURCE_NODE   *PMem64Pool,
> +  IN  UINT64              IoResStatus,
> +  IN  UINT64              Mem32ResStatus,
> +  IN  UINT64              PMem32ResStatus,
> +  IN  UINT64              Mem64ResStatus,
> +  IN  UINT64              PMem64ResStatus
> +  );
> +
> +/**
> +  Summary requests for all resource type, and construct ACPI resource
> +  requestor instance.
> +
> +  @param Bridge           detecting bridge
> +  @param IoNode           Pointer to instance of I/O resource Node
> +  @param Mem32Node        Pointer to instance of 32-bit memory resource
> Node
> +  @param PMem32Node       Pointer to instance of 32-bit Pmemory resource
> node
> +  @param Mem64Node        Pointer to instance of 64-bit memory resource
> node
> +  @param PMem64Node       Pointer to instance of 64-bit Pmemory resource
> node
> +  @param Config           Output buffer holding new constructed APCI resource
> requestor
> +
> +  @retval EFI_SUCCESS           Successfully constructed ACPI resource.
> +  @retval EFI_OUT_OF_RESOURCES  No memory available.
> +
> +**/
> +EFI_STATUS
> +ConstructAcpiResourceRequestor (
> +  IN PCI_IO_DEVICE      *Bridge,
> +  IN PCI_RESOURCE_NODE  *IoNode,
> +  IN PCI_RESOURCE_NODE  *Mem32Node,
> +  IN PCI_RESOURCE_NODE  *PMem32Node,
> +  IN PCI_RESOURCE_NODE  *Mem64Node,
> +  IN PCI_RESOURCE_NODE  *PMem64Node,
> +  OUT VOID              **Config
> +  );
> +
> +/**
> +  Get resource base from an acpi configuration descriptor.
> +
> +  @param Config       An acpi configuration descriptor.
> +  @param IoBase       Output of I/O resource base address.
> +  @param Mem32Base    Output of 32-bit memory base address.
> +  @param PMem32Base   Output of 32-bit prefetchable memory base
> address.
> +  @param Mem64Base    Output of 64-bit memory base address.
> +  @param PMem64Base   Output of 64-bit prefetchable memory base
> address.
> +
> +**/
> +VOID
> +GetResourceBase (
> +  IN VOID     *Config,
> +  OUT UINT64  *IoBase,
> +  OUT UINT64  *Mem32Base,
> +  OUT UINT64  *PMem32Base,
> +  OUT UINT64  *Mem64Base,
> +  OUT UINT64  *PMem64Base
> +  );
> +
> +/**
> +  Enumerate pci bridge, allocate resource and determine attribute
> +  for devices on this bridge.
> +
> +  @param BridgeDev    Pointer to instance of bridge device.
> +
> +  @retval EFI_SUCCESS Successfully enumerated PCI bridge.
> +  @retval other       Failed to enumerate.
> +
> +**/
> +EFI_STATUS
> +PciBridgeEnumerator (
> +  IN PCI_IO_DEVICE                                     *BridgeDev
> +  );
> +
> +/**
> +  Allocate all kinds of resource for PCI bridge.
> +
> +  @param  Bridge      Pointer to bridge instance.
> +
> +  @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.
> +  @retval other       Failed to allocate resource for bridge.
> +
> +**/
> +EFI_STATUS
> +PciBridgeResourceAllocator (
> +  IN PCI_IO_DEVICE  *Bridge
> +  );
> +
> +/**
> +  Get resource base address for a pci bridge device.
> +
> +  @param Bridge     Given Pci driver instance.
> +  @param IoBase     Output for base address of I/O type resource.
> +  @param Mem32Base  Output for base address of 32-bit memory type
> resource.
> +  @param PMem32Base Ooutput for base address of 32-bit Pmemory type
> resource.
> +  @param Mem64Base  Output for base address of 64-bit memory type
> resource.
> +  @param PMem64Base Output for base address of 64-bit Pmemory type
> resource.
> +
> +  @retval EFI_SUCCESS           Successfully got resource base address.
> +  @retval EFI_OUT_OF_RESOURCES  PCI bridge is not available.
> +
> +**/
> +EFI_STATUS
> +GetResourceBaseFromBridge (
> +  IN  PCI_IO_DEVICE *Bridge,
> +  OUT UINT64        *IoBase,
> +  OUT UINT64        *Mem32Base,
> +  OUT UINT64        *PMem32Base,
> +  OUT UINT64        *Mem64Base,
> +  OUT UINT64        *PMem64Base
> +  );
> +
> +/**
> +  Process Option Rom on this host bridge
> +
> +  @param PciResAlloc Pointer to instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_NOT_FOUND Can not find the root bridge instance.
> +  @retval EFI_SUCCESS   Success process.
> +**/
> +EFI_STATUS
> +PciHostBridgeP2CProcess (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  );
> +
> +/**
> +   These are the notifications from the PCI bus driver that it is about to enter
> a certain
> +   phase of the PCI enumeration process.
> +
> +   This member function can be used to notify the host bridge driver to
> perform specific actions,
> +   including any chipset-specific initialization, so that the chipset is ready to
> enter the next phase.
> +   Eight notification points are defined at this time. See belows:
> +   EfiPciHostBridgeBeginEnumeration       Resets the host bridge PCI
> apertures and internal data
> +                                          structures. The PCI enumerator should issue this
> notification
> +                                          before starting a fresh enumeration process.
> Enumeration cannot
> +                                          be restarted after sending any other notification such
> as
> +                                          EfiPciHostBridgeBeginBusAllocation.
> +   EfiPciHostBridgeBeginBusAllocation     The bus allocation phase is about to
> begin. No specific action is
> +                                          required here. This notification can be used to perform
> any
> +                                          chipset-specific programming.
> +   EfiPciHostBridgeEndBusAllocation       The bus allocation and bus
> programming phase is complete. No
> +                                          specific action is required here. This notification can be
> used to
> +                                          perform any chipset-specific programming.
> +   EfiPciHostBridgeBeginResourceAllocation
> +                                          The resource allocation phase is about to begin. No
> specific
> +                                          action is required here. This notification can be used to
> perform
> +                                          any chipset-specific programming.
> +   EfiPciHostBridgeAllocateResources      Allocates resources per previously
> submitted requests for all the PCI
> +                                          root bridges. These resource settings are returned on
> the next call to
> +                                          GetProposedResources(). Before calling NotifyPhase()
> with a Phase of
> +                                          EfiPciHostBridgeAllocateResource, the PCI bus
> enumerator is responsible
> +                                          for gathering I/O and memory requests for
> +                                          all the PCI root bridges and submitting these requests
> using
> +                                          SubmitResources(). This function pads the resource
> amount
> +                                          to suit the root bridge hardware, takes care of
> dependencies between
> +                                          the PCI root bridges, and calls the Global Coherency
> Domain (GCD)
> +                                          with the allocation request. In the case of padding, the
> allocated range
> +                                          could be bigger than what was requested.
> +   EfiPciHostBridgeSetResources           Programs the host bridge hardware to
> decode previously allocated
> +                                          resources (proposed resources) for all the PCI root
> bridges. After the
> +                                          hardware is programmed, reassigning resources will
> not be supported.
> +                                          The bus settings are not affected.
> +   EfiPciHostBridgeFreeResources          Deallocates resources that were
> previously allocated for all the PCI
> +                                          root bridges and resets the I/O and memory apertures
> to their initial
> +                                          state. The bus settings are not affected. If the request
> to allocate
> +                                          resources fails, the PCI enumerator can use this
> notification to
> +                                          deallocate previous resources, adjust the requests,
> and retry
> +                                          allocation.
> +   EfiPciHostBridgeEndResourceAllocation  The resource allocation phase is
> completed. No specific action is
> +                                          required here. This notification can be used to perform
> any chipsetspecific
> +                                          programming.
> +
> +   @param[in] PciResAlloc         The instance pointer of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> +   @param[in] Phase               The phase during enumeration
> +
> +   @retval EFI_NOT_READY          This phase cannot be entered at this time.
> For example, this error
> +                                  is valid for a Phase of EfiPciHostBridgeAllocateResources if
> +                                  SubmitResources() has not been called for one or more
> +                                  PCI root bridges before this call
> +   @retval EFI_DEVICE_ERROR       Programming failed due to a hardware
> error. This error is valid
> +                                  for a Phase of EfiPciHostBridgeSetResources.
> +   @retval EFI_INVALID_PARAMETER  Invalid phase parameter
> +   @retval EFI_OUT_OF_RESOURCES   The request could not be completed
> due to a lack of resources.
> +                                  This error is valid for a Phase of
> EfiPciHostBridgeAllocateResources if the
> +                                  previously submitted resource requests cannot be fulfilled
> or
> +                                  were only partially fulfilled.
> +   @retval EFI_SUCCESS            The notification was accepted without any
> errors.
> +
> +**/
> +EFI_STATUS
> +NotifyPhase (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc,
> +  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE       Phase
> +  );
> +
> +/**
> +  Provides the hooks from the PCI bus driver to every PCI controller
> (device/function) at various
> +  stages of the PCI enumeration process that allow the host bridge driver to
> preinitialize individual
> +  PCI controllers before enumeration.
> +
> +  This function is called during the PCI enumeration process. No specific
> action is expected from this
> +  member function. It allows the host bridge driver to preinitialize individual
> PCI controllers before
> +  enumeration.
> +
> +  @param Bridge            Pointer to the
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
> +  @param Bus               The bus number of the pci device.
> +  @param Device            The device number of the pci device.
> +  @param Func              The function number of the pci device.
> +  @param Phase             The phase of the PCI device enumeration.
> +
> +  @retval EFI_SUCCESS              The requested parameters were returned.
> +  @retval EFI_INVALID_PARAMETER    RootBridgeHandle is not a valid root
> bridge handle.
> +  @retval EFI_INVALID_PARAMETER    Phase is not a valid phase that is
> defined in
> +                                   EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.
> +  @retval EFI_DEVICE_ERROR         Programming failed due to a hardware
> error. The PCI enumerator should
> +                                   not enumerate this device, including its child devices if it is
> a PCI-to-PCI
> +                                   bridge.
> +
> +**/
> +EFI_STATUS
> +PreprocessController (
> +  IN PCI_IO_DEVICE                                  *Bridge,
> +  IN UINT8                                          Bus,
> +  IN UINT8                                          Device,
> +  IN UINT8                                          Func,
> +  IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE   Phase
> +  );
> +
> +/**
> +  This function allows the PCI bus driver to be notified to act as requested
> when a hot-plug event has
> +  happened on the hot-plug controller. Currently, the operations include
> add operation and remove operation..
> +
> +  @param This                 A pointer to the hot plug request protocol.
> +  @param Operation            The operation the PCI bus driver is requested to
> make.
> +  @param Controller           The handle of the hot-plug controller.
> +  @param RemainingDevicePath  The remaining device path for the PCI-like
> hot-plug device.
> +  @param NumberOfChildren     The number of child handles.
> +                              For a add operation, it is an output parameter.
> +                              For a remove operation, it's an input parameter.
> +  @param ChildHandleBuffer    The buffer which contains the child handles.
> +
> +  @retval EFI_INVALID_PARAMETER  Operation is not a legal value.
> +                                 Controller is NULL or not a valid handle.
> +                                 NumberOfChildren is NULL.
> +                                 ChildHandleBuffer is NULL while Operation is add.
> +  @retval EFI_OUT_OF_RESOURCES   There are no enough resources to start
> the devices.
> +  @retval EFI_NOT_FOUND          Can not find bridge according to controller
> handle.
> +  @retval EFI_SUCCESS            The handles for the specified device have been
> created or destroyed
> +                                 as requested, and for an add operation, the new handles
> are
> +                                 returned in ChildHandleBuffer.
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciHotPlugRequestNotify (
> +  IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL * This,
> +  IN EFI_PCI_HOTPLUG_OPERATION        Operation,
> +  IN EFI_HANDLE                       Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL         * RemainingDevicePath OPTIONAL,
> +  IN OUT UINT8                        *NumberOfChildren,
> +  IN OUT EFI_HANDLE                   * ChildHandleBuffer
> +  );
> +
> +/**
> +  Search hostbridge according to given handle
> +
> +  @param RootBridgeHandle  Host bridge handle.
> +
> +  @retval TRUE             Found host bridge handle.
> +  @retval FALSE            Not found hot bridge handle.
> +
> +**/
> +BOOLEAN
> +SearchHostBridgeHandle (
> +  IN EFI_HANDLE RootBridgeHandle
> +  );
> +
> +/**
> +  Add host bridge handle to global variable for enumerating.
> +
> +  @param HostBridgeHandle   Host bridge handle.
> +
> +  @retval EFI_SUCCESS       Successfully added host bridge.
> +  @retval EFI_ABORTED       Host bridge is NULL, or given host bridge
> +                            has been in host bridge list.
> +
> +**/
> +EFI_STATUS
> +AddHostBridgeEnumerator (
> +  IN EFI_HANDLE HostBridgeHandle
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.c
> new file mode 100644
> index 0000000000..99b04a462b
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.c
> @@ -0,0 +1,2885 @@
> +/** @file
> +  PCI emumeration support functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> +Copyright (c) 2021, American Megatrends International LLC.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +extern CHAR16  *mBarTypeStr[];
> +extern EDKII_DEVICE_SECURITY_PROTOCOL
> *mDeviceSecurityProtocol;
> +
> +#define OLD_ALIGN   0xFFFFFFFFFFFFFFFFULL
> +#define EVEN_ALIGN  0xFFFFFFFFFFFFFFFEULL
> +#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
> +#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
> +
> +/**
> +  This routine is used to check whether the pci device is present.
> +
> +  @param PciRootBridgeIo   Pointer to instance of
> EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Pci               Output buffer for PCI device configuration space.
> +  @param Bus               PCI bus NO.
> +  @param Device            PCI device NO.
> +  @param Func              PCI Func NO.
> +
> +  @retval EFI_NOT_FOUND    PCI device not present.
> +  @retval EFI_SUCCESS      PCI device is found.
> +
> +**/
> +EFI_STATUS
> +PciDevicePresent (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo,
> +  OUT PCI_TYPE00                          *Pci,
> +  IN  UINT8                               Bus,
> +  IN  UINT8                               Device,
> +  IN  UINT8                               Func
> +  )
> +{
> +  UINT64      Address;
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Create PCI address map in terms of Bus, Device and Func
> +  //
> +  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
> +
> +
> +//TiogaPass Override START : Skip SPI controller from Enumeration
> +
> +//
> +//
> +// It is necessary to skip SPI controller from Enumeration process otherwise
> SPI access runing DXE/DXE SMM
> +// will causes failures writting to SPI. This is a WA for LBG since currently OS
> hidde is not working.
> +//
> +  if(( Bus == 0x0) && ( Device == 0x1F) && (Func == 0x05)){
> +    DEBUG ((EFI_D_INFO, "DEBUG - Address - 0x%x  BUS %x DEV %x Func %x
> SKIP\n", Address, Bus, Device, Func));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +//TiogaPass Override END
> +
> +  //
> +  // Read the Vendor ID register
> +  //
> +  Status = PciRootBridgeIo->Pci.Read (
> +                                  PciRootBridgeIo,
> +                                  EfiPciWidthUint32,
> +                                  Address,
> +                                  1,
> +                                  Pci
> +                                  );
> +
> +  if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {
> +    //
> +    // Read the entire config header for the device
> +    //
> +    Status = PciRootBridgeIo->Pci.Read (
> +                                    PciRootBridgeIo,
> +                                    EfiPciWidthUint32,
> +                                    Address,
> +                                    sizeof (PCI_TYPE00) / sizeof (UINT32),
> +                                    Pci
> +                                    );
> +
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Collect all the resource information under this root bridge.
> +
> +  A database that records all the information about pci device subject to this
> +  root bridge will then be created.
> +
> +  @param Bridge         Parent bridge instance.
> +  @param StartBusNumber Bus number of beginning.
> +
> +  @retval EFI_SUCCESS   PCI device is found.
> +  @retval other         Some error occurred when reading PCI bridge
> information.
> +
> +**/
> +EFI_STATUS
> +PciPciDeviceInfoCollector (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber
> +  )
> +{
> +  EFI_STATUS          Status;
> +  PCI_TYPE00          Pci;
> +  UINT8               Device;
> +  UINT8               Func;
> +  UINT8               SecBus;
> +  PCI_IO_DEVICE       *PciIoDevice;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +
> +  Status  = EFI_SUCCESS;
> +  SecBus  = 0;
> +
> +  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
> +
> +    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
> +
> +      //
> +      // Check to see whether PCI device is present
> +      //
> +      Status = PciDevicePresent (
> +                 Bridge->PciRootBridgeIo,
> +                 &Pci,
> +                 (UINT8) StartBusNumber,
> +                 (UINT8) Device,
> +                 (UINT8) Func
> +                 );
> +
> +      if (EFI_ERROR (Status) && Func == 0) {
> +        //
> +        // go to next device if there is no Function 0
> +        //
> +        break;
> +      }
> +
> +      if (!EFI_ERROR (Status)) {
> +
> +        //
> +        // Call back to host bridge function
> +        //
> +        PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func,
> EfiPciBeforeResourceCollection);
> +
> +        //
> +        // Collect all the information about the PCI device discovered
> +        //
> +        Status = PciSearchDevice (
> +                   Bridge,
> +                   &Pci,
> +                   (UINT8) StartBusNumber,
> +                   Device,
> +                   Func,
> +                   &PciIoDevice
> +                   );
> +
> +        //
> +        // Recursively scan PCI busses on the other side of PCI-PCI bridges
> +        //
> +        //
> +        if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) ||
> IS_CARDBUS_BRIDGE (&Pci))) {
> +
> +          //
> +          // If it is PPB, we need to get the secondary bus to continue the
> enumeration
> +          //
> +          PciIo   = &(PciIoDevice->PciIo);
> +
> +          Status  = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8,
> PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);
> +
> +          if (EFI_ERROR (Status)) {
> +            return Status;
> +          }
> +
> +          //
> +          // Ensure secondary bus number is greater than the primary bus
> number to avoid
> +          // any potential dead loop when PcdPciDisableBusEnumeration is set
> to TRUE
> +          //
> +          if (SecBus <= StartBusNumber) {
> +            break;
> +          }
> +
> +          //
> +          // Get resource padding for PPB
> +          //
> +          GetResourcePaddingPpb (PciIoDevice);
> +
> +          //
> +          // Deep enumerate the next level bus
> +          //
> +          Status = PciPciDeviceInfoCollector (
> +                     PciIoDevice,
> +                     (UINT8) (SecBus)
> +                     );
> +
> +        }
> +
> +        if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
> +
> +          //
> +          // Skip sub functions, this is not a multi function device
> +          //
> +          Func = PCI_MAX_FUNC;
> +        }
> +      }
> +
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Search required device and create PCI device instance.
> +
> +  @param Bridge     Parent bridge instance.
> +  @param Pci        Input PCI device information block.
> +  @param Bus        PCI bus NO.
> +  @param Device     PCI device NO.
> +  @param Func       PCI func  NO.
> +  @param PciDevice  Output of searched PCI device instance.
> +
> +  @retval EFI_SUCCESS           Successfully created PCI device instance.
> +  @retval EFI_OUT_OF_RESOURCES  Cannot get PCI device information.
> +
> +**/
> +EFI_STATUS
> +PciSearchDevice (
> +  IN  PCI_IO_DEVICE                         *Bridge,
> +  IN  PCI_TYPE00                            *Pci,
> +  IN  UINT8                                 Bus,
> +  IN  UINT8                                 Device,
> +  IN  UINT8                                 Func,
> +  OUT PCI_IO_DEVICE                         **PciDevice
> +  )
> +{
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = NULL;
> +
> +  DEBUG ((
> +    EFI_D_INFO,
> +    "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",
> +    IS_PCI_BRIDGE (Pci) ?     L"PPB" :
> +    IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :
> +                              L"PCI",
> +    Bus, Device, Func
> +    ));
> +
> +  if (!IS_PCI_BRIDGE (Pci)) {
> +
> +    if (IS_CARDBUS_BRIDGE (Pci)) {
> +      PciIoDevice = GatherP2CInfo (
> +                      Bridge,
> +                      Pci,
> +                      Bus,
> +                      Device,
> +                      Func
> +                      );
> +      if ((PciIoDevice != NULL) && gFullEnumeration) {
> +        InitializeP2C (PciIoDevice);
> +      }
> +    } else {
> +
> +      //
> +      // Create private data for Pci Device
> +      //
> +      PciIoDevice = GatherDeviceInfo (
> +                      Bridge,
> +                      Pci,
> +                      Bus,
> +                      Device,
> +                      Func
> +                      );
> +
> +    }
> +
> +  } else {
> +
> +    //
> +    // Create private data for PPB
> +    //
> +    PciIoDevice = GatherPpbInfo (
> +                    Bridge,
> +                    Pci,
> +                    Bus,
> +                    Device,
> +                    Func
> +                    );
> +
> +    //
> +    // Special initialization for PPB including making the PPB quiet
> +    //
> +    if ((PciIoDevice != NULL) && gFullEnumeration) {
> +      InitializePpb (PciIoDevice);
> +    }
> +  }
> +
> +  if (PciIoDevice == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Update the bar information for this PCI device so as to support some
> specific device
> +  //
> +  UpdatePciInfo (PciIoDevice);
> +
> +  if (PciIoDevice->DevicePath == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Detect this function has option rom
> +  //
> +  if (gFullEnumeration) {
> +
> +    if (!IS_CARDBUS_BRIDGE (Pci)) {
> +
> +      GetOpRomInfo (PciIoDevice);
> +
> +    }
> +
> +    ResetPowerManagementFeature (PciIoDevice);
> +
> +  }
> +
> +  //
> +  // Insert it into a global tree for future reference
> +  //
> +  InsertPciDevice (Bridge, PciIoDevice);
> +
> +  //
> +  // Determine PCI device attributes
> +  //
> +
> +  if (PciDevice != NULL) {
> +    *PciDevice = PciIoDevice;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Dump the PPB padding resource information.
> +
> +  @param PciIoDevice     PCI IO instance.
> +  @param ResourceType    The desired resource type to dump.
> +                         PciBarTypeUnknown means to dump all types of resources.
> +**/
> +VOID
> +DumpPpbPaddingResource (
> +  IN PCI_IO_DEVICE                    *PciIoDevice,
> +  IN PCI_BAR_TYPE                     ResourceType
> +  )
> +{
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
> +  PCI_BAR_TYPE                      Type;
> +
> +  if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
> +    return;
> +  }
> +
> +  if (ResourceType == PciBarTypeIo16 || ResourceType == PciBarTypeIo32) {
> +    ResourceType = PciBarTypeIo;
> +  }
> +
> +  for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor-
> >Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {
> +
> +    Type = PciBarTypeUnknown;
> +    if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
> Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
> +      Type = PciBarTypeIo;
> +    } else if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
> Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
> +
> +      if (Descriptor->AddrSpaceGranularity == 32) {
> +        //
> +        // prefetchable
> +        //
> +        if (Descriptor->SpecificFlag ==
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E) {
> +          Type = PciBarTypePMem32;
> +        }
> +
> +        //
> +        // Non-prefetchable
> +        //
> +        if (Descriptor->SpecificFlag == 0) {
> +          Type = PciBarTypeMem32;
> +        }
> +      }
> +
> +      if (Descriptor->AddrSpaceGranularity == 64) {
> +        //
> +        // prefetchable
> +        //
> +        if (Descriptor->SpecificFlag ==
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E) {
> +          Type = PciBarTypePMem64;
> +        }
> +
> +        //
> +        // Non-prefetchable
> +        //
> +        if (Descriptor->SpecificFlag == 0) {
> +          Type = PciBarTypeMem64;
> +        }
> +      }
> +    }
> +
> +    if ((Type != PciBarTypeUnknown) && ((ResourceType ==
> PciBarTypeUnknown) || (ResourceType == Type))) {
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "   Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
> +        mBarTypeStr[Type], Descriptor->AddrRangeMax, Descriptor->AddrLen
> +        ));
> +    }
> +  }
> +
> +}
> +
> +/**
> +  Dump the PCI BAR information.
> +
> +  @param PciIoDevice     PCI IO instance.
> +**/
> +VOID
> +DumpPciBars (
> +  IN PCI_IO_DEVICE                    *PciIoDevice
> +  )
> +{
> +  UINTN                               Index;
> +
> +  for (Index = 0; Index < PCI_MAX_BAR; Index++) {
> +    if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {
> +      continue;
> +    }
> +
> +    DEBUG ((
> +      EFI_D_INFO,
> +      "   BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset =
> 0x%02x\n",
> +      Index, mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType,
> PciBarTypeMaxType)],
> +      PciIoDevice->PciBar[Index].Alignment, PciIoDevice-
> >PciBar[Index].Length, PciIoDevice->PciBar[Index].Offset
> +      ));
> +  }
> +
> +  for (Index = 0; Index < PCI_MAX_BAR; Index++) {
> +    if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) &&
> (PciIoDevice->VfPciBar[Index].Length == 0)) {
> +      continue;
> +    }
> +
> +    DEBUG ((
> +      EFI_D_INFO,
> +      " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset =
> 0x%02x\n",
> +      Index, mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType,
> PciBarTypeMaxType)],
> +      PciIoDevice->VfPciBar[Index].Alignment, PciIoDevice-
> >VfPciBar[Index].Length, PciIoDevice->VfPciBar[Index].Offset
> +      ));
> +  }
> +  DEBUG ((EFI_D_INFO, "\n"));
> +}
> +
> +/**
> +  Create PCI device instance for PCI device.
> +
> +  @param Bridge   Parent bridge instance.
> +  @param Pci      Input PCI device information block.
> +  @param Bus      PCI device Bus NO.
> +  @param Device   PCI device Device NO.
> +  @param Func     PCI device's func NO.
> +
> +  @return  Created PCI device instance.
> +
> +**/
> +PCI_IO_DEVICE *
> +GatherDeviceInfo (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  )
> +{
> +  UINTN                           Offset;
> +  UINTN                           BarIndex;
> +  PCI_IO_DEVICE                   *PciIoDevice;
> +
> +  PciIoDevice = CreatePciIoDevice (
> +                  Bridge,
> +                  Pci,
> +                  Bus,
> +                  Device,
> +                  Func
> +                  );
> +
> +  if (PciIoDevice == NULL) {
> +    return NULL;
> +  }
> +
> +  //
> +  // If it is a full enumeration, disconnect the device in advance
> +  //
> +  if (gFullEnumeration) {
> +
> +    PCI_DISABLE_COMMAND_REGISTER (PciIoDevice,
> EFI_PCI_COMMAND_BITS_OWNED);
> +
> +  }
> +
> +  //
> +  // Start to parse the bars
> +  //
> +  for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex <
> PCI_MAX_BAR; BarIndex++) {
> +    Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
> +  }
> +
> +  //
> +  // Parse the SR-IOV VF bars
> +  //
> +  if (PcdGetBool (PcdSrIovSupport) && PciIoDevice->SrIovCapabilityOffset
> != 0) {
> +    for (Offset = PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;
> +         Offset <= PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;
> +         BarIndex++) {
> +
> +      ASSERT (BarIndex < PCI_MAX_BAR);
> +      Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);
> +    }
> +  }
> +
> +  DEBUG_CODE (DumpPciBars (PciIoDevice););
> +  return PciIoDevice;
> +}
> +
> +/**
> +  Create PCI device instance for PCI-PCI bridge.
> +
> +  @param Bridge   Parent bridge instance.
> +  @param Pci      Input PCI device information block.
> +  @param Bus      PCI device Bus NO.
> +  @param Device   PCI device Device NO.
> +  @param Func     PCI device's func NO.
> +
> +  @return  Created PCI device instance.
> +
> +**/
> +PCI_IO_DEVICE *
> +GatherPpbInfo (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  )
> +{
> +  PCI_IO_DEVICE                   *PciIoDevice;
> +  EFI_STATUS                      Status;
> +  UINT8                           Value;
> +  EFI_PCI_IO_PROTOCOL             *PciIo;
> +  UINT8                           Temp;
> +  UINT32                          PMemBaseLimit;
> +  UINT16                          PrefetchableMemoryBase;
> +  UINT16                          PrefetchableMemoryLimit;
> +
> +  PciIoDevice = CreatePciIoDevice (
> +                  Bridge,
> +                  Pci,
> +                  Bus,
> +                  Device,
> +                  Func
> +                  );
> +
> +  if (PciIoDevice == NULL) {
> +    return NULL;
> +  }
> +
> +  if (gFullEnumeration) {
> +    PCI_DISABLE_COMMAND_REGISTER (PciIoDevice,
> EFI_PCI_COMMAND_BITS_OWNED);
> +
> +    //
> +    // Initialize the bridge control register
> +    //
> +    PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice,
> EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
> +
> +  }
> +
> +  //
> +  // PPB can have two BARs
> +  //
> +  if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
> +    //
> +    // Not 64-bit bar
> +    //
> +    PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
> +  }
> +
> +  PciIo = &PciIoDevice->PciIo;
> +
> +  //
> +  // Test whether it support 32 decode or not
> +  //
> +  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
> +  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
> +
> +  if (Value != 0) {
> +    if ((Value & 0x01) != 0) {
> +      PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
> +    } else {
> +      PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
> +  // PCI bridge supporting non-standard I/O window alignment less than 4K.
> +  //
> +
> +  PciIoDevice->BridgeIoAlignment = 0xFFF;
> +  if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {
> +    //
> +    // Check any bits of bit 3-1 of I/O Base Register are writable.
> +    // if so, it is assumed non-standard I/O window alignment is supported by
> this bridge.
> +    // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content
> can't be assumed.
> +    //
> +    Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));
> +    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
> +    PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
> +    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
> +    Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));
> +    switch (Value) {
> +      case BIT3:
> +        PciIoDevice->BridgeIoAlignment = 0x7FF;
> +        break;
> +      case BIT3 | BIT2:
> +        PciIoDevice->BridgeIoAlignment = 0x3FF;
> +        break;
> +      case BIT3 | BIT2 | BIT1:
> +        PciIoDevice->BridgeIoAlignment = 0x1FF;
> +        break;
> +    }
> +  }
> +
> +  Status = BarExisted (
> +            PciIoDevice,
> +            0x24,
> +            NULL,
> +            &PMemBaseLimit
> +            );
> +
> +  //
> +  // Test if it supports 64 memory or not
> +  //
> +  // The bottom 4 bits of both the Prefetchable Memory Base and
> Prefetchable Memory Limit
> +  // registers:
> +  //   0 - the bridge supports only 32 bit addresses.
> +  //   1 - the bridge supports 64-bit addresses.
> +  //
> +  PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);
> +  PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);
> +  if (!EFI_ERROR (Status) &&
> +      (PrefetchableMemoryBase & 0x000f) == 0x0001 &&
> +      (PrefetchableMemoryLimit & 0x000f) == 0x0001) {
> +    Status = BarExisted (
> +              PciIoDevice,
> +              0x28,
> +              NULL,
> +              NULL
> +              );
> +
> +    if (!EFI_ERROR (Status)) {
> +      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
> +      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
> +    } else {
> +      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Memory 32 code is required for ppb
> +  //
> +  PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
> +
> +  GetResourcePaddingPpb (PciIoDevice);
> +
> +  DEBUG_CODE (
> +    DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);
> +    DumpPciBars (PciIoDevice);
> +  );
> +
> +  return PciIoDevice;
> +}
> +
> +
> +/**
> +  Create PCI device instance for PCI Card bridge device.
> +
> +  @param Bridge   Parent bridge instance.
> +  @param Pci      Input PCI device information block.
> +  @param Bus      PCI device Bus NO.
> +  @param Device   PCI device Device NO.
> +  @param Func     PCI device's func NO.
> +
> +  @return  Created PCI device instance.
> +
> +**/
> +PCI_IO_DEVICE *
> +GatherP2CInfo (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  )
> +{
> +  PCI_IO_DEVICE                   *PciIoDevice;
> +
> +  PciIoDevice = CreatePciIoDevice (
> +                  Bridge,
> +                  Pci,
> +                  Bus,
> +                  Device,
> +                  Func
> +                  );
> +
> +  if (PciIoDevice == NULL) {
> +    return NULL;
> +  }
> +
> +  if (gFullEnumeration) {
> +    PCI_DISABLE_COMMAND_REGISTER (PciIoDevice,
> EFI_PCI_COMMAND_BITS_OWNED);
> +
> +    //
> +    // Initialize the bridge control register
> +    //
> +    PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice,
> EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
> +  }
> +
> +  //
> +  // P2C only has one bar that is in 0x10
> +  //
> +  PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
> +
> +  //
> +  // Read PciBar information from the bar register
> +  //
> +  GetBackPcCardBar (PciIoDevice);
> +  PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED  |
> +                         EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
> +                         EFI_BRIDGE_IO32_DECODE_SUPPORTED;
> +
> +  DEBUG_CODE (DumpPciBars (PciIoDevice););
> +
> +  return PciIoDevice;
> +}
> +
> +/**
> +  Create device path for pci device.
> +
> +  @param ParentDevicePath  Parent bridge's path.
> +  @param PciIoDevice       Pci device instance.
> +
> +  @return Device path protocol instance for specific pci device.
> +
> +**/
> +EFI_DEVICE_PATH_PROTOCOL *
> +CreatePciDevicePath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
> +  IN  PCI_IO_DEVICE            *PciIoDevice
> +  )
> +{
> +
> +  PCI_DEVICE_PATH PciNode;
> +
> +  //
> +  // Create PCI device path
> +  //
> +  PciNode.Header.Type     = HARDWARE_DEVICE_PATH;
> +  PciNode.Header.SubType  = HW_PCI_DP;
> +  SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
> +
> +  PciNode.Device          = PciIoDevice->DeviceNumber;
> +  PciNode.Function        = PciIoDevice->FunctionNumber;
> +  PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath,
> &PciNode.Header);
> +
> +  return PciIoDevice->DevicePath;
> +}
> +
> +/**
> +  Check whether the PCI IOV VF bar is existed or not.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param Offset            The offset.
> +  @param BarLengthValue    The bar length value returned.
> +  @param OriginalBarValue  The original bar value returned.
> +
> +  @retval EFI_NOT_FOUND    The bar doesn't exist.
> +  @retval EFI_SUCCESS      The bar exist.
> +
> +**/
> +EFI_STATUS
> +VfBarExisted (
> +  IN PCI_IO_DEVICE *PciIoDevice,
> +  IN UINTN         Offset,
> +  OUT UINT32       *BarLengthValue,
> +  OUT UINT32       *OriginalBarValue
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT32              OriginalValue;
> +  UINT32              Value;
> +  EFI_TPL             OldTpl;
> +
> +  //
> +  // Ensure it is called properly
> +  //
> +  ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
> +  if (PciIoDevice->SrIovCapabilityOffset == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  PciIo = &PciIoDevice->PciIo;
> +
> +  //
> +  // Preserve the original value
> +  //
> +
> +  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1,
> &OriginalValue);
> +
> +  //
> +  // Raise TPL to high level to disable timer interrupt while the BAR is probed
> +  //
> +  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);
> +  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);
> +
> +  //
> +  // Write back the original value
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1,
> &OriginalValue);
> +
> +  //
> +  // Restore TPL to its original level
> +  //
> +  gBS->RestoreTPL (OldTpl);
> +
> +  if (BarLengthValue != NULL) {
> +    *BarLengthValue = Value;
> +  }
> +
> +  if (OriginalBarValue != NULL) {
> +    *OriginalBarValue = OriginalValue;
> +  }
> +
> +  if (Value == 0) {
> +    return EFI_NOT_FOUND;
> +  } else {
> +    return EFI_SUCCESS;
> +  }
> +}
> +
> +/**
> +  Check whether the bar is existed or not.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param Offset            The offset.
> +  @param BarLengthValue    The bar length value returned.
> +  @param OriginalBarValue  The original bar value returned.
> +
> +  @retval EFI_NOT_FOUND    The bar doesn't exist.
> +  @retval EFI_SUCCESS      The bar exist.
> +
> +**/
> +EFI_STATUS
> +BarExisted (
> +  IN  PCI_IO_DEVICE *PciIoDevice,
> +  IN  UINTN         Offset,
> +  OUT UINT32        *BarLengthValue,
> +  OUT UINT32        *OriginalBarValue
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT32              OriginalValue;
> +  UINT32              Value;
> +  EFI_TPL             OldTpl;
> +
> +  PciIo = &PciIoDevice->PciIo;
> +
> +  //
> +  // Preserve the original value
> +  //
> +  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1,
> &OriginalValue);
> +
> +  //
> +  // Raise TPL to high level to disable timer interrupt while the BAR is probed
> +  //
> +  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
> +  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);
> +
> +  //
> +  // Write back the original value
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1,
> &OriginalValue);
> +
> +  //
> +  // Restore TPL to its original level
> +  //
> +  gBS->RestoreTPL (OldTpl);
> +
> +  if (BarLengthValue != NULL) {
> +    *BarLengthValue = Value;
> +  }
> +
> +  if (OriginalBarValue != NULL) {
> +    *OriginalBarValue = OriginalValue;
> +  }
> +
> +  if (Value == 0) {
> +    return EFI_NOT_FOUND;
> +  } else {
> +    return EFI_SUCCESS;
> +  }
> +}
> +
> +/**
> +  Test whether the device can support given attributes.
> +
> +  @param PciIoDevice      Pci device instance.
> +  @param Command          Input command register value, and
> +                          returned supported register value.
> +  @param BridgeControl    Input bridge control value for PPB or P2C, and
> +                          returned supported bridge control value.
> +  @param OldCommand       Returned and stored old command register
> offset.
> +  @param OldBridgeControl Returned and stored old Bridge control value
> for PPB or P2C.
> +
> +**/
> +VOID
> +PciTestSupportedAttribute (
> +  IN     PCI_IO_DEVICE                      *PciIoDevice,
> +  IN OUT UINT16                             *Command,
> +  IN OUT UINT16                             *BridgeControl,
> +     OUT UINT16                             *OldCommand,
> +     OUT UINT16                             *OldBridgeControl
> +  )
> +{
> +  EFI_TPL OldTpl;
> +
> +  //
> +  // Preserve the original value
> +  //
> +  PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
> +
> +  //
> +  // Raise TPL to high level to disable timer interrupt while the BAR is probed
> +  //
> +  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> +
> +  PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
> +  PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
> +
> +  //
> +  // Write back the original value
> +  //
> +  PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
> +
> +  //
> +  // Restore TPL to its original level
> +  //
> +  gBS->RestoreTPL (OldTpl);
> +
> +  if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE
> (&PciIoDevice->Pci)) {
> +
> +    //
> +    // Preserve the original value
> +    //
> +    PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
> +
> +    //
> +    // Raise TPL to high level to disable timer interrupt while the BAR is
> probed
> +    //
> +    OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> +
> +    PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
> +    PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
> +
> +    //
> +    // Write back the original value
> +    //
> +    PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
> +
> +    //
> +    // Restore TPL to its original level
> +    //
> +    gBS->RestoreTPL (OldTpl);
> +
> +  } else {
> +    *OldBridgeControl = 0;
> +    *BridgeControl    = 0;
> +  }
> +}
> +
> +/**
> +  Set the supported or current attributes of a PCI device.
> +
> +  @param PciIoDevice    Structure pointer for PCI device.
> +  @param Command        Command register value.
> +  @param BridgeControl  Bridge control value for PPB or P2C.
> +  @param Option         Make a choice of EFI_SET_SUPPORTS or
> EFI_SET_ATTRIBUTES.
> +
> +**/
> +VOID
> +PciSetDeviceAttribute (
> +  IN PCI_IO_DEVICE                      *PciIoDevice,
> +  IN UINT16                             Command,
> +  IN UINT16                             BridgeControl,
> +  IN UINTN                              Option
> +  )
> +{
> +  UINT64  Attributes;
> +
> +  Attributes = 0;
> +
> +  if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
> +  }
> +
> +  if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
> +  }
> +
> +  if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
> +  }
> +
> +  if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
> +  }
> +
> +  if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
> +  }
> +
> +  if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
> +  }
> +
> +  if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
> +    Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
> +  }
> +
> +  if (Option == EFI_SET_SUPPORTS) {
> +
> +    Attributes |= (UINT64)
> (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
> +                  EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED        |
> +                  EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE       |
> +                  EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE      |
> +                  EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM         |
> +                  EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
> +
> +    if (IS_PCI_LPC (&PciIoDevice->Pci)) {
> +        Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
> +        Attributes |= (mReserveIsaAliases ? (UINT64)
> EFI_PCI_IO_ATTRIBUTE_ISA_IO : \
> +                                            (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
> +    }
> +
> +    if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE
> (&PciIoDevice->Pci)) {
> +      //
> +      // For bridge, it should support IDE attributes
> +      //
> +      Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
> +      Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
> +
> +      if (mReserveVgaAliases) {
> +        Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \
> +                                EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);
> +      } else {
> +        Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \
> +                                EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
> +      }
> +    } else {
> +
> +      if (IS_PCI_IDE (&PciIoDevice->Pci)) {
> +        Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
> +        Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
> +      }
> +
> +      if (IS_PCI_VGA (&PciIoDevice->Pci)) {
> +        Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
> +        Attributes |= (mReserveVgaAliases ? (UINT64)
> EFI_PCI_IO_ATTRIBUTE_VGA_IO : \
> +                                            (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
> +      }
> +    }
> +
> +    PciIoDevice->Supports = Attributes;
> +    PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
> +                               EFI_PCI_IO_ATTRIBUTE_IO |
> EFI_PCI_IO_ATTRIBUTE_MEMORY | \
> +                               EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
> +
> +  } else {
> +    //
> +    // When this attribute is clear, the RomImage and RomSize fields in the
> PCI IO were
> +    // initialized based on the PCI option ROM found through the ROM BAR of
> the PCI controller.
> +    // When this attribute is set, the PCI option ROM described by the
> RomImage and RomSize
> +    // fields is not from the the ROM BAR of the PCI controller.
> +    //
> +    if (!PciIoDevice->EmbeddedRom) {
> +      Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;
> +    }
> +    PciIoDevice->Attributes = Attributes;
> +  }
> +}
> +
> +/**
> +  Determine if the device can support Fast Back to Back attribute.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param StatusIndex  Status register value.
> +
> +  @retval EFI_SUCCESS       This device support Fast Back to Back attribute.
> +  @retval EFI_UNSUPPORTED   This device doesn't support Fast Back to Back
> attribute.
> +
> +**/
> +EFI_STATUS
> +GetFastBackToBackSupport (
> +  IN PCI_IO_DEVICE                      *PciIoDevice,
> +  IN UINT8                              StatusIndex
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  EFI_STATUS          Status;
> +  UINT32              StatusRegister;
> +
> +  //
> +  // Read the status register
> +  //
> +  PciIo   = &PciIoDevice->PciIo;
> +  Status  = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1,
> &StatusRegister);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Check the Fast B2B bit
> +  //
> +  if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
> +    return EFI_SUCCESS;
> +  } else {
> +    return EFI_UNSUPPORTED;
> +  }
> +}
> +
> +/**
> +  Process the option ROM for all the children of the specified parent PCI
> device.
> +  It can only be used after the first full Option ROM process.
> +
> +  @param PciIoDevice Pci device instance.
> +
> +**/
> +VOID
> +ProcessOptionRomLight (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  )
> +{
> +  PCI_IO_DEVICE   *Temp;
> +  LIST_ENTRY      *CurrentLink;
> +
> +  //
> +  // For RootBridge, PPB , P2C, go recursively to traverse all its children
> +  //
> +  CurrentLink = PciIoDevice->ChildList.ForwardLink;
> +  while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
> +
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +      ProcessOptionRomLight (Temp);
> +    }
> +
> +    Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp);
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +}
> +
> +/**
> +  Determine the related attributes of all devices under a Root Bridge.
> +
> +  @param PciIoDevice   PCI device instance.
> +
> +**/
> +EFI_STATUS
> +DetermineDeviceAttribute (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  )
> +{
> +  UINT16          Command;
> +  UINT16          BridgeControl;
> +  UINT16          OldCommand;
> +  UINT16          OldBridgeControl;
> +  BOOLEAN         FastB2BSupport;
> +  PCI_IO_DEVICE   *Temp;
> +  LIST_ENTRY      *CurrentLink;
> +  EFI_STATUS      Status;
> +
> +  //
> +  // For Root Bridge, just copy it by RootBridgeIo protocol
> +  // so as to keep consistent with the actual attribute
> +  //
> +  if (PciIoDevice->Parent == NULL) {
> +    Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
> +                                            PciIoDevice->PciRootBridgeIo,
> +                                            &PciIoDevice->Supports,
> +                                            &PciIoDevice->Attributes
> +                                            );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +    //
> +    // Assume the PCI Root Bridge supports DAC
> +    //
> +    PciIoDevice->Supports |=
> (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
> +                              EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
> +                              EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
> +
> +  } else {
> +
> +    //
> +    // Set the attributes to be checked for common PCI devices and PPB or
> P2C
> +    // Since some devices only support part of them, it is better to set the
> +    // attribute according to its command or bridge control register
> +    //
> +    Command = EFI_PCI_COMMAND_IO_SPACE     |
> +              EFI_PCI_COMMAND_MEMORY_SPACE |
> +              EFI_PCI_COMMAND_BUS_MASTER   |
> +              EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
> +
> +    BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA |
> EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
> +
> +    //
> +    // Test whether the device can support attributes above
> +    //
> +    PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl,
> &OldCommand, &OldBridgeControl);
> +
> +    //
> +    // Set the supported attributes for specified PCI device
> +    //
> +    PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl,
> EFI_SET_SUPPORTS);
> +
> +    //
> +    // Set the current attributes for specified PCI device
> +    //
> +    PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl,
> EFI_SET_ATTRIBUTES);
> +
> +    //
> +    // Enable other PCI supported attributes but not defined in
> PCI_IO_PROTOCOL
> +    // For PCI Express devices, Memory Write and Invalidate is hardwired to
> 0b so only enable it for PCI devices.
> +    if (!PciIoDevice->IsPciExp) {
> +      PCI_ENABLE_COMMAND_REGISTER (PciIoDevice,
> EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
> +    }
> +  }
> +
> +  FastB2BSupport = TRUE;
> +
> +  //
> +  // P2C can not support FB2B on the secondary side
> +  //
> +  if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
> +    FastB2BSupport = FALSE;
> +  }
> +
> +  //
> +  // For RootBridge, PPB , P2C, go recursively to traverse all its children
> +  //
> +  CurrentLink = PciIoDevice->ChildList.ForwardLink;
> +  while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
> +
> +    Temp    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +    Status  = DetermineDeviceAttribute (Temp);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +    //
> +    // Detect Fast Back to Back support for the device under the bridge
> +    //
> +    Status = GetFastBackToBackSupport (Temp,
> PCI_PRIMARY_STATUS_OFFSET);
> +    if (FastB2BSupport && EFI_ERROR (Status)) {
> +      FastB2BSupport = FALSE;
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +  //
> +  // Set or clear Fast Back to Back bit for the whole bridge
> +  //
> +  if (!IsListEmpty (&PciIoDevice->ChildList)) {
> +
> +    if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +
> +      Status = GetFastBackToBackSupport (PciIoDevice,
> PCI_BRIDGE_STATUS_REGISTER_OFFSET);
> +
> +      if (EFI_ERROR (Status) || (!FastB2BSupport)) {
> +        FastB2BSupport = FALSE;
> +        PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice,
> EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
> +      } else {
> +        PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice,
> EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
> +      }
> +    }
> +
> +    CurrentLink = PciIoDevice->ChildList.ForwardLink;
> +    while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
> +      Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +      if (FastB2BSupport) {
> +        PCI_ENABLE_COMMAND_REGISTER (Temp,
> EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
> +      } else {
> +        PCI_DISABLE_COMMAND_REGISTER (Temp,
> EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
> +      }
> +
> +      CurrentLink = CurrentLink->ForwardLink;
> +    }
> +  }
> +  //
> +  // End for IsListEmpty
> +  //
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This routine is used to update the bar information for those incompatible
> PCI device.
> +
> +  @param PciIoDevice      Input Pci device instance. Output Pci device
> instance with updated
> +                          Bar information.
> +
> +  @retval EFI_SUCCESS     Successfully updated bar information.
> +  @retval EFI_UNSUPPORTED Given PCI device doesn't belong to
> incompatible PCI device list.
> +
> +**/
> +EFI_STATUS
> +UpdatePciInfo (
> +  IN OUT PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             BarIndex;
> +  BOOLEAN                           SetFlag;
> +  VOID                              *Configuration;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
> +
> +  Configuration = NULL;
> +  Status        = EFI_SUCCESS;
> +
> +  if (gIncompatiblePciDeviceSupport == NULL) {
> +    //
> +    // It can only be supported after the Incompatible PCI Device
> +    // Support Protocol has been installed
> +    //
> +    Status = gBS->LocateProtocol (
> +                    &gEfiIncompatiblePciDeviceSupportProtocolGuid,
> +                    NULL,
> +                    (VOID **) &gIncompatiblePciDeviceSupport
> +                    );
> +  }
> +  if (Status == EFI_SUCCESS) {
> +      //
> +      // Check whether the device belongs to incompatible devices from
> protocol or not
> +      // If it is , then get its special requirement in the ACPI table
> +      //
> +      Status = gIncompatiblePciDeviceSupport->CheckDevice (
> +                                                gIncompatiblePciDeviceSupport,
> +                                                PciIoDevice->Pci.Hdr.VendorId,
> +                                                PciIoDevice->Pci.Hdr.DeviceId,
> +                                                PciIoDevice->Pci.Hdr.RevisionID,
> +                                                PciIoDevice->Pci.Device.SubsystemVendorID,
> +                                                PciIoDevice->Pci.Device.SubsystemID,
> +                                                &Configuration
> +                                                );
> +
> +  }
> +
> +  if (EFI_ERROR (Status) || Configuration == NULL ) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Update PCI device information from the ACPI table
> +  //
> +  Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
> +
> +  while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
> +
> +    if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> +      //
> +      // The format is not support
> +      //
> +      break;
> +    }
> +
> +    for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
> +      if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&
> +          (Ptr->AddrTranslationOffset != MAX_UINT8) &&
> +          (Ptr->AddrTranslationOffset != BarIndex)
> +          ) {
> +        //
> +        // Skip updating when AddrTranslationOffset is not MAX_UINT64 or
> MAX_UINT8 (wide match).
> +        // Skip updating when current BarIndex doesn't equal to
> AddrTranslationOffset.
> +        // Comparing against MAX_UINT8 is to keep backward compatibility.
> +        //
> +        continue;
> +      }
> +
> +      SetFlag = FALSE;
> +      switch (Ptr->ResType) {
> +      case ACPI_ADDRESS_SPACE_TYPE_MEM:
> +
> +        //
> +        // Make sure the bar is memory type
> +        //
> +        if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
> +          SetFlag = TRUE;
> +
> +          //
> +          // Ignored if granularity is 0.
> +          // Ignored if PCI BAR is I/O or 32-bit memory.
> +          // If PCI BAR is 64-bit memory and granularity is 32, then
> +          // the PCI BAR resource is allocated below 4GB.
> +          // If PCI BAR is 64-bit memory and granularity is 64, then
> +          // the PCI BAR resource is allocated above 4GB.
> +          //
> +          if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {
> +            switch (Ptr->AddrSpaceGranularity) {
> +            case 32:
> +              PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
> +            case 64:
> +              PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
> +              break;
> +            default:
> +              break;
> +            }
> +          }
> +
> +          if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {
> +            switch (Ptr->AddrSpaceGranularity) {
> +            case 32:
> +              PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
> +            case 64:
> +              PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
> +              break;
> +            default:
> +              break;
> +            }
> +          }
> +        }
> +        break;
> +
> +      case ACPI_ADDRESS_SPACE_TYPE_IO:
> +
> +        //
> +        // Make sure the bar is IO type
> +        //
> +        if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
> +          SetFlag = TRUE;
> +        }
> +        break;
> +      }
> +
> +      if (SetFlag) {
> +
> +        //
> +        // Update the new alignment for the device
> +        //
> +        SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr-
> >AddrRangeMax);
> +
> +        //
> +        // Update the new length for the device
> +        //
> +        if (Ptr->AddrLen != 0) {
> +          PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
> +        }
> +      }
> +    }
> +
> +    Ptr++;
> +  }
> +
> +  FreePool (Configuration);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This routine will update the alignment with the new alignment.
> +  Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN
> is to keep
> +  backward compatibility.
> +
> +  @param Alignment    Input Old alignment. Output updated alignment.
> +  @param NewAlignment New alignment.
> +
> +**/
> +VOID
> +SetNewAlign (
> +  IN OUT UINT64     *Alignment,
> +  IN     UINT64     NewAlignment
> +  )
> +{
> +  UINT64  OldAlignment;
> +  UINTN   ShiftBit;
> +
> +  //
> +  // The new alignment is the same as the original,
> +  // so skip it
> +  //
> +  if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {
> +    return ;
> +  }
> +  //
> +  // Check the validity of the parameter
> +  //
> +   if (NewAlignment != EVEN_ALIGN  &&
> +       NewAlignment != SQUAD_ALIGN &&
> +       NewAlignment != DQUAD_ALIGN ) {
> +    *Alignment = NewAlignment;
> +    return ;
> +  }
> +
> +  OldAlignment  = (*Alignment) + 1;
> +  ShiftBit      = 0;
> +
> +  //
> +  // Get the first non-zero hex value of the length
> +  //
> +  while ((OldAlignment & 0x0F) == 0x00) {
> +    OldAlignment = RShiftU64 (OldAlignment, 4);
> +    ShiftBit += 4;
> +  }
> +
> +  //
> +  // Adjust the alignment to even, quad or double quad boundary
> +  //
> +  if (NewAlignment == EVEN_ALIGN) {
> +    if ((OldAlignment & 0x01) != 0) {
> +      OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
> +    }
> +  } else if (NewAlignment == SQUAD_ALIGN) {
> +    if ((OldAlignment & 0x03) != 0) {
> +      OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
> +    }
> +  } else if (NewAlignment == DQUAD_ALIGN) {
> +    if ((OldAlignment & 0x07) != 0) {
> +      OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
> +    }
> +  }
> +
> +  //
> +  // Update the old value
> +  //
> +  NewAlignment  = LShiftU64 (OldAlignment, ShiftBit) - 1;
> +  *Alignment    = NewAlignment;
> +
> +  return ;
> +}
> +
> +/**
> +  Parse PCI IOV VF bar information and fill them into PCI device instance.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Offset       Bar offset.
> +  @param BarIndex     Bar index.
> +
> +  @return Next bar offset.
> +
> +**/
> +UINTN
> +PciIovParseVfBar (
> +  IN PCI_IO_DEVICE  *PciIoDevice,
> +  IN UINTN          Offset,
> +  IN UINTN          BarIndex
> +  )
> +{
> +  UINT32      Value;
> +  UINT32      OriginalValue;
> +  UINT32      Mask;
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Ensure it is called properly
> +  //
> +  ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
> +  if (PciIoDevice->SrIovCapabilityOffset == 0) {
> +    return 0;
> +  }
> +
> +  OriginalValue = 0;
> +  Value         = 0;
> +
> +  Status = VfBarExisted (
> +            PciIoDevice,
> +            Offset,
> +            &Value,
> +            &OriginalValue
> +            );
> +
> +  if (EFI_ERROR (Status)) {
> +    PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
> +    PciIoDevice->VfPciBar[BarIndex].Length      = 0;
> +    PciIoDevice->VfPciBar[BarIndex].Alignment   = 0;
> +
> +    //
> +    // Scan all the BARs anyway
> +    //
> +    PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
> +    return Offset + 4;
> +  }
> +
> +  PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
> +  if ((Value & 0x01) != 0) {
> +    //
> +    // Device I/Os. Impossible
> +    //
> +    ASSERT (FALSE);
> +    return Offset + 4;
> +
> +  } else {
> +
> +    Mask  = 0xfffffff0;
> +
> +    PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
> +
> +    switch (Value & 0x07) {
> +
> +    //
> +    //memory space; anywhere in 32 bit address space
> +    //
> +    case 0x00:
> +      if ((Value & 0x08) != 0) {
> +        PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
> +      } else {
> +        PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
> +      }
> +
> +      PciIoDevice->VfPciBar[BarIndex].Length    = (~(Value & Mask)) + 1;
> +      PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >VfPciBar[BarIndex].Length - 1;
> +
> +      //
> +      // Adjust Length
> +      //
> +      PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice-
> >VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
> +      //
> +      // Adjust Alignment
> +      //
> +      if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice-
> >SystemPageSize - 1) {
> +        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >SystemPageSize - 1;
> +      }
> +
> +      break;
> +
> +    //
> +    // memory space; anywhere in 64 bit address space
> +    //
> +    case 0x04:
> +      if ((Value & 0x08) != 0) {
> +        PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
> +      } else {
> +        PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
> +      }
> +
> +      //
> +      // According to PCI 2.2,if the bar indicates a memory 64 decoding, next
> bar
> +      // is regarded as an extension for the first bar. As a result
> +      // the sizing will be conducted on combined 64 bit value
> +      // Here just store the masked first 32bit value for future size
> +      // calculation
> +      //
> +      PciIoDevice->VfPciBar[BarIndex].Length    = Value & Mask;
> +      PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >VfPciBar[BarIndex].Length - 1;
> +
> +      if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice-
> >SystemPageSize - 1) {
> +        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >SystemPageSize - 1;
> +      }
> +
> +      //
> +      // Increment the offset to point to next DWORD
> +      //
> +      Offset += 4;
> +
> +      Status = VfBarExisted (
> +                PciIoDevice,
> +                Offset,
> +                &Value,
> +                &OriginalValue
> +                );
> +
> +      if (EFI_ERROR (Status)) {
> +        PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
> +        return Offset + 4;
> +      }
> +
> +      //
> +      // Fix the length to support some special 64 bit BAR
> +      //
> +      Value |= ((UINT32) -1 << HighBitSet32 (Value));
> +
> +      //
> +      // Calculate the size of 64bit bar
> +      //
> +      PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)
> OriginalValue, 32);
> +
> +      PciIoDevice->VfPciBar[BarIndex].Length    = PciIoDevice-
> >VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
> +      PciIoDevice->VfPciBar[BarIndex].Length    = (~(PciIoDevice-
> >VfPciBar[BarIndex].Length)) + 1;
> +      PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >VfPciBar[BarIndex].Length - 1;
> +
> +      //
> +      // Adjust Length
> +      //
> +      PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice-
> >VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
> +      //
> +      // Adjust Alignment
> +      //
> +      if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice-
> >SystemPageSize - 1) {
> +        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >SystemPageSize - 1;
> +      }
> +
> +      break;
> +
> +    //
> +    // reserved
> +    //
> +    default:
> +      PciIoDevice->VfPciBar[BarIndex].BarType   = PciBarTypeUnknown;
> +      PciIoDevice->VfPciBar[BarIndex].Length    = (~(Value & Mask)) + 1;
> +      PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >VfPciBar[BarIndex].Length - 1;
> +
> +      if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice-
> >SystemPageSize - 1) {
> +        PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice-
> >SystemPageSize - 1;
> +      }
> +
> +      break;
> +    }
> +  }
> +
> +  //
> +  // Check the length again so as to keep compatible with some special bars
> +  //
> +  if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
> +    PciIoDevice->VfPciBar[BarIndex].BarType     = PciBarTypeUnknown;
> +    PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
> +    PciIoDevice->VfPciBar[BarIndex].Alignment   = 0;
> +  }
> +
> +  //
> +  // Increment number of bar
> +  //
> +  return Offset + 4;
> +}
> +
> +/**
> +  Parse PCI bar information and fill them into PCI device instance.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Offset       Bar offset.
> +  @param BarIndex     Bar index.
> +
> +  @return Next bar offset.
> +
> +**/
> +UINTN
> +PciParseBar (
> +  IN PCI_IO_DEVICE  *PciIoDevice,
> +  IN UINTN          Offset,
> +  IN UINTN          BarIndex
> +  )
> +{
> +  UINT32      Value;
> +  UINT32      OriginalValue;
> +  UINT32      Mask;
> +  EFI_STATUS  Status;
> +
> +  OriginalValue = 0;
> +  Value         = 0;
> +
> +  Status = BarExisted (
> +             PciIoDevice,
> +             Offset,
> +             &Value,
> +             &OriginalValue
> +             );
> +
> +  if (EFI_ERROR (Status)) {
> +    PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
> +    PciIoDevice->PciBar[BarIndex].Length      = 0;
> +    PciIoDevice->PciBar[BarIndex].Alignment   = 0;
> +
> +    //
> +    // Some devices don't fully comply to PCI spec 2.2. So be to scan all the
> BARs anyway
> +    //
> +    PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
> +    return Offset + 4;
> +  }
> +
> +  PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;
> +  PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
> +  if ((Value & 0x01) != 0) {
> +    //
> +    // Device I/Os
> +    //
> +    Mask = 0xfffffffc;
> +
> +    if ((Value & 0xFFFF0000) != 0) {
> +      //
> +      // It is a IO32 bar
> +      //
> +      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo32;
> +      PciIoDevice->PciBar[BarIndex].Length    = ((~(Value & Mask)) + 1);
> +      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice-
> >PciBar[BarIndex].Length - 1;
> +
> +    } else {
> +      //
> +      // It is a IO16 bar
> +      //
> +      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo16;
> +      PciIoDevice->PciBar[BarIndex].Length    = 0x0000FFFF & ((~(Value &
> Mask)) + 1);
> +      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice-
> >PciBar[BarIndex].Length - 1;
> +
> +    }
> +    //
> +    // Workaround. Some platforms implement IO bar with 0 length
> +    // Need to treat it as no-bar
> +    //
> +    if (PciIoDevice->PciBar[BarIndex].Length == 0) {
> +      PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
> +    }
> +
> +    PciIoDevice->PciBar[BarIndex].BaseAddress   = OriginalValue & Mask;
> +
> +  } else {
> +
> +    Mask  = 0xfffffff0;
> +
> +    PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
> +
> +    switch (Value & 0x07) {
> +
> +    //
> +    //memory space; anywhere in 32 bit address space
> +    //
> +    case 0x00:
> +      if ((Value & 0x08) != 0) {
> +        PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
> +      } else {
> +        PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
> +      }
> +
> +      PciIoDevice->PciBar[BarIndex].Length    = (~(Value & Mask)) + 1;
> +      if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
> +        //
> +        // Force minimum 4KByte alignment for Virtualization technology for
> Directed I/O
> +        //
> +        PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
> +      } else {
> +        PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice-
> >PciBar[BarIndex].Length - 1;
> +      }
> +      break;
> +
> +    //
> +    // memory space; anywhere in 64 bit address space
> +    //
> +    case 0x04:
> +      if ((Value & 0x08) != 0) {
> +        PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
> +      } else {
> +        PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
> +      }
> +
> +      //
> +      // According to PCI 2.2,if the bar indicates a memory 64 decoding, next
> bar
> +      // is regarded as an extension for the first bar. As a result
> +      // the sizing will be conducted on combined 64 bit value
> +      // Here just store the masked first 32bit value for future size
> +      // calculation
> +      //
> +      PciIoDevice->PciBar[BarIndex].Length    = Value & Mask;
> +      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice-
> >PciBar[BarIndex].Length - 1;
> +
> +      //
> +      // Increment the offset to point to next DWORD
> +      //
> +      Offset += 4;
> +
> +      Status = BarExisted (
> +                 PciIoDevice,
> +                 Offset,
> +                 &Value,
> +                 &OriginalValue
> +                 );
> +
> +      if (EFI_ERROR (Status)) {
> +        //
> +        // the high 32 bit does not claim any BAR, we need to re-check the low
> 32 bit BAR again
> +        //
> +        if (PciIoDevice->PciBar[BarIndex].Length == 0) {
> +          //
> +          // some device implement MMIO bar with 0 length, need to treat it as
> no-bar
> +          //
> +          PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
> +          return Offset + 4;
> +        }
> +      }
> +
> +      //
> +      // Fix the length to support some special 64 bit BAR
> +      //
> +      if (Value == 0) {
> +        DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64
> BAR returns 0, change to 0xFFFFFFFF.\n"));
> +        Value = (UINT32) -1;
> +      } else {
> +        Value |= ((UINT32)(-1) << HighBitSet32 (Value));
> +      }
> +
> +      //
> +      // Calculate the size of 64bit bar
> +      //
> +      PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)
> OriginalValue, 32);
> +
> +      PciIoDevice->PciBar[BarIndex].Length    = PciIoDevice-
> >PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
> +      PciIoDevice->PciBar[BarIndex].Length    = (~(PciIoDevice-
> >PciBar[BarIndex].Length)) + 1;
> +      if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
> +        //
> +        // Force minimum 4KByte alignment for Virtualization technology for
> Directed I/O
> +        //
> +        PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
> +      } else {
> +        PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice-
> >PciBar[BarIndex].Length - 1;
> +      }
> +
> +      break;
> +
> +    //
> +    // reserved
> +    //
> +    default:
> +      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeUnknown;
> +      PciIoDevice->PciBar[BarIndex].Length    = (~(Value & Mask)) + 1;
> +      if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
> +        //
> +        // Force minimum 4KByte alignment for Virtualization technology for
> Directed I/O
> +        //
> +        PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
> +      } else {
> +        PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice-
> >PciBar[BarIndex].Length - 1;
> +      }
> +      break;
> +    }
> +  }
> +
> +  //
> +  // Check the length again so as to keep compatible with some special bars
> +  //
> +  if (PciIoDevice->PciBar[BarIndex].Length == 0) {
> +    PciIoDevice->PciBar[BarIndex].BarType     = PciBarTypeUnknown;
> +    PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
> +    PciIoDevice->PciBar[BarIndex].Alignment   = 0;
> +  }
> +
> +  //
> +  // Increment number of bar
> +  //
> +  return Offset + 4;
> +}
> +
> +/**
> +  This routine is used to initialize the bar of a PCI device.
> +
> +  @param PciIoDevice Pci device instance.
> +
> +  @note It can be called typically when a device is going to be rejected.
> +
> +**/
> +VOID
> +InitializePciDevice (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT8               Offset;
> +
> +  PciIo = &(PciIoDevice->PciIo);
> +
> +  //
> +  // Put all the resource apertures
> +  // Resource base is set to all ones so as to indicate its resource
> +  // has not been allocated
> +  //
> +  for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
> +    PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
> +  }
> +}
> +
> +/**
> +  This routine is used to initialize the bar of a PCI-PCI Bridge device.
> +
> +  @param  PciIoDevice PCI-PCI bridge device instance.
> +
> +**/
> +VOID
> +InitializePpb (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +
> +  PciIo = &(PciIoDevice->PciIo);
> +
> +  //
> +  // Put all the resource apertures including IO16
> +  // Io32, pMem32, pMem64 to quiescent state
> +  // Resource base all ones, Resource limit all zeros
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
> +
> +  //
> +  // Don't support use io32 as for now
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
> +
> +  //
> +  // Force Interrupt line to zero for cards that come up randomly
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
> +}
> +
> +/**
> +  This routine is used to initialize the bar of a PCI Card Bridge device.
> +
> +  @param PciIoDevice  PCI Card bridge device.
> +
> +**/
> +VOID
> +InitializeP2C (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +
> +  PciIo = &(PciIoDevice->PciIo);
> +
> +  //
> +  // Put all the resource apertures including IO16
> +  // Io32, pMem32, pMem64 to quiescent state(
> +  // Resource base all ones, Resource limit all zeros
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
> +
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
> +
> +  //
> +  // Force Interrupt line to zero for cards that come up randomly
> +  //
> +  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
> +}
> +
> +/**
> +  Authenticate the PCI device by using DeviceSecurityProtocol.
> +
> +  @param PciIoDevice  PCI device.
> +
> +  @retval EFI_SUCCESS     The device passes the authentication.
> +  @return not EFI_SUCCESS The device failes the authentication or
> +                          unexpected error happen during authentication.
> +**/
> +EFI_STATUS
> +AuthenticatePciDevice (
> +  IN PCI_IO_DEVICE            *PciIoDevice
> +  )
> +{
> +  EDKII_DEVICE_IDENTIFIER  DeviceIdentifier;
> +  EFI_STATUS               Status;
> +
> +  if (mDeviceSecurityProtocol != NULL) {
> +    //
> +    // Prepare the parameter
> +    //
> +    DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;
> +    CopyGuid (&DeviceIdentifier.DeviceType,
> &gEdkiiDeviceIdentifierTypePciGuid);
> +    DeviceIdentifier.DeviceHandle = NULL;
> +    Status = gBS->InstallMultipleProtocolInterfaces (
> +                    &DeviceIdentifier.DeviceHandle,
> +                    &gEfiDevicePathProtocolGuid,
> +                    PciIoDevice->DevicePath,
> +                    &gEdkiiDeviceIdentifierTypePciGuid,
> +                    &PciIoDevice->PciIo,
> +                    NULL
> +                    );
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +
> +    //
> +    // Do DeviceAuthentication
> +    //
> +    Status = mDeviceSecurityProtocol->DeviceAuthenticate
> (mDeviceSecurityProtocol, &DeviceIdentifier);
> +    //
> +    // Always uninstall, because they are only for Authentication.
> +    // No need to check return Status.
> +    //
> +    gBS->UninstallMultipleProtocolInterfaces (
> +                    DeviceIdentifier.DeviceHandle,
> +                    &gEfiDevicePathProtocolGuid,
> +                    PciIoDevice->DevicePath,
> +                    &gEdkiiDeviceIdentifierTypePciGuid,
> +                    &PciIoDevice->PciIo,
> +                    NULL
> +                    );
> +    return Status;
> +  }
> +
> +  //
> +  // Device Security Protocol is not found, just return success
> +  //
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Create and initialize general PCI I/O device instance for
> +  PCI device/bridge device/hotplug bridge device.
> +
> +  @param Bridge            Parent bridge instance.
> +  @param Pci               Input Pci information block.
> +  @param Bus               Device Bus NO.
> +  @param Device            Device device NO.
> +  @param Func              Device func NO.
> +
> +  @return Instance of PCI device. NULL means no instance created.
> +
> +**/
> +PCI_IO_DEVICE *
> +CreatePciIoDevice (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  )
> +{
> +  PCI_IO_DEVICE        *PciIoDevice;
> +  EFI_PCI_IO_PROTOCOL  *PciIo;
> +  EFI_STATUS           Status;
> +
> +  PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
> +  if (PciIoDevice == NULL) {
> +    return NULL;
> +  }
> +
> +  PciIoDevice->Signature        = PCI_IO_DEVICE_SIGNATURE;
> +  PciIoDevice->Handle           = NULL;
> +  PciIoDevice->PciRootBridgeIo  = Bridge->PciRootBridgeIo;
> +  PciIoDevice->DevicePath       = NULL;
> +  PciIoDevice->BusNumber        = Bus;
> +  PciIoDevice->DeviceNumber     = Device;
> +  PciIoDevice->FunctionNumber   = Func;
> +  PciIoDevice->Decodes          = 0;
> +
> +  if (gFullEnumeration) {
> +    PciIoDevice->Allocated = FALSE;
> +  } else {
> +    PciIoDevice->Allocated = TRUE;
> +  }
> +
> +  PciIoDevice->Registered         = FALSE;
> +  PciIoDevice->Attributes         = 0;
> +  PciIoDevice->Supports           = 0;
> +  PciIoDevice->BusOverride        = FALSE;
> +  PciIoDevice->AllOpRomProcessed  = FALSE;
> +
> +  PciIoDevice->IsPciExp           = FALSE;
> +
> +  CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
> +
> +  //
> +  // Initialize the PCI I/O instance structure
> +  //
> +  InitializePciIoInstance (PciIoDevice);
> +  InitializePciDriverOverrideInstance (PciIoDevice);
> +  InitializePciLoadFile2 (PciIoDevice);
> +  PciIo = &PciIoDevice->PciIo;
> +
> +  //
> +  // Create a device path for this PCI device and store it into its private data
> +  //
> +  CreatePciDevicePath (
> +    Bridge->DevicePath,
> +    PciIoDevice
> +    );
> +
> +  //
> +  // Detect if PCI Express Device
> +  //
> +  PciIoDevice->PciExpressCapabilityOffset = 0;
> +  Status = LocateCapabilityRegBlock (
> +             PciIoDevice,
> +             EFI_PCI_CAPABILITY_ID_PCIEXP,
> +             &PciIoDevice->PciExpressCapabilityOffset,
> +             NULL
> +             );
> +  if (!EFI_ERROR (Status)) {
> +    PciIoDevice->IsPciExp = TRUE;
> +  }
> +
> +  //
> +  // Now we can do the authentication check for the device.
> +  //
> +  Status = AuthenticatePciDevice (PciIoDevice);
> +  //
> +  // If authentication fails, skip this device.
> +  //
> +  if (EFI_ERROR(Status)) {
> +    if (PciIoDevice->DevicePath != NULL) {
> +      FreePool (PciIoDevice->DevicePath);
> +    }
> +    FreePool (PciIoDevice);
> +    return NULL;
> +  }
> +
> +  if (PcdGetBool (PcdAriSupport)) {
> +    //
> +    // Check if the device is an ARI device.
> +    //
> +    Status = LocatePciExpressCapabilityRegBlock (
> +               PciIoDevice,
> +               EFI_PCIE_CAPABILITY_ID_ARI,
> +               &PciIoDevice->AriCapabilityOffset,
> +               NULL
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // We need to enable ARI feature before calculate BusReservation,
> +      // because FirstVFOffset and VFStride may change after that.
> +      //
> +      EFI_PCI_IO_PROTOCOL  *ParentPciIo;
> +      UINT32               Data32;
> +
> +      //
> +      // Check if its parent supports ARI forwarding.
> +      //
> +      ParentPciIo = &Bridge->PciIo;
> +      ParentPciIo->Pci.Read (
> +                          ParentPciIo,
> +                          EfiPciIoWidthUint32,
> +                          Bridge->PciExpressCapabilityOffset +
> EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
> +                          1,
> +                          &Data32
> +                          );
> +      if ((Data32 &
> EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
> +        //
> +        // ARI forward support in bridge, so enable it.
> +        //
> +        ParentPciIo->Pci.Read (
> +                            ParentPciIo,
> +                            EfiPciIoWidthUint32,
> +                            Bridge->PciExpressCapabilityOffset +
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
> +                            1,
> +                            &Data32
> +                            );
> +        if ((Data32 &
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
> +          Data32 |=
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
> +          ParentPciIo->Pci.Write (
> +                              ParentPciIo,
> +                              EfiPciIoWidthUint32,
> +                              Bridge->PciExpressCapabilityOffset +
> EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
> +                              1,
> +                              &Data32
> +                              );
> +          DEBUG ((
> +            EFI_D_INFO,
> +            " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
> +            Bridge->BusNumber,
> +            Bridge->DeviceNumber,
> +            Bridge->FunctionNumber
> +            ));
> +        }
> +      }
> +
> +      DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice-
> >AriCapabilityOffset));
> +    }
> +  }
> +
> +  //
> +  // Initialization for SR-IOV
> +  //
> +
> +  if (PcdGetBool (PcdSrIovSupport)) {
> +    Status = LocatePciExpressCapabilityRegBlock (
> +               PciIoDevice,
> +               EFI_PCIE_CAPABILITY_ID_SRIOV,
> +               &PciIoDevice->SrIovCapabilityOffset,
> +               NULL
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      UINT32    SupportedPageSize;
> +      UINT16    VFStride;
> +      UINT16    FirstVFOffset;
> +      UINT16    Data16;
> +      UINT32    PFRid;
> +      UINT32    LastVF;
> +
> +      //
> +      // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy
> for the device.
> +      //
> +      if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0)
> {
> +        PciIo->Pci.Read (
> +                     PciIo,
> +                     EfiPciIoWidthUint16,
> +                     PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
> +                     1,
> +                     &Data16
> +                     );
> +        Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
> +        PciIo->Pci.Write (
> +                     PciIo,
> +                     EfiPciIoWidthUint16,
> +                     PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
> +                     1,
> +                     &Data16
> +                     );
> +      }
> +
> +      //
> +      // Calculate SystemPageSize
> +      //
> +
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint32,
> +                   PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
> +                   1,
> +                   &SupportedPageSize
> +                   );
> +      PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) &
> SupportedPageSize);
> +      ASSERT (PciIoDevice->SystemPageSize != 0);
> +
> +      PciIo->Pci.Write (
> +                   PciIo,
> +                   EfiPciIoWidthUint32,
> +                   PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
> +                   1,
> +                   &PciIoDevice->SystemPageSize
> +                   );
> +      //
> +      // Adjust SystemPageSize for Alignment usage later
> +      //
> +      PciIoDevice->SystemPageSize <<= 12;
> +
> +      //
> +      // Calculate BusReservation for PCI IOV
> +      //
> +
> +      //
> +      // Read First FirstVFOffset, InitialVFs, and VFStride
> +      //
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
> +                   1,
> +                   &FirstVFOffset
> +                   );
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
> +                   1,
> +                   &PciIoDevice->InitialVFs
> +                   );
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PciIoDevice->SrIovCapabilityOffset +
> EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
> +                   1,
> +                   &VFStride
> +                   );
> +      //
> +      // Calculate LastVF
> +      //
> +      PFRid = EFI_PCI_RID(Bus, Device, Func);
> +      LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
> +
> +      //
> +      // Calculate ReservedBusNum for this PF
> +      //
> +      PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID
> (LastVF) - Bus + 1);
> +
> +      DEBUG ((
> +        EFI_D_INFO,
> +        " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x;
> FirstVFOffset = 0x%x;\n",
> +        SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset
> +        ));
> +      DEBUG ((
> +        EFI_D_INFO,
> +        "         InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
> +        PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice-
> >SrIovCapabilityOffset
> +        ));
> +    }
> +  }
> +
> +  if (PcdGetBool (PcdMrIovSupport)) {
> +    Status = LocatePciExpressCapabilityRegBlock (
> +               PciIoDevice,
> +               EFI_PCIE_CAPABILITY_ID_MRIOV,
> +               &PciIoDevice->MrIovCapabilityOffset,
> +               NULL
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice-
> >MrIovCapabilityOffset));
> +    }
> +  }
> +
> +  PciIoDevice->ResizableBarOffset = 0;
> +  if (PcdGetBool (PcdPcieResizableBarSupport)) {
> +    Status = LocatePciExpressCapabilityRegBlock (
> +               PciIoDevice,
> +               PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,
> +               &PciIoDevice->ResizableBarOffset,
> +               NULL
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL
> ResizableBarControl;
> +      UINT32                                                  Offset;
> +      Offset = PciIoDevice->ResizableBarOffset + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
> +                + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),
> +      PciIo->Pci.Read (
> +              PciIo,
> +              EfiPciIoWidthUint8,
> +              Offset,
> +              sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),
> +              &ResizableBarControl
> +              );
> +      PciIoDevice->ResizableBarNumber =
> ResizableBarControl.Bits.ResizableBarNumber;
> +      PciProgramResizableBar (PciIoDevice, PciResizableBarMax);
> +    }
> +  }
> +
> +  //
> +  // Initialize the reserved resource list
> +  //
> +  InitializeListHead (&PciIoDevice->ReservedResourceList);
> +
> +  //
> +  // Initialize the driver list
> +  //
> +  InitializeListHead (&PciIoDevice->OptionRomDriverList);
> +
> +  //
> +  // Initialize the child list
> +  //
> +  InitializeListHead (&PciIoDevice->ChildList);
> +
> +  return PciIoDevice;
> +}
> +
> +/**
> +  This routine is used to enumerate entire pci bus system
> +  in a given platform.
> +
> +  It is only called on the second start on the same Root Bridge.
> +
> +  @param  Controller     Parent bridge handler.
> +
> +  @retval EFI_SUCCESS    PCI enumeration finished successfully.
> +  @retval other          Some error occurred when enumerating the pci bus
> system.
> +
> +**/
> +EFI_STATUS
> +PciEnumeratorLight (
> +  IN EFI_HANDLE                    Controller
> +  )
> +{
> +
> +  EFI_STATUS                        Status;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;
> +  PCI_IO_DEVICE                     *RootBridgeDev;
> +  UINT16                            MinBus;
> +  UINT16                            MaxBus;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
> +
> +  MinBus      = 0;
> +  MaxBus      = PCI_MAX_BUS;
> +  Descriptors = NULL;
> +
> +  //
> +  // If this root bridge has been already enumerated, then return
> successfully
> +  //
> +  if (GetRootBridgeByHandle (Controller) != NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Open pci root bridge io protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  (VOID **) &PciRootBridgeIo,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
> +    return Status;
> +  }
> +
> +  Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)
> &Descriptors);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) ==
> EFI_SUCCESS) {
> +
> +    //
> +    // Create a device node for root bridge device with a NULL host bridge
> controller handle
> +    //
> +    RootBridgeDev = CreateRootBridge (Controller);
> +
> +    if (RootBridgeDev == NULL) {
> +      Descriptors++;
> +      continue;
> +    }
> +
> +    //
> +    // Record the root bridge-io protocol
> +    //
> +    RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
> +
> +    Status = PciPciDeviceInfoCollector (
> +               RootBridgeDev,
> +               (UINT8) MinBus
> +               );
> +
> +    if (!EFI_ERROR (Status)) {
> +
> +      //
> +      // Remove those PCI devices which are rejected when full enumeration
> +      //
> +      RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
> +
> +      //
> +      // Process option rom light
> +      //
> +      ProcessOptionRomLight (RootBridgeDev);
> +
> +      //
> +      // Determine attributes for all devices under this root bridge
> +      //
> +      DetermineDeviceAttribute (RootBridgeDev);
> +
> +      //
> +      // If successfully, insert the node into device pool
> +      //
> +      InsertRootBridge (RootBridgeDev);
> +    } else {
> +
> +      //
> +      // If unsuccessfully, destroy the entire node
> +      //
> +      DestroyRootBridge (RootBridgeDev);
> +    }
> +
> +    Descriptors++;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get bus range from PCI resource descriptor list.
> +
> +  @param Descriptors  A pointer to the address space descriptor.
> +  @param MinBus       The min bus returned.
> +  @param MaxBus       The max bus returned.
> +  @param BusRange     The bus range returned.
> +
> +  @retval EFI_SUCCESS    Successfully got bus range.
> +  @retval EFI_NOT_FOUND  Can not find the specific bus.
> +
> +**/
> +EFI_STATUS
> +PciGetBusRange (
> +  IN     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  **Descriptors,
> +  OUT    UINT16                             *MinBus,
> +  OUT    UINT16                             *MaxBus,
> +  OUT    UINT16                             *BusRange
> +  )
> +{
> +  while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
> +    if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
> +      if (MinBus != NULL) {
> +        *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
> +      }
> +
> +      if (MaxBus != NULL) {
> +        *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
> +      }
> +
> +      if (BusRange != NULL) {
> +        *BusRange = (UINT16) (*Descriptors)->AddrLen;
> +      }
> +
> +      return EFI_SUCCESS;
> +    }
> +
> +    (*Descriptors)++;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This routine can be used to start the root bridge.
> +
> +  @param RootBridgeDev     Pci device instance.
> +
> +  @retval EFI_SUCCESS      This device started.
> +  @retval other            Failed to get PCI Root Bridge I/O protocol.
> +
> +**/
> +EFI_STATUS
> +StartManagingRootBridge (
> +  IN PCI_IO_DEVICE *RootBridgeDev
> +  )
> +{
> +  EFI_HANDLE                      RootBridgeHandle;
> +  EFI_STATUS                      Status;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  //
> +  // Get the root bridge handle
> +  //
> +  RootBridgeHandle = RootBridgeDev->Handle;
> +  PciRootBridgeIo  = NULL;
> +
> +  //
> +  // Get the pci root bridge io protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +                  RootBridgeHandle,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  (VOID **) &PciRootBridgeIo,
> +                  gPciBusDriverBinding.DriverBindingHandle,
> +                  RootBridgeHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +
> +  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
> +    return Status;
> +  }
> +
> +  //
> +  // Store the PciRootBridgeIo protocol into root bridge private data
> +  //
> +  RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
> +
> +  return EFI_SUCCESS;
> +
> +}
> +
> +/**
> +  This routine can be used to check whether a PCI device should be rejected
> when light enumeration.
> +
> +  @param PciIoDevice  Pci device instance.
> +
> +  @retval TRUE      This device should be rejected.
> +  @retval FALSE     This device shouldn't be rejected.
> +
> +**/
> +BOOLEAN
> +IsPciDeviceRejected (
> +  IN PCI_IO_DEVICE *PciIoDevice
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT32      TestValue;
> +  UINT32      OldValue;
> +  UINT32      Mask;
> +  UINT8       BarOffset;
> +
> +  //
> +  // PPB should be skip!
> +  //
> +  if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +    return FALSE;
> +  }
> +
> +  if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
> +    //
> +    // Only test base registers for P2C
> +    //
> +    for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof
> (UINT32)) {
> +
> +      Mask    = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
> +      Status  = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
> +      if (EFI_ERROR (Status)) {
> +        continue;
> +      }
> +
> +      TestValue = TestValue & Mask;
> +      if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
> +        //
> +        // The bar isn't programed, so it should be rejected
> +        //
> +        return TRUE;
> +      }
> +    }
> +
> +    return FALSE;
> +  }
> +
> +  for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
> +    //
> +    // Test PCI devices
> +    //
> +    Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    if ((TestValue & 0x01) != 0) {
> +
> +      //
> +      // IO Bar
> +      //
> +      Mask      = 0xFFFFFFFC;
> +      TestValue = TestValue & Mask;
> +      if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
> +        return TRUE;
> +      }
> +
> +    } else {
> +
> +      //
> +      // Mem Bar
> +      //
> +      Mask      = 0xFFFFFFF0;
> +      TestValue = TestValue & Mask;
> +
> +      if ((TestValue & 0x07) == 0x04) {
> +
> +        //
> +        // Mem64 or PMem64
> +        //
> +        BarOffset += sizeof (UINT32);
> +        if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
> +
> +          //
> +          // Test its high 32-Bit BAR
> +          //
> +          Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
> +          if (TestValue == OldValue) {
> +            return TRUE;
> +          }
> +        }
> +
> +      } else {
> +
> +        //
> +        // Mem32 or PMem32
> +        //
> +        if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
> +          return TRUE;
> +        }
> +      }
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Reset all bus number from specific bridge.
> +
> +  @param Bridge           Parent specific bridge.
> +  @param StartBusNumber   Start bus number.
> +
> +**/
> +VOID
> +ResetAllPpbBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  PCI_TYPE00                      Pci;
> +  UINT8                           Device;
> +  UINT32                          Register;
> +  UINT8                           Func;
> +  UINT64                          Address;
> +  UINT8                           SecondaryBus;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  PciRootBridgeIo = Bridge->PciRootBridgeIo;
> +
> +  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
> +    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
> +
> +      //
> +      // Check to see whether a pci device is present
> +      //
> +      Status = PciDevicePresent (
> +                 PciRootBridgeIo,
> +                 &Pci,
> +                 StartBusNumber,
> +                 Device,
> +                 Func
> +                 );
> +
> +      if (EFI_ERROR (Status) && Func == 0) {
> +        //
> +        // go to next device if there is no Function 0
> +        //
> +        break;
> +      }
> +
> +      if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
> +
> +        Register  = 0;
> +        Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
> +        Status    = PciRootBridgeIo->Pci.Read (
> +                                           PciRootBridgeIo,
> +                                           EfiPciWidthUint32,
> +                                           Address,
> +                                           1,
> +                                           &Register
> +                                           );
> +        SecondaryBus = (UINT8)(Register >> 8);
> +
> +        if (SecondaryBus != 0) {
> +          ResetAllPpbBusNumber (Bridge, SecondaryBus);
> +        }
> +
> +        //
> +        // Reset register 18h, 19h, 1Ah on PCI Bridge
> +        //
> +        Register &= 0xFF000000;
> +        Status = PciRootBridgeIo->Pci.Write (
> +                                        PciRootBridgeIo,
> +                                        EfiPciWidthUint32,
> +                                        Address,
> +                                        1,
> +                                        &Register
> +                                        );
> +      }
> +
> +      if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
> +        //
> +        // Skip sub functions, this is not a multi function device
> +        //
> +        Func = PCI_MAX_FUNC;
> +      }
> +    }
> +  }
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.h
> new file mode 100644
> index 0000000000..1d39c5171d
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciEnumeratorSupport.h
> @@ -0,0 +1,480 @@
> +/** @file
> +  PCI enumeration support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_ENUMERATOR_SUPPORT_H_
> +#define _EFI_PCI_ENUMERATOR_SUPPORT_H_
> +
> +/**
> +  This routine is used to check whether the pci device is present.
> +
> +  @param PciRootBridgeIo   Pointer to instance of
> EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
> +  @param Pci               Output buffer for PCI device configuration space.
> +  @param Bus               PCI bus NO.
> +  @param Device            PCI device NO.
> +  @param Func              PCI Func NO.
> +
> +  @retval EFI_NOT_FOUND    PCI device not present.
> +  @retval EFI_SUCCESS      PCI device is found.
> +
> +**/
> +EFI_STATUS
> +PciDevicePresent (
> +  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo,
> +  OUT PCI_TYPE00                          *Pci,
> +  IN  UINT8                               Bus,
> +  IN  UINT8                               Device,
> +  IN  UINT8                               Func
> +  );
> +
> +/**
> +  Collect all the resource information under this root bridge.
> +
> +  A database that records all the information about pci device subject to this
> +  root bridge will then be created.
> +
> +  @param Bridge         Parent bridge instance.
> +  @param StartBusNumber Bus number of beginning.
> +
> +  @retval EFI_SUCCESS   PCI device is found.
> +  @retval other         Some error occurred when reading PCI bridge
> information.
> +
> +**/
> +EFI_STATUS
> +PciPciDeviceInfoCollector (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber
> +  );
> +
> +/**
> +  Search required device and create PCI device instance.
> +
> +  @param Bridge     Parent bridge instance.
> +  @param Pci        Input PCI device information block.
> +  @param Bus        PCI bus NO.
> +  @param Device     PCI device NO.
> +  @param Func       PCI func  NO.
> +  @param PciDevice  Output of searched PCI device instance.
> +
> +  @retval EFI_SUCCESS           Successfully created PCI device instance.
> +  @retval EFI_OUT_OF_RESOURCES  Cannot get PCI device information.
> +
> +**/
> +EFI_STATUS
> +PciSearchDevice (
> +  IN  PCI_IO_DEVICE                         *Bridge,
> +  IN  PCI_TYPE00                            *Pci,
> +  IN  UINT8                                 Bus,
> +  IN  UINT8                                 Device,
> +  IN  UINT8                                 Func,
> +  OUT PCI_IO_DEVICE                         **PciDevice
> +  );
> +
> +/**
> +  Create PCI device instance for PCI device.
> +
> +  @param Bridge   Parent bridge instance.
> +  @param Pci      Input PCI device information block.
> +  @param Bus      PCI device Bus NO.
> +  @param Device   PCI device Device NO.
> +  @param Func     PCI device's func NO.
> +
> +  @return  Created PCI device instance.
> +
> +**/
> +PCI_IO_DEVICE *
> +GatherDeviceInfo (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  );
> +
> +/**
> +  Create PCI device instance for PCI-PCI bridge.
> +
> +  @param Bridge   Parent bridge instance.
> +  @param Pci      Input PCI device information block.
> +  @param Bus      PCI device Bus NO.
> +  @param Device   PCI device Device NO.
> +  @param Func     PCI device's func NO.
> +
> +  @return  Created PCI device instance.
> +
> +**/
> +PCI_IO_DEVICE *
> +GatherPpbInfo (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  );
> +
> +/**
> +  Create PCI device instance for PCI Card bridge device.
> +
> +  @param Bridge   Parent bridge instance.
> +  @param Pci      Input PCI device information block.
> +  @param Bus      PCI device Bus NO.
> +  @param Device   PCI device Device NO.
> +  @param Func     PCI device's func NO.
> +
> +  @return  Created PCI device instance.
> +
> +**/
> +PCI_IO_DEVICE *
> +GatherP2CInfo (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  );
> +
> +/**
> +  Create device path for pci device.
> +
> +  @param ParentDevicePath  Parent bridge's path.
> +  @param PciIoDevice       Pci device instance.
> +
> +  @return Device path protocol instance for specific pci device.
> +
> +**/
> +EFI_DEVICE_PATH_PROTOCOL *
> +CreatePciDevicePath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
> +  IN  PCI_IO_DEVICE            *PciIoDevice
> +  );
> +
> +/**
> +  Check whether the PCI IOV VF bar is existed or not.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param Offset            The offset.
> +  @param BarLengthValue    The bar length value returned.
> +  @param OriginalBarValue  The original bar value returned.
> +
> +  @retval EFI_NOT_FOUND    The bar doesn't exist.
> +  @retval EFI_SUCCESS      The bar exist.
> +
> +**/
> +EFI_STATUS
> +VfBarExisted (
> +  IN PCI_IO_DEVICE *PciIoDevice,
> +  IN UINTN         Offset,
> +  OUT UINT32       *BarLengthValue,
> +  OUT UINT32       *OriginalBarValue
> +  );
> +
> +/**
> +  Check whether the bar is existed or not.
> +
> +  @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
> +  @param Offset            The offset.
> +  @param BarLengthValue    The bar length value returned.
> +  @param OriginalBarValue  The original bar value returned.
> +
> +  @retval EFI_NOT_FOUND    The bar doesn't exist.
> +  @retval EFI_SUCCESS      The bar exist.
> +
> +**/
> +EFI_STATUS
> +BarExisted (
> +  IN  PCI_IO_DEVICE *PciIoDevice,
> +  IN  UINTN         Offset,
> +  OUT UINT32        *BarLengthValue,
> +  OUT UINT32        *OriginalBarValue
> +  );
> +
> +/**
> +  Test whether the device can support given attributes.
> +
> +  @param PciIoDevice      Pci device instance.
> +  @param Command          Input command register value, and
> +                          returned supported register value.
> +  @param BridgeControl    Input bridge control value for PPB or P2C, and
> +                          returned supported bridge control value.
> +  @param OldCommand       Returned and stored old command register
> offset.
> +  @param OldBridgeControl Returned and stored old Bridge control value
> for PPB or P2C.
> +
> +**/
> +VOID
> +PciTestSupportedAttribute (
> +  IN     PCI_IO_DEVICE                      *PciIoDevice,
> +  IN OUT UINT16                             *Command,
> +  IN OUT UINT16                             *BridgeControl,
> +     OUT UINT16                             *OldCommand,
> +     OUT UINT16                             *OldBridgeControl
> +  );
> +
> +/**
> +  Set the supported or current attributes of a PCI device.
> +
> +  @param PciIoDevice    Structure pointer for PCI device.
> +  @param Command        Command register value.
> +  @param BridgeControl  Bridge control value for PPB or P2C.
> +  @param Option         Make a choice of EFI_SET_SUPPORTS or
> EFI_SET_ATTRIBUTES.
> +
> +**/
> +VOID
> +PciSetDeviceAttribute (
> +  IN PCI_IO_DEVICE                      *PciIoDevice,
> +  IN UINT16                             Command,
> +  IN UINT16                             BridgeControl,
> +  IN UINTN                              Option
> +  );
> +
> +/**
> +  Determine if the device can support Fast Back to Back attribute.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param StatusIndex  Status register value.
> +
> +  @retval EFI_SUCCESS       This device support Fast Back to Back attribute.
> +  @retval EFI_UNSUPPORTED   This device doesn't support Fast Back to Back
> attribute.
> +
> +**/
> +EFI_STATUS
> +GetFastBackToBackSupport (
> +  IN PCI_IO_DEVICE                      *PciIoDevice,
> +  IN UINT8                              StatusIndex
> +  );
> +
> +/**
> +  Determine the related attributes of all devices under a Root Bridge.
> +
> +  @param PciIoDevice   PCI device instance.
> +
> +**/
> +EFI_STATUS
> +DetermineDeviceAttribute (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  );
> +
> +/**
> +  This routine is used to update the bar information for those incompatible
> PCI device.
> +
> +  @param PciIoDevice      Input Pci device instance. Output Pci device
> instance with updated
> +                          Bar information.
> +
> +  @retval EFI_SUCCESS     Successfully updated bar information.
> +  @retval EFI_UNSUPPORTED Given PCI device doesn't belong to
> incompatible PCI device list.
> +
> +**/
> +EFI_STATUS
> +UpdatePciInfo (
> +  IN OUT PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +/**
> +  This routine will update the alignment with the new alignment.
> +
> +  @param Alignment    Input Old alignment. Output updated alignment.
> +  @param NewAlignment New alignment.
> +
> +**/
> +VOID
> +SetNewAlign (
> +  IN OUT UINT64     *Alignment,
> +  IN     UINT64     NewAlignment
> +  );
> +
> +/**
> +  Parse PCI bar information and fill them into PCI device instance.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Offset       Bar offset.
> +  @param BarIndex     Bar index.
> +
> +  @return Next bar offset.
> +
> +**/
> +UINTN
> +PciParseBar (
> +  IN PCI_IO_DEVICE  *PciIoDevice,
> +  IN UINTN          Offset,
> +  IN UINTN          BarIndex
> +  );
> +
> +/**
> +  Parse PCI IOV VF bar information and fill them into PCI device instance.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Offset       Bar offset.
> +  @param BarIndex     Bar index.
> +
> +  @return Next bar offset.
> +
> +**/
> +UINTN
> +PciIovParseVfBar (
> +  IN PCI_IO_DEVICE  *PciIoDevice,
> +  IN UINTN          Offset,
> +  IN UINTN          BarIndex
> +  );
> +
> +/**
> +  This routine is used to initialize the bar of a PCI device.
> +
> +  @param PciIoDevice Pci device instance.
> +
> +  @note It can be called typically when a device is going to be rejected.
> +
> +**/
> +VOID
> +InitializePciDevice (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +/**
> +  This routine is used to initialize the bar of a PCI-PCI Bridge device.
> +
> +  @param  PciIoDevice PCI-PCI bridge device instance.
> +
> +**/
> +VOID
> +InitializePpb (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +/**
> +  This routine is used to initialize the bar of a PCI Card Bridge device.
> +
> +  @param PciIoDevice  PCI Card bridge device.
> +
> +**/
> +VOID
> +InitializeP2C (
> +  IN PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +/**
> +  Create and initialize general PCI I/O device instance for
> +  PCI device/bridge device/hotplug bridge device.
> +
> +  @param Bridge            Parent bridge instance.
> +  @param Pci               Input Pci information block.
> +  @param Bus               Device Bus NO.
> +  @param Device            Device device NO.
> +  @param Func              Device func NO.
> +
> +  @return Instance of PCI device. NULL means no instance created.
> +
> +**/
> +PCI_IO_DEVICE *
> +CreatePciIoDevice (
> +  IN PCI_IO_DEVICE                    *Bridge,
> +  IN PCI_TYPE00                       *Pci,
> +  IN UINT8                            Bus,
> +  IN UINT8                            Device,
> +  IN UINT8                            Func
> +  );
> +
> +/**
> +  This routine is used to enumerate entire pci bus system
> +  in a given platform.
> +
> +  It is only called on the second start on the same Root Bridge.
> +
> +  @param  Controller     Parent bridge handler.
> +
> +  @retval EFI_SUCCESS    PCI enumeration finished successfully.
> +  @retval other          Some error occurred when enumerating the pci bus
> system.
> +
> +**/
> +EFI_STATUS
> +PciEnumeratorLight (
> +  IN EFI_HANDLE                    Controller
> +  );
> +
> +/**
> +  Get bus range from PCI resource descriptor list.
> +
> +  @param Descriptors  A pointer to the address space descriptor.
> +  @param MinBus       The min bus returned.
> +  @param MaxBus       The max bus returned.
> +  @param BusRange     The bus range returned.
> +
> +  @retval EFI_SUCCESS    Successfully got bus range.
> +  @retval EFI_NOT_FOUND  Can not find the specific bus.
> +
> +**/
> +EFI_STATUS
> +PciGetBusRange (
> +  IN     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  **Descriptors,
> +  OUT    UINT16                             *MinBus,
> +  OUT    UINT16                             *MaxBus,
> +  OUT    UINT16                             *BusRange
> +  );
> +
> +/**
> +  This routine can be used to start the root bridge.
> +
> +  @param RootBridgeDev     Pci device instance.
> +
> +  @retval EFI_SUCCESS      This device started.
> +  @retval other            Failed to get PCI Root Bridge I/O protocol.
> +
> +**/
> +EFI_STATUS
> +StartManagingRootBridge (
> +  IN PCI_IO_DEVICE *RootBridgeDev
> +  );
> +
> +/**
> +  This routine can be used to check whether a PCI device should be rejected
> when light enumeration.
> +
> +  @param PciIoDevice  Pci device instance.
> +
> +  @retval TRUE      This device should be rejected.
> +  @retval FALSE     This device shouldn't be rejected.
> +
> +**/
> +BOOLEAN
> +IsPciDeviceRejected (
> +  IN PCI_IO_DEVICE *PciIoDevice
> +  );
> +
> +/**
> +  Reset all bus number from specific bridge.
> +
> +  @param Bridge           Parent specific bridge.
> +  @param StartBusNumber   Start bus number.
> +
> +**/
> +VOID
> +ResetAllPpbBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber
> +  );
> +
> +/**
> +  Dump the PPB padding resource information.
> +
> +  @param PciIoDevice     PCI IO instance.
> +  @param ResourceType    The desired resource type to dump.
> +                         PciBarTypeUnknown means to dump all types of resources.
> +**/
> +VOID
> +DumpPpbPaddingResource (
> +  IN PCI_IO_DEVICE                    *PciIoDevice,
> +  IN PCI_BAR_TYPE                     ResourceType
> +  );
> +
> +/**
> +  Dump the PCI BAR information.
> +
> +  @param PciIoDevice     PCI IO instance.
> +**/
> +VOID
> +DumpPciBars (
> +  IN PCI_IO_DEVICE                    *PciIoDevice
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.c
> new file mode 100644
> index 0000000000..d6d06b061a
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.c
> @@ -0,0 +1,484 @@
> +/** @file
> +  PCI Hot Plug support functions implementation for PCI Bus module..
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +EFI_PCI_HOT_PLUG_INIT_PROTOCOL  *gPciHotPlugInit = NULL;
> +EFI_HPC_LOCATION                *gPciRootHpcPool = NULL;
> +UINTN                           gPciRootHpcCount = 0;
> +ROOT_HPC_DATA                   *gPciRootHpcData = NULL;
> +
> +
> +/**
> +  Event notification function to set Hot Plug controller status.
> +
> +  @param  Event                    The event that invoke this function.
> +  @param  Context                  The calling context, pointer to
> ROOT_HPC_DATA.
> +
> +**/
> +VOID
> +EFIAPI
> +PciHPCInitialized (
> +  IN EFI_EVENT    Event,
> +  IN VOID         *Context
> +  )
> +{
> +  ROOT_HPC_DATA   *HpcData;
> +
> +  HpcData               = (ROOT_HPC_DATA *) Context;
> +  HpcData->Initialized  = TRUE;
> +}
> +
> +/**
> +  Compare two device paths to check if they are exactly same.
> +
> +  @param DevicePath1    A pointer to the first device path data structure.
> +  @param DevicePath2    A pointer to the second device path data structure.
> +
> +  @retval TRUE    They are same.
> +  @retval FALSE   They are not same.
> +
> +**/
> +BOOLEAN
> +EfiCompareDevicePath (
> +  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
> +  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
> +  )
> +{
> +  UINTN Size1;
> +  UINTN Size2;
> +
> +  Size1 = GetDevicePathSize (DevicePath1);
> +  Size2 = GetDevicePathSize (DevicePath2);
> +
> +  if (Size1 != Size2) {
> +    return FALSE;
> +  }
> +
> +  if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Check hot plug support and initialize root hot plug private data.
> +
> +  If Hot Plug is supported by the platform, call PCI Hot Plug Init protocol
> +  to get PCI Hot Plug controller's information and constructor the root hot
> plug
> +  private data structure.
> +
> +  @retval EFI_SUCCESS           They are same.
> +  @retval EFI_UNSUPPORTED       No PCI Hot Plug controller on the platform.
> +  @retval EFI_OUT_OF_RESOURCES  No memory to constructor root hot
> plug private
> +                                data structure.
> +
> +**/
> +EFI_STATUS
> +InitializeHotPlugSupport (
> +  VOID
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EFI_HPC_LOCATION  *HpcList;
> +  UINTN             HpcCount;
> +
> +  //
> +  // Locate the PciHotPlugInit Protocol
> +  // If it doesn't exist, that means there is no
> +  // hot plug controller supported on the platform
> +  // the PCI Bus driver is running on. HotPlug Support
> +  // is an optional feature, so absence of the protocol
> +  // won't incur the penalty.
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gEfiPciHotPlugInitProtocolGuid,
> +                  NULL,
> +                  (VOID **) &gPciHotPlugInit
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Status = gPciHotPlugInit->GetRootHpcList (
> +                              gPciHotPlugInit,
> +                              &HpcCount,
> +                              &HpcList
> +                              );
> +
> +  if (!EFI_ERROR (Status)) {
> +
> +    gPciRootHpcPool   = HpcList;
> +    gPciRootHpcCount  = HpcCount;
> +    gPciRootHpcData   = AllocateZeroPool (sizeof (ROOT_HPC_DATA) *
> gPciRootHpcCount);
> +    if (gPciRootHpcData == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Test whether device path is for root pci hot plug bus.
> +
> +  @param HpbDevicePath  A pointer to device path data structure to be
> tested.
> +  @param HpIndex        If HpIndex is not NULL, return the index of root hot
> +                        plug in global array when TRUE is returned.
> +
> +  @retval TRUE          The device path is for root pci hot plug bus.
> +  @retval FALSE         The device path is not for root pci hot plug bus.
> +
> +**/
> +BOOLEAN
> +IsRootPciHotPlugBus (
> +  IN  EFI_DEVICE_PATH_PROTOCOL        *HpbDevicePath,
> +  OUT UINTN                           *HpIndex    OPTIONAL
> +  )
> +{
> +  UINTN Index;
> +
> +  for (Index = 0; Index < gPciRootHpcCount; Index++) {
> +
> +    if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpbDevicePath,
> HpbDevicePath)) {
> +
> +      if (HpIndex != NULL) {
> +        *HpIndex = Index;
> +      }
> +
> +      return TRUE;
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Test whether device path is for root pci hot plug controller.
> +
> +  @param HpcDevicePath  A pointer to device path data structure to be
> tested.
> +  @param HpIndex        If HpIndex is not NULL, return the index of root hot
> +                        plug in global array when TRUE is returned.
> +
> +  @retval TRUE          The device path is for root pci hot plug controller.
> +  @retval FALSE         The device path is not for root pci hot plug controller.
> +
> +**/
> +BOOLEAN
> +IsRootPciHotPlugController (
> +  IN EFI_DEVICE_PATH_PROTOCOL         *HpcDevicePath,
> +  OUT UINTN                           *HpIndex
> +  )
> +{
> +  UINTN Index;
> +
> +  for (Index = 0; Index < gPciRootHpcCount; Index++) {
> +
> +    if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpcDevicePath,
> HpcDevicePath)) {
> +
> +      if (HpIndex != NULL) {
> +        *HpIndex = Index;
> +      }
> +
> +      return TRUE;
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Creating event object for PCI Hot Plug controller.
> +
> +  @param  HpIndex   Index of hot plug device in global array.
> +  @param  Event     The returned event that invoke this function.
> +
> +  @return Status of create event.
> +
> +**/
> +EFI_STATUS
> +CreateEventForHpc (
> +  IN  UINTN      HpIndex,
> +  OUT EFI_EVENT  *Event
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  Status = gBS->CreateEvent (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_CALLBACK,
> +                  PciHPCInitialized,
> +                  gPciRootHpcData + HpIndex,
> +                  &((gPciRootHpcData + HpIndex)->Event)
> +                  );
> +
> +  if (!EFI_ERROR (Status)) {
> +    *Event = (gPciRootHpcData + HpIndex)->Event;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Wait for all root PCI Hot Plug controller finished initializing.
> +
> +  @param TimeoutInMicroSeconds  Microseconds to wait for all root HPCs'
> initialization.
> +
> +  @retval EFI_SUCCESS           All HPCs initialization finished.
> +  @retval EFI_TIMEOUT           Not ALL HPCs initialization finished in
> Microseconds.
> +
> +**/
> +EFI_STATUS
> +AllRootHPCInitialized (
> +  IN  UINTN           TimeoutInMicroSeconds
> +  )
> +{
> +  UINT32  Delay;
> +  UINTN   Index;
> +
> +  Delay = (UINT32) ((TimeoutInMicroSeconds / 30) + 1);
> +
> +  do {
> +    for (Index = 0; Index < gPciRootHpcCount; Index++) {
> +
> +      if (gPciRootHpcData[Index].Found &&
> !gPciRootHpcData[Index].Initialized) {
> +        break;
> +      }
> +    }
> +
> +    if (Index == gPciRootHpcCount) {
> +      return EFI_SUCCESS;
> +    }
> +
> +    //
> +    // Stall for 30 microseconds..
> +    //
> +    gBS->Stall (30);
> +
> +    Delay--;
> +
> +  } while (Delay > 0);
> +
> +  return EFI_TIMEOUT;
> +}
> +
> +/**
> +  Check whether PCI-PCI bridge has PCI Hot Plug capability register block.
> +
> +  @param PciIoDevice    A Pointer to the PCI-PCI bridge.
> +
> +  @retval TRUE    PCI device is HPC.
> +  @retval FALSE   PCI device is not HPC.
> +
> +**/
> +BOOLEAN
> +IsSHPC (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  )
> +{
> +
> +  EFI_STATUS  Status;
> +  UINT8       Offset;
> +
> +  if (PciIoDevice == NULL) {
> +    return FALSE;
> +  }
> +
> +  Offset = 0;
> +  Status = LocateCapabilityRegBlock (
> +            PciIoDevice,
> +            EFI_PCI_CAPABILITY_ID_SHPC,
> +            &Offset,
> +            NULL
> +            );
> +
> +  //
> +  // If the PCI-PCI bridge has the hot plug controller build-in,
> +  // then return TRUE;
> +  //
> +  if (!EFI_ERROR (Status)) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Check whether PciIoDevice supports PCIe hotplug.
> +
> +  This is equivalent to the following condition:
> +  - the device is either a PCIe switch downstream port or a root port,
> +  - and the device has the SlotImplemented bit set in its PCIe capability
> +    register,
> +  - and the device has the HotPlugCapable bit set in its slot capabilities
> +    register.
> +
> +  @param[in] PciIoDevice  The device being checked.
> +
> +  @retval TRUE   PciIoDevice is a PCIe port that accepts a hot-plugged device.
> +  @retval FALSE  Otherwise.
> +
> +**/
> +BOOLEAN
> +SupportsPcieHotplug (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  )
> +{
> +  UINT32                       Offset;
> +  EFI_STATUS                   Status;
> +  PCI_REG_PCIE_CAPABILITY      Capability;
> +  PCI_REG_PCIE_SLOT_CAPABILITY SlotCapability;
> +
> +  if (PciIoDevice == NULL) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Read the PCI Express Capabilities Register
> +  //
> +  if (!PciIoDevice->IsPciExp) {
> +    return FALSE;
> +  }
> +  Offset = PciIoDevice->PciExpressCapabilityOffset +
> +           OFFSET_OF (PCI_CAPABILITY_PCIEXP, Capability);
> +  Status = PciIoDevice->PciIo.Pci.Read (
> +                                    &PciIoDevice->PciIo,
> +                                    EfiPciIoWidthUint16,
> +                                    Offset,
> +                                    1,
> +                                    &Capability
> +                                    );
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Check the contents of the register
> +  //
> +  switch (Capability.Bits.DevicePortType) {
> +  case PCIE_DEVICE_PORT_TYPE_ROOT_PORT:
> +  case PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT:
> +    break;
> +  default:
> +    return FALSE;
> +  }
> +  if (!Capability.Bits.SlotImplemented) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Read the Slot Capabilities Register
> +  //
> +  Offset = PciIoDevice->PciExpressCapabilityOffset +
> +           OFFSET_OF (PCI_CAPABILITY_PCIEXP, SlotCapability);
> +  Status = PciIoDevice->PciIo.Pci.Read (
> +                                    &PciIoDevice->PciIo,
> +                                    EfiPciIoWidthUint32,
> +                                    Offset,
> +                                    1,
> +                                    &SlotCapability
> +                                    );
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Check the contents of the register
> +  //
> +  if (SlotCapability.Bits.HotPlugCapable) {
> +    return TRUE;
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +  Get resource padding if the specified PCI bridge is a hot plug bus.
> +
> +  @param PciIoDevice    PCI bridge instance.
> +
> +**/
> +VOID
> +GetResourcePaddingForHpb (
> +  IN PCI_IO_DEVICE      *PciIoDevice
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_HPC_STATE                     State;
> +  UINT64                            PciAddress;
> +  EFI_HPC_PADDING_ATTRIBUTES        Attributes;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
> +
> +  if (IsPciHotPlugBus (PciIoDevice)) {
> +    //
> +    // If PCI-PCI bridge device is PCI Hot Plug bus.
> +    //
> +    PciAddress = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice-
> >DeviceNumber, PciIoDevice->FunctionNumber, 0);
> +    Status = gPciHotPlugInit->GetResourcePadding (
> +                                gPciHotPlugInit,
> +                                PciIoDevice->DevicePath,
> +                                PciAddress,
> +                                &State,
> +                                (VOID **) &Descriptors,
> +                                &Attributes
> +                                );
> +
> +    if (EFI_ERROR (Status)) {
> +      return;
> +    }
> +
> +    if ((State & EFI_HPC_STATE_ENABLED) != 0 && (State &
> EFI_HPC_STATE_INITIALIZED) != 0) {
> +      PciIoDevice->ResourcePaddingDescriptors = Descriptors;
> +      PciIoDevice->PaddingAttributes          = Attributes;
> +    }
> +
> +    return;
> +  }
> +}
> +
> +/**
> +  Test whether PCI device is hot plug bus.
> +
> +  @param PciIoDevice  PCI device instance.
> +
> +  @retval TRUE    PCI device is a hot plug bus.
> +  @retval FALSE   PCI device is not a hot plug bus.
> +
> +**/
> +BOOLEAN
> +IsPciHotPlugBus (
> +  PCI_IO_DEVICE                       *PciIoDevice
> +  )
> +{
> +  if (IsSHPC (PciIoDevice)) {
> +    //
> +    // If the PPB has the hot plug controller build-in,
> +    // then return TRUE;
> +    //
> +    return TRUE;
> +  }
> +
> +  if (SupportsPcieHotplug (PciIoDevice)) {
> +    //
> +    // If the PPB is a PCIe root complex port or a switch downstream port, and
> +    // implements a hot-plug capable slot, then also return TRUE.
> +    //
> +    return TRUE;
> +  }
> +
> +  //
> +  // Otherwise, see if it is a Root HPC
> +  //
> +  if(IsRootPciHotPlugBus (PciIoDevice->DevicePath, NULL)) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.h
> new file mode 100644
> index 0000000000..0b69237a3d
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciHotPlugSupport.h
> @@ -0,0 +1,205 @@
> +/** @file
> +  PCI Hot Plug support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_HOT_PLUG_SUPPORT_H_
> +#define _EFI_PCI_HOT_PLUG_SUPPORT_H_
> +
> +//
> +// stall 1 second, its unit is 100ns
> +//
> +#define STALL_1_SECOND        1000000
> +
> +//
> +// PCI Hot Plug controller private data
> +//
> +typedef struct {
> +  EFI_EVENT Event;
> +  BOOLEAN   Found;
> +  BOOLEAN   Initialized;
> +  VOID      *Padding;
> +} ROOT_HPC_DATA;
> +
> +//
> +// Reference of some global variables
> +//
> +extern EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit;
> +extern EFI_HPC_LOCATION               *gPciRootHpcPool;
> +extern ROOT_HPC_DATA                  *gPciRootHpcData;
> +
> +/**
> +  Event notification function to set Hot Plug controller status.
> +
> +  @param  Event                    The event that invoke this function.
> +  @param  Context                  The calling context, pointer to
> ROOT_HPC_DATA.
> +
> +**/
> +VOID
> +EFIAPI
> +PciHPCInitialized (
> +  IN EFI_EVENT    Event,
> +  IN VOID         *Context
> +  );
> +
> +/**
> +  Compare two device paths to check if they are exactly same.
> +
> +  @param DevicePath1    A pointer to the first device path data structure.
> +  @param DevicePath2    A pointer to the second device path data structure.
> +
> +  @retval TRUE    They are same.
> +  @retval FALSE   They are not same.
> +
> +**/
> +BOOLEAN
> +EfiCompareDevicePath (
> +  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
> +  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
> +  );
> +
> +/**
> +  Check hot plug support and initialize root hot plug private data.
> +
> +  If Hot Plug is supported by the platform, call PCI Hot Plug Init protocol
> +  to get PCI Hot Plug controller's information and constructor the root hot
> plug
> +  private data structure.
> +
> +  @retval EFI_SUCCESS           They are same.
> +  @retval EFI_UNSUPPORTED       No PCI Hot Plug controller on the platform.
> +  @retval EFI_OUT_OF_RESOURCES  No memory to constructor root hot
> plug private
> +                                data structure.
> +
> +**/
> +EFI_STATUS
> +InitializeHotPlugSupport (
> +  VOID
> +  );
> +
> +/**
> +  Test whether PCI device is hot plug bus.
> +
> +  @param PciIoDevice  PCI device instance.
> +
> +  @retval TRUE    PCI device is a hot plug bus.
> +  @retval FALSE   PCI device is not a hot plug bus.
> +
> +**/
> +BOOLEAN
> +IsPciHotPlugBus (
> +  PCI_IO_DEVICE                       *PciIoDevice
> +  );
> +
> +/**
> +  Test whether device path is for root pci hot plug bus.
> +
> +  @param HpbDevicePath  A pointer to device path data structure to be
> tested.
> +  @param HpIndex        If HpIndex is not NULL, return the index of root hot
> +                        plug in global array when TRUE is returned.
> +
> +  @retval TRUE          The device path is for root pci hot plug bus.
> +  @retval FALSE         The device path is not for root pci hot plug bus.
> +
> +**/
> +BOOLEAN
> +IsRootPciHotPlugBus (
> +  IN  EFI_DEVICE_PATH_PROTOCOL        *HpbDevicePath,
> +  OUT UINTN                           *HpIndex    OPTIONAL
> +  );
> +
> +/**
> +  Test whether device path is for root pci hot plug controller.
> +
> +  @param HpcDevicePath  A pointer to device path data structure to be
> tested.
> +  @param HpIndex        If HpIndex is not NULL, return the index of root hot
> +                        plug in global array when TRUE is returned.
> +
> +  @retval TRUE          The device path is for root pci hot plug controller.
> +  @retval FALSE         The device path is not for root pci hot plug controller.
> +
> +**/
> +BOOLEAN
> +IsRootPciHotPlugController (
> +  IN EFI_DEVICE_PATH_PROTOCOL         *HpcDevicePath,
> +  OUT UINTN                           *HpIndex
> +  );
> +
> +/**
> +  Creating event object for PCI Hot Plug controller.
> +
> +  @param  HpIndex   Index of hot plug device in global array.
> +  @param  Event     The returned event that invoke this function.
> +
> +  @return Status of create event.
> +
> +**/
> +EFI_STATUS
> +CreateEventForHpc (
> +  IN  UINTN      HpIndex,
> +  OUT EFI_EVENT  *Event
> +  );
> +
> +/**
> +  Wait for all root PCI Hot Plug controller finished initializing.
> +
> +  @param TimeoutInMicroSeconds  Microseconds to wait for all root HPCs'
> initialization.
> +
> +  @retval EFI_SUCCESS           All HPCs initialization finished.
> +  @retval EFI_TIMEOUT           Not ALL HPCs initialization finished in
> Microseconds.
> +
> +**/
> +EFI_STATUS
> +AllRootHPCInitialized (
> +  IN  UINTN           TimeoutInMicroSeconds
> +  );
> +
> +/**
> +  Check whether PCI-PCI bridge has PCI Hot Plug capability register block.
> +
> +  @param PciIoDevice    A Pointer to the PCI-PCI bridge.
> +
> +  @retval TRUE    PCI device is HPC.
> +  @retval FALSE   PCI device is not HPC.
> +
> +**/
> +BOOLEAN
> +IsSHPC (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  );
> +
> +/**
> +  Check whether PciIoDevice supports PCIe hotplug.
> +
> +  This is equivalent to the following condition:
> +  - the device is either a PCIe switch downstream port or a root port,
> +  - and the device has the SlotImplemented bit set in its PCIe capability
> +    register,
> +  - and the device has the HotPlugCapable bit set in its slot capabilities
> +    register.
> +
> +  @param[in] PciIoDevice  The device being checked.
> +
> +  @retval TRUE   PciIoDevice is a PCIe port that accepts a hot-plugged device.
> +  @retval FALSE  Otherwise.
> +
> +**/
> +BOOLEAN
> +SupportsPcieHotplug (
> +  IN PCI_IO_DEVICE                      *PciIoDevice
> +  );
> +
> +/**
> +  Get resource padding if the specified PCI bridge is a hot plug bus.
> +
> +  @param PciIoDevice    PCI bridge instance.
> +
> +**/
> +VOID
> +GetResourcePaddingForHpb (
> +  IN PCI_IO_DEVICE      *PciIoDevice
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.c
> new file mode 100644
> index 0000000000..c656056315
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.c
> @@ -0,0 +1,2087 @@
> +/** @file
> +  EFI PCI IO protocol functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +extern EDKII_IOMMU_PROTOCOL                          *mIoMmuProtocol;
> +
> +//
> +// Pci Io Protocol Interface
> +//
> +EFI_PCI_IO_PROTOCOL  mPciIoInterface = {
> +  PciIoPollMem,
> +  PciIoPollIo,
> +  {
> +    PciIoMemRead,
> +    PciIoMemWrite
> +  },
> +  {
> +    PciIoIoRead,
> +    PciIoIoWrite
> +  },
> +  {
> +    PciIoConfigRead,
> +    PciIoConfigWrite
> +  },
> +  PciIoCopyMem,
> +  PciIoMap,
> +  PciIoUnmap,
> +  PciIoAllocateBuffer,
> +  PciIoFreeBuffer,
> +  PciIoFlush,
> +  PciIoGetLocation,
> +  PciIoAttributes,
> +  PciIoGetBarAttributes,
> +  PciIoSetBarAttributes,
> +  0,
> +  NULL
> +};
> +
> +/**
> +  Initializes a PCI I/O Instance.
> +
> +  @param PciIoDevice    Pci device instance.
> +
> +**/
> +VOID
> +InitializePciIoInstance (
> +  IN PCI_IO_DEVICE               *PciIoDevice
> +  )
> +{
> +  CopyMem (&PciIoDevice->PciIo, &mPciIoInterface, sizeof
> (EFI_PCI_IO_PROTOCOL));
> +}
> +
> +/**
> +  Verifies access to a PCI Base Address Register (BAR).
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param BarIndex     The BAR index of the standard PCI Configuration
> header to use as the
> +                      base address for the memory or I/O operation to perform.
> +  @param Type         Operation type could be memory or I/O.
> +  @param Width        Signifies the width of the memory or I/O operations.
> +  @param Count        The number of memory or I/O operations to perform.
> +  @param Offset       The offset within the PCI configuration space for the PCI
> controller.
> +
> +  @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
> +  @retval EFI_SUCCESS           Successfully verified.
> +
> +**/
> +EFI_STATUS
> +PciIoVerifyBarAccess (
> +  IN PCI_IO_DEVICE                   *PciIoDevice,
> +  IN UINT8                           BarIndex,
> +  IN PCI_BAR_TYPE                    Type,
> +  IN IN EFI_PCI_IO_PROTOCOL_WIDTH    Width,
> +  IN IN UINTN                        Count,
> +  IN UINT64                          *Offset
> +  )
> +{
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // BarIndex 0-5 is legal
> +  //
> +  if (BarIndex >= PCI_MAX_BAR) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
> +  // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
> +  //
> +  if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
> +    Count = 1;
> +  }
> +
> +  Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
> +
> +  if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice-
> >PciBar[BarIndex].Length) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Verifies access to a PCI Configuration Header.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Width        Signifies the width of the memory or I/O operations.
> +  @param Count        The number of memory or I/O operations to perform.
> +  @param Offset       The offset within the PCI configuration space for the PCI
> controller.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid Width
> +  @retval EFI_UNSUPPORTED        Offset overflowed.
> +  @retval EFI_SUCCESS            Successfully verified.
> +
> +**/
> +EFI_STATUS
> +PciIoVerifyConfigAccess (
> +  IN PCI_IO_DEVICE              *PciIoDevice,
> +  IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN UINTN                      Count,
> +  IN UINT64                     *Offset
> +  )
> +{
> +  UINT64  ExtendOffset;
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
> +  //
> +  Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
> +
> +  if (PciIoDevice->IsPciExp) {
> +    if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >=
> PCI_EXP_MAX_CONFIG_OFFSET) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    ExtendOffset  = LShiftU64 (*Offset, 32);
> +    *Offset       = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice-
> >DeviceNumber, PciIoDevice->FunctionNumber, 0);
> +    *Offset       = (*Offset) | ExtendOffset;
> +
> +  } else {
> +    if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >=
> PCI_MAX_CONFIG_OFFSET) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice-
> >DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Reads from the memory space of a PCI controller. Returns either when the
> polling exit criteria is
> +  satisfied or after a defined duration.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory operation.
> +  @param  Mask                  Mask used for the polling criteria.
> +  @param  Value                 The comparison value used for the polling exit
> criteria.
> +  @param  Delay                 The number of 100 ns units to poll.
> +  @param  Result                Pointer to the last value read from the memory
> location.
> +
> +  @retval EFI_SUCCESS           The last data returned from the access matched
> the poll exit criteria.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this
> PCI controller.
> +  @retval EFI_TIMEOUT           Delay expired before a match occurred.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoPollMem (
> +  IN  EFI_PCI_IO_PROTOCOL        *This,
> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN  UINT8                      BarIndex,
> +  IN  UINT64                     Offset,
> +  IN  UINT64                     Mask,
> +  IN  UINT64                     Value,
> +  IN  UINT64                     Delay,
> +  OUT UINT64                     *Result
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem,
> Width, 1, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (Width > EfiPciIoWidthUint64) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Status  = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +      if ((*Result & Mask) == Value || Delay == 0) {
> +        return EFI_SUCCESS;
> +      }
> +      do {
> +        //
> +        // Stall 10 us = 100 * 100ns
> +        //
> +        gBS->Stall (10);
> +
> +        Status  = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +        if ((*Result & Mask) == Value) {
> +          return EFI_SUCCESS;
> +        }
> +        if (Delay <= 100) {
> +          return EFI_TIMEOUT;
> +        }
> +        Delay -= 100;
> +      } while (TRUE);
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->PollMem (
> +                                           PciIoDevice->PciRootBridgeIo,
> +                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                           Offset,
> +                                           Mask,
> +                                           Value,
> +                                           Delay,
> +                                           Result
> +                                           );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Reads from the memory space of a PCI controller. Returns either when the
> polling exit criteria is
> +  satisfied or after a defined duration.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory operation.
> +  @param  Mask                  Mask used for the polling criteria.
> +  @param  Value                 The comparison value used for the polling exit
> criteria.
> +  @param  Delay                 The number of 100 ns units to poll.
> +  @param  Result                Pointer to the last value read from the memory
> location.
> +
> +  @retval EFI_SUCCESS           The last data returned from the access matched
> the poll exit criteria.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this
> PCI controller.
> +  @retval EFI_TIMEOUT           Delay expired before a match occurred.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoPollIo (
> +  IN  EFI_PCI_IO_PROTOCOL        *This,
> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN  UINT8                      BarIndex,
> +  IN  UINT64                     Offset,
> +  IN  UINT64                     Mask,
> +  IN  UINT64                     Value,
> +  IN  UINT64                     Delay,
> +  OUT UINT64                     *Result
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width > EfiPciIoWidthUint64) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width,
> 1, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Status  = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +      if ((*Result & Mask) == Value || Delay == 0) {
> +        return EFI_SUCCESS;
> +      }
> +      do {
> +        //
> +        // Stall 10 us = 100 * 100ns
> +        //
> +        gBS->Stall (10);
> +
> +        Status  = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +        if ((*Result & Mask) == Value) {
> +          return EFI_SUCCESS;
> +        }
> +        if (Delay <= 100) {
> +          return EFI_TIMEOUT;
> +        }
> +        Delay -= 100;
> +      } while (TRUE);
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->PollIo (
> +                                           PciIoDevice->PciRootBridgeIo,
> +                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                           Offset,
> +                                           Mask,
> +                                           Value,
> +                                           Delay,
> +                                           Result
> +                                           );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoMemRead (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Buffer == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem,
> Width, Count, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
> +                                              PciIoDevice->PciRootBridgeIo,
> +                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                              Offset,
> +                                              Count,
> +                                              Buffer
> +                                              );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoMemWrite (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Buffer == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem,
> Width, Count, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
> +                                              PciIoDevice->PciRootBridgeIo,
> +                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                              Offset,
> +                                              Count,
> +                                              Buffer
> +                                              );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoIoRead (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Buffer == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width,
> Count, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Io.Read (
> +                                              PciIoDevice->PciRootBridgeIo,
> +                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                              Offset,
> +                                              Count,
> +                                              Buffer
> +                                              );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoIoWrite (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Buffer == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width,
> Count, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Io.Write (
> +                                              PciIoDevice->PciRootBridgeIo,
> +                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                              Offset,
> +                                              Count,
> +                                              Buffer
> +                                              );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in PCI configuration
> space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory operations.
> +  @param  Offset                The offset within the PCI configuration space for
> the PCI controller.
> +  @param  Count                 The number of PCI configuration operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI configuration header of the PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoConfigRead (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT32                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +  UINT64        Address;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  Address     = Offset;
> +  Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
> +                                               PciIoDevice->PciRootBridgeIo,
> +                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                               Address,
> +                                               Count,
> +                                               Buffer
> +                                               );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in PCI configuration
> space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory operations.
> +  @param  Offset                The offset within the PCI configuration space for
> the PCI controller.
> +  @param  Count                 The number of PCI configuration operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI configuration header of the PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoConfigWrite (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT32                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +  UINT64        Address;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  Address     = Offset;
> +  Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
> +                                              PciIoDevice->PciRootBridgeIo,
> +                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                              Address,
> +                                              Count,
> +                                              Buffer
> +                                              );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Enables a PCI driver to copy one region of PCI memory space to another
> region of PCI
> +  memory space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory operations.
> +  @param  DestBarIndex          The BAR index in the standard PCI
> Configuration header to use as the
> +                                base address for the memory operation to perform.
> +  @param  DestOffset            The destination offset within the BAR specified
> by DestBarIndex to
> +                                start the memory writes for the copy operation.
> +  @param  SrcBarIndex           The BAR index in the standard PCI Configuration
> header to use as the
> +                                base address for the memory operation to perform.
> +  @param  SrcOffset             The source offset within the BAR specified by
> SrcBarIndex to start
> +                                the memory reads for the copy operation.
> +  @param  Count                 The number of memory operations to perform.
> Bytes moved is Width
> +                                size * Count, starting at DestOffset and SrcOffset.
> +
> +  @retval EFI_SUCCESS           The data was copied from one memory region
> to another memory region.
> +  @retval EFI_UNSUPPORTED       DestBarIndex not valid for this PCI
> controller.
> +  @retval EFI_UNSUPPORTED       SrcBarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by DestOffset,
> Width, and Count
> +                                is not valid for the PCI BAR specified by DestBarIndex.
> +  @retval EFI_UNSUPPORTED       The address range specified by SrcOffset,
> Width, and Count is
> +                                not valid for the PCI BAR specified by SrcBarIndex.
> +  @retval EFI_INVALID_PARAMETER Width is invalid.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoCopyMem (
> +  IN EFI_PCI_IO_PROTOCOL              *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
> +  IN     UINT8                        DestBarIndex,
> +  IN     UINT64                       DestOffset,
> +  IN     UINT8                        SrcBarIndex,
> +  IN     UINT64                       SrcOffset,
> +  IN     UINTN                        Count
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Width >= EfiPciIoWidthMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Width == EfiPciIoWidthFifoUint8  ||
> +      Width == EfiPciIoWidthFifoUint16 ||
> +      Width == EfiPciIoWidthFifoUint32 ||
> +      Width == EfiPciIoWidthFifoUint64 ||
> +      Width == EfiPciIoWidthFillUint8  ||
> +      Width == EfiPciIoWidthFillUint16 ||
> +      Width == EfiPciIoWidthFillUint32 ||
> +      Width == EfiPciIoWidthFillUint64) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex,
> PciBarTypeMem, Width, Count, &DestOffset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem,
> Width, Count, &SrcOffset);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
> +  //
> +  if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
> +    if ((SrcOffset & ((1 << (Width & 0x03)) - 1)) != 0 || (DestOffset & ((1 <<
> (Width & 0x03)) - 1)) != 0) {
> +      Count *=  (UINTN)(1 << (Width & 0x03));
> +      Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
> +    }
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->CopyMem (
> +                                          PciIoDevice->PciRootBridgeIo,
> +                                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)
> Width,
> +                                          DestOffset,
> +                                          SrcOffset,
> +                                          Count
> +                                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Provides the PCI controller-specific addresses needed to access system
> memory.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Operation             Indicates if the bus master is going to read or
> write to system memory.
> +  @param  HostAddress           The system memory address to map to the PCI
> controller.
> +  @param  NumberOfBytes         On input the number of bytes to map. On
> output the number of bytes
> +                                that were mapped.
> +  @param  DeviceAddress         The resulting map address for the bus master
> PCI controller to use to
> +                                access the hosts HostAddress.
> +  @param  Mapping               A resulting value to pass to Unmap().
> +
> +  @retval EFI_SUCCESS           The range was mapped for the returned
> NumberOfBytes.
> +  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a
> common buffer.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_DEVICE_ERROR      The system hardware could not map the
> requested address.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoMap (
> +  IN     EFI_PCI_IO_PROTOCOL            *This,
> +  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
> +  IN     VOID                           *HostAddress,
> +  IN OUT UINTN                          *NumberOfBytes,
> +  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
> +  OUT    VOID                           **Mapping
> +  )
> +{
> +  EFI_STATUS                                 Status;
> +  PCI_IO_DEVICE                              *PciIoDevice;
> +  UINT64                                     IoMmuAttribute;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION
> RootBridgeIoOperation;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress ==
> NULL || Mapping == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  RootBridgeIoOperation =
> (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)Operation;
> +  if ((PciIoDevice->Attributes &
> EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
> +    RootBridgeIoOperation =
> (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)(Operation +
> EfiPciOperationBusMasterRead64);
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Map (
> +                                          PciIoDevice->PciRootBridgeIo,
> +                                          RootBridgeIoOperation,
> +                                          HostAddress,
> +                                          NumberOfBytes,
> +                                          DeviceAddress,
> +                                          Mapping
> +                                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  if (mIoMmuProtocol != NULL) {
> +    if (!EFI_ERROR (Status)) {
> +      switch (Operation) {
> +      case EfiPciIoOperationBusMasterRead:
> +        IoMmuAttribute = EDKII_IOMMU_ACCESS_READ;
> +        break;
> +      case EfiPciIoOperationBusMasterWrite:
> +        IoMmuAttribute = EDKII_IOMMU_ACCESS_WRITE;
> +        break;
> +      case EfiPciIoOperationBusMasterCommonBuffer:
> +        IoMmuAttribute = EDKII_IOMMU_ACCESS_READ |
> EDKII_IOMMU_ACCESS_WRITE;
> +        break;
> +      default:
> +        ASSERT(FALSE);
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      mIoMmuProtocol->SetAttribute (
> +                        mIoMmuProtocol,
> +                        PciIoDevice->Handle,
> +                        *Mapping,
> +                        IoMmuAttribute
> +                        );
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Completes the Map() operation and releases any corresponding
> resources.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Mapping               The mapping value returned from Map().
> +
> +  @retval EFI_SUCCESS           The range was unmapped.
> +  @retval EFI_DEVICE_ERROR      The data was not committed to the target
> system memory.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoUnmap (
> +  IN  EFI_PCI_IO_PROTOCOL  *This,
> +  IN  VOID                 *Mapping
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if (mIoMmuProtocol != NULL) {
> +    mIoMmuProtocol->SetAttribute (
> +                      mIoMmuProtocol,
> +                      PciIoDevice->Handle,
> +                      Mapping,
> +                      0
> +                      );
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Unmap (
> +                                          PciIoDevice->PciRootBridgeIo,
> +                                          Mapping
> +                                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Allocates pages that are suitable for an
> EfiPciIoOperationBusMasterCommonBuffer
> +  or EfiPciOperationBusMasterCommonBuffer64 mapping.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Type                  This parameter is not used and must be ignored.
> +  @param  MemoryType            The type of memory to allocate,
> EfiBootServicesData or
> +                                EfiRuntimeServicesData.
> +  @param  Pages                 The number of pages to allocate.
> +  @param  HostAddress           A pointer to store the base system memory
> address of the
> +                                allocated range.
> +  @param  Attributes            The requested bit mask of attributes for the
> allocated range.
> +
> +  @retval EFI_SUCCESS           The requested memory pages were allocated.
> +  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal
> attribute bits are
> +                                MEMORY_WRITE_COMBINE, MEMORY_CACHED and
> DUAL_ADDRESS_CYCLE.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be
> allocated.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoAllocateBuffer (
> +  IN  EFI_PCI_IO_PROTOCOL   *This,
> +  IN  EFI_ALLOCATE_TYPE     Type,
> +  IN  EFI_MEMORY_TYPE       MemoryType,
> +  IN  UINTN                 Pages,
> +  OUT VOID                  **HostAddress,
> +  IN  UINT64                Attributes
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  if ((Attributes &
> +      (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
> EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) != 0){
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if ((PciIoDevice->Attributes &
> EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
> +    Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
> +  }
> +
> +  Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
> +                                          PciIoDevice->PciRootBridgeIo,
> +                                          Type,
> +                                          MemoryType,
> +                                          Pages,
> +                                          HostAddress,
> +                                          Attributes
> +                                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Frees memory that was allocated with AllocateBuffer().
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Pages                 The number of pages to free.
> +  @param  HostAddress           The base system memory address of the
> allocated range.
> +
> +  @retval EFI_SUCCESS           The requested memory pages were freed.
> +  @retval EFI_INVALID_PARAMETER The memory range specified by
> HostAddress and Pages
> +                                was not allocated with AllocateBuffer().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoFreeBuffer (
> +  IN  EFI_PCI_IO_PROTOCOL   *This,
> +  IN  UINTN                 Pages,
> +  IN  VOID                  *HostAddress
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
> +                                          PciIoDevice->PciRootBridgeIo,
> +                                          Pages,
> +                                          HostAddress
> +                                          );
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Flushes all PCI posted write transactions from a PCI host bridge to system
> memory.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +
> +  @retval EFI_SUCCESS           The PCI posted write transactions were flushed
> from the PCI host
> +                                bridge to system memory.
> +  @retval EFI_DEVICE_ERROR      The PCI posted write transactions were not
> flushed from the PCI
> +                                host bridge due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoFlush (
> +  IN  EFI_PCI_IO_PROTOCOL  *This
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  Status = PciIoDevice->PciRootBridgeIo->Flush (
> +                                           PciIoDevice->PciRootBridgeIo
> +                                           );
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Retrieves this PCI controller's current PCI bus number, device number, and
> function number.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  SegmentNumber         The PCI controller's current PCI segment
> number.
> +  @param  BusNumber             The PCI controller's current PCI bus number.
> +  @param  DeviceNumber          The PCI controller's current PCI device
> number.
> +  @param  FunctionNumber        The PCI controller's current PCI function
> number.
> +
> +  @retval EFI_SUCCESS           The PCI controller location was returned.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoGetLocation (
> +  IN  EFI_PCI_IO_PROTOCOL  *This,
> +  OUT UINTN                *Segment,
> +  OUT UINTN                *Bus,
> +  OUT UINTN                *Device,
> +  OUT UINTN                *Function
> +  )
> +{
> +  PCI_IO_DEVICE *PciIoDevice;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if (Segment == NULL || Bus == NULL || Device == NULL || Function ==
> NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Segment  = PciIoDevice->PciRootBridgeIo->SegmentNumber;
> +  *Bus      = PciIoDevice->BusNumber;
> +  *Device   = PciIoDevice->DeviceNumber;
> +  *Function = PciIoDevice->FunctionNumber;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check BAR type for PCI resource.
> +
> +  @param PciIoDevice   PCI device instance.
> +  @param BarIndex      The BAR index of the standard PCI Configuration
> header to use as the
> +                       base address for the memory or I/O operation to perform.
> +  @param BarType       Memory or I/O.
> +
> +  @retval TRUE         Pci device's bar type is same with input BarType.
> +  @retval TRUE         Pci device's bar type is not same with input BarType.
> +
> +**/
> +BOOLEAN
> +CheckBarType (
> +  IN PCI_IO_DEVICE          *PciIoDevice,
> +  IN UINT8                  BarIndex,
> +  IN PCI_BAR_TYPE           BarType
> +  )
> +{
> +  switch (BarType) {
> +
> +  case PciBarTypeMem:
> +
> +    if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32  &&
> +        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
> +        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
> +        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64    ) {
> +      return FALSE;
> +    }
> +
> +    return TRUE;
> +
> +  case PciBarTypeIo:
> +    if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
> +        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
> +      return FALSE;
> +    }
> +
> +    return TRUE;
> +
> +  default:
> +    break;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Set/Disable new attributes to a Root Bridge.
> +
> +  @param  PciIoDevice  Pci device instance.
> +  @param  Attributes   New attribute want to be set.
> +  @param  Operation    Set or Disable.
> +
> +  @retval  EFI_UNSUPPORTED  If root bridge does not support change
> attribute.
> +  @retval  EFI_SUCCESS      Successfully set new attributes.
> +
> +**/
> +EFI_STATUS
> +ModifyRootBridgeAttributes (
> +  IN  PCI_IO_DEVICE                            *PciIoDevice,
> +  IN  UINT64                                   Attributes,
> +  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
> +  )
> +{
> +  UINT64      PciRootBridgeSupports;
> +  UINT64      PciRootBridgeAttributes;
> +  UINT64      NewPciRootBridgeAttributes;
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Get the current attributes of this PCI device's PCI Root Bridge
> +  //
> +  Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
> +                                          PciIoDevice->PciRootBridgeIo,
> +                                          &PciRootBridgeSupports,
> +                                          &PciRootBridgeAttributes
> +                                          );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Mask off attributes not supported by PCI root bridge.
> +  //
> +  Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
> +                          EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
> +                          EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
> +
> +  //
> +  // Record the new attribute of the Root Bridge
> +  //
> +  if (Operation == EfiPciIoAttributeOperationEnable) {
> +    NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;
> +  } else {
> +    NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);
> +  }
> +
> +  //
> +  // Call the PCI Root Bridge to attempt to modify the attributes
> +  //
> +  if ((NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) != 0) {
> +
> +    Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
> +                                            PciIoDevice->PciRootBridgeIo,
> +                                            NewPciRootBridgeAttributes,
> +                                            NULL,
> +                                            NULL
> +                                            );
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // The PCI Root Bridge could not modify the attributes, so return the
> error.
> +      //
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Also update the attributes for this Root Bridge structure
> +  //
> +  PciIoDevice->Attributes = NewPciRootBridgeAttributes;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check whether this device can be enable/disable to snoop.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Operation    Enable/Disable.
> +
> +  @retval EFI_UNSUPPORTED  Pci device is not GFX device or not support
> snoop.
> +  @retval EFI_SUCCESS      Snoop can be supported.
> +
> +**/
> +EFI_STATUS
> +SupportPaletteSnoopAttributes (
> +  IN PCI_IO_DEVICE                            *PciIoDevice,
> +  IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
> +  )
> +{
> +  PCI_IO_DEVICE *Temp;
> +  UINT16        VGACommand;
> +
> +  //
> +  // Snoop attribute can be only modified by GFX
> +  //
> +  if (!IS_PCI_GFX (&PciIoDevice->Pci)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Get the boot VGA on the same Host Bridge
> +  //
> +  Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo-
> >ParentHandle);
> +
> +  if (Temp == NULL) {
> +    //
> +    // If there is no VGA device on the segment, set
> +    // this graphics card to decode the palette range
> +    //
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // Check these two agents are on the same path
> +  //
> +  if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {
> +    //
> +    // they are not on the same path, so snoop can be enabled or disabled
> +    //
> +    return EFI_SUCCESS;
> +  }
> +  //
> +  // Check if they are on the same bus
> +  //
> +  if (Temp->Parent == PciIoDevice->Parent) {
> +
> +    PCI_READ_COMMAND_REGISTER (Temp, &VGACommand);
> +
> +    //
> +    // If they are on the same bus, either one can
> +    // be set to snoop, the other set to decode
> +    //
> +    if ((VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
> +      //
> +      // VGA has set to snoop, so GFX can be only set to disable snoop
> +      //
> +      if (Operation == EfiPciIoAttributeOperationEnable) {
> +        return EFI_UNSUPPORTED;
> +      }
> +    } else {
> +      //
> +      // VGA has disabled to snoop, so GFX can be only enabled
> +      //
> +      if (Operation == EfiPciIoAttributeOperationDisable) {
> +        return EFI_UNSUPPORTED;
> +      }
> +    }
> +
> +    return EFI_SUCCESS;
> +  }
> +
> +  //
> +  // If they are on  the same path but on the different bus
> +  // The first agent is set to snoop, the second one set to
> +  // decode
> +  //
> +
> +  if (Temp->BusNumber < PciIoDevice->BusNumber) {
> +    //
> +    // GFX should be set to decode
> +    //
> +    if (Operation == EfiPciIoAttributeOperationDisable) {
> +      PCI_ENABLE_COMMAND_REGISTER (Temp,
> EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
> +      Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
> +    } else {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +  } else {
> +    //
> +    // GFX should be set to snoop
> +    //
> +    if (Operation == EfiPciIoAttributeOperationEnable) {
> +      PCI_DISABLE_COMMAND_REGISTER (Temp,
> EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
> +      Temp->Attributes &=
> (~(UINT64)EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
> +    } else {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Performs an operation on the attributes that this PCI controller supports.
> The operations include
> +  getting the set of supported attributes, retrieving the current attributes,
> setting the current
> +  attributes, enabling attributes, and disabling attributes.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Operation             The operation to perform on the attributes for
> this PCI controller.
> +  @param  Attributes            The mask of attributes that are used for Set,
> Enable, and Disable
> +                                operations.
> +  @param  Result                A pointer to the result mask of attributes that are
> returned for the Get
> +                                and Supported operations.
> +
> +  @retval EFI_SUCCESS           The operation on the PCI controller's attributes
> was completed.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +  @retval EFI_UNSUPPORTED       one or more of the bits set in
> +                                Attributes are not supported by this PCI controller or one of
> +                                its parent bridges when Operation is Set, Enable or Disable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoAttributes (
> +  IN EFI_PCI_IO_PROTOCOL                       * This,
> +  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
> +  IN  UINT64                                   Attributes,
> +  OUT UINT64                                   *Result OPTIONAL
> +  )
> +{
> +  EFI_STATUS    Status;
> +
> +  PCI_IO_DEVICE *PciIoDevice;
> +  PCI_IO_DEVICE *UpStreamBridge;
> +  PCI_IO_DEVICE *Temp;
> +
> +  UINT64        Supports;
> +  UINT64        UpStreamAttributes;
> +  UINT16        BridgeControl;
> +  UINT16        Command;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  switch (Operation) {
> +  case EfiPciIoAttributeOperationGet:
> +    if (Result == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    *Result = PciIoDevice->Attributes;
> +    return EFI_SUCCESS;
> +
> +  case EfiPciIoAttributeOperationSupported:
> +    if (Result == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    *Result = PciIoDevice->Supports;
> +    return EFI_SUCCESS;
> +
> +  case EfiPciIoAttributeOperationSet:
> +    Status = PciIoDevice->PciIo.Attributes (
> +                                  &(PciIoDevice->PciIo),
> +                                  EfiPciIoAttributeOperationEnable,
> +                                  Attributes,
> +                                  NULL
> +                                  );
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    Status = PciIoDevice->PciIo.Attributes (
> +                                  &(PciIoDevice->PciIo),
> +                                  EfiPciIoAttributeOperationDisable,
> +                                  (~Attributes) & (PciIoDevice->Supports),
> +                                  NULL
> +                                  );
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    return EFI_SUCCESS;
> +
> +  case EfiPciIoAttributeOperationEnable:
> +  case EfiPciIoAttributeOperationDisable:
> +    break;
> +
> +  default:
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  //
> +  // Just a trick for ENABLE attribute
> +  // EFI_PCI_DEVICE_ENABLE is not defined in UEFI spec, which is the
> internal usage.
> +  // So, this logic doesn't conform to UEFI spec, which should be removed.
> +  // But this trick logic is still kept for some binary drivers that depend on it.
> +  //
> +  if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {
> +    Attributes &= (PciIoDevice->Supports);
> +
> +    //
> +    // Raise the EFI_P_PC_ENABLE Status code
> +    //
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_PROGRESS_CODE,
> +      EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  //
> +  // Check VGA and VGA16, they can not be set at the same time
> +  //
> +  if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO |
> EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) != 0) {
> +    if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
> EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // If no attributes can be supported, then return.
> +  // Otherwise, set the attributes that it can support.
> +  //
> +  Supports = (PciIoDevice->Supports) & Attributes;
> +  if (Supports != Attributes) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // For Root Bridge, just call RootBridgeIo to set attributes;
> +  //
> +  if (PciIoDevice->Parent == NULL) {
> +    Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes,
> Operation);
> +    return Status;
> +  }
> +
> +  Command       = 0;
> +  BridgeControl = 0;
> +
> +  //
> +  // For PPB & P2C, set relevant attribute bits
> +  //
> +  if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE
> (&PciIoDevice->Pci)) {
> +
> +    if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO |
> EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
> +      BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;
> +    }
> +
> +    if ((Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) != 0) {
> +      BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;
> +    }
> +
> +    if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO |
> EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
> +      Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
> +    }
> +
> +    if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 |
> EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
> +      BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA_16;
> +    }
> +
> +  } else {
> +    //
> +    // Do with the attributes on VGA
> +    // Only for VGA's legacy resource, we just can enable once.
> +    //
> +    if ((Attributes &
> +        (EFI_PCI_IO_ATTRIBUTE_VGA_IO    |
> +         EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
> +         EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY)) != 0) {
> +      //
> +      // Check if a VGA has been enabled before enabling a new one
> +      //
> +      if (Operation == EfiPciIoAttributeOperationEnable) {
> +        //
> +        // Check if there have been an active VGA device on the same Host
> Bridge
> +        //
> +        Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo-
> >ParentHandle);
> +        if (Temp != NULL && Temp != PciIoDevice) {
> +          //
> +          // An active VGA has been detected, so can not enable another
> +          //
> +          return EFI_UNSUPPORTED;
> +        }
> +      }
> +    }
> +
> +    //
> +    // Do with the attributes on GFX
> +    //
> +    if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO |
> EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
> +
> +      if (Operation == EfiPciIoAttributeOperationEnable) {
> +        //
> +        // Check if snoop can be enabled in current configuration
> +        //
> +        Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);
> +
> +        if (EFI_ERROR (Status)) {
> +
> +          //
> +          // Enable operation is forbidden, so mask the bit in attributes
> +          // so as to keep consistent with the actual Status
> +          //
> +          // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
> +          //
> +          //
> +          //
> +          return EFI_UNSUPPORTED;
> +
> +        }
> +      }
> +
> +      //
> +      // It can be supported, so get ready to set the bit
> +      //
> +      Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
> +    }
> +  }
> +
> +  if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
> +    Command |= EFI_PCI_COMMAND_IO_SPACE;
> +  }
> +
> +  if ((Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) != 0) {
> +    Command |= EFI_PCI_COMMAND_MEMORY_SPACE;
> +  }
> +
> +  if ((Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) != 0) {
> +    Command |= EFI_PCI_COMMAND_BUS_MASTER;
> +  }
> +  //
> +  // The upstream bridge should be also set to relevant attribute
> +  // expect for IO, Mem and BusMaster
> +  //
> +  UpStreamAttributes = Attributes &
> +                       (~(EFI_PCI_IO_ATTRIBUTE_IO     |
> +                          EFI_PCI_IO_ATTRIBUTE_MEMORY |
> +                          EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
> +                          )
> +                        );
> +  UpStreamBridge = PciIoDevice->Parent;
> +
> +  if (Operation == EfiPciIoAttributeOperationEnable) {
> +    //
> +    // Enable relevant attributes to command register and bridge control
> register
> +    //
> +    Status = PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, Command);
> +    if (BridgeControl != 0) {
> +      Status = PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice,
> BridgeControl);
> +    }
> +
> +    PciIoDevice->Attributes |= Attributes;
> +
> +    //
> +    // Enable attributes of the upstream bridge
> +    //
> +    Status = UpStreamBridge->PciIo.Attributes (
> +                                    &(UpStreamBridge->PciIo),
> +                                    EfiPciIoAttributeOperationEnable,
> +                                    UpStreamAttributes,
> +                                    NULL
> +                                    );
> +  } else {
> +
> +    //
> +    // Disable relevant attributes to command register and bridge control
> register
> +    //
> +    Status = PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, Command);
> +    if (BridgeControl != 0) {
> +      Status = PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice,
> BridgeControl);
> +    }
> +
> +    PciIoDevice->Attributes &= (~Attributes);
> +    Status = EFI_SUCCESS;
> +
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +      EFI_ERROR_CODE | EFI_ERROR_MINOR,
> +      EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
> +      PciIoDevice->DevicePath
> +      );
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Retrieve the AddrTranslationOffset from RootBridgeIo for the
> +  specified range.
> +
> +  @param RootBridgeIo    Root Bridge IO instance.
> +  @param AddrRangeMin    The base address of the MMIO.
> +  @param AddrLen         The length of the MMIO.
> +
> +  @retval The AddrTranslationOffset from RootBridgeIo for the
> +          specified range, or (UINT64) -1 if the range is not
> +          found in RootBridgeIo.
> +**/
> +UINT64
> +GetMmioAddressTranslationOffset (
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *RootBridgeIo,
> +  UINT64                            AddrRangeMin,
> +  UINT64                            AddrLen
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
> +
> +  Status = RootBridgeIo->Configuration (
> +                           RootBridgeIo,
> +                           (VOID **) &Configuration
> +                           );
> +  if (EFI_ERROR (Status)) {
> +    return (UINT64) -1;
> +  }
> +
> +  // According to UEFI 2.7,
> EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration()
> +  // returns host address instead of device address, while
> AddrTranslationOffset
> +  // is not zero, and device address = host address + AddrTranslationOffset,
> so
> +  // we convert host address to device address for range compare.
> +  while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
> +    if ((Configuration->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
> +        (Configuration->AddrRangeMin + Configuration-
> >AddrTranslationOffset <= AddrRangeMin) &&
> +        (Configuration->AddrRangeMin + Configuration->AddrLen +
> Configuration->AddrTranslationOffset >= AddrRangeMin + AddrLen)
> +        ) {
> +      return Configuration->AddrTranslationOffset;
> +    }
> +    Configuration++;
> +  }
> +
> +  //
> +  // The resource occupied by BAR should be in the range reported by
> RootBridge.
> +  //
> +  ASSERT (FALSE);
> +  return (UINT64) -1;
> +}
> +
> +/**
> +  Gets the attributes that this PCI controller supports setting on a BAR using
> +  SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for resource range. The legal range for this
> field is 0..5.
> +  @param  Supports              A pointer to the mask of attributes that this PCI
> controller supports
> +                                setting for this BAR with SetBarAttributes().
> +  @param  Resources             A pointer to the resource descriptors that
> describe the current
> +                                configuration of this BAR of the PCI controller.
> +
> +  @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that
> the PCI
> +                                controller supports are returned in Supports. If Resources
> +                                is not NULL, then the resource descriptors that the PCI
> +                                controller is currently using are returned in Resources.
> +  @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough resources
> available to allocate
> +                                Resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoGetBarAttributes (
> +  IN EFI_PCI_IO_PROTOCOL             * This,
> +  IN  UINT8                          BarIndex,
> +  OUT UINT64                         *Supports, OPTIONAL
> +  OUT VOID                           **Resources OPTIONAL
> +  )
> +{
> +  PCI_IO_DEVICE                     *PciIoDevice;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
> +  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  if (Supports == NULL && Resources == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice-
> >PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // This driver does not support modifications to the WRITE_COMBINE or
> +  // CACHED attributes for BAR ranges.
> +  //
> +  if (Supports != NULL) {
> +    *Supports = PciIoDevice->Supports &
> EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED &
> EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
> +  }
> +
> +  if (Resources != NULL) {
> +    Descriptor = AllocateZeroPool (sizeof
> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof
> (EFI_ACPI_END_TAG_DESCRIPTOR));
> +    if (Descriptor == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    *Resources   = Descriptor;
> +
> +    Descriptor->Desc         = ACPI_ADDRESS_SPACE_DESCRIPTOR;
> +    Descriptor->Len          = (UINT16) (sizeof
> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
> +    Descriptor->AddrRangeMin = PciIoDevice-
> >PciBar[BarIndex].BaseAddress;
> +    Descriptor->AddrLen      = PciIoDevice->PciBar[BarIndex].Length;
> +    Descriptor->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
> +
> +    switch (PciIoDevice->PciBar[BarIndex].BarType) {
> +    case PciBarTypeIo16:
> +    case PciBarTypeIo32:
> +      //
> +      // Io
> +      //
> +      Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
> +      break;
> +
> +    case PciBarTypePMem32:
> +      //
> +      // prefetchable
> +      //
> +      Descriptor->SpecificFlag =
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E;
> +      //
> +      // Fall through
> +      //
> +    case PciBarTypeMem32:
> +      //
> +      // Mem
> +      //
> +      Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      //
> +      // 32 bit
> +      //
> +      Descriptor->AddrSpaceGranularity = 32;
> +      break;
> +
> +    case PciBarTypePMem64:
> +      //
> +      // prefetchable
> +      //
> +      Descriptor->SpecificFlag =
> EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABL
> E;
> +      //
> +      // Fall through
> +      //
> +    case PciBarTypeMem64:
> +      //
> +      // Mem
> +      //
> +      Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
> +      //
> +      // 64 bit
> +      //
> +      Descriptor->AddrSpaceGranularity = 64;
> +      break;
> +
> +    default:
> +      break;
> +    }
> +
> +    //
> +    // put the checksum
> +    //
> +    End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
> +    End->Desc     = ACPI_END_TAG_DESCRIPTOR;
> +    End->Checksum = 0;
> +
> +    //
> +    // Get the Address Translation Offset
> +    //
> +    if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
> +      Descriptor->AddrTranslationOffset = GetMmioAddressTranslationOffset
> (
> +                                            PciIoDevice->PciRootBridgeIo,
> +                                            Descriptor->AddrRangeMin,
> +                                            Descriptor->AddrLen
> +                                            );
> +      if (Descriptor->AddrTranslationOffset == (UINT64) -1) {
> +        FreePool (Descriptor);
> +        return EFI_UNSUPPORTED;
> +      }
> +    }
> +
> +    // According to UEFI spec 2.7, we need return host address for
> +    // PciIo->GetBarAttributes, and host address = device address -
> translation.
> +    Descriptor->AddrRangeMin -= Descriptor->AddrTranslationOffset;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Sets the attributes for a range of a BAR on a PCI controller.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Attributes            The mask of attributes to set for the resource
> range specified by
> +                                BarIndex, Offset, and Length.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for resource range. The legal range for this
> field is 0..5.
> +  @param  Offset                A pointer to the BAR relative base address of the
> resource range to be
> +                                modified by the attributes specified by Attributes.
> +  @param  Length                A pointer to the length of the resource range to
> be modified by the
> +                                attributes specified by Attributes.
> +
> +  @retval EFI_SUCCESS           The set of attributes specified by Attributes for
> the resource
> +                                range specified by BarIndex, Offset, and Length were
> +                                set on the PCI controller, and the actual resource range is
> returned
> +                                in Offset and Length.
> +  @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set
> the attributes on the
> +                                resource range specified by BarIndex, Offset, and
> +                                Length.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoSetBarAttributes (
> +  IN EFI_PCI_IO_PROTOCOL              *This,
> +  IN     UINT64                       Attributes,
> +  IN     UINT8                        BarIndex,
> +  IN OUT UINT64                       *Offset,
> +  IN OUT UINT64                       *Length
> +  )
> +{
> +  EFI_STATUS    Status;
> +  PCI_IO_DEVICE *PciIoDevice;
> +  UINT64        NonRelativeOffset;
> +  UINT64        Supports;
> +
> +  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
> +
> +  //
> +  // Make sure Offset and Length are not NULL
> +  //
> +  if (Offset == NULL || Length == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  //
> +  // This driver does not support setting the WRITE_COMBINE or the
> CACHED attributes.
> +  // If Attributes is not 0, then return EFI_UNSUPPORTED.
> +  //
> +  Supports = PciIoDevice->Supports &
> EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED &
> EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
> +
> +  if (Attributes != (Attributes & Supports)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  //
> +  // Attributes must be supported.  Make sure the BAR range described by
> BarIndex, Offset, and
> +  // Length are valid for this PCI device.
> +  //
> +  NonRelativeOffset = *Offset;
> +  Status = PciIoVerifyBarAccess (
> +            PciIoDevice,
> +            BarIndex,
> +            PciBarTypeMem,
> +            EfiPciIoWidthUint8,
> +            (UINT32) *Length,
> +            &NonRelativeOffset
> +            );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Test whether two Pci devices has same parent bridge.
> +
> +  @param PciDevice1  The first pci device for testing.
> +  @param PciDevice2  The second pci device for testing.
> +
> +  @retval TRUE       Two Pci device has the same parent bridge.
> +  @retval FALSE      Two Pci device has not the same parent bridge.
> +
> +**/
> +BOOLEAN
> +PciDevicesOnTheSamePath (
> +  IN PCI_IO_DEVICE        *PciDevice1,
> +  IN PCI_IO_DEVICE        *PciDevice2
> +  )
> +{
> +  BOOLEAN   Existed1;
> +  BOOLEAN   Existed2;
> +
> +  if (PciDevice1->Parent == PciDevice2->Parent) {
> +    return TRUE;
> +  }
> +
> +  Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);
> +  Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);
> +
> +  return (BOOLEAN) (Existed1 || Existed2);
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.h
> new file mode 100644
> index 0000000000..c00516ee6a
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciIo.h
> @@ -0,0 +1,660 @@
> +/** @file
> +  EFI PCI IO protocol functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_IO_PROTOCOL_H_
> +#define _EFI_PCI_IO_PROTOCOL_H_
> +
> +/**
> +  Initializes a PCI I/O Instance.
> +
> +  @param PciIoDevice    Pci device instance.
> +
> +**/
> +VOID
> +InitializePciIoInstance (
> +  IN PCI_IO_DEVICE               *PciIoDevice
> +  );
> +
> +/**
> +  Verifies access to a PCI Base Address Register (BAR).
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param BarIndex     The BAR index of the standard PCI Configuration
> header to use as the
> +                      base address for the memory or I/O operation to perform.
> +  @param Type         Operation type could be memory or I/O.
> +  @param Width        Signifies the width of the memory or I/O operations.
> +  @param Count        The number of memory or I/O operations to perform.
> +  @param Offset       The offset within the PCI configuration space for the PCI
> controller.
> +
> +  @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
> +  @retval EFI_SUCCESS           Successfully verified.
> +
> +**/
> +EFI_STATUS
> +PciIoVerifyBarAccess (
> +  IN PCI_IO_DEVICE                   *PciIoDevice,
> +  IN UINT8                           BarIndex,
> +  IN PCI_BAR_TYPE                    Type,
> +  IN IN EFI_PCI_IO_PROTOCOL_WIDTH    Width,
> +  IN IN UINTN                        Count,
> +  IN UINT64                          *Offset
> +  );
> +
> +/**
> +  Verifies access to a PCI Configuration Header.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Width        Signifies the width of the memory or I/O operations.
> +  @param Count        The number of memory or I/O operations to perform.
> +  @param Offset       The offset within the PCI configuration space for the PCI
> controller.
> +
> +  @retval EFI_INVALID_PARAMETER  Invalid Width
> +  @retval EFI_UNSUPPORTED        Offset overflowed.
> +  @retval EFI_SUCCESS            Successfully verified.
> +
> +**/
> +EFI_STATUS
> +PciIoVerifyConfigAccess (
> +  IN PCI_IO_DEVICE              *PciIoDevice,
> +  IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN UINTN                      Count,
> +  IN UINT64                     *Offset
> +  );
> +
> +/**
> +  Reads from the memory space of a PCI controller. Returns either when the
> polling exit criteria is
> +  satisfied or after a defined duration.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory operation.
> +  @param  Mask                  Mask used for the polling criteria.
> +  @param  Value                 The comparison value used for the polling exit
> criteria.
> +  @param  Delay                 The number of 100 ns units to poll.
> +  @param  Result                Pointer to the last value read from the memory
> location.
> +
> +  @retval EFI_SUCCESS           The last data returned from the access matched
> the poll exit criteria.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this
> PCI controller.
> +  @retval EFI_TIMEOUT           Delay expired before a match occurred.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoPollMem (
> +  IN  EFI_PCI_IO_PROTOCOL        *This,
> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN  UINT8                      BarIndex,
> +  IN  UINT64                     Offset,
> +  IN  UINT64                     Mask,
> +  IN  UINT64                     Value,
> +  IN  UINT64                     Delay,
> +  OUT UINT64                     *Result
> +  );
> +
> +/**
> +  Reads from the memory space of a PCI controller. Returns either when the
> polling exit criteria is
> +  satisfied or after a defined duration.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory operation.
> +  @param  Mask                  Mask used for the polling criteria.
> +  @param  Value                 The comparison value used for the polling exit
> criteria.
> +  @param  Delay                 The number of 100 ns units to poll.
> +  @param  Result                Pointer to the last value read from the memory
> location.
> +
> +  @retval EFI_SUCCESS           The last data returned from the access matched
> the poll exit criteria.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       Offset is not valid for the BarIndex of this
> PCI controller.
> +  @retval EFI_TIMEOUT           Delay expired before a match occurred.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoPollIo (
> +  IN  EFI_PCI_IO_PROTOCOL        *This,
> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN  UINT8                      BarIndex,
> +  IN  UINT64                     Offset,
> +  IN  UINT64                     Mask,
> +  IN  UINT64                     Value,
> +  IN  UINT64                     Delay,
> +  OUT UINT64                     *Result
> +  );
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoMemRead (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  );
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoMemWrite (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  );
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoIoRead (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  );
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in the PCI memory or
> I/O space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory or I/O
> operations.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for the memory or I/O operation to perform.
> +  @param  Offset                The offset within the selected BAR to start the
> memory or I/O operation.
> +  @param  Count                 The number of memory or I/O operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI BAR specified by BarIndex.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoIoWrite (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT8                      BarIndex,
> +  IN     UINT64                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  );
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in PCI configuration
> space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory operations.
> +  @param  Offset                The offset within the PCI configuration space for
> the PCI controller.
> +  @param  Count                 The number of PCI configuration operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI configuration header of the PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoConfigRead (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT32                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  );
> +
> +/**
> +  Enable a PCI driver to access PCI controller registers in PCI configuration
> space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory operations.
> +  @param  Offset                The offset within the PCI configuration space for
> the PCI controller.
> +  @param  Count                 The number of PCI configuration operations to
> perform.
> +  @param  Buffer                For read operations, the destination buffer to
> store the results. For write
> +                                operations, the source buffer to write data from.
> +
> +
> +  @retval EFI_SUCCESS           The data was read from or written to the PCI
> controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by Offset,
> Width, and Count is not
> +                                valid for the PCI configuration header of the PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoConfigWrite (
> +  IN     EFI_PCI_IO_PROTOCOL        *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
> +  IN     UINT32                     Offset,
> +  IN     UINTN                      Count,
> +  IN OUT VOID                       *Buffer
> +  );
> +
> +/**
> +  Enables a PCI driver to copy one region of PCI memory space to another
> region of PCI
> +  memory space.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Width                 Signifies the width of the memory operations.
> +  @param  DestBarIndex          The BAR index in the standard PCI
> Configuration header to use as the
> +                                base address for the memory operation to perform.
> +  @param  DestOffset            The destination offset within the BAR specified
> by DestBarIndex to
> +                                start the memory writes for the copy operation.
> +  @param  SrcBarIndex           The BAR index in the standard PCI Configuration
> header to use as the
> +                                base address for the memory operation to perform.
> +  @param  SrcOffset             The source offset within the BAR specified by
> SrcBarIndex to start
> +                                the memory reads for the copy operation.
> +  @param  Count                 The number of memory operations to perform.
> Bytes moved is Width
> +                                size * Count, starting at DestOffset and SrcOffset.
> +
> +  @retval EFI_SUCCESS           The data was copied from one memory region
> to another memory region.
> +  @retval EFI_UNSUPPORTED       DestBarIndex not valid for this PCI
> controller.
> +  @retval EFI_UNSUPPORTED       SrcBarIndex not valid for this PCI controller.
> +  @retval EFI_UNSUPPORTED       The address range specified by DestOffset,
> Width, and Count
> +                                is not valid for the PCI BAR specified by DestBarIndex.
> +  @retval EFI_UNSUPPORTED       The address range specified by SrcOffset,
> Width, and Count is
> +                                not valid for the PCI BAR specified by SrcBarIndex.
> +  @retval EFI_INVALID_PARAMETER Width is invalid.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoCopyMem (
> +  IN EFI_PCI_IO_PROTOCOL              *This,
> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
> +  IN     UINT8                        DestBarIndex,
> +  IN     UINT64                       DestOffset,
> +  IN     UINT8                        SrcBarIndex,
> +  IN     UINT64                       SrcOffset,
> +  IN     UINTN                        Count
> +  );
> +
> +/**
> +  Provides the PCI controller-specific addresses needed to access system
> memory.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Operation             Indicates if the bus master is going to read or
> write to system memory.
> +  @param  HostAddress           The system memory address to map to the PCI
> controller.
> +  @param  NumberOfBytes         On input the number of bytes to map. On
> output the number of bytes
> +                                that were mapped.
> +  @param  DeviceAddress         The resulting map address for the bus master
> PCI controller to use to
> +                                access the hosts HostAddress.
> +  @param  Mapping               A resulting value to pass to Unmap().
> +
> +  @retval EFI_SUCCESS           The range was mapped for the returned
> NumberOfBytes.
> +  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a
> common buffer.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +  @retval EFI_OUT_OF_RESOURCES  The request could not be completed
> due to a lack of resources.
> +  @retval EFI_DEVICE_ERROR      The system hardware could not map the
> requested address.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoMap (
> +  IN     EFI_PCI_IO_PROTOCOL            *This,
> +  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
> +  IN     VOID                           *HostAddress,
> +  IN OUT UINTN                          *NumberOfBytes,
> +  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
> +  OUT    VOID                           **Mapping
> +  );
> +
> +/**
> +  Completes the Map() operation and releases any corresponding
> resources.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Mapping               The mapping value returned from Map().
> +
> +  @retval EFI_SUCCESS           The range was unmapped.
> +  @retval EFI_DEVICE_ERROR      The data was not committed to the target
> system memory.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoUnmap (
> +  IN  EFI_PCI_IO_PROTOCOL  *This,
> +  IN  VOID                 *Mapping
> +  );
> +
> +/**
> +  Allocates pages that are suitable for an
> EfiPciIoOperationBusMasterCommonBuffer
> +  or EfiPciOperationBusMasterCommonBuffer64 mapping.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Type                  This parameter is not used and must be ignored.
> +  @param  MemoryType            The type of memory to allocate,
> EfiBootServicesData or
> +                                EfiRuntimeServicesData.
> +  @param  Pages                 The number of pages to allocate.
> +  @param  HostAddress           A pointer to store the base system memory
> address of the
> +                                allocated range.
> +  @param  Attributes            The requested bit mask of attributes for the
> allocated range.
> +
> +  @retval EFI_SUCCESS           The requested memory pages were allocated.
> +  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal
> attribute bits are
> +                                MEMORY_WRITE_COMBINE, MEMORY_CACHED and
> DUAL_ADDRESS_CYCLE.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be
> allocated.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoAllocateBuffer (
> +  IN  EFI_PCI_IO_PROTOCOL   *This,
> +  IN  EFI_ALLOCATE_TYPE     Type,
> +  IN  EFI_MEMORY_TYPE       MemoryType,
> +  IN  UINTN                 Pages,
> +  OUT VOID                  **HostAddress,
> +  IN  UINT64                Attributes
> +  );
> +
> +/**
> +  Frees memory that was allocated with AllocateBuffer().
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Pages                 The number of pages to free.
> +  @param  HostAddress           The base system memory address of the
> allocated range.
> +
> +  @retval EFI_SUCCESS           The requested memory pages were freed.
> +  @retval EFI_INVALID_PARAMETER The memory range specified by
> HostAddress and Pages
> +                                was not allocated with AllocateBuffer().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoFreeBuffer (
> +  IN  EFI_PCI_IO_PROTOCOL   *This,
> +  IN  UINTN                 Pages,
> +  IN  VOID                  *HostAddress
> +  );
> +
> +/**
> +  Flushes all PCI posted write transactions from a PCI host bridge to system
> memory.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +
> +  @retval EFI_SUCCESS           The PCI posted write transactions were flushed
> from the PCI host
> +                                bridge to system memory.
> +  @retval EFI_DEVICE_ERROR      The PCI posted write transactions were not
> flushed from the PCI
> +                                host bridge due to a hardware error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoFlush (
> +  IN  EFI_PCI_IO_PROTOCOL  *This
> +  );
> +
> +/**
> +  Retrieves this PCI controller's current PCI bus number, device number, and
> function number.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  SegmentNumber         The PCI controller's current PCI segment
> number.
> +  @param  BusNumber             The PCI controller's current PCI bus number.
> +  @param  DeviceNumber          The PCI controller's current PCI device
> number.
> +  @param  FunctionNumber        The PCI controller's current PCI function
> number.
> +
> +  @retval EFI_SUCCESS           The PCI controller location was returned.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoGetLocation (
> +  IN  EFI_PCI_IO_PROTOCOL  *This,
> +  OUT UINTN                *Segment,
> +  OUT UINTN                *Bus,
> +  OUT UINTN                *Device,
> +  OUT UINTN                *Function
> +  );
> +
> +/**
> +  Check BAR type for PCI resource.
> +
> +  @param PciIoDevice   PCI device instance.
> +  @param BarIndex      The BAR index of the standard PCI Configuration
> header to use as the
> +                       base address for the memory or I/O operation to perform.
> +  @param BarType       Memory or I/O.
> +
> +  @retval TRUE         Pci device's bar type is same with input BarType.
> +  @retval TRUE         Pci device's bar type is not same with input BarType.
> +
> +**/
> +BOOLEAN
> +CheckBarType (
> +  IN PCI_IO_DEVICE          *PciIoDevice,
> +  IN UINT8                  BarIndex,
> +  IN PCI_BAR_TYPE           BarType
> +  );
> +
> +/**
> +  Set/Disable new attributes to a Root Bridge.
> +
> +  @param  PciIoDevice  Pci device instance.
> +  @param  Attributes   New attribute want to be set.
> +  @param  Operation    Set or Disable.
> +
> +  @retval  EFI_UNSUPPORTED  If root bridge does not support change
> attribute.
> +  @retval  EFI_SUCCESS      Successfully set new attributes.
> +
> +**/
> +EFI_STATUS
> +ModifyRootBridgeAttributes (
> +  IN  PCI_IO_DEVICE                            *PciIoDevice,
> +  IN  UINT64                                   Attributes,
> +  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
> +  );
> +
> +/**
> +  Check whether this device can be enable/disable to snoop.
> +
> +  @param PciIoDevice  Pci device instance.
> +  @param Operation    Enable/Disable.
> +
> +  @retval EFI_UNSUPPORTED  Pci device is not GFX device or not support
> snoop.
> +  @retval EFI_SUCCESS      Snoop can be supported.
> +
> +**/
> +EFI_STATUS
> +SupportPaletteSnoopAttributes (
> +  IN PCI_IO_DEVICE                            *PciIoDevice,
> +  IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
> +  );
> +
> +/**
> +  Performs an operation on the attributes that this PCI controller supports.
> The operations include
> +  getting the set of supported attributes, retrieving the current attributes,
> setting the current
> +  attributes, enabling attributes, and disabling attributes.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Operation             The operation to perform on the attributes for
> this PCI controller.
> +  @param  Attributes            The mask of attributes that are used for Set,
> Enable, and Disable
> +                                operations.
> +  @param  Result                A pointer to the result mask of attributes that are
> returned for the Get
> +                                and Supported operations.
> +
> +  @retval EFI_SUCCESS           The operation on the PCI controller's attributes
> was completed.
> +  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> +  @retval EFI_UNSUPPORTED       one or more of the bits set in
> +                                Attributes are not supported by this PCI controller or one of
> +                                its parent bridges when Operation is Set, Enable or Disable.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoAttributes (
> +  IN EFI_PCI_IO_PROTOCOL                       * This,
> +  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
> +  IN  UINT64                                   Attributes,
> +  OUT UINT64                                   *Result OPTIONAL
> +  );
> +
> +/**
> +  Gets the attributes that this PCI controller supports setting on a BAR using
> +  SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for resource range. The legal range for this
> field is 0..5.
> +  @param  Supports              A pointer to the mask of attributes that this PCI
> controller supports
> +                                setting for this BAR with SetBarAttributes().
> +  @param  Resources             A pointer to the resource descriptors that
> describe the current
> +                                configuration of this BAR of the PCI controller.
> +
> +  @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that
> the PCI
> +                                controller supports are returned in Supports. If Resources
> +                                is not NULL, then the resource descriptors that the PCI
> +                                controller is currently using are returned in Resources.
> +  @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough resources
> available to allocate
> +                                Resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoGetBarAttributes (
> +  IN EFI_PCI_IO_PROTOCOL             * This,
> +  IN  UINT8                          BarIndex,
> +  OUT UINT64                         *Supports, OPTIONAL
> +  OUT VOID                           **Resources OPTIONAL
> +  );
> +
> +/**
> +  Sets the attributes for a range of a BAR on a PCI controller.
> +
> +  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param  Attributes            The mask of attributes to set for the resource
> range specified by
> +                                BarIndex, Offset, and Length.
> +  @param  BarIndex              The BAR index of the standard PCI Configuration
> header to use as the
> +                                base address for resource range. The legal range for this
> field is 0..5.
> +  @param  Offset                A pointer to the BAR relative base address of the
> resource range to be
> +                                modified by the attributes specified by Attributes.
> +  @param  Length                A pointer to the length of the resource range to
> be modified by the
> +                                attributes specified by Attributes.
> +
> +  @retval EFI_SUCCESS           The set of attributes specified by Attributes for
> the resource
> +                                range specified by BarIndex, Offset, and Length were
> +                                set on the PCI controller, and the actual resource range is
> returned
> +                                in Offset and Length.
> +  @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
> +  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
> +  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set
> the attributes on the
> +                                resource range specified by BarIndex, Offset, and
> +                                Length.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciIoSetBarAttributes (
> +  IN EFI_PCI_IO_PROTOCOL              *This,
> +  IN     UINT64                       Attributes,
> +  IN     UINT8                        BarIndex,
> +  IN OUT UINT64                       *Offset,
> +  IN OUT UINT64                       *Length
> +  );
> +
> +
> +/**
> +  Test whether two Pci devices has same parent bridge.
> +
> +  @param PciDevice1  The first pci device for testing.
> +  @param PciDevice2  The second pci device for testing.
> +
> +  @retval TRUE       Two Pci device has the same parent bridge.
> +  @retval FALSE      Two Pci device has not the same parent bridge.
> +
> +**/
> +BOOLEAN
> +PciDevicesOnTheSamePath (
> +  IN PCI_IO_DEVICE        *PciDevice1,
> +  IN PCI_IO_DEVICE        *PciDevice2
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.c
> new file mode 100644
> index 0000000000..2b76100740
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.c
> @@ -0,0 +1,1809 @@
> +/** @file
> +  Internal library implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +CHAR16 *mBarTypeStr[] = {
> +  L"Unknow",
> +  L"  Io16",
> +  L"  Io32",
> +  L" Mem32",
> +  L"PMem32",
> +  L" Mem64",
> +  L"PMem64",
> +  L" OpRom",
> +  L"    Io",
> +  L"   Mem",
> +  L"Unknow"
> +  };
> +
> +/**
> +  Retrieve the max bus number that is assigned to the Root Bridge hierarchy.
> +  It can support the case that there are multiple bus ranges.
> +
> +  @param  Bridge           Bridge device instance.
> +
> +  @retval                  The max bus number that is assigned to this Root Bridge
> hierarchy.
> +
> +**/
> +UINT16
> +PciGetMaxBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge
> +  )
> +{
> +  PCI_IO_DEVICE                      *RootBridge;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *BusNumberRanges;
> +  UINT64                             MaxNumberInRange;
> +
> +  //
> +  // Get PCI Root Bridge device
> +  //
> +  RootBridge = Bridge;
> +  while (RootBridge->Parent != NULL) {
> +    RootBridge = RootBridge->Parent;
> +  }
> +  MaxNumberInRange = 0;
> +  //
> +  // Iterate the bus number ranges to get max PCI bus number
> +  //
> +  BusNumberRanges = RootBridge->BusNumberRanges;
> +  while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
> +    MaxNumberInRange = BusNumberRanges->AddrRangeMin +
> BusNumberRanges->AddrLen - 1;
> +    BusNumberRanges++;
> +  }
> +  return (UINT16) MaxNumberInRange;
> +}
> +
> +/**
> +  Retrieve the PCI Card device BAR information via PciIo interface.
> +
> +  @param PciIoDevice        PCI Card device instance.
> +
> +**/
> +VOID
> +GetBackPcCardBar (
> +  IN  PCI_IO_DEVICE                  *PciIoDevice
> +  )
> +{
> +  UINT32  Address;
> +
> +  if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +    return;
> +  }
> +
> +  //
> +  // Read PciBar information from the bar register
> +  //
> +  if (!gFullEnumeration) {
> +    Address = 0;
> +    PciIoDevice->PciIo.Pci.Read (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoWidthUint32,
> +                             PCI_CARD_MEMORY_BASE_0,
> +                             1,
> +                             &Address
> +                             );
> +
> +    (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress  = (UINT64) (Address);
> +    (PciIoDevice->PciBar)[P2C_MEM_1].Length       = 0x2000000;
> +    (PciIoDevice->PciBar)[P2C_MEM_1].BarType      = PciBarTypeMem32;
> +
> +    Address = 0;
> +    PciIoDevice->PciIo.Pci.Read (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoWidthUint32,
> +                             PCI_CARD_MEMORY_BASE_1,
> +                             1,
> +                             &Address
> +                             );
> +    (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress  = (UINT64) (Address);
> +    (PciIoDevice->PciBar)[P2C_MEM_2].Length       = 0x2000000;
> +    (PciIoDevice->PciBar)[P2C_MEM_2].BarType      = PciBarTypePMem32;
> +
> +    Address = 0;
> +    PciIoDevice->PciIo.Pci.Read (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoWidthUint32,
> +                             PCI_CARD_IO_BASE_0_LOWER,
> +                             1,
> +                             &Address
> +                             );
> +    (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
> +    (PciIoDevice->PciBar)[P2C_IO_1].Length      = 0x100;
> +    (PciIoDevice->PciBar)[P2C_IO_1].BarType     = PciBarTypeIo16;
> +
> +    Address = 0;
> +    PciIoDevice->PciIo.Pci.Read (
> +                             &(PciIoDevice->PciIo),
> +                             EfiPciIoWidthUint32,
> +                             PCI_CARD_IO_BASE_1_LOWER,
> +                             1,
> +                             &Address
> +                             );
> +    (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
> +    (PciIoDevice->PciBar)[P2C_IO_2].Length      = 0x100;
> +    (PciIoDevice->PciBar)[P2C_IO_2].BarType     = PciBarTypeIo16;
> +
> +  }
> +
> +  if (gPciHotPlugInit != NULL && FeaturePcdGet
> (PcdPciBusHotplugDeviceSupport)) {
> +    GetResourcePaddingForHpb (PciIoDevice);
> +  }
> +}
> +
> +/**
> +  Remove rejected pci device from specific root bridge
> +  handle.
> +
> +  @param RootBridgeHandle  Specific parent root bridge handle.
> +  @param Bridge            Bridge device instance.
> +
> +**/
> +VOID
> +RemoveRejectedPciDevices (
> +  IN EFI_HANDLE        RootBridgeHandle,
> +  IN PCI_IO_DEVICE     *Bridge
> +  )
> +{
> +  PCI_IO_DEVICE   *Temp;
> +  LIST_ENTRY      *CurrentLink;
> +  LIST_ENTRY      *LastLink;
> +
> +  if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +    return;
> +  }
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (IS_PCI_BRIDGE (&Temp->Pci)) {
> +      //
> +      // Remove rejected devices recusively
> +      //
> +      RemoveRejectedPciDevices (RootBridgeHandle, Temp);
> +    } else {
> +      //
> +      // Skip rejection for all PPBs, while detect rejection for others
> +      //
> +      if (IsPciDeviceRejected (Temp)) {
> +
> +        //
> +        // For P2C, remove all devices on it
> +        //
> +        if (!IsListEmpty (&Temp->ChildList)) {
> +          RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
> +        }
> +
> +        //
> +        // Finally remove itself
> +        //
> +        LastLink = CurrentLink->BackLink;
> +        RemoveEntryList (CurrentLink);
> +        FreePciDevice (Temp);
> +
> +        CurrentLink = LastLink;
> +      }
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +}
> +
> +/**
> +  Dump the resourc map of the bridge device.
> +
> +  @param[in] BridgeResource   Resource descriptor of the bridge device.
> +**/
> +VOID
> +DumpBridgeResource (
> +  IN PCI_RESOURCE_NODE     *BridgeResource
> +  )
> +{
> +  LIST_ENTRY               *Link;
> +  PCI_RESOURCE_NODE        *Resource;
> +  PCI_BAR                  *Bar;
> +
> +  if ((BridgeResource != NULL) && (BridgeResource->Length != 0)) {
> +    DEBUG ((
> +      EFI_D_INFO, "Type = %s; Base = 0x%lx;\tLength = 0x%lx;\tAlignment =
> 0x%lx\n",
> +      mBarTypeStr[MIN (BridgeResource->ResType, PciBarTypeMaxType)],
> +      BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress,
> +      BridgeResource->Length, BridgeResource->Alignment
> +      ));
> +    for ( Link = GetFirstNode (&BridgeResource->ChildList)
> +        ; !IsNull (&BridgeResource->ChildList, Link)
> +        ; Link = GetNextNode (&BridgeResource->ChildList, Link)
> +        ) {
> +      Resource = RESOURCE_NODE_FROM_LINK (Link);
> +      if (Resource->ResourceUsage == PciResUsageTypical) {
> +        Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource-
> >PciDev->PciBar;
> +        DEBUG ((
> +          EFI_D_INFO, "   Base = 0x%lx;\tLength = 0x%lx;\tAlignment =
> 0x%lx;\tOwner = %s [%02x|%02x|%02x:",
> +          Bar[Resource->Bar].BaseAddress, Resource->Length, Resource-
> >Alignment,
> +          IS_PCI_BRIDGE (&Resource->PciDev->Pci)     ? L"PPB" :
> +          IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" :
> +                                                       L"PCI",
> +          Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,
> +          Resource->PciDev->FunctionNumber
> +          ));
> +
> +        if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) &&
> !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) ||
> +            (IS_PCI_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar <
> PPB_IO_RANGE)) ||
> +            (IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar
> < P2C_MEM_1))
> +            ) {
> +          //
> +          // The resource requirement comes from the device itself.
> +          //
> +          DEBUG ((EFI_D_INFO, "%02x]", Bar[Resource->Bar].Offset));
> +        } else {
> +          //
> +          // The resource requirement comes from the subordinate devices.
> +          //
> +          DEBUG ((EFI_D_INFO, "**]"));
> +        }
> +      } else {
> +        DEBUG ((EFI_D_INFO, "   Base = Padding;\tLength = 0x%lx;\tAlignment
> = 0x%lx", Resource->Length, Resource->Alignment));
> +      }
> +      if (BridgeResource->ResType != Resource->ResType) {
> +        DEBUG ((EFI_D_INFO, "; Type = %s", mBarTypeStr[MIN (Resource-
> >ResType, PciBarTypeMaxType)]));
> +      }
> +      DEBUG ((EFI_D_INFO, "\n"));
> +    }
> +  }
> +}
> +
> +/**
> +  Find the corresponding resource node for the Device in child list of
> BridgeResource.
> +
> +  @param[in]  Device          Pointer to PCI_IO_DEVICE.
> +  @param[in]  BridgeResource  Pointer to PCI_RESOURCE_NODE.
> +  @param[out] DeviceResources Pointer to a buffer to receive resources for
> the Device.
> +
> +  @return Count of the resource descriptors returned.
> +**/
> +UINTN
> +FindResourceNode (
> +  IN  PCI_IO_DEVICE     *Device,
> +  IN  PCI_RESOURCE_NODE *BridgeResource,
> +  OUT PCI_RESOURCE_NODE **DeviceResources OPTIONAL
> +  )
> +{
> +  LIST_ENTRY               *Link;
> +  PCI_RESOURCE_NODE        *Resource;
> +  UINTN                    Count;
> +
> +  Count = 0;
> +  for ( Link = BridgeResource->ChildList.ForwardLink
> +      ; Link != &BridgeResource->ChildList
> +      ; Link = Link->ForwardLink
> +      ) {
> +    Resource = RESOURCE_NODE_FROM_LINK (Link);
> +    if (Resource->PciDev == Device) {
> +      if (DeviceResources != NULL) {
> +        DeviceResources[Count] = Resource;
> +      }
> +      Count++;
> +    }
> +  }
> +
> +  return Count;
> +}
> +
> +/**
> +  Dump the resource map of all the devices under Bridge.
> +
> +  @param[in] Bridge        Bridge device instance.
> +  @param[in] Resources     Resource descriptors for the bridge device.
> +  @param[in] ResourceCount Count of resource descriptors.
> +**/
> +VOID
> +DumpResourceMap (
> +  IN PCI_IO_DEVICE     *Bridge,
> +  IN PCI_RESOURCE_NODE **Resources,
> +  IN UINTN             ResourceCount
> +  )
> +{
> +  EFI_STATUS           Status;
> +  LIST_ENTRY           *Link;
> +  PCI_IO_DEVICE        *Device;
> +  UINTN                Index;
> +  CHAR16               *Str;
> +  PCI_RESOURCE_NODE    **ChildResources;
> +  UINTN                ChildResourceCount;
> +
> +  DEBUG ((EFI_D_INFO, "PciBus: Resource Map for "));
> +
> +  Status = gBS->OpenProtocol (
> +                  Bridge->Handle,
> +                  &gEfiPciRootBridgeIoProtocolGuid,
> +                  NULL,
> +                  NULL,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      EFI_D_INFO, "Bridge [%02x|%02x|%02x]\n",
> +      Bridge->BusNumber, Bridge->DeviceNumber, Bridge->FunctionNumber
> +      ));
> +  } else {
> +    Str = ConvertDevicePathToText (
> +            DevicePathFromHandle (Bridge->Handle),
> +            FALSE,
> +            FALSE
> +            );
> +    DEBUG ((EFI_D_INFO, "Root Bridge %s\n", Str != NULL ? Str : L""));
> +    if (Str != NULL) {
> +      FreePool (Str);
> +    }
> +  }
> +
> +  for (Index = 0; Index < ResourceCount; Index++) {
> +    DumpBridgeResource (Resources[Index]);
> +  }
> +  DEBUG ((EFI_D_INFO, "\n"));
> +
> +  for ( Link = Bridge->ChildList.ForwardLink
> +      ; Link != &Bridge->ChildList
> +      ; Link = Link->ForwardLink
> +      ) {
> +    Device = PCI_IO_DEVICE_FROM_LINK (Link);
> +    if (IS_PCI_BRIDGE (&Device->Pci)) {
> +
> +      ChildResourceCount = 0;
> +      for (Index = 0; Index < ResourceCount; Index++) {
> +        ChildResourceCount += FindResourceNode (Device, Resources[Index],
> NULL);
> +      }
> +      ChildResources = AllocatePool (sizeof (PCI_RESOURCE_NODE *) *
> ChildResourceCount);
> +      ASSERT (ChildResources != NULL);
> +      ChildResourceCount = 0;
> +      for (Index = 0; Index < ResourceCount; Index++) {
> +        ChildResourceCount += FindResourceNode (Device, Resources[Index],
> &ChildResources[ChildResourceCount]);
> +      }
> +
> +      DumpResourceMap (Device, ChildResources, ChildResourceCount);
> +      FreePool (ChildResources);
> +    }
> +  }
> +}
> +
> +/**
> +  Adjust the Devices' BAR size to minimum value if it support Resizeable BAR
> capability.
> +
> +  @param RootBridgeDev  Pointer to instance of PCI_IO_DEVICE..
> +
> +  @return TRUE if BAR size is adjusted.
> +
> +**/
> +BOOLEAN
> +AdjustPciDeviceBarSize (
> +  IN PCI_IO_DEVICE *RootBridgeDev
> +  )
> +{
> +  PCI_IO_DEVICE     *PciIoDevice;
> +  LIST_ENTRY        *CurrentLink;
> +  BOOLEAN           Adjusted;
> +  UINTN             Offset;
> +  UINTN             BarIndex;
> +
> +  Adjusted    = FALSE;
> +  CurrentLink = RootBridgeDev->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &RootBridgeDev->ChildList)
> {
> +    PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +      if (AdjustPciDeviceBarSize (PciIoDevice)) {
> +        Adjusted = TRUE;
> +      }
> +    } else {
> +      if (PciIoDevice->ResizableBarOffset != 0) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "PciBus: [%02x|%02x|%02x] Adjust Pci Device Bar Size\n",
> +          PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice-
> >FunctionNumber
> +          ));
> +        PciProgramResizableBar (PciIoDevice, PciResizableBarMin);
> +        //
> +        // Start to parse the bars
> +        //
> +        for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex <
> PCI_MAX_BAR; BarIndex++) {
> +          Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
> +        }
> +        Adjusted = TRUE;
> +        DEBUG_CODE (DumpPciBars (PciIoDevice););
> +      }
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return Adjusted;
> +}
> +
> +/**
> +  Submits the I/O and memory resource requirements for the specified PCI
> Host Bridge.
> +
> +  @param PciResAlloc  Point to protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_SUCCESS           Successfully finished resource allocation.
> +  @retval EFI_NOT_FOUND         Cannot get root bridge instance.
> +  @retval EFI_OUT_OF_RESOURCES  Platform failed to program the
> resources if no hot plug supported.
> +  @retval other                 Some error occurred when allocating resources for
> the PCI Host Bridge.
> +
> +  @note   Feature flag PcdPciBusHotplugDeviceSupport determine whether
> need support hotplug.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeResourceAllocator (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  )
> +{
> +  PCI_IO_DEVICE                                  *RootBridgeDev;
> +  EFI_HANDLE                                     RootBridgeHandle;
> +  VOID                                           *AcpiConfig;
> +  EFI_STATUS                                     Status;
> +  UINT64                                         IoBase;
> +  UINT64                                         Mem32Base;
> +  UINT64                                         PMem32Base;
> +  UINT64                                         Mem64Base;
> +  UINT64                                         PMem64Base;
> +  UINT64                                         IoResStatus;
> +  UINT64                                         Mem32ResStatus;
> +  UINT64                                         PMem32ResStatus;
> +  UINT64                                         Mem64ResStatus;
> +  UINT64                                         PMem64ResStatus;
> +  UINT32                                         MaxOptionRomSize;
> +  PCI_RESOURCE_NODE                              *IoBridge;
> +  PCI_RESOURCE_NODE                              *Mem32Bridge;
> +  PCI_RESOURCE_NODE                              *PMem32Bridge;
> +  PCI_RESOURCE_NODE                              *Mem64Bridge;
> +  PCI_RESOURCE_NODE                              *PMem64Bridge;
> +  PCI_RESOURCE_NODE                              IoPool;
> +  PCI_RESOURCE_NODE                              Mem32Pool;
> +  PCI_RESOURCE_NODE                              PMem32Pool;
> +  PCI_RESOURCE_NODE                              Mem64Pool;
> +  PCI_RESOURCE_NODE                              PMem64Pool;
> +  EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD
> HandleExtendedData;
> +  EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD
> AllocFailExtendedData;
> +  BOOLEAN                                        ResizableBarNeedAdjust;
> +  BOOLEAN                                        ResizableBarAdjusted;
> +
> +  ResizableBarNeedAdjust = PcdGetBool (PcdPcieResizableBarSupport);
> +
> +  //
> +  // It may try several times if the resource allocation fails
> +  //
> +  while (TRUE) {
> +    //
> +    // Initialize resource pool
> +    //
> +    InitializeResourcePool (&IoPool, PciBarTypeIo16);
> +    InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
> +    InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
> +    InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
> +    InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
> +
> +    RootBridgeDev     = NULL;
> +    RootBridgeHandle  = 0;
> +
> +    while (PciResAlloc->GetNextRootBridge (PciResAlloc,
> &RootBridgeHandle) == EFI_SUCCESS) {
> +      //
> +      // Get Root Bridge Device by handle
> +      //
> +      RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
> +
> +      if (RootBridgeDev == NULL) {
> +        return EFI_NOT_FOUND;
> +      }
> +
> +      //
> +      // Create the entire system resource map from the information collected
> by
> +      // enumerator. Several resource tree was created
> +      //
> +
> +      //
> +      // If non-standard PCI Bridge I/O window alignment is supported,
> +      // set I/O aligment to minimum possible alignment for root bridge.
> +      //
> +      IoBridge = CreateResourceNode (
> +                   RootBridgeDev,
> +                   0,
> +                   FeaturePcdGet (PcdPciBridgeIoAlignmentProbe) ? 0x1FF: 0xFFF,
> +                   RB_IO_RANGE,
> +                   PciBarTypeIo16,
> +                   PciResUsageTypical
> +                   );
> +
> +      Mem32Bridge = CreateResourceNode (
> +                      RootBridgeDev,
> +                      0,
> +                      0xFFFFF,
> +                      RB_MEM32_RANGE,
> +                      PciBarTypeMem32,
> +                      PciResUsageTypical
> +                      );
> +
> +      PMem32Bridge = CreateResourceNode (
> +                       RootBridgeDev,
> +                       0,
> +                       0xFFFFF,
> +                       RB_PMEM32_RANGE,
> +                       PciBarTypePMem32,
> +                       PciResUsageTypical
> +                       );
> +
> +      Mem64Bridge = CreateResourceNode (
> +                      RootBridgeDev,
> +                      0,
> +                      0xFFFFF,
> +                      RB_MEM64_RANGE,
> +                      PciBarTypeMem64,
> +                      PciResUsageTypical
> +                      );
> +
> +      PMem64Bridge = CreateResourceNode (
> +                       RootBridgeDev,
> +                       0,
> +                       0xFFFFF,
> +                       RB_PMEM64_RANGE,
> +                       PciBarTypePMem64,
> +                       PciResUsageTypical
> +                       );
> +
> +      //
> +      // Get the max ROM size that the root bridge can process
> +      // Insert to resource map so that there will be dedicate MEM32 resource
> range for Option ROM.
> +      // All devices' Option ROM share the same MEM32 resource.
> +      //
> +      MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
> +      if (MaxOptionRomSize != 0) {
> +        RootBridgeDev->PciBar[0].BarType   = PciBarTypeOpRom;
> +        RootBridgeDev->PciBar[0].Length    = MaxOptionRomSize;
> +        RootBridgeDev->PciBar[0].Alignment = MaxOptionRomSize - 1;
> +        GetResourceFromDevice (RootBridgeDev, IoBridge, Mem32Bridge,
> PMem32Bridge, Mem64Bridge, PMem64Bridge);
> +      }
> +
> +      //
> +      // Create resourcemap by going through all the devices subject to this
> root bridge
> +      //
> +      CreateResourceMap (
> +        RootBridgeDev,
> +        IoBridge,
> +        Mem32Bridge,
> +        PMem32Bridge,
> +        Mem64Bridge,
> +        PMem64Bridge
> +        );
> +
> +      //
> +      // Based on the all the resource tree, construct ACPI resource node to
> +      // submit the resource aperture to pci host bridge protocol
> +      //
> +      Status = ConstructAcpiResourceRequestor (
> +                 RootBridgeDev,
> +                 IoBridge,
> +                 Mem32Bridge,
> +                 PMem32Bridge,
> +                 Mem64Bridge,
> +                 PMem64Bridge,
> +                 &AcpiConfig
> +                 );
> +
> +      //
> +      // Insert these resource nodes into the database
> +      //
> +      InsertResourceNode (&IoPool, IoBridge);
> +      InsertResourceNode (&Mem32Pool, Mem32Bridge);
> +      InsertResourceNode (&PMem32Pool, PMem32Bridge);
> +      InsertResourceNode (&Mem64Pool, Mem64Bridge);
> +      InsertResourceNode (&PMem64Pool, PMem64Bridge);
> +
> +      if (Status == EFI_SUCCESS) {
> +        //
> +        // Submit the resource requirement
> +        //
> +        Status = PciResAlloc->SubmitResources (
> +                                PciResAlloc,
> +                                RootBridgeDev->Handle,
> +                                AcpiConfig
> +                                );
> +        //
> +        // If SubmitResources returns error, PciBus isn't able to start.
> +        // It's a fatal error so assertion is added.
> +        //
> +        DEBUG ((EFI_D_INFO, "PciBus: HostBridge->SubmitResources() - %r\n",
> Status));
> +        ASSERT_EFI_ERROR (Status);
> +      }
> +
> +      //
> +      // Free acpi resource node
> +      //
> +      if (AcpiConfig != NULL) {
> +        FreePool (AcpiConfig);
> +      }
> +
> +      if (EFI_ERROR (Status)) {
> +        //
> +        // Destroy all the resource tree
> +        //
> +        DestroyResourceTree (&IoPool);
> +        DestroyResourceTree (&Mem32Pool);
> +        DestroyResourceTree (&PMem32Pool);
> +        DestroyResourceTree (&Mem64Pool);
> +        DestroyResourceTree (&PMem64Pool);
> +        return Status;
> +      }
> +    }
> +    //
> +    // End while, at least one Root Bridge should be found.
> +    //
> +    ASSERT (RootBridgeDev != NULL);
> +
> +    //
> +    // Notify platform to start to program the resource
> +    //
> +    Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
> +    DEBUG ((EFI_D_INFO, "PciBus: HostBridge-
> >NotifyPhase(AllocateResources) - %r\n", Status));
> +    if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +      //
> +      // If Hot Plug is not supported
> +      //
> +      if (EFI_ERROR (Status)) {
> +        //
> +        // Allocation failed, then return
> +        //
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +      //
> +      // Allocation succeed.
> +      // Get host bridge handle for status report, and then skip the main while
> +      //
> +      HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo-
> >ParentHandle;
> +
> +      break;
> +
> +    } else {
> +      //
> +      // If Hot Plug is supported
> +      //
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // Allocation succeed, then continue the following
> +        //
> +        break;
> +      }
> +
> +      //
> +      // If the resource allocation is unsuccessful, free resources on bridge
> +      //
> +
> +      RootBridgeDev     = NULL;
> +      RootBridgeHandle  = 0;
> +
> +      IoResStatus       = EFI_RESOURCE_SATISFIED;
> +      Mem32ResStatus    = EFI_RESOURCE_SATISFIED;
> +      PMem32ResStatus   = EFI_RESOURCE_SATISFIED;
> +      Mem64ResStatus    = EFI_RESOURCE_SATISFIED;
> +      PMem64ResStatus   = EFI_RESOURCE_SATISFIED;
> +
> +      while (PciResAlloc->GetNextRootBridge (PciResAlloc,
> &RootBridgeHandle) == EFI_SUCCESS) {
> +        //
> +        // Get RootBridg Device by handle
> +        //
> +        RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
> +        if (RootBridgeDev == NULL) {
> +          return EFI_NOT_FOUND;
> +        }
> +
> +        //
> +        // Get host bridge handle for status report
> +        //
> +        HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo-
> >ParentHandle;
> +
> +        //
> +        // Get acpi resource node for all the resource types
> +        //
> +        AcpiConfig = NULL;
> +
> +        Status = PciResAlloc->GetProposedResources (
> +                                PciResAlloc,
> +                                RootBridgeDev->Handle,
> +                                &AcpiConfig
> +                                );
> +
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +
> +        if (AcpiConfig != NULL) {
> +          //
> +          // Adjust resource allocation policy for each RB
> +          //
> +          GetResourceAllocationStatus (
> +            AcpiConfig,
> +            &IoResStatus,
> +            &Mem32ResStatus,
> +            &PMem32ResStatus,
> +            &Mem64ResStatus,
> +            &PMem64ResStatus
> +            );
> +          FreePool (AcpiConfig);
> +        }
> +      }
> +      //
> +      // End while
> +      //
> +
> +      //
> +      // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
> +      //
> +      //
> +      // It is very difficult to follow the spec here
> +      // Device path , Bar index can not be get here
> +      //
> +      ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
> +
> +      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> +            EFI_PROGRESS_CODE,
> +            EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
> +            (VOID *) &AllocFailExtendedData,
> +            sizeof (AllocFailExtendedData)
> +            );
> +
> +     //
> +     // When resource conflict happens, adjust the BAR size first.
> +     // Only when adjusting BAR size doesn't help or BAR size cannot be
> adjusted,
> +     // reject the device who requests largest resource that causes conflict.
> +     //
> +      ResizableBarAdjusted = FALSE;
> +      if (ResizableBarNeedAdjust) {
> +        ResizableBarAdjusted = AdjustPciDeviceBarSize (RootBridgeDev);
> +        ResizableBarNeedAdjust = FALSE;
> +      }
> +      if (!ResizableBarAdjusted) {
> +        Status = PciHostBridgeAdjustAllocation (
> +                  &IoPool,
> +                  &Mem32Pool,
> +                  &PMem32Pool,
> +                  &Mem64Pool,
> +                  &PMem64Pool,
> +                  IoResStatus,
> +                  Mem32ResStatus,
> +                  PMem32ResStatus,
> +                  Mem64ResStatus,
> +                  PMem64ResStatus
> +                  );
> +      }
> +      //
> +      // Destroy all the resource tree
> +      //
> +      DestroyResourceTree (&IoPool);
> +      DestroyResourceTree (&Mem32Pool);
> +      DestroyResourceTree (&PMem32Pool);
> +      DestroyResourceTree (&Mem64Pool);
> +      DestroyResourceTree (&PMem64Pool);
> +
> +      NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
> +
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +    }
> +  }
> +  //
> +  // End main while
> +  //
> +
> +  //
> +  // Raise the EFI_IOB_PCI_RES_ALLOC status code
> +  //
> +  REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> +        EFI_PROGRESS_CODE,
> +        EFI_IO_BUS_PCI | EFI_IOB_PCI_RES_ALLOC,
> +        (VOID *) &HandleExtendedData,
> +        sizeof (HandleExtendedData)
> +        );
> +
> +  //
> +  // Notify pci bus driver starts to program the resource
> +  //
> +  Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  RootBridgeDev     = NULL;
> +
> +  RootBridgeHandle  = 0;
> +
> +  while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle)
> == EFI_SUCCESS) {
> +    //
> +    // Get RootBridg Device by handle
> +    //
> +    RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
> +
> +    if (RootBridgeDev == NULL) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    //
> +    // Get acpi resource node for all the resource types
> +    //
> +    AcpiConfig = NULL;
> +    Status = PciResAlloc->GetProposedResources (
> +                            PciResAlloc,
> +                            RootBridgeDev->Handle,
> +                            &AcpiConfig
> +                            );
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    //
> +    // Get the resource base by interpreting acpi resource node
> +    //
> +    //
> +    GetResourceBase (
> +      AcpiConfig,
> +      &IoBase,
> +      &Mem32Base,
> +      &PMem32Base,
> +      &Mem64Base,
> +      &PMem64Base
> +      );
> +
> +    //
> +    // Create the entire system resource map from the information collected
> by
> +    // enumerator. Several resource tree was created
> +    //
> +    FindResourceNode (RootBridgeDev, &IoPool, &IoBridge);
> +    FindResourceNode (RootBridgeDev, &Mem32Pool, &Mem32Bridge);
> +    FindResourceNode (RootBridgeDev, &PMem32Pool, &PMem32Bridge);
> +    FindResourceNode (RootBridgeDev, &Mem64Pool, &Mem64Bridge);
> +    FindResourceNode (RootBridgeDev, &PMem64Pool, &PMem64Bridge);
> +
> +    ASSERT (IoBridge     != NULL);
> +    ASSERT (Mem32Bridge  != NULL);
> +    ASSERT (PMem32Bridge != NULL);
> +    ASSERT (Mem64Bridge  != NULL);
> +    ASSERT (PMem64Bridge != NULL);
> +
> +    //
> +    // Program IO resources
> +    //
> +    ProgramResource (
> +      IoBase,
> +      IoBridge
> +      );
> +
> +    //
> +    // Program Mem32 resources
> +    //
> +    ProgramResource (
> +      Mem32Base,
> +      Mem32Bridge
> +      );
> +
> +    //
> +    // Program PMem32 resources
> +    //
> +    ProgramResource (
> +      PMem32Base,
> +      PMem32Bridge
> +      );
> +
> +    //
> +    // Program Mem64 resources
> +    //
> +    ProgramResource (
> +      Mem64Base,
> +      Mem64Bridge
> +      );
> +
> +    //
> +    // Program PMem64 resources
> +    //
> +    ProgramResource (
> +      PMem64Base,
> +      PMem64Bridge
> +      );
> +
> +    //
> +    // Process Option ROM for this root bridge after all BARs are
> programmed.
> +    // The PPB's MEM32 RANGE BAR is re-programmed to the Option ROM
> BAR Base in order to
> +    // shadow the Option ROM of the devices under the PPB.
> +    // After the shadow, Option ROM BAR decoding is turned off and the
> PPB's MEM32 RANGE
> +    // BAR is restored back to the original value.
> +    // The original value is programmed by ProgramResource() above.
> +    //
> +    DEBUG ((
> +      DEBUG_INFO, "Process Option ROM: BAR Base/Length = %lx/%lx\n",
> +      RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev-
> >PciBar[0].Length
> +      ));
> +    ProcessOptionRom (RootBridgeDev, RootBridgeDev-
> >PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length);
> +
> +    IoBridge    ->PciDev->PciBar[IoBridge    ->Bar].BaseAddress = IoBase;
> +    Mem32Bridge ->PciDev->PciBar[Mem32Bridge ->Bar].BaseAddress =
> Mem32Base;
> +    PMem32Bridge->PciDev->PciBar[PMem32Bridge->Bar].BaseAddress =
> PMem32Base;
> +    Mem64Bridge ->PciDev->PciBar[Mem64Bridge ->Bar].BaseAddress =
> Mem64Base;
> +    PMem64Bridge->PciDev->PciBar[PMem64Bridge->Bar].BaseAddress =
> PMem64Base;
> +
> +    //
> +    // Dump the resource map for current root bridge
> +    //
> +    DEBUG_CODE (
> +      PCI_RESOURCE_NODE *Resources[5];
> +      Resources[0] = IoBridge;
> +      Resources[1] = Mem32Bridge;
> +      Resources[2] = PMem32Bridge;
> +      Resources[3] = Mem64Bridge;
> +      Resources[4] = PMem64Bridge;
> +      DumpResourceMap (RootBridgeDev, Resources, ARRAY_SIZE
> (Resources));
> +    );
> +
> +    FreePool (AcpiConfig);
> +  }
> +
> +  //
> +  // Destroy all the resource tree
> +  //
> +  DestroyResourceTree (&IoPool);
> +  DestroyResourceTree (&Mem32Pool);
> +  DestroyResourceTree (&PMem32Pool);
> +  DestroyResourceTree (&Mem64Pool);
> +  DestroyResourceTree (&PMem64Pool);
> +
> +  //
> +  // Notify the resource allocation phase is to end
> +  //
> +  Status = NotifyPhase (PciResAlloc,
> EfiPciHostBridgeEndResourceAllocation);
> +
> +  return Status;
> +}
> +
> +/**
> +  Allocate NumberOfBuses buses and return the next available PCI bus
> number.
> +
> +  @param  Bridge           Bridge device instance.
> +  @param  StartBusNumber   Current available PCI bus number.
> +  @param  NumberOfBuses    Number of buses enumerated below the
> StartBusNumber.
> +  @param  NextBusNumber    Next available PCI bus number.
> +
> +  @retval EFI_SUCCESS           Available bus number resource is enough. Next
> available PCI bus number
> +                                is returned in NextBusNumber.
> +  @retval EFI_OUT_OF_RESOURCES  Available bus number resource is not
> enough for allocation.
> +
> +**/
> +EFI_STATUS
> +PciAllocateBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber,
> +  IN UINT8                              NumberOfBuses,
> +  OUT UINT8                             *NextBusNumber
> +  )
> +{
> +  PCI_IO_DEVICE                      *RootBridge;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *BusNumberRanges;
> +  UINT8                              NextNumber;
> +  UINT64                             MaxNumberInRange;
> +
> +  //
> +  // Get PCI Root Bridge device
> +  //
> +  RootBridge = Bridge;
> +  while (RootBridge->Parent != NULL) {
> +    RootBridge = RootBridge->Parent;
> +  }
> +
> +  //
> +  // Get next available PCI bus number
> +  //
> +  BusNumberRanges = RootBridge->BusNumberRanges;
> +  while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
> +    MaxNumberInRange = BusNumberRanges->AddrRangeMin +
> BusNumberRanges->AddrLen - 1;
> +    if (StartBusNumber >= BusNumberRanges->AddrRangeMin &&
> StartBusNumber <=  MaxNumberInRange) {
> +      NextNumber = (UINT8)(StartBusNumber + NumberOfBuses);
> +      while (NextNumber > MaxNumberInRange) {
> +        ++BusNumberRanges;
> +        if (BusNumberRanges->Desc == ACPI_END_TAG_DESCRIPTOR) {
> +          return EFI_OUT_OF_RESOURCES;
> +        }
> +        NextNumber = (UINT8)(NextNumber + (BusNumberRanges-
> >AddrRangeMin - (MaxNumberInRange + 1)));
> +        MaxNumberInRange = BusNumberRanges->AddrRangeMin +
> BusNumberRanges->AddrLen - 1;
> +      }
> +      *NextBusNumber = NextNumber;
> +      return EFI_SUCCESS;
> +    }
> +    BusNumberRanges++;
> +  }
> +  return EFI_OUT_OF_RESOURCES;
> +}
> +
> +/**
> +  Scan pci bus and assign bus number to the given PCI bus system.
> +
> +  @param  Bridge           Bridge device instance.
> +  @param  StartBusNumber   start point.
> +  @param  SubBusNumber     Point to sub bus number.
> +  @param  PaddedBusRange   Customized bus number.
> +
> +  @retval EFI_SUCCESS      Successfully scanned and assigned bus number.
> +  @retval other            Some error occurred when scanning pci bus.
> +
> +  @note   Feature flag PcdPciBusHotplugDeviceSupport determine whether
> need support hotplug.
> +
> +**/
> +EFI_STATUS
> +PciScanBus (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber,
> +  OUT UINT8                             *SubBusNumber,
> +  OUT UINT8                             *PaddedBusRange
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  PCI_TYPE00                        Pci;
> +  UINT8                             Device;
> +  UINT8                             Func;
> +  UINT64                            Address;
> +  UINT8                             SecondBus;
> +  UINT8                             PaddedSubBus;
> +  UINT16                            Register;
> +  UINTN                             HpIndex;
> +  PCI_IO_DEVICE                     *PciDevice;
> +  EFI_EVENT                         Event;
> +  EFI_HPC_STATE                     State;
> +  UINT64                            PciAddress;
> +  EFI_HPC_PADDING_ATTRIBUTES        Attributes;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *NextDescriptors;
> +  UINT16                            BusRange;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;
> +  BOOLEAN                           BusPadding;
> +  UINT32                            TempReservedBusNum;
> +
> +  PciRootBridgeIo = Bridge->PciRootBridgeIo;
> +  SecondBus       = 0;
> +  Register        = 0;
> +  State           = 0;
> +  Attributes      = (EFI_HPC_PADDING_ATTRIBUTES) 0;
> +  BusRange        = 0;
> +  BusPadding      = FALSE;
> +  PciDevice       = NULL;
> +  PciAddress      = 0;
> +
> +  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
> +    TempReservedBusNum = 0;
> +    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
> +
> +      //
> +      // Check to see whether a pci device is present
> +      //
> +      Status = PciDevicePresent (
> +                PciRootBridgeIo,
> +                &Pci,
> +                StartBusNumber,
> +                Device,
> +                Func
> +                );
> +
> +      if (EFI_ERROR (Status) && Func == 0) {
> +        //
> +        // go to next device if there is no Function 0
> +        //
> +        break;
> +      }
> +
> +      if (EFI_ERROR (Status)) {
> +        continue;
> +      }
> +
> +      //
> +      // Get the PCI device information
> +      //
> +      Status = PciSearchDevice (
> +                Bridge,
> +                &Pci,
> +                StartBusNumber,
> +                Device,
> +                Func,
> +                &PciDevice
> +                );
> +
> +      if (EFI_ERROR (Status)) {
> +        continue;
> +      }
> +
> +      PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
> +
> +      if (!IS_PCI_BRIDGE (&Pci)) {
> +        //
> +        // PCI bridges will be called later
> +        // Here just need for PCI device or PCI to cardbus controller
> +        // EfiPciBeforeChildBusEnumeration for PCI Device Node
> +        //
> +        PreprocessController (
> +            PciDevice,
> +            PciDevice->BusNumber,
> +            PciDevice->DeviceNumber,
> +            PciDevice->FunctionNumber,
> +            EfiPciBeforeChildBusEnumeration
> +            );
> +      }
> +
> +      if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +        //
> +        // For Pci Hotplug controller devcie only
> +        //
> +        if (gPciHotPlugInit != NULL) {
> +          //
> +          // Check if it is a Hotplug PCI controller
> +          //
> +          if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
> +            gPciRootHpcData[HpIndex].Found = TRUE;
> +
> +            if (!gPciRootHpcData[HpIndex].Initialized) {
> +
> +              Status = CreateEventForHpc (HpIndex, &Event);
> +
> +              ASSERT (!EFI_ERROR (Status));
> +
> +              Status = gPciHotPlugInit->InitializeRootHpc (
> +                                          gPciHotPlugInit,
> +                                          gPciRootHpcPool[HpIndex].HpcDevicePath,
> +                                          PciAddress,
> +                                          Event,
> +                                          &State
> +                                          );
> +
> +              PreprocessController (
> +                PciDevice,
> +                PciDevice->BusNumber,
> +                PciDevice->DeviceNumber,
> +                PciDevice->FunctionNumber,
> +                EfiPciBeforeChildBusEnumeration
> +              );
> +            }
> +          }
> +        }
> +      }
> +
> +      if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
> +        //
> +        // For PPB
> +        //
> +        if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +          //
> +          // If Hot Plug is supported,
> +          // Get the bridge information
> +          //
> +          BusPadding = FALSE;
> +          if (gPciHotPlugInit != NULL) {
> +
> +            if (IsPciHotPlugBus (PciDevice)) {
> +
> +              //
> +              // If it is initialized, get the padded bus range
> +              //
> +              Status = gPciHotPlugInit->GetResourcePadding (
> +                                          gPciHotPlugInit,
> +                                          PciDevice->DevicePath,
> +                                          PciAddress,
> +                                          &State,
> +                                          (VOID **) &Descriptors,
> +                                          &Attributes
> +                                          );
> +
> +              if (EFI_ERROR (Status)) {
> +                return Status;
> +              }
> +
> +              BusRange = 0;
> +              NextDescriptors = Descriptors;
> +              Status = PciGetBusRange (
> +                        &NextDescriptors,
> +                        NULL,
> +                        NULL,
> +                        &BusRange
> +                        );
> +
> +              FreePool (Descriptors);
> +
> +              if (!EFI_ERROR (Status)) {
> +                BusPadding = TRUE;
> +              } else if (Status != EFI_NOT_FOUND) {
> +                //
> +                // EFI_NOT_FOUND is not a real error. It indicates no bus number
> padding requested.
> +                //
> +                return Status;
> +              }
> +            }
> +          }
> +        }
> +
> +        Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1,
> SubBusNumber);
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +        SecondBus = *SubBusNumber;
> +
> +        Register  = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
> +        Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func,
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
> +
> +        Status = PciRootBridgeIo->Pci.Write (
> +                                        PciRootBridgeIo,
> +                                        EfiPciWidthUint16,
> +                                        Address,
> +                                        1,
> +                                        &Register
> +                                        );
> +
> +
> +        //
> +        // If it is PPB, resursively search down this bridge
> +        //
> +        if (IS_PCI_BRIDGE (&Pci)) {
> +
> +          //
> +          // Temporarily initialize SubBusNumber to maximum bus number to
> ensure the
> +          // PCI configuration transaction to go through any PPB
> +          //
> +          Register  = PciGetMaxBusNumber (Bridge);
> +          Address   = EFI_PCI_ADDRESS (StartBusNumber, Device, Func,
> PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
> +          Status = PciRootBridgeIo->Pci.Write (
> +                                          PciRootBridgeIo,
> +                                          EfiPciWidthUint8,
> +                                          Address,
> +                                          1,
> +                                          &Register
> +                                          );
> +
> +          //
> +          // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
> +          //
> +          PreprocessController (
> +            PciDevice,
> +            PciDevice->BusNumber,
> +            PciDevice->DeviceNumber,
> +            PciDevice->FunctionNumber,
> +            EfiPciBeforeChildBusEnumeration
> +            );
> +
> +          Status = PciScanBus (
> +                    PciDevice,
> +                    SecondBus,
> +                    SubBusNumber,
> +                    PaddedBusRange
> +                    );
> +          if (EFI_ERROR (Status)) {
> +            return Status;
> +          }
> +        }
> +
> +        if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
> +          //
> +          // Ensure the device is enabled and initialized
> +          //
> +          if ((Attributes == EfiPaddingPciRootBridge) &&
> +              (State & EFI_HPC_STATE_ENABLED) != 0    &&
> +              (State & EFI_HPC_STATE_INITIALIZED) != 0) {
> +            *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +
> *PaddedBusRange);
> +          } else {
> +            //
> +            // Reserve the larger one between the actual occupied bus number
> and padded bus number
> +            //
> +            Status = PciAllocateBusNumber (PciDevice, SecondBus, (UINT8)
> (BusRange), &PaddedSubBus);
> +            if (EFI_ERROR (Status)) {
> +              return Status;
> +            }
> +            *SubBusNumber = MAX (PaddedSubBus, *SubBusNumber);
> +          }
> +        }
> +
> +        //
> +        // Set the current maximum bus number under the PPB
> +        //
> +        Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func,
> PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
> +
> +        Status = PciRootBridgeIo->Pci.Write (
> +                                        PciRootBridgeIo,
> +                                        EfiPciWidthUint8,
> +                                        Address,
> +                                        1,
> +                                        SubBusNumber
> +                                        );
> +      } else  {
> +        //
> +        // It is device. Check PCI IOV for Bus reservation
> +        // Go through each function, just reserve the MAX ReservedBusNum
> for one device
> +        //
> +        if (PcdGetBool (PcdSrIovSupport) && PciDevice->SrIovCapabilityOffset
> != 0) {
> +          if (TempReservedBusNum < PciDevice->ReservedBusNum) {
> +
> +            Status = PciAllocateBusNumber (PciDevice, *SubBusNumber, (UINT8)
> (PciDevice->ReservedBusNum - TempReservedBusNum), SubBusNumber);
> +            if (EFI_ERROR (Status)) {
> +              return Status;
> +            }
> +            TempReservedBusNum = PciDevice->ReservedBusNum;
> +
> +            if (Func == 0) {
> +              DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n",
> *SubBusNumber));
> +            } else {
> +              DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x
> (Update)\n", *SubBusNumber));
> +            }
> +          }
> +        }
> +      }
> +
> +      if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
> +
> +        //
> +        // Skip sub functions, this is not a multi function device
> +        //
> +
> +        Func = PCI_MAX_FUNC;
> +      }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Process Option Rom on the specified root bridge.
> +
> +  @param Bridge  Pci root bridge device instance.
> +
> +  @retval EFI_SUCCESS   Success process.
> +  @retval other         Some error occurred when processing Option Rom on
> the root bridge.
> +
> +**/
> +EFI_STATUS
> +PciRootBridgeP2CProcess (
> +  IN PCI_IO_DEVICE *Bridge
> +  )
> +{
> +  LIST_ENTRY      *CurrentLink;
> +  PCI_IO_DEVICE   *Temp;
> +  EFI_HPC_STATE   State;
> +  UINT64          PciAddress;
> +  EFI_STATUS      Status;
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
> +
> +      if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet
> (PcdPciBusHotplugDeviceSupport)) {
> +
> +        //
> +        // Raise the EFI_IOB_PCI_HPC_INIT status code
> +        //
> +        REPORT_STATUS_CODE_WITH_DEVICE_PATH (
> +          EFI_PROGRESS_CODE,
> +          EFI_IO_BUS_PCI | EFI_IOB_PCI_HPC_INIT,
> +          Temp->DevicePath
> +          );
> +
> +        PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp-
> >DeviceNumber, Temp->FunctionNumber, 0);
> +        Status = gPciHotPlugInit->InitializeRootHpc (
> +                                    gPciHotPlugInit,
> +                                    Temp->DevicePath,
> +                                    PciAddress,
> +                                    NULL,
> +                                    &State
> +                                    );
> +
> +        if (!EFI_ERROR (Status)) {
> +          Status = PciBridgeEnumerator (Temp);
> +
> +          if (EFI_ERROR (Status)) {
> +            return Status;
> +          }
> +        }
> +
> +        CurrentLink = CurrentLink->ForwardLink;
> +        continue;
> +
> +      }
> +    }
> +
> +    if (!IsListEmpty (&Temp->ChildList)) {
> +      Status = PciRootBridgeP2CProcess (Temp);
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Process Option Rom on the specified host bridge.
> +
> +  @param PciResAlloc    Pointer to instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_SUCCESS   Success process.
> +  @retval EFI_NOT_FOUND Can not find the root bridge instance.
> +  @retval other         Some error occurred when processing Option Rom on
> the host bridge.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeP2CProcess (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  )
> +{
> +  EFI_HANDLE    RootBridgeHandle;
> +  PCI_IO_DEVICE *RootBridgeDev;
> +  EFI_STATUS    Status;
> +
> +  if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  RootBridgeHandle = NULL;
> +
> +  while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle)
> == EFI_SUCCESS) {
> +
> +    //
> +    // Get RootBridg Device by handle
> +    //
> +    RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
> +
> +    if (RootBridgeDev == NULL) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    Status = PciRootBridgeP2CProcess (RootBridgeDev);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function is used to enumerate the entire host bridge
> +  in a given platform.
> +
> +  @param PciResAlloc   A pointer to the PCI Host Resource Allocation
> protocol.
> +
> +  @retval EFI_SUCCESS            Successfully enumerated the host bridge.
> +  @retval EFI_OUT_OF_RESOURCES   No enough memory available.
> +  @retval other                  Some error occurred when enumerating the host
> bridge.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeEnumerator (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  )
> +{
> +  EFI_HANDLE                        RootBridgeHandle;
> +  PCI_IO_DEVICE                     *RootBridgeDev;
> +  EFI_STATUS                        Status;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL   *PciRootBridgeIo;
> +  UINT16                            MinBus;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
> +  UINT8                             StartBusNumber;
> +  LIST_ENTRY                        RootBridgeList;
> +  LIST_ENTRY                        *Link;
> +
> +  if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
> +    InitializeHotPlugSupport ();
> +  }
> +
> +  InitializeListHead (&RootBridgeList);
> +
> +  //
> +  // Notify the bus allocation phase is about to start
> +  //
> +  Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n"));
> +  RootBridgeHandle = NULL;
> +  while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle)
> == EFI_SUCCESS) {
> +
> +    //
> +    // if a root bridge instance is found, create root bridge device for it
> +    //
> +
> +    RootBridgeDev = CreateRootBridge (RootBridgeHandle);
> +
> +    if (RootBridgeDev == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    //
> +    // Enumerate all the buses under this root bridge
> +    //
> +    Status = PciRootBridgeEnumerator (
> +              PciResAlloc,
> +              RootBridgeDev
> +              );
> +
> +    if (gPciHotPlugInit != NULL && FeaturePcdGet
> (PcdPciBusHotplugDeviceSupport)) {
> +      InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
> +    } else {
> +      DestroyRootBridge (RootBridgeDev);
> +    }
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
> +  //
> +  // Notify the bus allocation phase is finished for the first time
> +  //
> +  NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
> +
> +  if (gPciHotPlugInit != NULL && FeaturePcdGet
> (PcdPciBusHotplugDeviceSupport)) {
> +    //
> +    // Reset all assigned PCI bus number in all PPB
> +    //
> +    RootBridgeHandle = NULL;
> +    Link = GetFirstNode (&RootBridgeList);
> +    while ((PciResAlloc->GetNextRootBridge (PciResAlloc,
> &RootBridgeHandle) == EFI_SUCCESS) &&
> +      (!IsNull (&RootBridgeList, Link))) {
> +      RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
> +      //
> +      // Get the Bus information
> +      //
> +      Status = PciResAlloc->StartBusEnumeration (
> +                              PciResAlloc,
> +                              RootBridgeHandle,
> +                              (VOID **) &Configuration
> +                              );
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +
> +      //
> +      // Get the bus number to start with
> +      //
> +      StartBusNumber  = (UINT8) (Configuration->AddrRangeMin);
> +
> +      ResetAllPpbBusNumber (
> +        RootBridgeDev,
> +        StartBusNumber
> +      );
> +
> +      FreePool (Configuration);
> +      Link = RemoveEntryList (Link);
> +      DestroyRootBridge (RootBridgeDev);
> +    }
> +
> +    //
> +    // Wait for all HPC initialized
> +    //
> +    Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
> +
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((EFI_D_ERROR, "Some root HPC failed to initialize\n"));
> +      return Status;
> +    }
> +
> +    //
> +    // Notify the bus allocation phase is about to start for the 2nd time
> +    //
> +    Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n"));
> +    RootBridgeHandle = NULL;
> +    while (PciResAlloc->GetNextRootBridge (PciResAlloc,
> &RootBridgeHandle) == EFI_SUCCESS) {
> +
> +      //
> +      // if a root bridge instance is found, create root bridge device for it
> +      //
> +      RootBridgeDev = CreateRootBridge (RootBridgeHandle);
> +
> +      if (RootBridgeDev == NULL) {
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      //
> +      // Enumerate all the buses under this root bridge
> +      //
> +      Status = PciRootBridgeEnumerator (
> +                PciResAlloc,
> +                RootBridgeDev
> +                );
> +
> +      DestroyRootBridge (RootBridgeDev);
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +    }
> +
> +    //
> +    // Notify the bus allocation phase is to end for the 2nd time
> +    //
> +    NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
> +  }
> +
> +  //
> +  // Notify the resource allocation phase is to start
> +  //
> +  Status = NotifyPhase (PciResAlloc,
> EfiPciHostBridgeBeginResourceAllocation);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  RootBridgeHandle = NULL;
> +  while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle)
> == EFI_SUCCESS) {
> +
> +    //
> +    // if a root bridge instance is found, create root bridge device for it
> +    //
> +    RootBridgeDev = CreateRootBridge (RootBridgeHandle);
> +
> +    if (RootBridgeDev == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    Status = StartManagingRootBridge (RootBridgeDev);
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
> +    Status          = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)
> &Descriptors);
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    //
> +    // Determine root bridge attribute by calling interface of Pcihostbridge
> +    // protocol
> +    //
> +    DetermineRootBridgeAttributes (
> +      PciResAlloc,
> +      RootBridgeDev
> +      );
> +
> +    //
> +    // Collect all the resource information under this root bridge
> +    // A database that records all the information about pci device subject to
> this
> +    // root bridge will then be created
> +    //
> +    Status = PciPciDeviceInfoCollector (
> +              RootBridgeDev,
> +              (UINT8) MinBus
> +              );
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    InsertRootBridge (RootBridgeDev);
> +
> +    //
> +    // Record the hostbridge handle
> +    //
> +    AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo-
> >ParentHandle);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function is used to program the Resizable BAR Register.
> +
> +  @param PciIoDevice            A pointer to the PCI_IO_DEVICE.
> +  @param ResizableBarOp         PciResizableBarMax: Set BAR to max size
> +                                PciResizableBarMin: set BAR to min size.
> +
> +  @retval EFI_SUCCESS           Successfully enumerated the host bridge.
> +  @retval other                 Some error occurred when enumerating the host
> bridge.
> +
> +**/
> +EFI_STATUS
> +PciProgramResizableBar (
> +  IN PCI_IO_DEVICE                *PciIoDevice,
> +  IN PCI_RESIZABLE_BAR_OPERATION  ResizableBarOp
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL  *PciIo;
> +  UINT64                Capabilities;
> +  UINT32                Index;
> +  UINT32                Offset;
> +  INTN                  Bit;
> +  UINTN                 ResizableBarNumber;
> +  EFI_STATUS            Status;
> +  PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY
> Entries[PCI_MAX_BAR];
> +
> +  ASSERT (PciIoDevice->ResizableBarOffset != 0);
> +
> +  DEBUG ((DEBUG_INFO, "   Programs Resizable BAR register, offset:
> 0x%08x, number: %d\n",
> +        PciIoDevice->ResizableBarOffset, PciIoDevice->ResizableBarNumber));
> +
> +  ResizableBarNumber = MIN (PciIoDevice->ResizableBarNumber,
> PCI_MAX_BAR);
> +  PciIo = &PciIoDevice->PciIo;
> +  Status = PciIo->Pci.Read (
> +          PciIo,
> +          EfiPciIoWidthUint8,
> +          PciIoDevice->ResizableBarOffset + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER),
> +          sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY) *
> ResizableBarNumber,
> +          (VOID *)(&Entries)
> +          );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  for (Index = 0; Index < ResizableBarNumber; Index++) {
> +
> +    //
> +    // When the bit of Capabilities Set, indicates that the Function supports
> +    // operating with the BAR sized to (2^Bit) MB.
> +    // Example:
> +    // Bit 0 is set: supports operating with the BAR sized to 1 MB
> +    // Bit 1 is set: supports operating with the BAR sized to 2 MB
> +    // Bit n is set: supports operating with the BAR sized to (2^n) MB
> +    //
> +    Capabilities =
> LShiftU64(Entries[Index].ResizableBarControl.Bits.BarSizeCapability, 28)
> +                  | Entries[Index].ResizableBarCapability.Bits.BarSizeCapability;
> +
> +    if (ResizableBarOp == PciResizableBarMax) {
> +      Bit = HighBitSet64(Capabilities);
> +    } else {
> +      ASSERT (ResizableBarOp == PciResizableBarMin);
> +      Bit = LowBitSet64(Capabilities);
> +    }
> +
> +    ASSERT (Bit >= 0);
> +
> +    Offset = PciIoDevice->ResizableBarOffset + sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
> +            + Index * sizeof
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY)
> +            + OFFSET_OF
> (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY,
> ResizableBarControl);
> +
> +    Entries[Index].ResizableBarControl.Bits.BarSize = (UINT32) Bit;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "   Resizable Bar: Offset = 0x%x, Bar Size Capability = 0x%016lx, New Bar
> Size = 0x%lx\n",
> +      OFFSET_OF (PCI_TYPE00,
> Device.Bar[Entries[Index].ResizableBarControl.Bits.BarIndex]),
> +      Capabilities, LShiftU64 (SIZE_1MB, Bit)
> +      ));
> +    PciIo->Pci.Write (
> +            PciIo,
> +            EfiPciIoWidthUint32,
> +            Offset,
> +            1,
> +            &Entries[Index].ResizableBarControl.Uint32
> +            );
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.h
> new file mode 100644
> index 0000000000..70ab07a8c3
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciLib.h
> @@ -0,0 +1,179 @@
> +/** @file
> +  Internal library declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_LIB_H_
> +#define _EFI_PCI_LIB_H_
> +
> +
> +typedef struct {
> +  EFI_HANDLE            Handle;
> +} EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD;
> +
> +typedef struct {
> +  UINT32                             Bar;
> +  UINT16                             DevicePathSize;
> +  UINT16                             ReqResSize;
> +  UINT16                             AllocResSize;
> +  UINT8                              *DevicePath;
> +  UINT8                              *ReqRes;
> +  UINT8                              *AllocRes;
> +} EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD;
> +
> +typedef enum {
> +  PciResizableBarMin = 0x00,
> +  PciResizableBarMax = 0xFF
> +} PCI_RESIZABLE_BAR_OPERATION;
> +
> +/**
> +  Retrieve the PCI Card device BAR information via PciIo interface.
> +
> +  @param PciIoDevice        PCI Card device instance.
> +
> +**/
> +VOID
> +GetBackPcCardBar (
> +  IN  PCI_IO_DEVICE                  *PciIoDevice
> +  );
> +
> +/**
> +  Remove rejected pci device from specific root bridge
> +  handle.
> +
> +  @param RootBridgeHandle  Specific parent root bridge handle.
> +  @param Bridge            Bridge device instance.
> +
> +**/
> +VOID
> +RemoveRejectedPciDevices (
> +  IN EFI_HANDLE        RootBridgeHandle,
> +  IN PCI_IO_DEVICE     *Bridge
> +  );
> +
> +/**
> +  Submits the I/O and memory resource requirements for the specified PCI
> Host Bridge.
> +
> +  @param PciResAlloc  Point to protocol instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_SUCCESS           Successfully finished resource allocation.
> +  @retval EFI_NOT_FOUND         Cannot get root bridge instance.
> +  @retval EFI_OUT_OF_RESOURCES  Platform failed to program the
> resources if no hot plug supported.
> +  @retval other                 Some error occurred when allocating resources for
> the PCI Host Bridge.
> +
> +  @note   Feature flag PcdPciBusHotplugDeviceSupport determine whether
> need support hotplug.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeResourceAllocator (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  );
> +
> +/**
> +  Allocate NumberOfBuses buses and return the next available PCI bus
> number.
> +
> +  @param  Bridge           Bridge device instance.
> +  @param  StartBusNumber   Current available PCI bus number.
> +  @param  NumberOfBuses    Number of buses enumerated below the
> StartBusNumber.
> +  @param  NextBusNumber    Next available PCI bus number.
> +
> +  @retval EFI_SUCCESS           Available bus number resource is enough. Next
> available PCI bus number
> +                                is returned in NextBusNumber.
> +  @retval EFI_OUT_OF_RESOURCES  Available bus number resource is not
> enough for allocation.
> +
> +**/
> +EFI_STATUS
> +PciAllocateBusNumber (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber,
> +  IN UINT8                              NumberOfBuses,
> +  OUT UINT8                             *NextBusNumber
> +  );
> +
> +/**
> +  Scan pci bus and assign bus number to the given PCI bus system.
> +
> +  @param  Bridge           Bridge device instance.
> +  @param  StartBusNumber   start point.
> +  @param  SubBusNumber     Point to sub bus number.
> +  @param  PaddedBusRange   Customized bus number.
> +
> +  @retval EFI_SUCCESS      Successfully scanned and assigned bus number.
> +  @retval other            Some error occurred when scanning pci bus.
> +
> +  @note   Feature flag PcdPciBusHotplugDeviceSupport determine whether
> need support hotplug.
> +
> +**/
> +EFI_STATUS
> +PciScanBus (
> +  IN PCI_IO_DEVICE                      *Bridge,
> +  IN UINT8                              StartBusNumber,
> +  OUT UINT8                             *SubBusNumber,
> +  OUT UINT8                             *PaddedBusRange
> +  );
> +
> +/**
> +  Process Option Rom on the specified root bridge.
> +
> +  @param Bridge  Pci root bridge device instance.
> +
> +  @retval EFI_SUCCESS   Success process.
> +  @retval other         Some error occurred when processing Option Rom on
> the root bridge.
> +
> +**/
> +EFI_STATUS
> +PciRootBridgeP2CProcess (
> +  IN PCI_IO_DEVICE *Bridge
> +  );
> +
> +/**
> +  Process Option Rom on the specified host bridge.
> +
> +  @param PciResAlloc    Pointer to instance of
> EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
> +
> +  @retval EFI_SUCCESS   Success process.
> +  @retval EFI_NOT_FOUND Can not find the root bridge instance.
> +  @retval other         Some error occurred when processing Option Rom on
> the host bridge.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeP2CProcess (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  );
> +
> +/**
> +  This function is used to enumerate the entire host bridge
> +  in a given platform.
> +
> +  @param PciResAlloc   A pointer to the PCI Host Resource Allocation
> protocol.
> +
> +  @retval EFI_SUCCESS            Successfully enumerated the host bridge.
> +  @retval EFI_OUT_OF_RESOURCES   No enough memory available.
> +  @retval other                  Some error occurred when enumerating the host
> bridge.
> +
> +**/
> +EFI_STATUS
> +PciHostBridgeEnumerator (
> +  IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
> *PciResAlloc
> +  );
> +
> +/**
> +  This function is used to program the Resizable BAR Register.
> +
> +  @param PciIoDevice            A pointer to the PCI_IO_DEVICE.
> +  @param ResizableBarOp         PciResizableBarMax: Set BAR to max size
> +                                PciResizableBarMin: set BAR to min size.
> +
> +  @retval EFI_SUCCESS           Successfully enumerated the host bridge.
> +  @retval other                 Some error occurred when enumerating the host
> bridge.
> +
> +**/
> +EFI_STATUS
> +PciProgramResizableBar (
> +  IN PCI_IO_DEVICE                *PciIoDevice,
> +  IN PCI_RESIZABLE_BAR_OPERATION  ResizableBarOp
> +  );
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.c
> new file mode 100644
> index 0000000000..efdfa2d415
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.c
> @@ -0,0 +1,776 @@
> +/** @file
> +  PCI Rom supporting funtions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2021, American Megatrends International LLC.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +/**
> +  Load the EFI Image from Option ROM
> +
> +  @param PciIoDevice   PCI IO device instance.
> +  @param FilePath      The file path of the EFI Image
> +  @param BufferSize    On input the size of Buffer in bytes. On output with a
> return
> +                       code of EFI_SUCCESS, the amount of data transferred to Buffer.
> +                       On output with a return code of EFI_BUFFER_TOO_SMALL,
> +                       the size of Buffer required to retrieve the requested file.
> +  @param Buffer        The memory buffer to transfer the file to. If Buffer is
> NULL,
> +                       then no the size of the requested file is returned in BufferSize.
> +
> +  @retval EFI_SUCCESS           The file was loaded.
> +  @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
> +                                BufferSize is NULL.
> +  @retval EFI_NOT_FOUND         Not found PCI Option Rom on PCI device.
> +  @retval EFI_DEVICE_ERROR      Failed to decompress PCI Option Rom
> image.
> +  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the
> current directory entry.
> +                                BufferSize has been updated with the size needed to
> complete the request.
> +**/
> +EFI_STATUS
> +LocalLoadFile2 (
> +  IN PCI_IO_DEVICE            *PciIoDevice,
> +  IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
> +  IN OUT UINTN                *BufferSize,
> +  IN VOID                     *Buffer      OPTIONAL
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
> *EfiOpRomImageNode;
> +  EFI_PCI_EXPANSION_ROM_HEADER              *EfiRomHeader;
> +  PCI_DATA_STRUCTURE                        *Pcir;
> +  UINT32                                    ImageSize;
> +  UINT8                                     *ImageBuffer;
> +  UINT32                                    ImageLength;
> +  UINT32                                    DestinationSize;
> +  UINT32                                    ScratchSize;
> +  VOID                                      *Scratch;
> +  EFI_DECOMPRESS_PROTOCOL                   *Decompress;
> +  UINT32                                    InitializationSize;
> +
> +  EfiOpRomImageNode =
> (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath;
> +  if ((EfiOpRomImageNode == NULL) ||
> +      (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) ||
> +      (DevicePathSubType (FilePath) !=
> MEDIA_RELATIVE_OFFSET_RANGE_DP) ||
> +      (DevicePathNodeLength (FilePath) != sizeof
> (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) ||
> +      (!IsDevicePathEnd (NextDevicePathNode (FilePath))) ||
> +      (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode-
> >EndingOffset) ||
> +      (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) ||
> +      (BufferSize == NULL)
> +      ) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (
> +      (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode-
> >StartingOffset
> +      );
> +  if (EfiRomHeader->Signature !=
> PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +
> +  Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader +
> EfiRomHeader->PcirOffset);
> +  ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
> +
> +  if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
> +      (EfiRomHeader->EfiSignature ==
> EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
> +      ((EfiRomHeader->EfiSubsystem ==
> EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
> +       (EfiRomHeader->EfiSubsystem ==
> EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) &&
> +      (EfiRomHeader->CompressionType <=
> EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED)
> +       ) {
> +
> +    ImageSize = Pcir->ImageLength * 512;
> +    InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512;
> +    if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset
> >=  InitializationSize) {
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    ImageBuffer             = (UINT8 *) EfiRomHeader + EfiRomHeader-
> >EfiImageHeaderOffset;
> +    ImageLength             = InitializationSize - EfiRomHeader-
> >EfiImageHeaderOffset;
> +
> +    if (EfiRomHeader->CompressionType !=
> EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
> +      //
> +      // Uncompressed: Copy the EFI Image directly to user's buffer
> +      //
> +      if (Buffer == NULL || *BufferSize < ImageLength) {
> +        *BufferSize = ImageLength;
> +        return EFI_BUFFER_TOO_SMALL;
> +      }
> +
> +      *BufferSize = ImageLength;
> +      CopyMem (Buffer, ImageBuffer, ImageLength);
> +      return EFI_SUCCESS;
> +
> +    } else {
> +      //
> +      // Compressed: Uncompress before copying
> +      //
> +      Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL,
> (VOID **) &Decompress);
> +      if (EFI_ERROR (Status)) {
> +        return EFI_DEVICE_ERROR;
> +      }
> +      Status = Decompress->GetInfo (
> +                             Decompress,
> +                             ImageBuffer,
> +                             ImageLength,
> +                             &DestinationSize,
> +                             &ScratchSize
> +                             );
> +      if (EFI_ERROR (Status)) {
> +        return EFI_DEVICE_ERROR;
> +      }
> +
> +      if (Buffer == NULL || *BufferSize < DestinationSize) {
> +        *BufferSize = DestinationSize;
> +        return EFI_BUFFER_TOO_SMALL;
> +      }
> +
> +      *BufferSize = DestinationSize;
> +      Scratch = AllocatePool (ScratchSize);
> +      if (Scratch == NULL) {
> +        return EFI_DEVICE_ERROR;
> +      }
> +
> +      Status = Decompress->Decompress (
> +                             Decompress,
> +                             ImageBuffer,
> +                             ImageLength,
> +                             Buffer,
> +                             DestinationSize,
> +                             Scratch,
> +                             ScratchSize
> +                             );
> +      FreePool (Scratch);
> +
> +      if (EFI_ERROR (Status)) {
> +        return EFI_DEVICE_ERROR;
> +      }
> +      return EFI_SUCCESS;
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Initialize a PCI LoadFile2 instance.
> +
> +  @param PciIoDevice   PCI IO Device.
> +
> +**/
> +VOID
> +InitializePciLoadFile2 (
> +  IN PCI_IO_DEVICE       *PciIoDevice
> +  )
> +{
> +  PciIoDevice->LoadFile2.LoadFile = LoadFile2;
> +}
> +
> +/**
> +  Causes the driver to load a specified file.
> +
> +  @param This        Indicates a pointer to the calling context.
> +  @param FilePath    The device specific path of the file to load.
> +  @param BootPolicy  Should always be FALSE.
> +  @param BufferSize  On input the size of Buffer in bytes. On output with a
> return
> +                     code of EFI_SUCCESS, the amount of data transferred to Buffer.
> +                     On output with a return code of EFI_BUFFER_TOO_SMALL,
> +                     the size of Buffer required to retrieve the requested file.
> +  @param Buffer      The memory buffer to transfer the file to. If Buffer is
> NULL,
> +                     then no the size of the requested file is returned in BufferSize.
> +
> +  @retval EFI_SUCCESS           The file was loaded.
> +  @retval EFI_UNSUPPORTED       BootPolicy is TRUE.
> +  @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
> +                                BufferSize is NULL.
> +  @retval EFI_NOT_FOUND         Not found PCI Option Rom on PCI device.
> +  @retval EFI_DEVICE_ERROR      Failed to decompress PCI Option Rom
> image.
> +  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the
> current directory entry.
> +                                BufferSize has been updated with the size needed to
> complete the request.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +LoadFile2 (
> +  IN EFI_LOAD_FILE2_PROTOCOL  *This,
> +  IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
> +  IN BOOLEAN                  BootPolicy,
> +  IN OUT UINTN                *BufferSize,
> +  IN VOID                     *Buffer      OPTIONAL
> +  )
> +{
> +  PCI_IO_DEVICE                             *PciIoDevice;
> +
> +  if (BootPolicy) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This);
> +
> +  return LocalLoadFile2 (
> +           PciIoDevice,
> +           FilePath,
> +           BufferSize,
> +           Buffer
> +           );
> +}
> +
> +/**
> +  Get Pci device's oprom information.
> +
> +  @param PciIoDevice    Input Pci device instance.
> +                        Output Pci device instance with updated OptionRom size.
> +
> +  @retval EFI_NOT_FOUND Pci device has not Option Rom.
> +  @retval EFI_SUCCESS   Pci device has Option Rom.
> +
> +**/
> +EFI_STATUS
> +GetOpRomInfo (
> +  IN OUT PCI_IO_DEVICE    *PciIoDevice
> +  )
> +{
> +  UINT8                           RomBarIndex;
> +  UINT32                          AllOnes;
> +  UINT64                          Address;
> +  EFI_STATUS                      Status;
> +  UINT8                           Bus;
> +  UINT8                           Device;
> +  UINT8                           Function;
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +
> +  Bus             = PciIoDevice->BusNumber;
> +  Device          = PciIoDevice->DeviceNumber;
> +  Function        = PciIoDevice->FunctionNumber;
> +
> +  PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
> +
> +  //
> +  // Offset is 0x30 if is not ppb
> +  //
> +
> +  //
> +  // 0x30
> +  //
> +  RomBarIndex = PCI_EXPANSION_ROM_BASE;
> +
> +  if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
> +    //
> +    // If is ppb, 0x38
> +    //
> +    RomBarIndex = PCI_BRIDGE_ROMBAR;
> +  }
> +  //
> +  // The bit0 is 0 to prevent the enabling of the Rom address decoder
> +  //
> +  AllOnes = 0xfffffffe;
> +  Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
> +
> +  Status = PciRootBridgeIo->Pci.Write (
> +                                  PciRootBridgeIo,
> +                                  EfiPciWidthUint32,
> +                                  Address,
> +                                  1,
> +                                  &AllOnes
> +                                  );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Read back
> +  //
> +  Status = PciRootBridgeIo->Pci.Read(
> +                                  PciRootBridgeIo,
> +                                  EfiPciWidthUint32,
> +                                  Address,
> +                                  1,
> +                                  &AllOnes
> +                                  );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Bits [1, 10] are reserved
> +  //
> +  AllOnes &= 0xFFFFF800;
> +  if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  PciIoDevice->RomSize = (~AllOnes) + 1;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check if the RomImage contains EFI Images.
> +
> +  @param  RomImage  The ROM address of Image for check.
> +  @param  RomSize   Size of ROM for check.
> +
> +  @retval TRUE     ROM contain EFI Image.
> +  @retval FALSE    ROM not contain EFI Image.
> +
> +**/
> +BOOLEAN
> +ContainEfiImage (
> +  IN VOID            *RomImage,
> +  IN UINT64          RomSize
> +  )
> +{
> +  PCI_EXPANSION_ROM_HEADER  *RomHeader;
> +  PCI_DATA_STRUCTURE        *RomPcir;
> +  UINT8                     Indicator;
> +
> +  Indicator = 0;
> +  RomHeader = RomImage;
> +  if (RomHeader == NULL) {
> +    return FALSE;
> +  }
> +
> +  do {
> +    if (RomHeader->Signature !=
> PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
> +      RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *)
> RomHeader + 512);
> +      continue;
> +    }
> +
> +    //
> +    // The PCI Data Structure must be DWORD aligned.
> +    //
> +    if (RomHeader->PcirOffset == 0 ||
> +        (RomHeader->PcirOffset & 3) != 0 ||
> +        (UINT8 *) RomHeader + RomHeader->PcirOffset + sizeof
> (PCI_DATA_STRUCTURE) > (UINT8 *) RomImage + RomSize) {
> +      break;
> +    }
> +
> +    RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader +
> RomHeader->PcirOffset);
> +    if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
> +      break;
> +    }
> +
> +    if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) {
> +      return TRUE;
> +    }
> +
> +    Indicator = RomPcir->Indicator;
> +    RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader
> + RomPcir->ImageLength * 512);
> +  } while (((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) &&
> ((Indicator & 0x80) == 0x00));
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Load Option Rom image for specified PCI device.
> +
> +  @param PciDevice Pci device instance.
> +  @param RomBase   Base address of Option Rom.
> +
> +  @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
> +  @retval EFI_SUCESS           Successfully loaded Option Rom.
> +
> +**/
> +EFI_STATUS
> +LoadOpRomImage (
> +  IN PCI_IO_DEVICE   *PciDevice,
> +  IN UINT64          RomBase
> +  )
> +{
> +  UINT8                     RomBarIndex;
> +  UINT8                     Indicator;
> +  UINT16                    OffsetPcir;
> +  UINT32                    RomBarOffset;
> +  UINT32                    RomBar;
> +  EFI_STATUS                RetStatus;
> +  BOOLEAN                   FirstCheck;
> +  UINT8                     *Image;
> +  PCI_EXPANSION_ROM_HEADER  *RomHeader;
> +  PCI_DATA_STRUCTURE        *RomPcir;
> +  UINT64                    RomSize;
> +  UINT64                    RomImageSize;
> +  UINT32                    LegacyImageLength;
> +  UINT8                     *RomInMemory;
> +  UINT8                     CodeType;
> +
> +  RomSize       = PciDevice->RomSize;
> +
> +  Indicator     = 0;
> +  RomImageSize  = 0;
> +  RomInMemory   = NULL;
> +  CodeType      = 0xFF;
> +
> +  //
> +  // Get the RomBarIndex
> +  //
> +
> +  //
> +  // 0x30
> +  //
> +  RomBarIndex = PCI_EXPANSION_ROM_BASE;
> +  if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
> +    //
> +    // if is ppb
> +    //
> +
> +    //
> +    // 0x38
> +    //
> +    RomBarIndex = PCI_BRIDGE_ROMBAR;
> +  }
> +  //
> +  // Allocate memory for Rom header and PCIR
> +  //
> +  RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
> +  if (RomHeader == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
> +  if (RomPcir == NULL) {
> +    FreePool (RomHeader);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  RomBar = (UINT32) RomBase;
> +
> +  //
> +  // Enable RomBar
> +  //
> +  RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
> +
> +  RomBarOffset  = RomBar;
> +  RetStatus     = EFI_NOT_FOUND;
> +  FirstCheck    = TRUE;
> +  LegacyImageLength = 0;
> +
> +  do {
> +    PciDevice->PciRootBridgeIo->Mem.Read (
> +                                      PciDevice->PciRootBridgeIo,
> +                                      EfiPciWidthUint8,
> +                                      RomBarOffset,
> +                                      sizeof (PCI_EXPANSION_ROM_HEADER),
> +                                      (UINT8 *) RomHeader
> +                                      );
> +
> +    if (RomHeader->Signature !=
> PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
> +      RomBarOffset = RomBarOffset + 512;
> +      if (FirstCheck) {
> +        break;
> +      } else {
> +        RomImageSize = RomImageSize + 512;
> +        continue;
> +      }
> +    }
> +
> +    FirstCheck  = FALSE;
> +    OffsetPcir  = RomHeader->PcirOffset;
> +    //
> +    // If the pointer to the PCI Data Structure is invalid, no further images can
> be located.
> +    // The PCI Data Structure must be DWORD aligned.
> +    //
> +    if (OffsetPcir == 0 ||
> +        (OffsetPcir & 3) != 0 ||
> +        RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) >
> RomSize) {
> +      break;
> +    }
> +    PciDevice->PciRootBridgeIo->Mem.Read (
> +                                      PciDevice->PciRootBridgeIo,
> +                                      EfiPciWidthUint8,
> +                                      RomBarOffset + OffsetPcir,
> +                                      sizeof (PCI_DATA_STRUCTURE),
> +                                      (UINT8 *) RomPcir
> +                                      );
> +    //
> +    // If a valid signature is not present in the PCI Data Structure, no further
> images can be located.
> +    //
> +    if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
> +      break;
> +    }
> +    if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
> +      break;
> +    }
> +    if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
> +      CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
> +      LegacyImageLength =
> ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)-
> >Size512) * 512;
> +    }
> +    Indicator     = RomPcir->Indicator;
> +    RomImageSize  = RomImageSize + RomPcir->ImageLength * 512;
> +    RomBarOffset  = RomBarOffset + RomPcir->ImageLength * 512;
> +  } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) <
> RomSize));
> +
> +  //
> +  // Some Legacy Cards do not report the correct ImageLength so used the
> maximum
> +  // of the legacy length and the PCIR Image Length
> +  //
> +  if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
> +    RomImageSize = MAX (RomImageSize, LegacyImageLength);
> +  }
> +
> +  if (RomImageSize > 0) {
> +    RetStatus = EFI_SUCCESS;
> +    Image     = AllocatePool ((UINT32) RomImageSize);
> +    if (Image == NULL) {
> +      RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
> +      FreePool (RomHeader);
> +      FreePool (RomPcir);
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    //
> +    // Copy Rom image into memory
> +    //
> +    PciDevice->PciRootBridgeIo->Mem.Read (
> +                                      PciDevice->PciRootBridgeIo,
> +                                      EfiPciWidthUint8,
> +                                      RomBar,
> +                                      (UINT32) RomImageSize,
> +                                      Image
> +                                      );
> +    RomInMemory = Image;
> +  }
> +
> +  RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
> +
> +  PciDevice->EmbeddedRom    = TRUE;
> +  PciDevice->PciIo.RomSize  = RomImageSize;
> +  PciDevice->PciIo.RomImage = RomInMemory;
> +
> +  //TiogaPass Override START : Skip OPROM - Mellanox card which has SSVID
> 0x15B3 and SSDID 0x0031
> +  if (PciDevice->Pci.Hdr.VendorId == 0x15B3 && PciDevice->Pci.Hdr.DeviceId
> == 0x1015) {
> +    if (PciDevice->Pci.Device.SubsystemVendorID == 0x15B3 && PciDevice-
> >Pci.Device.SubsystemID == 0x0031) {
> +      PciDevice->PciIo.RomImage = NULL;
> +      PciDevice->PciIo.RomSize = 0;
> +      DEBUG((DEBUG_ERROR,"Device_MLX @ [B%X|D%X|F%X], VID=%X,
> DID=%X SVID=%X, SVDID=%XOverrides ROM file @ %X  size=%X .\n\n",
> +             PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice-
> >FunctionNumber,
> +             PciDevice->Pci.Hdr.VendorId, PciDevice->Pci.Hdr.DeviceId,
> PciDevice->Pci.Device.SubsystemVendorID,PciDevice-
> >Pci.Device.SubsystemID,PciDevice->PciIo.RomImage, PciDevice-
> >PciIo.RomSize));
> +    }
> +  }
> +  //TiogaPass Override END
> +
> +  // For OpROM read from PCI device:
> +  //   Add the Rom Image to internal database for later PCI light enumeration
> +  //
> +  PciRomAddImageMapping (
> +    NULL,
> +    PciDevice->PciRootBridgeIo->SegmentNumber,
> +    PciDevice->BusNumber,
> +    PciDevice->DeviceNumber,
> +    PciDevice->FunctionNumber,
> +    PciDevice->PciIo.RomImage,
> +    PciDevice->PciIo.RomSize
> +    );
> +
> +  //
> +  // Free allocated memory
> +  //
> +  FreePool (RomHeader);
> +  FreePool (RomPcir);
> +
> +  return RetStatus;
> +}
> +
> +/**
> +  Enable/Disable Option Rom decode.
> +
> +  @param PciDevice    Pci device instance.
> +  @param RomBarIndex  The BAR index of the standard PCI Configuration
> header to use as the
> +                      base address for resource range. The legal range for this field is
> 0..5.
> +  @param RomBar       Base address of Option Rom.
> +  @param Enable       Flag for enable/disable decode.
> +
> +**/
> +VOID
> +RomDecode (
> +  IN PCI_IO_DEVICE   *PciDevice,
> +  IN UINT8           RomBarIndex,
> +  IN UINT32          RomBar,
> +  IN BOOLEAN         Enable
> +  )
> +{
> +  UINT32              Value32;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +
> +  PciIo = &PciDevice->PciIo;
> +  if (Enable) {
> +
> +    //
> +    // set the Rom base address: now is hardcode
> +    // enable its decoder
> +    //
> +    Value32 = RomBar | 0x1;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
> +                 RomBarIndex,
> +                 1,
> +                 &Value32
> +                 );
> +
> +    //
> +    // Programe all upstream bridge
> +    //
> +    ProgramUpstreamBridgeForRom (PciDevice, RomBar, TRUE);
> +
> +    //
> +    // Setting the memory space bit in the function's command register
> +    //
> +    PCI_ENABLE_COMMAND_REGISTER(PciDevice,
> EFI_PCI_COMMAND_MEMORY_SPACE);
> +
> +  } else {
> +
> +    //
> +    // disable command register decode to memory
> +    //
> +    PCI_DISABLE_COMMAND_REGISTER(PciDevice,
> EFI_PCI_COMMAND_MEMORY_SPACE);
> +
> +    //
> +    // Destroy the programmed bar in all the upstream bridge.
> +    //
> +    ProgramUpstreamBridgeForRom (PciDevice, RomBar, FALSE);
> +
> +    //
> +    // disable rom decode
> +    //
> +    Value32 = 0xFFFFFFFE;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
> +                 RomBarIndex,
> +                 1,
> +                 &Value32
> +                 );
> +
> +  }
> +}
> +
> +/**
> +  Load and start the Option Rom image.
> +
> +  @param PciDevice       Pci device instance.
> +
> +  @retval EFI_SUCCESS    Successfully loaded and started PCI Option Rom
> image.
> +  @retval EFI_NOT_FOUND  Failed to process PCI Option Rom image.
> +
> +**/
> +EFI_STATUS
> +ProcessOpRomImage (
> +  IN  PCI_IO_DEVICE   *PciDevice
> +  )
> +{
> +  UINT8                                    Indicator;
> +  UINT32                                   ImageSize;
> +  VOID                                     *RomBar;
> +  UINT8                                    *RomBarOffset;
> +  EFI_HANDLE                               ImageHandle;
> +  EFI_STATUS                               Status;
> +  EFI_STATUS                               RetStatus;
> +  EFI_PCI_EXPANSION_ROM_HEADER             *EfiRomHeader;
> +  PCI_DATA_STRUCTURE                       *Pcir;
> +  EFI_DEVICE_PATH_PROTOCOL                 *PciOptionRomImageDevicePath;
> +  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH  EfiOpRomImageNode;
> +  VOID                                     *Buffer;
> +  UINTN                                    BufferSize;
> +
> +  Indicator = 0;
> +
> +  //
> +  // Get the Address of the Option Rom image
> +  //
> +  RomBar        = PciDevice->PciIo.RomImage;
> +  RomBarOffset  = (UINT8 *) RomBar;
> +  RetStatus     = EFI_NOT_FOUND;
> +
> +  if (RomBar == NULL) {
> +    return RetStatus;
> +  }
> +  ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)-
> >Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
> +
> +  do {
> +    EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
> +    if (EfiRomHeader->Signature !=
> PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
> +      RomBarOffset += 512;
> +      continue;
> +    }
> +
> +    Pcir        = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader-
> >PcirOffset);
> +    ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
> +    ImageSize   = (UINT32) (Pcir->ImageLength * 512);
> +    Indicator   = Pcir->Indicator;
> +
> +    //
> +    // Skip the image if it is not an EFI PCI Option ROM image
> +    //
> +    if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) {
> +      goto NextImage;
> +    }
> +
> +    //
> +    // Ignore the EFI PCI Option ROM image if it is an EFI application
> +    //
> +    if (EfiRomHeader->EfiSubsystem ==
> EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
> +      goto NextImage;
> +    }
> +
> +    //
> +    // Create Pci Option Rom Image device path header
> +    //
> +    EfiOpRomImageNode.Header.Type     = MEDIA_DEVICE_PATH;
> +    EfiOpRomImageNode.Header.SubType  =
> MEDIA_RELATIVE_OFFSET_RANGE_DP;
> +    SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof
> (EfiOpRomImageNode));
> +    EfiOpRomImageNode.StartingOffset  = (UINTN) RomBarOffset - (UINTN)
> RomBar;
> +    EfiOpRomImageNode.EndingOffset    = (UINTN) RomBarOffset +
> ImageSize - 1 - (UINTN) RomBar;
> +
> +    PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice-
> >DevicePath, &EfiOpRomImageNode.Header);
> +    ASSERT (PciOptionRomImageDevicePath != NULL);
> +
> +    //
> +    // load image and start image
> +    //
> +    BufferSize  = 0;
> +    Buffer      = NULL;
> +    ImageHandle = NULL;
> +
> +    Status = gBS->LoadImage (
> +                    FALSE,
> +                    gPciBusDriverBinding.DriverBindingHandle,
> +                    PciOptionRomImageDevicePath,
> +                    Buffer,
> +                    BufferSize,
> +                    &ImageHandle
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Record the Option ROM Image device path when LoadImage fails.
> +      // PciOverride.GetDriver() will try to look for the Image Handle using the
> device path later.
> +      //
> +      AddDriver (PciDevice, NULL, PciOptionRomImageDevicePath);
> +    } else {
> +      Status = gBS->StartImage (ImageHandle, NULL, NULL);
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // Record the Option ROM Image Handle
> +        //
> +        AddDriver (PciDevice, ImageHandle, NULL);
> +        PciRomAddImageMapping (
> +          ImageHandle,
> +          PciDevice->PciRootBridgeIo->SegmentNumber,
> +          PciDevice->BusNumber,
> +          PciDevice->DeviceNumber,
> +          PciDevice->FunctionNumber,
> +          PciDevice->PciIo.RomImage,
> +          PciDevice->PciIo.RomSize
> +          );
> +        RetStatus = EFI_SUCCESS;
> +      }
> +    }
> +    FreePool (PciOptionRomImageDevicePath);
> +
> +NextImage:
> +    RomBarOffset += ImageSize;
> +
> +  } while (((Indicator & 0x80) == 0x00) && (((UINTN) RomBarOffset - (UINTN)
> RomBar) < PciDevice->RomSize));
> +
> +  return RetStatus;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.h
> new file mode 100644
> index 0000000000..60e147a7b9
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciOptionRomSupport.h
> @@ -0,0 +1,136 @@
> +/** @file
> +  PCI Rom supporting functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_OPTION_ROM_SUPPORT_H_
> +#define _EFI_PCI_OPTION_ROM_SUPPORT_H_
> +
> +
> +/**
> +  Initialize a PCI LoadFile2 instance.
> +
> +  @param PciIoDevice   PCI IO Device.
> +
> +**/
> +VOID
> +InitializePciLoadFile2 (
> +  IN PCI_IO_DEVICE       *PciIoDevice
> +  );
> +
> +/**
> +  Causes the driver to load a specified file.
> +
> +  @param This        Indicates a pointer to the calling context.
> +  @param FilePath    The device specific path of the file to load.
> +  @param BootPolicy  Should always be FALSE.
> +  @param BufferSize  On input the size of Buffer in bytes. On output with a
> return
> +                     code of EFI_SUCCESS, the amount of data transferred to Buffer.
> +                     On output with a return code of EFI_BUFFER_TOO_SMALL,
> +                     the size of Buffer required to retrieve the requested file.
> +  @param Buffer      The memory buffer to transfer the file to. If Buffer is
> NULL,
> +                     then no the size of the requested file is returned in BufferSize.
> +
> +  @retval EFI_SUCCESS           The file was loaded.
> +  @retval EFI_UNSUPPORTED       BootPolicy is TRUE.
> +  @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
> +                                BufferSize is NULL.
> +  @retval EFI_NOT_FOUND         Not found PCI Option Rom on PCI device.
> +  @retval EFI_DEVICE_ERROR      Failed to decompress PCI Option Rom
> image.
> +  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the
> current directory entry.
> +                                BufferSize has been updated with the size needed to
> complete the request.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +LoadFile2 (
> +  IN EFI_LOAD_FILE2_PROTOCOL  *This,
> +  IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
> +  IN BOOLEAN                  BootPolicy,
> +  IN OUT UINTN                *BufferSize,
> +  IN VOID                     *Buffer      OPTIONAL
> +  );
> +
> +/**
> +  Check if the RomImage contains EFI Images.
> +
> +  @param  RomImage  The ROM address of Image for check.
> +  @param  RomSize   Size of ROM for check.
> +
> +  @retval TRUE     ROM contain EFI Image.
> +  @retval FALSE    ROM not contain EFI Image.
> +
> +**/
> +BOOLEAN
> +ContainEfiImage (
> +  IN VOID            *RomImage,
> +  IN UINT64          RomSize
> +  );
> +
> +/**
> +  Get Pci device's oprom information.
> +
> +  @param PciIoDevice    Input Pci device instance.
> +                        Output Pci device instance with updated OptionRom size.
> +
> +  @retval EFI_NOT_FOUND Pci device has not Option Rom.
> +  @retval EFI_SUCCESS   Pci device has Option Rom.
> +
> +**/
> +EFI_STATUS
> +GetOpRomInfo (
> +  IN OUT PCI_IO_DEVICE    *PciIoDevice
> +  );
> +
> +/**
> +  Load Option Rom image for specified PCI device.
> +
> +  @param PciDevice Pci device instance.
> +  @param RomBase   Base address of Option Rom.
> +
> +  @retval EFI_OUT_OF_RESOURCES No enough memory to hold image.
> +  @retval EFI_SUCESS           Successfully loaded Option Rom.
> +
> +**/
> +EFI_STATUS
> +LoadOpRomImage (
> +  IN PCI_IO_DEVICE   *PciDevice,
> +  IN UINT64          RomBase
> +  );
> +
> +/**
> +  Enable/Disable Option Rom decode.
> +
> +  @param PciDevice    Pci device instance.
> +  @param RomBarIndex  The BAR index of the standard PCI Configuration
> header to use as the
> +                      base address for resource range. The legal range for this field is
> 0..5.
> +  @param RomBar       Base address of Option Rom.
> +  @param Enable       Flag for enable/disable decode.
> +
> +**/
> +VOID
> +RomDecode (
> +  IN PCI_IO_DEVICE   *PciDevice,
> +  IN UINT8           RomBarIndex,
> +  IN UINT32          RomBar,
> +  IN BOOLEAN         Enable
> +  );
> +
> +/**
> +  Load and start the Option Rom image.
> +
> +  @param PciDevice       Pci device instance.
> +
> +  @retval EFI_SUCCESS    Successfully loaded and started PCI Option Rom
> image.
> +  @retval EFI_NOT_FOUND  Failed to process PCI Option Rom image.
> +
> +**/
> +EFI_STATUS
> +ProcessOpRomImage (
> +  IN PCI_IO_DEVICE   *PciDevice
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.c
> new file mode 100644
> index 0000000000..cf3f8164cd
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.c
> @@ -0,0 +1,82 @@
> +/** @file
> +  Power management support functions implementation for PCI Bus
> module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +/**
> +  This function is intended to turn off PWE assertion and
> +  put the device to D0 state if the device supports
> +  PCI Power Management.
> +
> +  @param PciIoDevice      PCI device instance.
> +
> +  @retval EFI_UNSUPPORTED PCI Device does not support power
> management.
> +  @retval EFI_SUCCESS     Turned off PWE successfully.
> +
> +**/
> +EFI_STATUS
> +ResetPowerManagementFeature (
> +  IN PCI_IO_DEVICE *PciIoDevice
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       PowerManagementRegBlock;
> +  UINT16      PowerManagementCSR;
> +
> +  PowerManagementRegBlock = 0;
> +
> +  Status = LocateCapabilityRegBlock (
> +            PciIoDevice,
> +            EFI_PCI_CAPABILITY_ID_PMI,
> +            &PowerManagementRegBlock,
> +            NULL
> +            );
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Turn off the PWE assertion and put the device into D0 State
> +  //
> +
> +  //
> +  // Read PMCSR
> +  //
> +  Status = PciIoDevice->PciIo.Pci.Read (
> +                                    &PciIoDevice->PciIo,
> +                                    EfiPciIoWidthUint16,
> +                                    PowerManagementRegBlock + 4,
> +                                    1,
> +                                    &PowerManagementCSR
> +                                    );
> +
> +  if (!EFI_ERROR (Status)) {
> +    //
> +    // Clear PME_Status bit
> +    //
> +    PowerManagementCSR |= BIT15;
> +    //
> +    // Clear PME_En bit. PowerState = D0.
> +    //
> +    PowerManagementCSR &= ~(BIT8 | BIT1 | BIT0);
> +
> +    //
> +    // Write PMCSR
> +    //
> +    Status = PciIoDevice->PciIo.Pci.Write (
> +                                      &PciIoDevice->PciIo,
> +                                      EfiPciIoWidthUint16,
> +                                      PowerManagementRegBlock + 4,
> +                                      1,
> +                                      &PowerManagementCSR
> +                                      );
> +  }
> +  return Status;
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.h
> new file mode 100644
> index 0000000000..44e97ec45a
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciPowerManagement.h
> @@ -0,0 +1,28 @@
> +/** @file
> +  Power management support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_POWER_MANAGEMENT_H_
> +#define _EFI_PCI_POWER_MANAGEMENT_H_
> +
> +/**
> +  This function is intended to turn off PWE assertion and
> +  put the device to D0 state if the device supports
> +  PCI Power Management.
> +
> +  @param PciIoDevice      PCI device instance.
> +
> +  @retval EFI_UNSUPPORTED PCI Device does not support power
> management.
> +  @retval EFI_SUCCESS     Turned off PWE successfully.
> +
> +**/
> +EFI_STATUS
> +ResetPowerManagementFeature (
> +  IN PCI_IO_DEVICE *PciIoDevice
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.c
> new file mode 100644
> index 0000000000..1461af7d5d
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.c
> @@ -0,0 +1,2292 @@
> +/** @file
> +  PCI resources support functions implementation for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// The default policy for the PCI bus driver is NOT to reserve I/O ranges for
> both ISA aliases and VGA aliases.
> +//
> +BOOLEAN mReserveIsaAliases = FALSE;
> +BOOLEAN mReserveVgaAliases = FALSE;
> +BOOLEAN mPolicyDetermined  = FALSE;
> +
> +/**
> +  The function is used to skip VGA range.
> +
> +  @param Start    Returned start address including VGA range.
> +  @param Length   The length of VGA range.
> +
> +**/
> +VOID
> +SkipVGAAperture (
> +  OUT UINT64   *Start,
> +  IN  UINT64   Length
> +  )
> +{
> +  UINT64  Original;
> +  UINT64  Mask;
> +  UINT64  StartOffset;
> +  UINT64  LimitOffset;
> +
> +  ASSERT (Start != NULL);
> +  //
> +  // For legacy VGA, bit 10 to bit 15 is not decoded
> +  //
> +  Mask        = 0x3FF;
> +
> +  Original    = *Start;
> +  StartOffset = Original & Mask;
> +  LimitOffset = ((*Start) + Length - 1) & Mask;
> +  if (LimitOffset >= VGABASE1) {
> +    *Start = *Start - StartOffset + VGALIMIT2 + 1;
> +  }
> +}
> +
> +/**
> +  This function is used to skip ISA aliasing aperture.
> +
> +  @param Start    Returned start address including ISA aliasing aperture.
> +  @param Length   The length of ISA aliasing aperture.
> +
> +**/
> +VOID
> +SkipIsaAliasAperture (
> +  OUT UINT64   *Start,
> +  IN  UINT64   Length
> +  )
> +{
> +
> +  UINT64  Original;
> +  UINT64  Mask;
> +  UINT64  StartOffset;
> +  UINT64  LimitOffset;
> +
> +  ASSERT (Start != NULL);
> +
> +  //
> +  // For legacy ISA, bit 10 to bit 15 is not decoded
> +  //
> +  Mask        = 0x3FF;
> +
> +  Original    = *Start;
> +  StartOffset = Original & Mask;
> +  LimitOffset = ((*Start) + Length - 1) & Mask;
> +
> +  if (LimitOffset >= ISABASE) {
> +    *Start = *Start - StartOffset + ISALIMIT + 1;
> +  }
> +}
> +
> +/**
> +  This function inserts a resource node into the resource list.
> +  The resource list is sorted in descend order.
> +
> +  @param Bridge  PCI resource node for bridge.
> +  @param ResNode Resource node want to be inserted.
> +
> +**/
> +VOID
> +InsertResourceNode (
> +  IN OUT PCI_RESOURCE_NODE   *Bridge,
> +  IN     PCI_RESOURCE_NODE   *ResNode
> +  )
> +{
> +  LIST_ENTRY        *CurrentLink;
> +  PCI_RESOURCE_NODE *Temp;
> +  UINT64            ResNodeAlignRest;
> +  UINT64            TempAlignRest;
> +
> +  ASSERT (Bridge  != NULL);
> +  ASSERT (ResNode != NULL);
> +
> +  InsertHeadList (&Bridge->ChildList, &ResNode->Link);
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;
> +  while (CurrentLink != &Bridge->ChildList) {
> +    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +
> +    if (ResNode->Alignment > Temp->Alignment) {
> +      break;
> +    } else if (ResNode->Alignment == Temp->Alignment) {
> +      ResNodeAlignRest  = ResNode->Length & ResNode->Alignment;
> +      TempAlignRest     = Temp->Length & Temp->Alignment;
> +      if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {
> +        break;
> +      }
> +    }
> +
> +    SwapListEntries (&ResNode->Link, CurrentLink);
> +
> +    CurrentLink = ResNode->Link.ForwardLink;
> +  }
> +}
> +
> +/**
> +  This routine is used to merge two different resource trees in need of
> +  resource degradation.
> +
> +  For example, if an upstream PPB doesn't support,
> +  prefetchable memory decoding, the PCI bus driver will choose to call this
> function
> +  to merge prefetchable memory resource list into normal memory list.
> +
> +  If the TypeMerge is TRUE, Res resource type is changed to the type of
> destination resource
> +  type.
> +  If Dst is NULL or Res is NULL, ASSERT ().
> +
> +  @param Dst        Point to destination resource tree.
> +  @param Res        Point to source resource tree.
> +  @param TypeMerge  If the TypeMerge is TRUE, Res resource type is
> changed to the type of
> +                    destination resource type.
> +
> +**/
> +VOID
> +MergeResourceTree (
> +  IN PCI_RESOURCE_NODE   *Dst,
> +  IN PCI_RESOURCE_NODE   *Res,
> +  IN BOOLEAN             TypeMerge
> +  )
> +{
> +
> +  LIST_ENTRY        *CurrentLink;
> +  PCI_RESOURCE_NODE *Temp;
> +
> +  ASSERT (Dst != NULL);
> +  ASSERT (Res != NULL);
> +
> +  while (!IsListEmpty (&Res->ChildList)) {
> +    CurrentLink = Res->ChildList.ForwardLink;
> +
> +    Temp        = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +
> +    if (TypeMerge) {
> +      Temp->ResType = Dst->ResType;
> +    }
> +
> +    RemoveEntryList (CurrentLink);
> +    InsertResourceNode (Dst, Temp);
> +  }
> +}
> +
> +/**
> +  This function is used to calculate the IO16 aperture
> +  for a bridge.
> +
> +  @param Bridge    PCI resource node for bridge.
> +
> +**/
> +VOID
> +CalculateApertureIo16 (
> +  IN PCI_RESOURCE_NODE    *Bridge
> +  )
> +{
> +  EFI_STATUS              Status;
> +  UINT64                  Aperture;
> +  LIST_ENTRY              *CurrentLink;
> +  PCI_RESOURCE_NODE       *Node;
> +  UINT64                  Offset;
> +  EFI_PCI_PLATFORM_POLICY PciPolicy;
> +  UINT64                  PaddingAperture;
> +
> +  if (!mPolicyDetermined) {
> +    //
> +    // Check PciPlatform policy
> +    //
> +    Status = EFI_NOT_FOUND;
> +    PciPolicy = 0;
> +    if (gPciPlatformProtocol != NULL) {
> +      Status = gPciPlatformProtocol->GetPlatformPolicy (
> +                                       gPciPlatformProtocol,
> +                                       &PciPolicy
> +                                       );
> +    }
> +
> +    if (EFI_ERROR (Status) && gPciOverrideProtocol != NULL) {
> +      Status = gPciOverrideProtocol->GetPlatformPolicy (
> +                                       gPciOverrideProtocol,
> +                                       &PciPolicy
> +                                       );
> +    }
> +
> +    if (!EFI_ERROR (Status)) {
> +      if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) {
> +        mReserveIsaAliases = TRUE;
> +      }
> +      if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) {
> +        mReserveVgaAliases = TRUE;
> +      }
> +    }
> +    mPolicyDetermined = TRUE;
> +  }
> +
> +  Aperture        = 0;
> +  PaddingAperture = 0;
> +
> +  if (Bridge == NULL) {
> +    return ;
> +  }
> +
> +  //
> +  // Assume the bridge is aligned
> +  //
> +  for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
> +      ; !IsNull (&Bridge->ChildList, CurrentLink)
> +      ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
> +      ) {
> +
> +    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +    if (Node->ResourceUsage == PciResUsagePadding) {
> +      ASSERT (PaddingAperture == 0);
> +      PaddingAperture = Node->Length;
> +      continue;
> +    }
> +    //
> +    // Consider the aperture alignment
> +    //
> +    Offset = Aperture & (Node->Alignment);
> +
> +    if (Offset != 0) {
> +
> +      Aperture = Aperture + (Node->Alignment + 1) - Offset;
> +
> +    }
> +
> +    //
> +    // IsaEnable and VGAEnable can not be implemented now.
> +    // If both of them are enabled, then the IO resource would
> +    // become too limited to meet the requirement of most of devices.
> +    //
> +    if (mReserveIsaAliases || mReserveVgaAliases) {
> +      if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE
> (&(Node->PciDev->Pci))) {
> +        //
> +        // Check if there is need to support ISA/VGA decoding
> +        // If so, we need to avoid isa/vga aliasing range
> +        //
> +        if (mReserveIsaAliases) {
> +          SkipIsaAliasAperture (
> +            &Aperture,
> +            Node->Length
> +            );
> +          Offset = Aperture & (Node->Alignment);
> +          if (Offset != 0) {
> +            Aperture = Aperture + (Node->Alignment + 1) - Offset;
> +          }
> +        } else if (mReserveVgaAliases) {
> +          SkipVGAAperture (
> +            &Aperture,
> +            Node->Length
> +            );
> +          Offset = Aperture & (Node->Alignment);
> +          if (Offset != 0) {
> +            Aperture = Aperture + (Node->Alignment + 1) - Offset;
> +          }
> +        }
> +      }
> +    }
> +
> +    Node->Offset = Aperture;
> +
> +    //
> +    // Increment aperture by the length of node
> +    //
> +    Aperture += Node->Length;
> +  }
> +
> +  //
> +  // Adjust the aperture with the bridge's alignment
> +  //
> +  Offset = Aperture & (Bridge->Alignment);
> +
> +  if (Offset != 0) {
> +    Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
> +  }
> +
> +  Bridge->Length = Aperture;
> +  //
> +  // At last, adjust the bridge's alignment to the first child's alignment
> +  // if the bridge has at least one child
> +  //
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +  if (CurrentLink != &Bridge->ChildList) {
> +    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +    if (Node->Alignment > Bridge->Alignment) {
> +      Bridge->Alignment = Node->Alignment;
> +    }
> +  }
> +
> +  //
> +  // Hotplug controller needs padding resources.
> +  // Use the larger one between the padding resource and actual occupied
> resource.
> +  //
> +  Bridge->Length = MAX (Bridge->Length, PaddingAperture);
> +}
> +
> +/**
> +  This function is used to calculate the resource aperture
> +  for a given bridge device.
> +
> +  @param Bridge      PCI resource node for given bridge device.
> +
> +**/
> +VOID
> +CalculateResourceAperture (
> +  IN PCI_RESOURCE_NODE    *Bridge
> +  )
> +{
> +  UINT64            Aperture[2];
> +  LIST_ENTRY        *CurrentLink;
> +  PCI_RESOURCE_NODE *Node;
> +
> +  if (Bridge == NULL) {
> +    return ;
> +  }
> +
> +  if (Bridge->ResType == PciBarTypeIo16) {
> +
> +    CalculateApertureIo16 (Bridge);
> +    return ;
> +  }
> +
> +  Aperture[PciResUsageTypical] = 0;
> +  Aperture[PciResUsagePadding] = 0;
> +  //
> +  // Assume the bridge is aligned
> +  //
> +  for ( CurrentLink = GetFirstNode (&Bridge->ChildList)
> +      ; !IsNull (&Bridge->ChildList, CurrentLink)
> +      ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)
> +      ) {
> +    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +
> +    //
> +    // It's possible for a bridge to contain multiple padding resource
> +    // nodes due to DegradeResource().
> +    //
> +    ASSERT ((Node->ResourceUsage == PciResUsageTypical) ||
> +            (Node->ResourceUsage == PciResUsagePadding));
> +    ASSERT (Node->ResourceUsage < ARRAY_SIZE (Aperture));
> +    //
> +    // Recode current aperture as a offset
> +    // Apply padding resource to meet alignment requirement
> +    // Node offset will be used in future real allocation
> +    //
> +    Node->Offset = ALIGN_VALUE (Aperture[Node->ResourceUsage], Node-
> >Alignment + 1);
> +
> +    //
> +    // Record the total aperture.
> +    //
> +    Aperture[Node->ResourceUsage] = Node->Offset + Node->Length;
> +  }
> +
> +  //
> +  // Adjust the aperture with the bridge's alignment
> +  //
> +  Aperture[PciResUsageTypical] = ALIGN_VALUE
> (Aperture[PciResUsageTypical], Bridge->Alignment + 1);
> +  Aperture[PciResUsagePadding] = ALIGN_VALUE
> (Aperture[PciResUsagePadding], Bridge->Alignment + 1);
> +
> +  //
> +  // Hotplug controller needs padding resources.
> +  // Use the larger one between the padding resource and actual occupied
> resource.
> +  //
> +  Bridge->Length = MAX (Aperture[PciResUsageTypical],
> Aperture[PciResUsagePadding]);
> +
> +  //
> +  // Adjust the bridge's alignment to the MAX (first) alignment of all children.
> +  //
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +  if (CurrentLink != &Bridge->ChildList) {
> +    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +    if (Node->Alignment > Bridge->Alignment) {
> +      Bridge->Alignment = Node->Alignment;
> +    }
> +  }
> +}
> +
> +/**
> +  Get IO/Memory resource info for given PCI device.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO .
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +GetResourceFromDevice (
> +  IN     PCI_IO_DEVICE     *PciDev,
> +  IN OUT PCI_RESOURCE_NODE *IoNode,
> +  IN OUT PCI_RESOURCE_NODE *Mem32Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem32Node,
> +  IN OUT PCI_RESOURCE_NODE *Mem64Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem64Node
> +  )
> +{
> +
> +  UINT8             Index;
> +  PCI_RESOURCE_NODE *Node;
> +  BOOLEAN           ResourceRequested;
> +
> +  Node              = NULL;
> +  ResourceRequested = FALSE;
> +
> +  for (Index = 0; Index < PCI_MAX_BAR; Index++) {
> +
> +    switch ((PciDev->PciBar)[Index].BarType) {
> +
> +    case PciBarTypeMem32:
> +    case PciBarTypeOpRom:
> +
> +      Node = CreateResourceNode (
> +              PciDev,
> +              (PciDev->PciBar)[Index].Length,
> +              (PciDev->PciBar)[Index].Alignment,
> +              Index,
> +              (PciDev->PciBar)[Index].BarType,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        Mem32Node,
> +        Node
> +        );
> +
> +      ResourceRequested = TRUE;
> +      break;
> +
> +    case PciBarTypeMem64:
> +
> +      Node = CreateResourceNode (
> +              PciDev,
> +              (PciDev->PciBar)[Index].Length,
> +              (PciDev->PciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypeMem64,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        Mem64Node,
> +        Node
> +        );
> +
> +      ResourceRequested = TRUE;
> +      break;
> +
> +    case PciBarTypePMem64:
> +
> +      Node = CreateResourceNode (
> +              PciDev,
> +              (PciDev->PciBar)[Index].Length,
> +              (PciDev->PciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypePMem64,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        PMem64Node,
> +        Node
> +        );
> +
> +      ResourceRequested = TRUE;
> +      break;
> +
> +    case PciBarTypePMem32:
> +
> +      Node = CreateResourceNode (
> +              PciDev,
> +              (PciDev->PciBar)[Index].Length,
> +              (PciDev->PciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypePMem32,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        PMem32Node,
> +        Node
> +        );
> +      ResourceRequested = TRUE;
> +      break;
> +
> +    case PciBarTypeIo16:
> +    case PciBarTypeIo32:
> +
> +      Node = CreateResourceNode (
> +              PciDev,
> +              (PciDev->PciBar)[Index].Length,
> +              (PciDev->PciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypeIo16,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        IoNode,
> +        Node
> +        );
> +      ResourceRequested = TRUE;
> +      break;
> +
> +    case PciBarTypeUnknown:
> +      break;
> +
> +    default:
> +      break;
> +    }
> +  }
> +
> +  //
> +  // Add VF resource
> +  //
> +  for (Index = 0; Index < PCI_MAX_BAR; Index++) {
> +
> +    switch ((PciDev->VfPciBar)[Index].BarType) {
> +
> +    case PciBarTypeMem32:
> +
> +      Node = CreateVfResourceNode (
> +              PciDev,
> +              (PciDev->VfPciBar)[Index].Length,
> +              (PciDev->VfPciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypeMem32,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        Mem32Node,
> +        Node
> +        );
> +
> +      break;
> +
> +    case PciBarTypeMem64:
> +
> +      Node = CreateVfResourceNode (
> +              PciDev,
> +              (PciDev->VfPciBar)[Index].Length,
> +              (PciDev->VfPciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypeMem64,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        Mem64Node,
> +        Node
> +        );
> +
> +      break;
> +
> +    case PciBarTypePMem64:
> +
> +      Node = CreateVfResourceNode (
> +              PciDev,
> +              (PciDev->VfPciBar)[Index].Length,
> +              (PciDev->VfPciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypePMem64,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        PMem64Node,
> +        Node
> +        );
> +
> +      break;
> +
> +    case PciBarTypePMem32:
> +
> +      Node = CreateVfResourceNode (
> +              PciDev,
> +              (PciDev->VfPciBar)[Index].Length,
> +              (PciDev->VfPciBar)[Index].Alignment,
> +              Index,
> +              PciBarTypePMem32,
> +              PciResUsageTypical
> +              );
> +
> +      InsertResourceNode (
> +        PMem32Node,
> +        Node
> +        );
> +      break;
> +
> +    case PciBarTypeIo16:
> +    case PciBarTypeIo32:
> +      break;
> +
> +    case PciBarTypeUnknown:
> +      break;
> +
> +    default:
> +      break;
> +    }
> +  }
> +  // If there is no resource requested from this device,
> +  // then we indicate this device has been allocated naturally.
> +  //
> +  if (!ResourceRequested) {
> +    PciDev->Allocated = TRUE;
> +  }
> +}
> +
> +/**
> +  This function is used to create a resource node.
> +
> +  @param PciDev       Pci device instance.
> +  @param Length       Length of Io/Memory resource.
> +  @param Alignment    Alignment of resource.
> +  @param Bar          Bar index.
> +  @param ResType      Type of resource: IO/Memory.
> +  @param ResUsage     Resource usage.
> +
> +  @return PCI resource node created for given PCI device.
> +          NULL means PCI resource node is not created.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +CreateResourceNode (
> +  IN PCI_IO_DEVICE         *PciDev,
> +  IN UINT64                Length,
> +  IN UINT64                Alignment,
> +  IN UINT8                 Bar,
> +  IN PCI_BAR_TYPE          ResType,
> +  IN PCI_RESOURCE_USAGE    ResUsage
> +  )
> +{
> +  PCI_RESOURCE_NODE *Node;
> +
> +  Node    = NULL;
> +
> +  Node    = AllocateZeroPool (sizeof (PCI_RESOURCE_NODE));
> +  ASSERT (Node != NULL);
> +  if (Node == NULL) {
> +    return NULL;
> +  }
> +
> +  Node->Signature     = PCI_RESOURCE_SIGNATURE;
> +  Node->PciDev        = PciDev;
> +  Node->Length        = Length;
> +  Node->Alignment     = Alignment;
> +  Node->Bar           = Bar;
> +  Node->ResType       = ResType;
> +  Node->Reserved      = FALSE;
> +  Node->ResourceUsage = ResUsage;
> +  InitializeListHead (&Node->ChildList);
> +
> +  return Node;
> +}
> +
> +/**
> +  This function is used to create a IOV VF resource node.
> +
> +  @param PciDev       Pci device instance.
> +  @param Length       Length of Io/Memory resource.
> +  @param Alignment    Alignment of resource.
> +  @param Bar          Bar index.
> +  @param ResType      Type of resource: IO/Memory.
> +  @param ResUsage     Resource usage.
> +
> +  @return PCI resource node created for given VF PCI device.
> +          NULL means PCI resource node is not created.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +CreateVfResourceNode (
> +  IN PCI_IO_DEVICE         *PciDev,
> +  IN UINT64                Length,
> +  IN UINT64                Alignment,
> +  IN UINT8                 Bar,
> +  IN PCI_BAR_TYPE          ResType,
> +  IN PCI_RESOURCE_USAGE    ResUsage
> +  )
> +{
> +  PCI_RESOURCE_NODE *Node;
> +
> +  Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType,
> ResUsage);
> +  if (Node == NULL) {
> +    return Node;
> +  }
> +
> +  Node->Virtual = TRUE;
> +
> +  return Node;
> +}
> +
> +/**
> +  This function is used to extract resource request from
> +  device node list.
> +
> +  @param Bridge     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +CreateResourceMap (
> +  IN     PCI_IO_DEVICE     *Bridge,
> +  IN OUT PCI_RESOURCE_NODE *IoNode,
> +  IN OUT PCI_RESOURCE_NODE *Mem32Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem32Node,
> +  IN OUT PCI_RESOURCE_NODE *Mem64Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem64Node
> +  )
> +{
> +  PCI_IO_DEVICE     *Temp;
> +  PCI_RESOURCE_NODE *IoBridge;
> +  PCI_RESOURCE_NODE *Mem32Bridge;
> +  PCI_RESOURCE_NODE *PMem32Bridge;
> +  PCI_RESOURCE_NODE *Mem64Bridge;
> +  PCI_RESOURCE_NODE *PMem64Bridge;
> +  LIST_ENTRY        *CurrentLink;
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
> +
> +    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
> +
> +    //
> +    // Create resource nodes for this device by scanning the
> +    // Bar array in the device private data
> +    // If the upstream bridge doesn't support this device,
> +    // no any resource node will be created for this device
> +    //
> +    GetResourceFromDevice (
> +      Temp,
> +      IoNode,
> +      Mem32Node,
> +      PMem32Node,
> +      Mem64Node,
> +      PMem64Node
> +      );
> +
> +    if (IS_PCI_BRIDGE (&Temp->Pci)) {
> +
> +      //
> +      // If the device has children, create a bridge resource node for this PPB
> +      // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
> +      // is aligned with 4KB (smaller alignments may be supported).
> +      //
> +      IoBridge = CreateResourceNode (
> +                   Temp,
> +                   0,
> +                   Temp->BridgeIoAlignment,
> +                   PPB_IO_RANGE,
> +                   PciBarTypeIo16,
> +                   PciResUsageTypical
> +                   );
> +
> +      Mem32Bridge = CreateResourceNode (
> +                      Temp,
> +                      0,
> +                      0xFFFFF,
> +                      PPB_MEM32_RANGE,
> +                      PciBarTypeMem32,
> +                      PciResUsageTypical
> +                      );
> +
> +      PMem32Bridge = CreateResourceNode (
> +                       Temp,
> +                       0,
> +                       0xFFFFF,
> +                       PPB_PMEM32_RANGE,
> +                       PciBarTypePMem32,
> +                       PciResUsageTypical
> +                       );
> +
> +      Mem64Bridge = CreateResourceNode (
> +                      Temp,
> +                      0,
> +                      0xFFFFF,
> +                      PPB_MEM64_RANGE,
> +                      PciBarTypeMem64,
> +                      PciResUsageTypical
> +                      );
> +
> +      PMem64Bridge = CreateResourceNode (
> +                       Temp,
> +                       0,
> +                       0xFFFFF,
> +                       PPB_PMEM64_RANGE,
> +                       PciBarTypePMem64,
> +                       PciResUsageTypical
> +                       );
> +
> +      //
> +      // Recursively create resource map on this bridge
> +      //
> +      CreateResourceMap (
> +        Temp,
> +        IoBridge,
> +        Mem32Bridge,
> +        PMem32Bridge,
> +        Mem64Bridge,
> +        PMem64Bridge
> +        );
> +
> +      if (ResourceRequestExisted (IoBridge)) {
> +        InsertResourceNode (
> +          IoNode,
> +          IoBridge
> +          );
> +      } else {
> +        FreePool (IoBridge);
> +        IoBridge = NULL;
> +      }
> +
> +      //
> +      // If there is node under this resource bridge,
> +      // then calculate bridge's aperture of this type
> +      // and insert it into the respective resource tree.
> +      // If no, delete this resource bridge
> +      //
> +      if (ResourceRequestExisted (Mem32Bridge)) {
> +        InsertResourceNode (
> +          Mem32Node,
> +          Mem32Bridge
> +          );
> +      } else {
> +        FreePool (Mem32Bridge);
> +        Mem32Bridge = NULL;
> +      }
> +
> +      //
> +      // If there is node under this resource bridge,
> +      // then calculate bridge's aperture of this type
> +      // and insert it into the respective resource tree.
> +      // If no, delete this resource bridge
> +      //
> +      if (ResourceRequestExisted (PMem32Bridge)) {
> +        InsertResourceNode (
> +          PMem32Node,
> +          PMem32Bridge
> +          );
> +      } else {
> +        FreePool (PMem32Bridge);
> +        PMem32Bridge = NULL;
> +      }
> +
> +      //
> +      // If there is node under this resource bridge,
> +      // then calculate bridge's aperture of this type
> +      // and insert it into the respective resource tree.
> +      // If no, delete this resource bridge
> +      //
> +      if (ResourceRequestExisted (Mem64Bridge)) {
> +        InsertResourceNode (
> +          Mem64Node,
> +          Mem64Bridge
> +          );
> +      } else {
> +        FreePool (Mem64Bridge);
> +        Mem64Bridge = NULL;
> +      }
> +
> +      //
> +      // If there is node under this resource bridge,
> +      // then calculate bridge's aperture of this type
> +      // and insert it into the respective resource tree.
> +      // If no, delete this resource bridge
> +      //
> +      if (ResourceRequestExisted (PMem64Bridge)) {
> +        InsertResourceNode (
> +          PMem64Node,
> +          PMem64Bridge
> +          );
> +      } else {
> +        FreePool (PMem64Bridge);
> +        PMem64Bridge = NULL;
> +      }
> +
> +    }
> +
> +    //
> +    // If it is P2C, apply hard coded resource padding
> +    //
> +    if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
> +      ResourcePaddingForCardBusBridge (
> +        Temp,
> +        IoNode,
> +        Mem32Node,
> +        PMem32Node,
> +        Mem64Node,
> +        PMem64Node
> +        );
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  //
> +  // To do some platform specific resource padding ...
> +  //
> +  ResourcePaddingPolicy (
> +    Bridge,
> +    IoNode,
> +    Mem32Node,
> +    PMem32Node,
> +    Mem64Node,
> +    PMem64Node
> +    );
> +
> +  //
> +  // Degrade resource if necessary
> +  //
> +  DegradeResource (
> +    Bridge,
> +    Mem32Node,
> +    PMem32Node,
> +    Mem64Node,
> +    PMem64Node
> +    );
> +
> +  //
> +  // Calculate resource aperture for this bridge device
> +  //
> +  CalculateResourceAperture (Mem32Node);
> +  CalculateResourceAperture (PMem32Node);
> +  CalculateResourceAperture (Mem64Node);
> +  CalculateResourceAperture (PMem64Node);
> +  CalculateResourceAperture (IoNode);
> +}
> +
> +/**
> +  This function is used to do the resource padding for a specific platform.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +ResourcePaddingPolicy (
> +  IN PCI_IO_DEVICE     *PciDev,
> +  IN PCI_RESOURCE_NODE *IoNode,
> +  IN PCI_RESOURCE_NODE *Mem32Node,
> +  IN PCI_RESOURCE_NODE *PMem32Node,
> +  IN PCI_RESOURCE_NODE *Mem64Node,
> +  IN PCI_RESOURCE_NODE *PMem64Node
> +  )
> +{
> +  //
> +  // Create padding resource node
> +  //
> +  if (PciDev->ResourcePaddingDescriptors != NULL) {
> +    ApplyResourcePadding (
> +      PciDev,
> +      IoNode,
> +      Mem32Node,
> +      PMem32Node,
> +      Mem64Node,
> +      PMem64Node
> +      );
> +  }
> +}
> +
> +/**
> +  This function is used to degrade resource if the upstream bridge
> +  doesn't support certain resource. Degradation path is
> +  PMEM64 -> MEM64  -> MEM32
> +  PMEM64 -> PMEM32 -> MEM32
> +  IO32   -> IO16.
> +
> +  @param Bridge     Pci device instance.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +DegradeResource (
> +  IN PCI_IO_DEVICE     *Bridge,
> +  IN PCI_RESOURCE_NODE *Mem32Node,
> +  IN PCI_RESOURCE_NODE *PMem32Node,
> +  IN PCI_RESOURCE_NODE *Mem64Node,
> +  IN PCI_RESOURCE_NODE *PMem64Node
> +  )
> +{
> +  PCI_IO_DEVICE        *PciIoDevice;
> +  LIST_ENTRY           *ChildDeviceLink;
> +  LIST_ENTRY           *ChildNodeLink;
> +  LIST_ENTRY           *NextChildNodeLink;
> +  PCI_RESOURCE_NODE    *ResourceNode;
> +
> +  if (FeaturePcdGet (PcdPciDegradeResourceForOptionRom)) {
> +    //
> +    // If any child device has both option ROM and 64-bit BAR, degrade its
> PMEM64/MEM64
> +    // requests in case that if a legacy option ROM image can not access 64-bit
> resources.
> +    //
> +    ChildDeviceLink = Bridge->ChildList.ForwardLink;
> +    while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList)
> {
> +      PciIoDevice = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);
> +      if (PciIoDevice->RomSize != 0) {
> +        if (!IsListEmpty (&Mem64Node->ChildList)) {
> +          ChildNodeLink = Mem64Node->ChildList.ForwardLink;
> +          while (ChildNodeLink != &Mem64Node->ChildList) {
> +            ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
> +            NextChildNodeLink = ChildNodeLink->ForwardLink;
> +
> +            if ((ResourceNode->PciDev == PciIoDevice) &&
> +                (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode-
> >Bar].BarTypeFixed)
> +                ) {
> +              RemoveEntryList (ChildNodeLink);
> +              InsertResourceNode (Mem32Node, ResourceNode);
> +            }
> +            ChildNodeLink = NextChildNodeLink;
> +          }
> +        }
> +
> +        if (!IsListEmpty (&PMem64Node->ChildList)) {
> +          ChildNodeLink = PMem64Node->ChildList.ForwardLink;
> +          while (ChildNodeLink != &PMem64Node->ChildList) {
> +            ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);
> +            NextChildNodeLink = ChildNodeLink->ForwardLink;
> +
> +            if ((ResourceNode->PciDev == PciIoDevice) &&
> +                (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode-
> >Bar].BarTypeFixed)
> +                ) {
> +              RemoveEntryList (ChildNodeLink);
> +              InsertResourceNode (PMem32Node, ResourceNode);
> +            }
> +            ChildNodeLink = NextChildNodeLink;
> +          }
> +        }
> +
> +      }
> +      ChildDeviceLink = ChildDeviceLink->ForwardLink;
> +    }
> +  }
> +
> +  //
> +  // If firmware is in 32-bit mode,
> +  // then degrade PMEM64/MEM64 requests
> +  //
> +  if (sizeof (UINTN) <= 4) {
> +    MergeResourceTree (
> +      Mem32Node,
> +      Mem64Node,
> +      TRUE
> +      );
> +
> +    MergeResourceTree (
> +      PMem32Node,
> +      PMem64Node,
> +      TRUE
> +      );
> +  } else {
> +    //
> +    // if the bridge does not support MEM64, degrade MEM64 to MEM32
> +    //
> +    if (!BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
> +        MergeResourceTree (
> +          Mem32Node,
> +          Mem64Node,
> +          TRUE
> +          );
> +    }
> +
> +    //
> +    // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32
> +    //
> +    if (!BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
> +      MergeResourceTree (
> +        PMem32Node,
> +        PMem64Node,
> +        TRUE
> +        );
> +    }
> +
> +    //
> +    // if both PMEM64 and PMEM32 requests from child devices, which can
> not be satisfied
> +    // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32
> to MEM32.
> +    //
> +    if (!IsListEmpty (&PMem64Node->ChildList) && Bridge->Parent != NULL) {
> +      MergeResourceTree (
> +        Mem32Node,
> +        PMem32Node,
> +        TRUE
> +        );
> +    }
> +  }
> +
> +  //
> +  // If bridge doesn't support Pmem32
> +  // degrade it to mem32
> +  //
> +  if (!BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
> +    MergeResourceTree (
> +      Mem32Node,
> +      PMem32Node,
> +      TRUE
> +      );
> +  }
> +
> +  //
> +  // if root bridge supports combined Pmem Mem decoding
> +  // merge these two type of resource
> +  //
> +  if (BridgeSupportResourceDecode (Bridge,
> EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
> +    MergeResourceTree (
> +      Mem32Node,
> +      PMem32Node,
> +      FALSE
> +      );
> +
> +    //
> +    // No need to check if to degrade MEM64 after merge, because
> +    // if there are PMEM64 still here, 64-bit decode should be supported
> +    // by the root bride.
> +    //
> +    MergeResourceTree (
> +      Mem64Node,
> +      PMem64Node,
> +      FALSE
> +      );
> +  }
> +}
> +
> +/**
> +  Test whether bridge device support decode resource.
> +
> +  @param Bridge    Bridge device instance.
> +  @param Decode    Decode type according to resource type.
> +
> +  @return TRUE     The bridge device support decode resource.
> +  @return FALSE    The bridge device don't support decode resource.
> +
> +**/
> +BOOLEAN
> +BridgeSupportResourceDecode (
> +  IN PCI_IO_DEVICE *Bridge,
> +  IN UINT32        Decode
> +  )
> +{
> +  if (((Bridge->Decodes) & Decode) != 0) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  This function is used to program the resource allocated
> +  for each resource node under specified bridge.
> +
> +  @param Base     Base address of resource to be programmed.
> +  @param Bridge   PCI resource node for the bridge device.
> +
> +  @retval EFI_SUCCESS            Successfully to program all resources
> +                                 on given PCI bridge device.
> +  @retval EFI_OUT_OF_RESOURCES   Base is all one.
> +
> +**/
> +EFI_STATUS
> +ProgramResource (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Bridge
> +  )
> +{
> +  LIST_ENTRY        *CurrentLink;
> +  PCI_RESOURCE_NODE *Node;
> +  EFI_STATUS        Status;
> +
> +  if (Base == gAllOne) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +  while (CurrentLink != &Bridge->ChildList) {
> +
> +    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +
> +    if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {
> +
> +      if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
> +        //
> +        // Program the PCI Card Bus device
> +        //
> +        ProgramP2C (Base, Node);
> +      } else {
> +        //
> +        // Program the PCI device BAR
> +        //
> +        ProgramBar (Base, Node);
> +      }
> +    } else {
> +      //
> +      // Program the PCI devices under this bridge
> +      //
> +      Status = ProgramResource (Base + Node->Offset, Node);
> +      if (EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +
> +      ProgramPpbApperture (Base, Node);
> +    }
> +
> +    CurrentLink = CurrentLink->ForwardLink;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Program Bar register for PCI device.
> +
> +  @param Base  Base address for PCI device resource to be programmed.
> +  @param Node  Point to resource node structure.
> +
> +**/
> +VOID
> +ProgramBar (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT64              Address;
> +  UINT32              Address32;
> +
> +  ASSERT (Node->Bar < PCI_MAX_BAR);
> +
> +  //
> +  // Check VF BAR
> +  //
> +  if (Node->Virtual) {
> +    ProgramVfBar (Base, Node);
> +    return;
> +  }
> +
> +  Address = 0;
> +  PciIo   = &(Node->PciDev->PciIo);
> +
> +  Address = Base + Node->Offset;
> +
> +  //
> +  // Indicate pci bus driver has allocated
> +  // resource for this device
> +  // It might be a temporary solution here since
> +  // pci device could have multiple bar
> +  //
> +  Node->PciDev->Allocated = TRUE;
> +
> +  switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
> +
> +  case PciBarTypeIo16:
> +  case PciBarTypeIo32:
> +  case PciBarTypeMem32:
> +  case PciBarTypePMem32:
> +
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (Node->PciDev->PciBar[Node->Bar]).Offset,
> +                 1,
> +                 &Address
> +                 );
> +  //
> +  // Continue to the case PciBarTypeOpRom to set the BaseAddress.
> +  // PciBarTypeOpRom is a virtual BAR only in root bridge, to capture
> +  // the MEM32 resource requirement for Option ROM shadow.
> +  //
> +
> +  case PciBarTypeOpRom:
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +
> +    break;
> +
> +  case PciBarTypeMem64:
> +  case PciBarTypePMem64:
> +
> +    Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
> +
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (Node->PciDev->PciBar[Node->Bar]).Offset,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 = (UINT32) RShiftU64 (Address, 32);
> +
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +
> +    break;
> +
> +  default:
> +    break;
> +  }
> +}
> +
> +/**
> +  Program IOV VF Bar register for PCI device.
> +
> +  @param Base  Base address for PCI device resource to be programmed.
> +  @param Node  Point to resource node structure.
> +
> +**/
> +EFI_STATUS
> +ProgramVfBar (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT64              Address;
> +  UINT32              Address32;
> +
> +  ASSERT (Node->Bar < PCI_MAX_BAR);
> +  ASSERT (Node->Virtual);
> +
> +  Address = 0;
> +  PciIo   = &(Node->PciDev->PciIo);
> +
> +  Address = Base + Node->Offset;
> +
> +  //
> +  // Indicate pci bus driver has allocated
> +  // resource for this device
> +  // It might be a temporary solution here since
> +  // pci device could have multiple bar
> +  //
> +  Node->PciDev->Allocated = TRUE;
> +
> +  switch ((Node->PciDev->VfPciBar[Node->Bar]).BarType) {
> +
> +  case PciBarTypeMem32:
> +  case PciBarTypePMem32:
> +
> +    PciIo->Pci.Write (
> +                PciIo,
> +                EfiPciIoWidthUint32,
> +                (Node->PciDev->VfPciBar[Node->Bar]).Offset,
> +                1,
> +                &Address
> +                );
> +
> +    Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
> +    break;
> +
> +  case PciBarTypeMem64:
> +  case PciBarTypePMem64:
> +
> +    Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
> +
> +    PciIo->Pci.Write (
> +                PciIo,
> +                EfiPciIoWidthUint32,
> +                (Node->PciDev->VfPciBar[Node->Bar]).Offset,
> +                1,
> +                &Address32
> +                );
> +
> +    Address32 = (UINT32) RShiftU64 (Address, 32);
> +
> +    PciIo->Pci.Write (
> +                PciIo,
> +                EfiPciIoWidthUint32,
> +                ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4),
> +                1,
> +                &Address32
> +                );
> +
> +    Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address;
> +    break;
> +
> +  case PciBarTypeIo16:
> +  case PciBarTypeIo32:
> +    break;
> +
> +  default:
> +    break;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Program PCI-PCI bridge aperture.
> +
> +  @param Base  Base address for resource.
> +  @param Node  Point to resource node structure.
> +
> +**/
> +VOID
> +ProgramPpbApperture (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT64              Address;
> +  UINT32              Address32;
> +
> +  Address = 0;
> +  //
> +  // If no device resource of this PPB, return anyway
> +  // Aperture is set default in the initialization code
> +  //
> +  if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding)
> {
> +    //
> +    // For padding resource node, just ignore when programming
> +    //
> +    return ;
> +  }
> +
> +  PciIo   = &(Node->PciDev->PciIo);
> +  Address = Base + Node->Offset;
> +
> +  //
> +  // Indicate the PPB resource has been allocated
> +  //
> +  Node->PciDev->Allocated = TRUE;
> +
> +  switch (Node->Bar) {
> +
> +  case PPB_BAR_0:
> +  case PPB_BAR_1:
> +    switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
> +
> +      case PciBarTypeIo16:
> +      case PciBarTypeIo32:
> +      case PciBarTypeMem32:
> +      case PciBarTypePMem32:
> +
> +        PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (Node->PciDev->PciBar[Node->Bar]).Offset,
> +                 1,
> +                 &Address
> +                 );
> +
> +        Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +        Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +        break;
> +
> +      case PciBarTypeMem64:
> +      case PciBarTypePMem64:
> +
> +        Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
> +
> +        PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (Node->PciDev->PciBar[Node->Bar]).Offset,
> +                 1,
> +                 &Address32
> +                 );
> +
> +        Address32 = (UINT32) RShiftU64 (Address, 32);
> +
> +        PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
> +                 1,
> +                 &Address32
> +                 );
> +
> +        Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +        Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +        break;
> +
> +      default:
> +        break;
> +    }
> +    break;
> +
> +  case PPB_IO_RANGE:
> +
> +    Address32 = ((UINT32) (Address)) >> 8;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint8,
> +                 0x1C,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 >>= 8;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint16,
> +                 0x30,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 = (UINT32) (Address + Node->Length - 1);
> +    Address32 = ((UINT32) (Address32)) >> 8;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint8,
> +                 0x1D,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 >>= 8;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint16,
> +                 0x32,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    break;
> +
> +  case PPB_MEM32_RANGE:
> +
> +    Address32 = ((UINT32) (Address)) >> 16;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint16,
> +                 0x20,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 = (UINT32) (Address + Node->Length - 1);
> +    Address32 = ((UINT32) (Address32)) >> 16;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint16,
> +                 0x22,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    break;
> +
> +  case PPB_PMEM32_RANGE:
> +  case PPB_PMEM64_RANGE:
> +
> +    Address32 = ((UINT32) (Address)) >> 16;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint16,
> +                 0x24,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 = (UINT32) (Address + Node->Length - 1);
> +    Address32 = ((UINT32) (Address32)) >> 16;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint16,
> +                 0x26,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 = (UINT32) RShiftU64 (Address, 32);
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 0x28,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 0x2C,
> +                 1,
> +                 &Address32
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    break;
> +
> +  default:
> +    break;
> +  }
> +}
> +
> +/**
> +  Program parent bridge for Option Rom.
> +
> +  @param PciDevice      Pci device instance.
> +  @param OptionRomBase  Base address for Option Rom.
> +  @param Enable         Enable or disable PCI memory.
> +
> +**/
> +VOID
> +ProgramUpstreamBridgeForRom (
> +  IN PCI_IO_DEVICE   *PciDevice,
> +  IN UINT32          OptionRomBase,
> +  IN BOOLEAN         Enable
> +  )
> +{
> +  PCI_IO_DEVICE       *Parent;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT16              Base;
> +  UINT16              Limit;
> +  //
> +  // For root bridge, just return.
> +  //
> +  Parent = PciDevice->Parent;
> +  while (Parent != NULL) {
> +    if (!IS_PCI_BRIDGE (&Parent->Pci)) {
> +      break;
> +    }
> +
> +    PciIo = &Parent->PciIo;
> +
> +    //
> +    // Program PPB to only open a single <= 16MB aperture
> +    //
> +    if (Enable) {
> +      //
> +      // Only cover MMIO for Option ROM.
> +      //
> +      Base  = (UINT16) (OptionRomBase >> 16);
> +      Limit = (UINT16) ((OptionRomBase + PciDevice->RomSize - 1) >> 16);
> +      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryBase),  1, &Base);
> +      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryLimit), 1, &Limit);
> +
> +      PCI_ENABLE_COMMAND_REGISTER (Parent,
> EFI_PCI_COMMAND_MEMORY_SPACE);
> +    } else {
> +      //
> +      // Cover 32bit MMIO for devices below the bridge.
> +      //
> +      if (Parent->PciBar[PPB_MEM32_RANGE].Length == 0) {
> +        //
> +        // When devices under the bridge contains Option ROM and doesn't
> require 32bit MMIO.
> +        //
> +        Base  = (UINT16) gAllOne;
> +        Limit = (UINT16) gAllZero;
> +      } else {
> +        Base  = (UINT16) ((UINT32) Parent-
> >PciBar[PPB_MEM32_RANGE].BaseAddress >> 16);
> +        Limit = (UINT16) ((UINT32) (Parent-
> >PciBar[PPB_MEM32_RANGE].BaseAddress
> +                                    + Parent->PciBar[PPB_MEM32_RANGE].Length - 1) >>
> 16);
> +      }
> +      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryBase),  1, &Base);
> +      PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01,
> Bridge.MemoryLimit), 1, &Limit);
> +
> +      PCI_DISABLE_COMMAND_REGISTER (Parent,
> EFI_PCI_COMMAND_MEMORY_SPACE);
> +    }
> +
> +    Parent = Parent->Parent;
> +  }
> +}
> +
> +/**
> +  Test whether resource exists for a bridge.
> +
> +  @param Bridge  Point to resource node for a bridge.
> +
> +  @retval TRUE   There is resource on the given bridge.
> +  @retval FALSE  There isn't resource on the given bridge.
> +
> +**/
> +BOOLEAN
> +ResourceRequestExisted (
> +  IN PCI_RESOURCE_NODE    *Bridge
> +  )
> +{
> +  if (Bridge != NULL) {
> +    if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
> +      return TRUE;
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Initialize resource pool structure.
> +
> +  @param ResourcePool Point to resource pool structure. This pool
> +                      is reset to all zero when returned.
> +  @param ResourceType Type of resource.
> +
> +**/
> +VOID
> +InitializeResourcePool (
> +  IN OUT PCI_RESOURCE_NODE   *ResourcePool,
> +  IN     PCI_BAR_TYPE        ResourceType
> +  )
> +{
> +  ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
> +  ResourcePool->ResType   = ResourceType;
> +  ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
> +  InitializeListHead (&ResourcePool->ChildList);
> +}
> +
> +/**
> +  Destroy given resource tree.
> +
> +  @param Bridge  PCI resource root node of resource tree.
> +
> +**/
> +VOID
> +DestroyResourceTree (
> +  IN PCI_RESOURCE_NODE *Bridge
> +  )
> +{
> +  PCI_RESOURCE_NODE *Temp;
> +  LIST_ENTRY        *CurrentLink;
> +
> +  while (!IsListEmpty (&Bridge->ChildList)) {
> +
> +    CurrentLink = Bridge->ChildList.ForwardLink;
> +
> +    Temp        = RESOURCE_NODE_FROM_LINK (CurrentLink);
> +    ASSERT (Temp);
> +
> +    RemoveEntryList (CurrentLink);
> +
> +    if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
> +      DestroyResourceTree (Temp);
> +    }
> +
> +    FreePool (Temp);
> +  }
> +}
> +
> +/**
> +  Insert resource padding for P2C.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +ResourcePaddingForCardBusBridge (
> +  IN PCI_IO_DEVICE        *PciDev,
> +  IN PCI_RESOURCE_NODE    *IoNode,
> +  IN PCI_RESOURCE_NODE    *Mem32Node,
> +  IN PCI_RESOURCE_NODE    *PMem32Node,
> +  IN PCI_RESOURCE_NODE    *Mem64Node,
> +  IN PCI_RESOURCE_NODE    *PMem64Node
> +  )
> +{
> +  PCI_RESOURCE_NODE *Node;
> +
> +  Node = NULL;
> +
> +  //
> +  // Memory Base/Limit Register 0
> +  // Bar 1 decodes memory range 0
> +  //
> +  Node = CreateResourceNode (
> +           PciDev,
> +           0x2000000,
> +           0x1ffffff,
> +           1,
> +           PciBarTypeMem32,
> +           PciResUsagePadding
> +           );
> +
> +  InsertResourceNode (
> +    Mem32Node,
> +    Node
> +    );
> +
> +  //
> +  // Memory Base/Limit Register 1
> +  // Bar 2 decodes memory range1
> +  //
> +  Node = CreateResourceNode (
> +           PciDev,
> +           0x2000000,
> +           0x1ffffff,
> +           2,
> +           PciBarTypePMem32,
> +           PciResUsagePadding
> +           );
> +
> +  InsertResourceNode (
> +    PMem32Node,
> +    Node
> +    );
> +
> +  //
> +  // Io Base/Limit
> +  // Bar 3 decodes io range 0
> +  //
> +  Node = CreateResourceNode (
> +           PciDev,
> +           0x100,
> +           0xff,
> +           3,
> +           PciBarTypeIo16,
> +           PciResUsagePadding
> +           );
> +
> +  InsertResourceNode (
> +    IoNode,
> +    Node
> +    );
> +
> +  //
> +  // Io Base/Limit
> +  // Bar 4 decodes io range 0
> +  //
> +  Node = CreateResourceNode (
> +           PciDev,
> +           0x100,
> +           0xff,
> +           4,
> +           PciBarTypeIo16,
> +           PciResUsagePadding
> +           );
> +
> +  InsertResourceNode (
> +    IoNode,
> +    Node
> +    );
> +}
> +
> +/**
> +  Program PCI Card device register for given resource node.
> +
> +  @param Base    Base address of PCI Card device to be programmed.
> +  @param Node    Given resource node.
> +
> +**/
> +VOID
> +ProgramP2C (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT64              Address;
> +  UINT64              TempAddress;
> +  UINT16              BridgeControl;
> +
> +  Address = 0;
> +  PciIo   = &(Node->PciDev->PciIo);
> +
> +  Address = Base + Node->Offset;
> +
> +  //
> +  // Indicate pci bus driver has allocated
> +  // resource for this device
> +  // It might be a temporary solution here since
> +  // pci device could have multiple bar
> +  //
> +  Node->PciDev->Allocated = TRUE;
> +
> +  switch (Node->Bar) {
> +
> +  case P2C_BAR_0:
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 (Node->PciDev->PciBar[Node->Bar]).Offset,
> +                 1,
> +                 &Address
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    break;
> +
> +  case P2C_MEM_1:
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_MEMORY_BASE_0,
> +                 1,
> +                 &Address
> +                 );
> +
> +    TempAddress = Address + Node->Length - 1;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_MEMORY_LIMIT_0,
> +                 1,
> +                 &TempAddress
> +                 );
> +
> +    if (Node->ResType == PciBarTypeMem32) {
> +      //
> +      // Set non-prefetchable bit
> +      //
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +
> +      BridgeControl &= (UINT16)
> ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
> +      PciIo->Pci.Write (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +
> +    } else {
> +      //
> +      // Set prefetchable bit
> +      //
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +
> +      BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE;
> +      PciIo->Pci.Write (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +    }
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;
> +
> +    break;
> +
> +  case P2C_MEM_2:
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_MEMORY_BASE_1,
> +                 1,
> +                 &Address
> +                 );
> +
> +    TempAddress = Address + Node->Length - 1;
> +
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_MEMORY_LIMIT_1,
> +                 1,
> +                 &TempAddress
> +                 );
> +
> +    if (Node->ResType == PciBarTypeMem32) {
> +
> +      //
> +      // Set non-prefetchable bit
> +      //
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +
> +      BridgeControl &= (UINT16)
> ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE);
> +      PciIo->Pci.Write (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +
> +    } else {
> +
> +      //
> +      // Set prefetchable bit
> +      //
> +      PciIo->Pci.Read (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +
> +      BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE;
> +      PciIo->Pci.Write (
> +                   PciIo,
> +                   EfiPciIoWidthUint16,
> +                   PCI_CARD_BRIDGE_CONTROL,
> +                   1,
> +                   &BridgeControl
> +                   );
> +    }
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;
> +    break;
> +
> +  case P2C_IO_1:
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_IO_BASE_0_LOWER,
> +                 1,
> +                 &Address
> +                 );
> +
> +    TempAddress = Address + Node->Length - 1;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_IO_LIMIT_0_LOWER,
> +                 1,
> +                 &TempAddress
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;
> +
> +    break;
> +
> +  case P2C_IO_2:
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_IO_BASE_1_LOWER,
> +                 1,
> +                 &Address
> +                 );
> +
> +    TempAddress = Address + Node->Length - 1;
> +    PciIo->Pci.Write (
> +                 PciIo,
> +                 EfiPciIoWidthUint32,
> +                 PCI_CARD_IO_LIMIT_1_LOWER,
> +                 1,
> +                 &TempAddress
> +                 );
> +
> +    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
> +    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
> +    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;
> +    break;
> +
> +  default:
> +    break;
> +  }
> +}
> +
> +/**
> +  Create padding resource node.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +ApplyResourcePadding (
> +  IN PCI_IO_DEVICE         *PciDev,
> +  IN PCI_RESOURCE_NODE     *IoNode,
> +  IN PCI_RESOURCE_NODE     *Mem32Node,
> +  IN PCI_RESOURCE_NODE     *PMem32Node,
> +  IN PCI_RESOURCE_NODE     *Mem64Node,
> +  IN PCI_RESOURCE_NODE     *PMem64Node
> +  )
> +{
> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
> +  PCI_RESOURCE_NODE                 *Node;
> +  UINT8                             DummyBarIndex;
> +
> +  DummyBarIndex = 0;
> +  Ptr           = PciDev->ResourcePaddingDescriptors;
> +
> +  while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc !=
> ACPI_END_TAG_DESCRIPTOR) {
> +
> +    if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType ==
> ACPI_ADDRESS_SPACE_TYPE_IO) {
> +      if (Ptr->AddrLen != 0) {
> +
> +        Node = CreateResourceNode (
> +                PciDev,
> +                Ptr->AddrLen,
> +                Ptr->AddrRangeMax,
> +                DummyBarIndex,
> +                PciBarTypeIo16,
> +                PciResUsagePadding
> +                );
> +        InsertResourceNode (
> +          IoNode,
> +          Node
> +          );
> +      }
> +
> +      Ptr++;
> +      continue;
> +    }
> +
> +    if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType ==
> ACPI_ADDRESS_SPACE_TYPE_MEM) {
> +
> +      if (Ptr->AddrSpaceGranularity == 32) {
> +
> +        //
> +        // prefetchable
> +        //
> +        if (Ptr->SpecificFlag == 0x6) {
> +          if (Ptr->AddrLen != 0) {
> +            Node = CreateResourceNode (
> +                    PciDev,
> +                    Ptr->AddrLen,
> +                    Ptr->AddrRangeMax,
> +                    DummyBarIndex,
> +                    PciBarTypePMem32,
> +                    PciResUsagePadding
> +                    );
> +            InsertResourceNode (
> +              PMem32Node,
> +              Node
> +              );
> +          }
> +
> +          Ptr++;
> +          continue;
> +        }
> +
> +        //
> +        // Non-prefetchable
> +        //
> +        if (Ptr->SpecificFlag == 0) {
> +          if (Ptr->AddrLen != 0) {
> +            Node = CreateResourceNode (
> +                    PciDev,
> +                    Ptr->AddrLen,
> +                    Ptr->AddrRangeMax,
> +                    DummyBarIndex,
> +                    PciBarTypeMem32,
> +                    PciResUsagePadding
> +                    );
> +            InsertResourceNode (
> +              Mem32Node,
> +              Node
> +              );
> +          }
> +
> +          Ptr++;
> +          continue;
> +        }
> +      }
> +
> +      if (Ptr->AddrSpaceGranularity == 64) {
> +
> +        //
> +        // prefetchable
> +        //
> +        if (Ptr->SpecificFlag == 0x6) {
> +          if (Ptr->AddrLen != 0) {
> +            Node = CreateResourceNode (
> +                    PciDev,
> +                    Ptr->AddrLen,
> +                    Ptr->AddrRangeMax,
> +                    DummyBarIndex,
> +                    PciBarTypePMem64,
> +                    PciResUsagePadding
> +                    );
> +            InsertResourceNode (
> +              PMem64Node,
> +              Node
> +              );
> +          }
> +
> +          Ptr++;
> +          continue;
> +        }
> +
> +        //
> +        // Non-prefetchable
> +        //
> +        if (Ptr->SpecificFlag == 0) {
> +          if (Ptr->AddrLen != 0) {
> +            Node = CreateResourceNode (
> +                    PciDev,
> +                    Ptr->AddrLen,
> +                    Ptr->AddrRangeMax,
> +                    DummyBarIndex,
> +                    PciBarTypeMem64,
> +                    PciResUsagePadding
> +                    );
> +            InsertResourceNode (
> +              Mem64Node,
> +              Node
> +              );
> +          }
> +
> +          Ptr++;
> +          continue;
> +        }
> +      }
> +    }
> +
> +    Ptr++;
> +  }
> +}
> +
> +/**
> +  Get padding resource for PCI-PCI bridge.
> +
> +  @param  PciIoDevice     PCI-PCI bridge device instance.
> +
> +  @note   Feature flag PcdPciBusHotplugDeviceSupport determines
> +          whether need to pad resource for them.
> +**/
> +VOID
> +GetResourcePaddingPpb (
> +  IN  PCI_IO_DEVICE                  *PciIoDevice
> +  )
> +{
> +  if (gPciHotPlugInit != NULL && FeaturePcdGet
> (PcdPciBusHotplugDeviceSupport)) {
> +    if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
> +      GetResourcePaddingForHpb (PciIoDevice);
> +    }
> +  }
> +}
> +
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.h
> new file mode 100644
> index 0000000000..2a33f77e55
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciResourceSupport.h
> @@ -0,0 +1,456 @@
> +/** @file
> +  PCI resources support functions declaration for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_RESOURCE_SUPPORT_H_
> +#define _EFI_PCI_RESOURCE_SUPPORT_H_
> +
> +typedef enum {
> +  PciResUsageTypical,
> +  PciResUsagePadding
> +} PCI_RESOURCE_USAGE;
> +
> +#define PCI_RESOURCE_SIGNATURE  SIGNATURE_32 ('p', 'c', 'r', 'c')
> +
> +typedef struct {
> +  UINT32              Signature;
> +  LIST_ENTRY          Link;
> +  LIST_ENTRY          ChildList;
> +  PCI_IO_DEVICE       *PciDev;
> +  UINT64              Alignment;
> +  UINT64              Offset;
> +  UINT8               Bar;
> +  PCI_BAR_TYPE        ResType;
> +  UINT64              Length;
> +  BOOLEAN             Reserved;
> +  PCI_RESOURCE_USAGE  ResourceUsage;
> +  BOOLEAN             Virtual;
> +} PCI_RESOURCE_NODE;
> +
> +#define RESOURCE_NODE_FROM_LINK(a) \
> +  CR (a, PCI_RESOURCE_NODE, Link, PCI_RESOURCE_SIGNATURE)
> +
> +/**
> +  The function is used to skip VGA range.
> +
> +  @param Start    Returned start address including VGA range.
> +  @param Length   The length of VGA range.
> +
> +**/
> +VOID
> +SkipVGAAperture (
> +  OUT UINT64   *Start,
> +  IN  UINT64   Length
> +  );
> +
> +/**
> +  This function is used to skip ISA aliasing aperture.
> +
> +  @param Start    Returned start address including ISA aliasing aperture.
> +  @param Length   The length of ISA aliasing aperture.
> +
> +**/
> +VOID
> +SkipIsaAliasAperture (
> +  OUT UINT64   *Start,
> +  IN  UINT64   Length
> +  );
> +
> +/**
> +  This function inserts a resource node into the resource list.
> +  The resource list is sorted in descend order.
> +
> +  @param Bridge  PCI resource node for bridge.
> +  @param ResNode Resource node want to be inserted.
> +
> +**/
> +VOID
> +InsertResourceNode (
> +  IN OUT PCI_RESOURCE_NODE   *Bridge,
> +  IN     PCI_RESOURCE_NODE   *ResNode
> +  );
> +
> +/**
> +  This routine is used to merge two different resource trees in need of
> +  resource degradation.
> +
> +  For example, if an upstream PPB doesn't support,
> +  prefetchable memory decoding, the PCI bus driver will choose to call this
> function
> +  to merge prefetchable memory resource list into normal memory list.
> +
> +  If the TypeMerge is TRUE, Res resource type is changed to the type of
> destination resource
> +  type.
> +  If Dst is NULL or Res is NULL, ASSERT ().
> +
> +  @param Dst        Point to destination resource tree.
> +  @param Res        Point to source resource tree.
> +  @param TypeMerge  If the TypeMerge is TRUE, Res resource type is
> changed to the type of
> +                    destination resource type.
> +
> +**/
> +VOID
> +MergeResourceTree (
> +  IN PCI_RESOURCE_NODE   *Dst,
> +  IN PCI_RESOURCE_NODE   *Res,
> +  IN BOOLEAN             TypeMerge
> +  );
> +
> +/**
> +  This function is used to calculate the IO16 aperture
> +  for a bridge.
> +
> +  @param Bridge    PCI resource node for bridge.
> +
> +**/
> +VOID
> +CalculateApertureIo16 (
> +  IN PCI_RESOURCE_NODE    *Bridge
> +  );
> +
> +/**
> +  This function is used to calculate the resource aperture
> +  for a given bridge device.
> +
> +  @param Bridge      PCI resource node for given bridge device.
> +
> +**/
> +VOID
> +CalculateResourceAperture (
> +  IN PCI_RESOURCE_NODE    *Bridge
> +  );
> +
> +/**
> +  Get IO/Memory resource info for given PCI device.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO .
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +GetResourceFromDevice (
> +  IN     PCI_IO_DEVICE     *PciDev,
> +  IN OUT PCI_RESOURCE_NODE *IoNode,
> +  IN OUT PCI_RESOURCE_NODE *Mem32Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem32Node,
> +  IN OUT PCI_RESOURCE_NODE *Mem64Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem64Node
> +  );
> +
> +/**
> +  This function is used to create a resource node.
> +
> +  @param PciDev       Pci device instance.
> +  @param Length       Length of Io/Memory resource.
> +  @param Alignment    Alignment of resource.
> +  @param Bar          Bar index.
> +  @param ResType      Type of resource: IO/Memory.
> +  @param ResUsage     Resource usage.
> +
> +  @return PCI resource node created for given PCI device.
> +          NULL means PCI resource node is not created.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +CreateResourceNode (
> +  IN PCI_IO_DEVICE         *PciDev,
> +  IN UINT64                Length,
> +  IN UINT64                Alignment,
> +  IN UINT8                 Bar,
> +  IN PCI_BAR_TYPE          ResType,
> +  IN PCI_RESOURCE_USAGE    ResUsage
> +  );
> +
> +/**
> +  This function is used to create a IOV VF resource node.
> +
> +  @param PciDev       Pci device instance.
> +  @param Length       Length of Io/Memory resource.
> +  @param Alignment    Alignment of resource.
> +  @param Bar          Bar index.
> +  @param ResType      Type of resource: IO/Memory.
> +  @param ResUsage     Resource usage.
> +
> +  @return PCI resource node created for given VF PCI device.
> +          NULL means PCI resource node is not created.
> +
> +**/
> +PCI_RESOURCE_NODE *
> +CreateVfResourceNode (
> +  IN PCI_IO_DEVICE         *PciDev,
> +  IN UINT64                Length,
> +  IN UINT64                Alignment,
> +  IN UINT8                 Bar,
> +  IN PCI_BAR_TYPE          ResType,
> +  IN PCI_RESOURCE_USAGE    ResUsage
> +  );
> +
> +/**
> +  This function is used to extract resource request from
> +  device node list.
> +
> +  @param Bridge     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +CreateResourceMap (
> +  IN     PCI_IO_DEVICE     *Bridge,
> +  IN OUT PCI_RESOURCE_NODE *IoNode,
> +  IN OUT PCI_RESOURCE_NODE *Mem32Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem32Node,
> +  IN OUT PCI_RESOURCE_NODE *Mem64Node,
> +  IN OUT PCI_RESOURCE_NODE *PMem64Node
> +  );
> +
> +/**
> +  This function is used to do the resource padding for a specific platform.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +ResourcePaddingPolicy (
> +  IN PCI_IO_DEVICE     *PciDev,
> +  IN PCI_RESOURCE_NODE *IoNode,
> +  IN PCI_RESOURCE_NODE *Mem32Node,
> +  IN PCI_RESOURCE_NODE *PMem32Node,
> +  IN PCI_RESOURCE_NODE *Mem64Node,
> +  IN PCI_RESOURCE_NODE *PMem64Node
> +  );
> +
> +/**
> +  This function is used to degrade resource if the upstream bridge
> +  doesn't support certain resource. Degradation path is
> +  PMEM64 -> MEM64  -> MEM32
> +  PMEM64 -> PMEM32 -> MEM32
> +  IO32   -> IO16.
> +
> +  @param Bridge     Pci device instance.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +DegradeResource (
> +  IN PCI_IO_DEVICE     *Bridge,
> +  IN PCI_RESOURCE_NODE *Mem32Node,
> +  IN PCI_RESOURCE_NODE *PMem32Node,
> +  IN PCI_RESOURCE_NODE *Mem64Node,
> +  IN PCI_RESOURCE_NODE *PMem64Node
> +  );
> +
> +/**
> +  Test whether bridge device support decode resource.
> +
> +  @param Bridge    Bridge device instance.
> +  @param Decode    Decode type according to resource type.
> +
> +  @return TRUE     The bridge device support decode resource.
> +  @return FALSE    The bridge device don't support decode resource.
> +
> +**/
> +BOOLEAN
> +BridgeSupportResourceDecode (
> +  IN PCI_IO_DEVICE *Bridge,
> +  IN UINT32        Decode
> +  );
> +
> +/**
> +  This function is used to program the resource allocated
> +  for each resource node under specified bridge.
> +
> +  @param Base     Base address of resource to be programmed.
> +  @param Bridge   PCI resource node for the bridge device.
> +
> +  @retval EFI_SUCCESS            Successfully to program all resources
> +                                 on given PCI bridge device.
> +  @retval EFI_OUT_OF_RESOURCES   Base is all one.
> +
> +**/
> +EFI_STATUS
> +ProgramResource (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Bridge
> +  );
> +
> +/**
> +  Program Bar register for PCI device.
> +
> +  @param Base  Base address for PCI device resource to be programmed.
> +  @param Node  Point to resource node structure.
> +
> +**/
> +VOID
> +ProgramBar (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  );
> +
> +/**
> +  Program IOV VF Bar register for PCI device.
> +
> +  @param Base  Base address for PCI device resource to be programmed.
> +  @param Node  Point to resource node structure.
> +
> +**/
> +EFI_STATUS
> +ProgramVfBar (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  );
> +
> +/**
> +  Program PCI-PCI bridge aperture.
> +
> +  @param Base  Base address for resource.
> +  @param Node  Point to resource node structure.
> +
> +**/
> +VOID
> +ProgramPpbApperture (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  );
> +
> +/**
> +  Program parent bridge for Option Rom.
> +
> +  @param PciDevice      Pci device instance.
> +  @param OptionRomBase  Base address for Option Rom.
> +  @param Enable         Enable or disable PCI memory.
> +
> +**/
> +VOID
> +ProgramUpstreamBridgeForRom (
> +  IN PCI_IO_DEVICE   *PciDevice,
> +  IN UINT32          OptionRomBase,
> +  IN BOOLEAN         Enable
> +  );
> +
> +/**
> +  Test whether resource exists for a bridge.
> +
> +  @param Bridge  Point to resource node for a bridge.
> +
> +  @retval TRUE   There is resource on the given bridge.
> +  @retval FALSE  There isn't resource on the given bridge.
> +
> +**/
> +BOOLEAN
> +ResourceRequestExisted (
> +  IN PCI_RESOURCE_NODE    *Bridge
> +  );
> +
> +/**
> +  Initialize resource pool structure.
> +
> +  @param ResourcePool Point to resource pool structure. This pool
> +                      is reset to all zero when returned.
> +  @param ResourceType Type of resource.
> +
> +**/
> +VOID
> +InitializeResourcePool (
> +  IN OUT PCI_RESOURCE_NODE   *ResourcePool,
> +  IN     PCI_BAR_TYPE        ResourceType
> +  );
> +
> +/**
> +  Destroy given resource tree.
> +
> +  @param Bridge  PCI resource root node of resource tree.
> +
> +**/
> +VOID
> +DestroyResourceTree (
> +  IN PCI_RESOURCE_NODE *Bridge
> +  );
> +
> +/**
> +  Insert resource padding for P2C.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +ResourcePaddingForCardBusBridge (
> +  IN PCI_IO_DEVICE        *PciDev,
> +  IN PCI_RESOURCE_NODE    *IoNode,
> +  IN PCI_RESOURCE_NODE    *Mem32Node,
> +  IN PCI_RESOURCE_NODE    *PMem32Node,
> +  IN PCI_RESOURCE_NODE    *Mem64Node,
> +  IN PCI_RESOURCE_NODE    *PMem64Node
> +  );
> +
> +/**
> +  Program PCI Card device register for given resource node.
> +
> +  @param Base    Base address of PCI Card device to be programmed.
> +  @param Node    Given resource node.
> +
> +**/
> +VOID
> +ProgramP2C (
> +  IN UINT64            Base,
> +  IN PCI_RESOURCE_NODE *Node
> +  );
> +
> +/**
> +  Create padding resource node.
> +
> +  @param PciDev     Pci device instance.
> +  @param IoNode     Resource info node for IO.
> +  @param Mem32Node  Resource info node for 32-bit memory.
> +  @param PMem32Node Resource info node for 32-bit Prefetchable
> Memory.
> +  @param Mem64Node  Resource info node for 64-bit memory.
> +  @param PMem64Node Resource info node for 64-bit Prefetchable
> Memory.
> +
> +**/
> +VOID
> +ApplyResourcePadding (
> +  IN PCI_IO_DEVICE         *PciDev,
> +  IN PCI_RESOURCE_NODE     *IoNode,
> +  IN PCI_RESOURCE_NODE     *Mem32Node,
> +  IN PCI_RESOURCE_NODE     *PMem32Node,
> +  IN PCI_RESOURCE_NODE     *Mem64Node,
> +  IN PCI_RESOURCE_NODE     *PMem64Node
> +  );
> +
> +/**
> +  Get padding resource for PCI-PCI bridge.
> +
> +  @param  PciIoDevice     PCI-PCI bridge device instance.
> +
> +  @note   Feature flag PcdPciBusHotplugDeviceSupport determines
> +          whether need to pad resource for them.
> +**/
> +VOID
> +GetResourcePaddingPpb (
> +  IN  PCI_IO_DEVICE                  *PciIoDevice
> +  );
> +
> +#endif
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.c
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.c
> new file mode 100644
> index 0000000000..507aed5cfe
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.c
> @@ -0,0 +1,135 @@
> +/** @file
> +  Set up ROM Table for PCI Bus module.
> +
> +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PciBus.h"
> +
> +//
> +// PCI ROM image information
> +//
> +typedef struct {
> +  EFI_HANDLE  ImageHandle;
> +  UINTN       Seg;
> +  UINT8       Bus;
> +  UINT8       Dev;
> +  UINT8       Func;
> +  VOID        *RomImage;
> +  UINT64      RomSize;
> +} PCI_ROM_IMAGE;
> +
> +UINTN          mNumberOfPciRomImages     = 0;
> +UINTN          mMaxNumberOfPciRomImages  = 0;
> +PCI_ROM_IMAGE  *mRomImageTable           = NULL;
> +
> +/**
> +  Add the Rom Image to internal database for later PCI light enumeration.
> +
> +  @param ImageHandle    Option Rom image handle.
> +  @param Seg            Segment of PCI space.
> +  @param Bus            Bus NO of PCI space.
> +  @param Dev            Dev NO of PCI space.
> +  @param Func           Func NO of PCI space.
> +  @param RomImage       Option Rom buffer.
> +  @param RomSize        Size of Option Rom buffer.
> +**/
> +VOID
> +PciRomAddImageMapping (
> +  IN  EFI_HANDLE  ImageHandle,
> +  IN  UINTN       Seg,
> +  IN  UINT8       Bus,
> +  IN  UINT8       Dev,
> +  IN  UINT8       Func,
> +  IN  VOID        *RomImage,
> +  IN  UINT64      RomSize
> +  )
> +{
> +  UINTN           Index;
> +  PCI_ROM_IMAGE   *NewTable;
> +
> +  for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
> +    if (mRomImageTable[Index].Seg  == Seg &&
> +        mRomImageTable[Index].Bus  == Bus &&
> +        mRomImageTable[Index].Dev  == Dev &&
> +        mRomImageTable[Index].Func == Func) {
> +      //
> +      // Expect once RomImage and RomSize are recorded, they will be passed
> in
> +      // later when updating ImageHandle
> +      //
> +      ASSERT ((mRomImageTable[Index].RomImage == NULL) || (RomImage
> == mRomImageTable[Index].RomImage));
> +      ASSERT ((mRomImageTable[Index].RomSize  == 0   ) || (RomSize  ==
> mRomImageTable[Index].RomSize ));
> +      break;
> +    }
> +  }
> +
> +  if (Index == mNumberOfPciRomImages) {
> +    //
> +    // Rom Image Table buffer needs to grow.
> +    //
> +    if (mNumberOfPciRomImages == mMaxNumberOfPciRomImages) {
> +      NewTable = ReallocatePool (
> +                   mMaxNumberOfPciRomImages * sizeof (PCI_ROM_IMAGE),
> +                   (mMaxNumberOfPciRomImages + 0x20) * sizeof
> (PCI_ROM_IMAGE),
> +                   mRomImageTable
> +                   );
> +      if (NewTable == NULL) {
> +        return ;
> +      }
> +
> +      mRomImageTable            = NewTable;
> +      mMaxNumberOfPciRomImages += 0x20;
> +    }
> +    //
> +    // Record the new PCI device
> +    //
> +    mRomImageTable[Index].Seg  = Seg;
> +    mRomImageTable[Index].Bus  = Bus;
> +    mRomImageTable[Index].Dev  = Dev;
> +    mRomImageTable[Index].Func = Func;
> +    mNumberOfPciRomImages++;
> +  }
> +
> +  mRomImageTable[Index].ImageHandle = ImageHandle;
> +  mRomImageTable[Index].RomImage    = RomImage;
> +  mRomImageTable[Index].RomSize     = RomSize;
> +}
> +
> +/**
> +  Get Option rom driver's mapping for PCI device.
> +
> +  @param PciIoDevice Device instance.
> +
> +  @retval TRUE   Found Image mapping.
> +  @retval FALSE  Cannot found image mapping.
> +
> +**/
> +BOOLEAN
> +PciRomGetImageMapping (
> +  IN  PCI_IO_DEVICE                       *PciIoDevice
> +  )
> +{
> +  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
> +  UINTN                           Index;
> +
> +  PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
> +
> +  for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
> +    if (mRomImageTable[Index].Seg  == PciRootBridgeIo->SegmentNumber
> &&
> +        mRomImageTable[Index].Bus  == PciIoDevice->BusNumber         &&
> +        mRomImageTable[Index].Dev  == PciIoDevice->DeviceNumber      &&
> +        mRomImageTable[Index].Func == PciIoDevice->FunctionNumber    ) {
> +
> +      if (mRomImageTable[Index].ImageHandle != NULL) {
> +        AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle, NULL);
> +      }
> +      PciIoDevice->PciIo.RomImage = mRomImageTable[Index].RomImage;
> +      PciIoDevice->PciIo.RomSize  = mRomImageTable[Index].RomSize;
> +      return TRUE;
> +    }
> +  }
> +
> +  return FALSE;
> +}
> diff --git
> a/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.h
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.h
> new file mode 100644
> index 0000000000..fb356bd6de
> --- /dev/null
> +++
> b/Platform/Intel/PurleyOpenBoardPkg/Override/MdeModulePkg/Bus/Pci/P
> ciBusDxe/PciRomTable.h
> @@ -0,0 +1,48 @@
> +/** @file
> +  Set up ROM Table for PCI Bus module.
> +
> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _EFI_PCI_ROM_TABLE_H_
> +#define _EFI_PCI_ROM_TABLE_H_
> +
> +/**
> +  Add the Rom Image to internal database for later PCI light enumeration.
> +
> +  @param ImageHandle    Option Rom image handle.
> +  @param Seg            Segment of PCI space.
> +  @param Bus            Bus NO of PCI space.
> +  @param Dev            Dev NO of PCI space.
> +  @param Func           Func NO of PCI space.
> +  @param RomImage       Option Rom buffer.
> +  @param RomSize        Size of Option Rom buffer.
> +**/
> +VOID
> +PciRomAddImageMapping (
> +  IN  EFI_HANDLE  ImageHandle,
> +  IN  UINTN       Seg,
> +  IN  UINT8       Bus,
> +  IN  UINT8       Dev,
> +  IN  UINT8       Func,
> +  IN  VOID        *RomImage,
> +  IN  UINT64      RomSize
> +  );
> +
> +/**
> +  Get Option rom driver's mapping for PCI device.
> +
> +  @param PciIoDevice Device instance.
> +
> +  @retval TRUE   Found Image mapping.
> +  @retval FALSE  Cannot found image mapping.
> +
> +**/
> +BOOLEAN
> +PciRomGetImageMapping (
> +  IN  PCI_IO_DEVICE                       *PciIoDevice
> +  );
> +
> +#endif
> --
> 2.25.0.windows.1
> 
> 
> Please consider the environment before printing this email.
> 
> The information contained in this message may be confidential and
> proprietary to American Megatrends (AMI).  This communication is intended
> to be read only by the individual or entity to whom it is addressed or by their
> designee. If the reader of this message is not the intended recipient, you are
> on notice that any distribution of this message, in any form, is strictly
> prohibited.  Please promptly notify the sender by reply e-mail or by
> telephone at 770-246-8600, and then delete or destroy all copies of the
> transmission.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#78330): https://edk2.groups.io/g/devel/message/78330
Mute This Topic: https://groups.io/mt/83594335/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list