audk/MdeModulePkg/Bus/Pci/PciBusDxe
Alex Williamson b0bc24aff5 The following call tree exposes a bug in the lifetime (ie. too late
creation) of PciIoDevice->DevicePath. The bug can be triggered when
PciBusDxe is built into OVMF, with qemu/KVM device assignment of
a PCI-express device on the default 440FX machine type.  OVMF
correctly discovers that the device is PCIe and begins probing
extended configuration space for the device.  The root bridge
has no way to access extended config space and correctly errors,
sending us into the error reporting chain seen below.  It's
possible that this error path could also be reproduced on physical
hardware when a PCI-to-PCIe bridge is present.

GatherDeviceInfo() | GatherPpbInfo() | GatherP2CInfo() [MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c]
  CreatePciIoDevice()                                  [MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c]
    AllocateZeroPool()
    LocateCapabilityRegBlock()                         [MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c]
    PciIoDevice->IsPciExp = TRUE
    LocatePciExpressCapabilityRegBlock()               [MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c]
      PciIoConfigRead() via funcptr                    [MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c]
        RootBridgeIoPciRead() via funcptr              [PcAtChipsetPkg/PciHostBridgeDxe/PciRootBridgeIo.c]
          FAILS
        REPORT_STATUS_CODE_WITH_DEVICE_PATH()          [MdePkg/Include/Library/ReportStatusCodeLib.h]
          ReportStatusCodeWithDevicePath()             [MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c]
            ASSERT (DevicePath != NULL) <--+
  CreatePciDevicePath()                    |           [MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c]
    sets PciIoDevice->DevicePath ----------+

In English:
- CreatePciIoDevice() allocates a zeroed out PCI_IO_DEVICE structure.
- PciIoConfigRead() tries to access the (extended) config space, and
  fails.
- PciIoConfigRead() wants to report a status code (read error) for the
  device path.
- Unfortuantely, PciIoDevice->DevicePath is still NULL at that point.
- The ASSERT() in ReportStatusCodeWithDevicePath() fires.

Fix it by moving CreatePciDevicePath() into CreatePciIoDevice(),
allowing PciIoDevice->DevicePath to be initialized before we
begin probing the device capabilities:

GatherDeviceInfo() | GatherPpbInfo() | GatherP2CInfo() [MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c]
  CreatePciIoDevice()                                  [MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c]
    AllocateZeroPool()
    CreatePciDevicePath()                              [MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c]
      sets PciIoDevice->DevicePath -----------+
    LocateCapabilityRegBlock()                |        [MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c]
    PciIoDevice->IsPciExp = TRUE              |
    LocatePciExpressCapabilityRegBlock()      |        [MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c]
      PciIoConfigRead() via funcptr           |        [MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c]
        RootBridgeIoPciRead() via funcptr     |        [PcAtChipsetPkg/PciHostBridgeDxe/PciRootBridgeIo.c]
          FAILS                               |
        REPORT_STATUS_CODE_WITH_DEVICE_PATH() |        [MdePkg/Include/Library/ReportStatusCodeLib.h]
          ReportStatusCodeWithDevicePath()    |        [MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c]
            ASSERT (DevicePath != NULL) <-----+

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15567 6f19259b-4bc3-4df7-8a09-765794883524
2014-06-19 01:41:15 +00:00
..
ComponentName.c Fix the comments to follow UEFI Spec regarding how to check an EFI_HANDLE is valid/invalid. 2011-07-06 03:55:36 +00:00
ComponentName.h Fix the comments to follow UEFI Spec regarding how to check an EFI_HANDLE is valid/invalid. 2011-07-06 03:55:36 +00:00
PciBus.c MdeModulePkg: introduce PcdPciDisableBusEnumeration 2013-12-08 01:35:32 +00:00
PciBus.h Update all the code to consume the ConvertDevicePathToText, ConvertDevicePathNodeToText, ConvertTextToDevicePath and ConvertTextToDeviceNode APIs in DevicePathLib. 2013-07-26 03:14:08 +00:00
PciBusDxe.inf MdeModulePkg: introduce PcdPciDisableBusEnumeration 2013-12-08 01:35:32 +00:00
PciCommand.c Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciCommand.h Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciDeviceSupport.c Cache the state whether the ROM image contains EFI Option ROM when loading the ROM content from PCI device to memory to avoid re-parsing the ROM image to check the EFI Option ROM. 2012-09-07 03:15:25 +00:00
PciDeviceSupport.h Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciDriverOverride.c Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciDriverOverride.h Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciEnumerator.c Change the PciBusDxe driver to install the PCI enumeration complete GUID in the PCI host bridge handle to follow PI Spec 1.3. 2013-08-16 09:20:58 +00:00
PciEnumerator.h Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciEnumeratorSupport.c The following call tree exposes a bug in the lifetime (ie. too late 2014-06-19 01:41:15 +00:00
PciEnumeratorSupport.h Fix bugs in the PCI bus driver to support SR-IOV. 2010-07-13 01:58:47 +00:00
PciHotPlugSupport.c The PCI HotPlug Init Protocol returns a list of Root HPC, but it is possible that some HPCs in the list are not found during PCI enumeration. In this case, the PCI HotPlug Init Protocol.InitializeRootHpc() will not be called for the un-found HPCs. However, in AllRootHPCInitialized(), all reported HPCs are checked to see if it has been initialized, so TIME_OUT happens. 2010-11-22 07:16:02 +00:00
PciHotPlugSupport.h The PCI HotPlug Init Protocol returns a list of Root HPC, but it is possible that some HPCs in the list are not found during PCI enumeration. In this case, the PCI HotPlug Init Protocol.InitializeRootHpc() will not be called for the un-found HPCs. However, in AllRootHPCInitialized(), all reported HPCs are checked to see if it has been initialized, so TIME_OUT happens. 2010-11-22 07:16:02 +00:00
PciIo.c Change PciIo::GetBarAttributes() to return unsupported for a unsupported bar even it's below 6 to follow the UEFI Spec. 2014-05-15 07:22:27 +00:00
PciIo.h Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciLib.c Update all the code to consume the ConvertDevicePathToText, ConvertDevicePathNodeToText, ConvertTextToDevicePath and ConvertTextToDeviceNode APIs in DevicePathLib. 2013-07-26 03:14:08 +00:00
PciLib.h MdeModulePkg PciBusDxe: The PCI Bus Driver is updated to support multiple PCI bus ranges for a PCI root bridge. 2011-10-28 09:59:40 +00:00
PciOptionRomSupport.c Cache the state whether the ROM image contains EFI Option ROM when loading the ROM content from PCI device to memory to avoid re-parsing the ROM image to check the EFI Option ROM. 2012-09-07 03:15:25 +00:00
PciOptionRomSupport.h Cache the state whether the ROM image contains EFI Option ROM when loading the ROM content from PCI device to memory to avoid re-parsing the ROM image to check the EFI Option ROM. 2012-09-07 03:15:25 +00:00
PciPowerManagement.c MdeModulePkg PciBusDxe and DuetPkg PciBusNoEnumerationDxe: Update ResetPowerManagementFeature() to clear 4 related R/W bits in the PMCSR register, leaving other bits preserved. 2012-04-12 01:49:27 +00:00
PciPowerManagement.h Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciResourceSupport.c Fix the bug which incorrectly programs the 64bit base address register in the PCI to PCI bridge. 2013-04-27 02:03:58 +00:00
PciResourceSupport.h Print resource allocation/bar programming when PciBus driver does PCI BUS enumeration. 2011-08-04 09:08:09 +00:00
PciRomTable.c Update the copyright notice format 2010-04-24 09:49:11 +00:00
PciRomTable.h Update the copyright notice format 2010-04-24 09:49:11 +00:00