[edk2-devel] [PATCH v3 6/6] BhyvePkg: Add AcpiPlatformDxe

Rebecca Cran rebecca at bsdio.com
Tue Apr 21 03:09:55 UTC 2020


Make a copy of OvmfPkg/AcpiPlatformDxe under BhyvePkg, with the changes
needed to support the bhyve hypervisor.

Signed-off-by: Rebecca Cran <rebecca at bsdio.com>
---
 BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c      | 250 +++++++++++++++++++
 BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h      |  76 ++++++
 BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf |  64 +++++
 BhyvePkg/AcpiPlatformDxe/Bhyve.c             | 138 ++++++++++
 BhyvePkg/AcpiPlatformDxe/EntryPoint.c        |  90 +++++++
 BhyvePkg/AcpiPlatformDxe/PciDecoding.c       | 192 ++++++++++++++
 6 files changed, 810 insertions(+)
 create mode 100644 BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c
 create mode 100644 BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h
 create mode 100644 BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
 create mode 100644 BhyvePkg/AcpiPlatformDxe/Bhyve.c
 create mode 100644 BhyvePkg/AcpiPlatformDxe/EntryPoint.c
 create mode 100644 BhyvePkg/AcpiPlatformDxe/PciDecoding.c

diff --git a/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c b/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c
new file mode 100644
index 0000000000..4814a9f1e6
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c
@@ -0,0 +1,250 @@
+/** @file
+  OVMF ACPI Platform Driver
+
+  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AcpiPlatform.h"
+
+EFI_STATUS
+EFIAPI
+InstallAcpiTable (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
+  IN   VOID                          *AcpiTableBuffer,
+  IN   UINTN                         AcpiTableBufferSize,
+  OUT  UINTN                         *TableKey
+  )
+{
+  return AcpiProtocol->InstallAcpiTable (
+                         AcpiProtocol,
+                         AcpiTableBuffer,
+                         AcpiTableBufferSize,
+                         TableKey
+                         );
+}
+
+
+/**
+  Locate the first instance of a protocol.  If the protocol requested is an
+  FV protocol, then it will return the first FV that contains the ACPI table
+  storage file.
+
+  @param  Instance      Return pointer to the first instance of the protocol
+
+  @return EFI_SUCCESS           The function completed successfully.
+  @return EFI_NOT_FOUND         The protocol could not be located.
+  @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
+
+**/
+EFI_STATUS
+LocateFvInstanceWithTables (
+  OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_HANDLE                    *HandleBuffer;
+  UINTN                         NumberOfHandles;
+  EFI_FV_FILETYPE               FileType;
+  UINT32                        FvStatus;
+  EFI_FV_FILE_ATTRIBUTES        Attributes;
+  UINTN                         Size;
+  UINTN                         Index;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+
+  FvStatus = 0;
+
+  //
+  // Locate protocol.
+  //
+  Status = gBS->LocateHandleBuffer (
+                   ByProtocol,
+                   &gEfiFirmwareVolume2ProtocolGuid,
+                   NULL,
+                   &NumberOfHandles,
+                   &HandleBuffer
+                   );
+  if (EFI_ERROR (Status)) {
+    //
+    // Defined errors at this time are not found and out of resources.
+    //
+    return Status;
+  }
+
+  //
+  // Looking for FV with ACPI storage file
+  //
+  for (Index = 0; Index < NumberOfHandles; Index++) {
+    //
+    // Get the protocol on this handle
+    // This should not fail because of LocateHandleBuffer
+    //
+    Status = gBS->HandleProtocol (
+                     HandleBuffer[Index],
+                     &gEfiFirmwareVolume2ProtocolGuid,
+                     (VOID**) &FvInstance
+                     );
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // See if it has the ACPI storage file
+    //
+    Status = FvInstance->ReadFile (
+                           FvInstance,
+                           (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
+                           NULL,
+                           &Size,
+                           &FileType,
+                           &Attributes,
+                           &FvStatus
+                           );
+
+    //
+    // If we found it, then we are done
+    //
+    if (Status == EFI_SUCCESS) {
+      *Instance = FvInstance;
+      break;
+    }
+  }
+
+  //
+  // Our exit status is determined by the success of the previous operations
+  // If the protocol was found, Instance already points to it.
+  //
+
+  //
+  // Free any allocated buffers
+  //
+  gBS->FreePool (HandleBuffer);
+
+  return Status;
+}
+
+
+/**
+  Find ACPI tables in an FV and install them.
+
+  This is now a fall-back path. Normally, we will search for tables provided
+  by the VMM first.
+
+  If that fails, we use this function to load the ACPI tables from an FV. The
+  sources for the FV based tables is located under OvmfPkg/AcpiTables.
+
+  @param  AcpiTable     Protocol instance pointer
+
+**/
+EFI_STATUS
+EFIAPI
+InstallOvmfFvTables (
+  IN  EFI_ACPI_TABLE_PROTOCOL     *AcpiTable
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL        *FwVol;
+  INTN                                 Instance;
+  EFI_ACPI_COMMON_HEADER               *CurrentTable;
+  UINTN                                TableHandle;
+  UINT32                               FvStatus;
+  UINTN                                TableSize;
+  UINTN                                Size;
+  EFI_ACPI_TABLE_INSTALL_ACPI_TABLE    TableInstallFunction;
+
+  Instance     = 0;
+  CurrentTable = NULL;
+  TableHandle  = 0;
+
+  TableInstallFunction = BhyveInstallAcpiTable;
+
+  //
+  // set FwVol (and use an ASSERT() below) to suppress incorrect
+  // compiler/analyzer warnings
+  //
+  FwVol = NULL;
+  //
+  // Locate the firmware volume protocol
+  //
+  Status = LocateFvInstanceWithTables (&FwVol);
+  if (EFI_ERROR (Status)) {
+    return EFI_ABORTED;
+  }
+  ASSERT (FwVol != NULL);
+
+  //
+  // Read tables from the storage file.
+  //
+  while (Status == EFI_SUCCESS) {
+
+    Status = FwVol->ReadSection (
+                      FwVol,
+                      (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
+                      EFI_SECTION_RAW,
+                      Instance,
+                      (VOID**) &CurrentTable,
+                      &Size,
+                      &FvStatus
+                      );
+    if (!EFI_ERROR (Status)) {
+      //
+      // Add the table
+      //
+      TableHandle = 0;
+
+      TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
+      ASSERT (Size >= TableSize);
+
+      //
+      // Install ACPI table
+      //
+      Status = TableInstallFunction (
+                 AcpiTable,
+                 CurrentTable,
+                 TableSize,
+                 &TableHandle
+                 );
+
+      //
+      // Free memory allocated by ReadSection
+      //
+      gBS->FreePool (CurrentTable);
+
+      if (EFI_ERROR (Status)) {
+        return EFI_ABORTED;
+      }
+
+      //
+      // Increment the instance
+      //
+      Instance++;
+      CurrentTable = NULL;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Effective entrypoint of Acpi Platform driver.
+
+  @param  ImageHandle
+  @param  SystemTable
+
+  @return EFI_SUCCESS
+  @return EFI_LOAD_ERROR
+  @return EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+EFIAPI
+InstallAcpiTables (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiTable
+  )
+{
+  EFI_STATUS Status;
+
+  Status = InstallOvmfFvTables (AcpiTable);
+
+  return Status;
+}
+
diff --git a/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h b/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h
new file mode 100644
index 0000000000..157ff42c07
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h
@@ -0,0 +1,76 @@
+/** @file
+  Sample ACPI Platform Driver
+
+  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ACPI_PLATFORM_H_INCLUDED_
+#define _ACPI_PLATFORM_H_INCLUDED_
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/XenPlatformLib.h>
+
+#include <IndustryStandard/Acpi.h>
+
+typedef struct {
+  EFI_PCI_IO_PROTOCOL *PciIo;
+  UINT64              PciAttributes;
+} ORIGINAL_ATTRIBUTES;
+
+typedef struct S3_CONTEXT S3_CONTEXT;
+
+EFI_STATUS
+EFIAPI
+InstallAcpiTable (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
+  IN   VOID                          *AcpiTableBuffer,
+  IN   UINTN                         AcpiTableBufferSize,
+  OUT  UINTN                         *TableKey
+  );
+
+EFI_STATUS
+EFIAPI
+BhyveInstallAcpiTable(
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
+  IN   VOID                          *AcpiTableBuffer,
+  IN   UINTN                         AcpiTableBufferSize,
+  OUT  UINTN                         *TableKey
+  );
+
+EFI_STATUS
+EFIAPI
+InstallXenTables (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
+  );
+
+EFI_STATUS
+EFIAPI
+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/BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
new file mode 100644
index 0000000000..6e931d85c0
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -0,0 +1,64 @@
+## @file
+#  OVMF ACPI Platform Driver
+#
+#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = AcpiPlatform
+  FILE_GUID                      = D5F92408-BAB5-44CA-8A60-C212F01D7E9D
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = AcpiPlatformEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  AcpiPlatform.c
+  AcpiPlatform.h
+  EntryPoint.c
+  PciDecoding.c
+  Bhyve.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  BhyvePkg/BhyvePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  UefiLib
+  PcdLib
+  BaseMemoryLib
+  DebugLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BhyveFwCtlLib
+  MemoryAllocationLib
+  BaseLib
+  DxeServicesTableLib
+  OrderedCollectionLib
+
+[Protocols]
+  gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED
+  gEfiFirmwareVolume2ProtocolGuid               # PROTOCOL SOMETIMES_CONSUMED
+  gEfiPciIoProtocolGuid                         # PROTOCOL SOMETIMES_CONSUMED
+
+[Guids]
+  gRootBridgesConnectedEventGroupGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
+
+[Depex]
+  gEfiAcpiTableProtocolGuid
diff --git a/BhyvePkg/AcpiPlatformDxe/Bhyve.c b/BhyvePkg/AcpiPlatformDxe/Bhyve.c
new file mode 100644
index 0000000000..7f1a5fd664
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/Bhyve.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+ * Copyright (C) 2012, Red Hat, Inc.
+ * Copyright (c) 2014, Pluribus Networks, 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 "AcpiPlatform.h"
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BhyveFwCtlLib.h>
+
+STATIC
+EFI_STATUS
+EFIAPI
+BhyveInstallAcpiMadtTable (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
+  IN   VOID                          *AcpiTableBuffer,
+  IN   UINTN                         AcpiTableBufferSize,
+  OUT  UINTN                         *TableKey
+  )
+{
+  UINT32                                              CpuCount;
+  UINTN                                               cSize;
+  UINTN                                               NewBufferSize;
+  EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
+  EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE         *LocalApic;
+  EFI_ACPI_1_0_IO_APIC_STRUCTURE                      *IoApic;
+  EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE    *Iso;
+  VOID                                                *Ptr;
+  UINTN                                               Loop;
+  EFI_STATUS                                          Status;
+
+  ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+
+  // Query the host for the number of vCPUs
+  CpuCount = 0;
+  cSize = sizeof(CpuCount);
+  if (BhyveFwCtlGet ("hw.ncpu", &CpuCount, &cSize) == RETURN_SUCCESS) {
+    DEBUG ((DEBUG_INFO, "Retrieved CpuCount %d\n", CpuCount));
+    ASSERT (CpuCount >= 1);
+  } else {
+    DEBUG ((DEBUG_INFO, "CpuCount retrieval error\n"));
+    CpuCount = 1;
+  }
+
+  NewBufferSize = 1                     * sizeof (*Madt) +
+                  CpuCount              * sizeof (*LocalApic) +
+                  1                     * sizeof (*IoApic) +
+                  1                     * sizeof (*Iso);
+
+  Madt = AllocatePool (NewBufferSize);
+  if (Madt == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+  Madt->Header.Length    = (UINT32) NewBufferSize;
+  Madt->LocalApicAddress = 0xFEE00000;
+  Madt->Flags            = EFI_ACPI_1_0_PCAT_COMPAT;
+  Ptr = Madt + 1;
+
+  LocalApic = Ptr;
+  for (Loop = 0; Loop < CpuCount; ++Loop) {
+    LocalApic->Type            = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
+    LocalApic->Length          = sizeof (*LocalApic);
+    LocalApic->AcpiProcessorId = (UINT8) Loop;
+    LocalApic->ApicId          = (UINT8) Loop;
+    LocalApic->Flags           = 1; // enabled
+    ++LocalApic;
+  }
+  Ptr = LocalApic;
+
+  IoApic = Ptr;
+  IoApic->Type             = EFI_ACPI_1_0_IO_APIC;
+  IoApic->Length           = sizeof (*IoApic);
+  IoApic->IoApicId         = (UINT8) CpuCount;
+  IoApic->Reserved         = EFI_ACPI_RESERVED_BYTE;
+  IoApic->IoApicAddress    = 0xFEC00000;
+  IoApic->SystemVectorBase = 0x00000000;
+  Ptr = IoApic + 1;
+
+  //
+  // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
+  //
+  Iso = Ptr;
+  Iso->Type                        = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
+  Iso->Length                      = sizeof (*Iso);
+  Iso->Bus                         = 0x00; // ISA
+  Iso->Source                      = 0x00; // IRQ0
+  Iso->GlobalSystemInterruptVector = 0x00000002;
+  Iso->Flags                       = 0x0000; // Conforms to specs of the bus
+  Ptr = Iso + 1;
+
+  ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
+  Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
+
+  FreePool (Madt);
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+BhyveInstallAcpiTable (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
+  IN   VOID                          *AcpiTableBuffer,
+  IN   UINTN                         AcpiTableBufferSize,
+  OUT  UINTN                         *TableKey
+  )
+{
+  EFI_ACPI_DESCRIPTION_HEADER        *Hdr;
+  EFI_ACPI_TABLE_INSTALL_ACPI_TABLE  TableInstallFunction;
+
+  Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
+  switch (Hdr->Signature) {
+  case EFI_ACPI_1_0_APIC_SIGNATURE:
+    TableInstallFunction = BhyveInstallAcpiMadtTable;
+    break;
+  default:
+    TableInstallFunction = InstallAcpiTable;
+  }
+
+  return TableInstallFunction (
+           AcpiProtocol,
+           AcpiTableBuffer,
+           AcpiTableBufferSize,
+           TableKey
+           );
+}
diff --git a/BhyvePkg/AcpiPlatformDxe/EntryPoint.c b/BhyvePkg/AcpiPlatformDxe/EntryPoint.c
new file mode 100644
index 0000000000..f66f892911
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/EntryPoint.c
@@ -0,0 +1,90 @@
+/** @file
+  Entry point of OVMF ACPI Platform Driver
+
+  Copyright (C) 2015, Red Hat, Inc.
+  Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/RootBridgesConnectedEventGroup.h>
+#include "AcpiPlatform.h"
+
+STATIC
+EFI_ACPI_TABLE_PROTOCOL *
+FindAcpiTableProtocol (
+  VOID
+  )
+{
+  EFI_STATUS              Status;
+  EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiAcpiTableProtocolGuid,
+                  NULL,
+                  (VOID**)&AcpiTable
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return AcpiTable;
+}
+
+
+STATIC
+VOID
+EFIAPI
+OnRootBridgesConnected (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  EFI_STATUS Status;
+
+  DEBUG ((DEBUG_INFO,
+    "%a: root bridges have been connected, installing ACPI tables\n",
+    __FUNCTION__));
+  Status = InstallAcpiTables (FindAcpiTableProtocol ());
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: InstallAcpiTables: %r\n", __FUNCTION__, Status));
+  }
+  gBS->CloseEvent (Event);
+}
+
+
+EFI_STATUS
+EFIAPI
+AcpiPlatformEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS Status;
+  EFI_EVENT  RootBridgesConnected;
+
+  //
+  // If the platform doesn't support PCI, or PCI enumeration has been disabled,
+  // install the tables at once, and let the entry point's return code reflect
+  // the full functionality.
+  //
+  if (PcdGetBool (PcdPciDisableBusEnumeration)) {
+    DEBUG ((DEBUG_INFO, "%a: PCI or its enumeration disabled, installing "
+      "ACPI tables\n", __FUNCTION__));
+    return InstallAcpiTables (FindAcpiTableProtocol ());
+  }
+
+  //
+  // Otherwise, delay installing the ACPI tables until root bridges are
+  // connected. The entry point's return status will only reflect the callback
+  // setup. (Note that we're a DXE_DRIVER; our entry point function is invoked
+  // strictly before BDS is entered and can connect the root bridges.)
+  //
+  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+                  OnRootBridgesConnected, NULL /* Context */,
+                  &gRootBridgesConnectedEventGroupGuid, &RootBridgesConnected);
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO,
+      "%a: waiting for root bridges to be connected, registered callback\n",
+      __FUNCTION__));
+  }
+
+  return Status;
+}
diff --git a/BhyvePkg/AcpiPlatformDxe/PciDecoding.c b/BhyvePkg/AcpiPlatformDxe/PciDecoding.c
new file mode 100644
index 0000000000..73894106c9
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/PciDecoding.c
@@ -0,0 +1,192 @@
+/** @file
+  Temporarily enable IO and MMIO decoding for all PCI devices while QEMU
+  regenerates the ACPI tables.
+
+  Copyright (C) 2016, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/MemoryAllocationLib.h>
+
+#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 ((DEBUG_WARN, "%a: LocateHandleBuffer(): %r\n", __FUNCTION__,
+      Status));
+    return;
+  }
+
+  OrigAttrs = AllocatePool (NoHandles * sizeof *OrigAttrs);
+  if (OrigAttrs == NULL) {
+    DEBUG ((DEBUG_WARN, "%a: AllocatePool(): out of resources\n",
+      __FUNCTION__));
+    goto FreeHandles;
+  }
+
+  for (Idx = 0; Idx < NoHandles; ++Idx) {
+    EFI_PCI_IO_PROTOCOL *PciIo;
+    UINT64              Attributes;
+
+    //
+    // 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 ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationGet: %r\n",
+        __FUNCTION__, Status));
+      goto RestoreAttributes;
+    }
+
+    //
+    // Retrieve supported attributes
+    //
+    Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSupported, 0,
+                      &Attributes);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: EfiPciIoAttributeOperationSupported: %r\n",
+        __FUNCTION__, Status));
+      goto RestoreAttributes;
+    }
+
+    //
+    // Enable IO and MMIO decoding
+    //
+    Attributes &= EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY;
+    Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationEnable,
+                      Attributes, NULL);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_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);
+}
-- 
2.20.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#57695): https://edk2.groups.io/g/devel/message/57695
Mute This Topic: https://groups.io/mt/73165362/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