diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h index 55b380b285..08dd7f8f7d 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -27,6 +28,11 @@ #include +typedef struct { + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 PciAttributes; +} ORIGINAL_ATTRIBUTES; + EFI_STATUS EFIAPI InstallAcpiTable ( @@ -73,5 +79,17 @@ InstallAcpiTables ( IN EFI_ACPI_TABLE_PROTOCOL *AcpiTable ); +VOID +EnablePciDecoding ( + OUT ORIGINAL_ATTRIBUTES **OriginalAttributes, + OUT UINTN *Count + ); + +VOID +RestorePciDecoding ( + IN ORIGINAL_ATTRIBUTES *OriginalAttributes, + IN UINTN Count + ); + #endif diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf index 8e98053994..654d3a0390 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -32,6 +32,7 @@ QemuFwCfgAcpi.c Xen.c EntryPoint.c + PciDecoding.c [Packages] MdePkg/MdePkg.dec @@ -57,6 +58,7 @@ [Protocols] gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED [Guids] gEfiXenInfoGuid diff --git a/OvmfPkg/AcpiPlatformDxe/PciDecoding.c b/OvmfPkg/AcpiPlatformDxe/PciDecoding.c new file mode 100644 index 0000000000..3b9b12ccc8 --- /dev/null +++ b/OvmfPkg/AcpiPlatformDxe/PciDecoding.c @@ -0,0 +1,186 @@ +/** @file + Temporarily enable IO and MMIO decoding for all PCI devices while QEMU + regenerates the ACPI tables. + + Copyright (C) 2016, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include + +#include "AcpiPlatform.h" + + +/** + Collect all PciIo protocol instances in the system. Save their original + attributes, and enable IO and MMIO decoding for each. + + This is a best effort function; it doesn't return status codes. Its + caller is supposed to proceed even if this function fails. + + @param[out] OriginalAttributes On output, a dynamically allocated array of + ORIGINAL_ATTRIBUTES elements. The array lists + the PciIo protocol instances found in the + system at the time of the call, plus the + original PCI attributes for each. + + Before returning, the function enables IO and + MMIO decoding for each PciIo instance it + finds. + + On error, or when no such instances are + found, OriginalAttributes is set to NULL. + + @param[out] Count On output, the number of elements in + OriginalAttributes. On error it is set to + zero. +**/ +VOID +EnablePciDecoding ( + OUT ORIGINAL_ATTRIBUTES **OriginalAttributes, + OUT UINTN *Count + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + EFI_HANDLE *Handles; + ORIGINAL_ATTRIBUTES *OrigAttrs; + UINTN Idx; + + *OriginalAttributes = NULL; + *Count = 0; + + if (PcdGetBool (PcdPciDisableBusEnumeration)) { + // + // The platform downloads ACPI tables from QEMU in general, but there are + // no root bridges in this execution. We're done. + // + return; + } + + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, + NULL /* SearchKey */, &NoHandles, &Handles); + if (Status == EFI_NOT_FOUND) { + // + // No PCI devices were found on either of the root bridges. We're done. + // + return; + } + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "%a: LocateHandleBuffer(): %r\n", __FUNCTION__, + Status)); + return; + } + + OrigAttrs = AllocatePool (NoHandles * sizeof *OrigAttrs); + if (OrigAttrs == NULL) { + DEBUG ((EFI_D_WARN, "%a: AllocatePool(): out of resources\n", + __FUNCTION__)); + goto FreeHandles; + } + + for (Idx = 0; Idx < NoHandles; ++Idx) { + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // Look up PciIo on the handle and stash it + // + Status = gBS->HandleProtocol (Handles[Idx], &gEfiPciIoProtocolGuid, + (VOID**)&PciIo); + ASSERT_EFI_ERROR (Status); + OrigAttrs[Idx].PciIo = PciIo; + + // + // Stash the current attributes + // + Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationGet, 0, + &OrigAttrs[Idx].PciAttributes); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "%a: EfiPciIoAttributeOperationGet: %r\n", + __FUNCTION__, Status)); + goto RestoreAttributes; + } + + // + // Enable IO and MMIO decoding + // + Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY, + NULL); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "%a: EfiPciIoAttributeOperationEnable: %r\n", + __FUNCTION__, Status)); + goto RestoreAttributes; + } + } + + // + // Success + // + FreePool (Handles); + *OriginalAttributes = OrigAttrs; + *Count = NoHandles; + return; + +RestoreAttributes: + while (Idx > 0) { + --Idx; + OrigAttrs[Idx].PciIo->Attributes (OrigAttrs[Idx].PciIo, + EfiPciIoAttributeOperationSet, + OrigAttrs[Idx].PciAttributes, + NULL + ); + } + FreePool (OrigAttrs); + +FreeHandles: + FreePool (Handles); +} + + +/** + Restore the original PCI attributes saved with EnablePciDecoding(). + + @param[in] OriginalAttributes The array allocated and populated by + EnablePciDecoding(). This parameter may be + NULL. If OriginalAttributes is NULL, then the + function is a no-op; otherwise the PciIo + attributes will be restored, and the + OriginalAttributes array will be freed. + + @param[in] Count The Count value stored by EnablePciDecoding(), + the number of elements in OriginalAttributes. + Count may be zero if and only if + OriginalAttributes is NULL. +**/ +VOID +RestorePciDecoding ( + IN ORIGINAL_ATTRIBUTES *OriginalAttributes, + IN UINTN Count + ) +{ + UINTN Idx; + + ASSERT ((OriginalAttributes == NULL) == (Count == 0)); + if (OriginalAttributes == NULL) { + return; + } + + for (Idx = 0; Idx < Count; ++Idx) { + OriginalAttributes[Idx].PciIo->Attributes ( + OriginalAttributes[Idx].PciIo, + EfiPciIoAttributeOperationSet, + OriginalAttributes[Idx].PciAttributes, + NULL + ); + } + FreePool (OriginalAttributes); +} diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c index 81620448a0..faaff3757c 100644 --- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c +++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c @@ -561,6 +561,8 @@ InstallQemuFwCfgTables ( UINTN FwCfgSize; QEMU_LOADER_ENTRY *LoaderStart; CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd; + ORIGINAL_ATTRIBUTES *OriginalPciAttributes; + UINTN OriginalPciAttributesCount; ORDERED_COLLECTION *Tracker; UINTN *InstalledKey; INT32 Installed; @@ -580,8 +582,10 @@ InstallQemuFwCfgTables ( if (LoaderStart == NULL) { return EFI_OUT_OF_RESOURCES; } + EnablePciDecoding (&OriginalPciAttributes, &OriginalPciAttributesCount); QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, LoaderStart); + RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount); LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry; Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare); diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf index c073b2a47e..d99f2d5a95 100644 --- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf +++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf @@ -30,6 +30,7 @@ QemuFwCfgAcpiPlatform.c QemuFwCfgAcpi.c EntryPoint.c + PciDecoding.c [Packages] MdePkg/MdePkg.dec @@ -47,6 +48,7 @@ [Protocols] gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED [Guids] gRootBridgesConnectedEventGroupGuid