public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Rebecca Cran" <rebecca@bsdio.com>
To: devel@edk2.groups.io, Jordan Justen <jordan.l.justen@intel.com>,
	Laszlo Ersek <lersek@redhat.com>,
	Ard Biesheuvel <ard.biesheuvel@arm.com>,
	Andrew Fish <afish@apple.com>, Leif Lindholm <leif@nuviainc.com>,
	Michael D Kinney <michael.d.kinney@intel.com>
Cc: Rebecca Cran <rebecca@bsdio.com>
Subject: [PATCH v4 6/6] BhyvePkg: Add AcpiPlatformDxe
Date: Fri, 24 Apr 2020 12:29:14 -0600	[thread overview]
Message-ID: <20200424182914.138915-7-rebecca@bsdio.com> (raw)
In-Reply-To: <20200424182914.138915-1-rebecca@bsdio.com>

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

Signed-off-by: Rebecca Cran <rebecca@bsdio.com>
---
 BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c      | 251 +++++++++++++++++++
 BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h      |  77 ++++++
 BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf |  65 +++++
 BhyvePkg/AcpiPlatformDxe/Bhyve.c             | 132 ++++++++++
 BhyvePkg/AcpiPlatformDxe/EntryPoint.c        |  90 +++++++
 BhyvePkg/AcpiPlatformDxe/PciDecoding.c       | 192 ++++++++++++++
 6 files changed, 807 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..31bbf6c474
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.c
@@ -0,0 +1,251 @@
+/** @file
+  OVMF ACPI Platform Driver
+
+  Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
+  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..d30cd11a1d
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/AcpiPlatform.h
@@ -0,0 +1,77 @@
+/** @file
+  Sample ACPI Platform Driver
+
+  Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
+  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..bc52fa5e2f
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -0,0 +1,65 @@
+## @file
+#  OVMF ACPI Platform Driver
+#
+#  Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
+#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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..6d42264b65
--- /dev/null
+++ b/BhyvePkg/AcpiPlatformDxe/Bhyve.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
+ * Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+ * Copyright (C) 2012, Red Hat, Inc.
+ * Copyright (c) 2014, Pluribus Networks, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ */
+#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.25.1



      parent reply	other threads:[~2020-04-24 18:29 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-24 18:29 [PATCH v4 0/6] Add BhyvePkg, to support the bhyve hypervisor Rebecca Cran
2020-04-24 18:29 ` [PATCH v4 1/6] OvmfPkg: Add bhyve support into AcpiTimerLib Rebecca Cran
2020-04-24 18:29 ` [PATCH v4 2/6] OvmfPkg: Add QemuFwCfgLibNull Rebecca Cran
2020-04-27  9:03   ` [edk2-devel] " Philippe Mathieu-Daudé
2020-04-27 17:33     ` Rebecca Cran
2020-04-28 11:27       ` Philippe Mathieu-Daudé
2020-04-28 16:12         ` Rebecca Cran
2020-04-24 18:29 ` [PATCH v4 3/6] OvmfPkg: Add VBE2 mode info structure to LegacyVgaBios.h Rebecca Cran
2020-04-24 18:29 ` [PATCH v4 4/6] Add BhyvePkg, to support the bhyve hypervisor Rebecca Cran
2020-04-24 18:29 ` [PATCH v4 5/6] BhyvePkg: Add PlatformPei Rebecca Cran
2020-04-24 18:29 ` Rebecca Cran [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200424182914.138915-7-rebecca@bsdio.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox