From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232]) by mx.groups.io with SMTP id smtpd.web12.2191.1587438609258306790 for ; Mon, 20 Apr 2020 20:10:09 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: bsdio.com, ip: 166.70.13.232, mailfrom: rebecca@bsdio.com) Received: from in02.mta.xmission.com ([166.70.13.52]) by out02.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jQjIW-0000Di-Ga; Mon, 20 Apr 2020 21:10:08 -0600 Received: from mta4.zcs.xmission.com ([166.70.13.68]) by in02.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jQjIU-0008CS-QO; Mon, 20 Apr 2020 21:10:08 -0600 Received: from localhost (localhost [127.0.0.1]) by mta4.zcs.xmission.com (Postfix) with ESMTP id A33B65003C1; Mon, 20 Apr 2020 21:10:06 -0600 (MDT) X-Amavis-Modified: Mail body modified (using disclaimer) - mta4.zcs.xmission.com Received: from mta4.zcs.xmission.com ([127.0.0.1]) by localhost (mta4.zcs.xmission.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id oFylI0u43sxf; Mon, 20 Apr 2020 21:10:06 -0600 (MDT) Received: from photon.int.bluestop.org (c-174-52-16-57.hsd1.ut.comcast.net [174.52.16.57]) by mta4.zcs.xmission.com (Postfix) with ESMTPSA id 50C9B5002C5; Mon, 20 Apr 2020 21:10:06 -0600 (MDT) From: "Rebecca Cran" To: devel@edk2.groups.io Cc: Jordan Justen , Laszlo Ersek , Ard Biesheuvel , Leif Lindholm , Michael Kinney , Andrew Fish , Peter Grehan , Rebecca Cran Date: Mon, 20 Apr 2020 21:09:55 -0600 Message-Id: <20200421030955.114850-7-rebecca@bsdio.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200421030955.114850-1-rebecca@bsdio.com> References: <20200421030955.114850-1-rebecca@bsdio.com> MIME-Version: 1.0 X-XM-SPF: eid=1jQjIU-0008CS-QO;;;mid=<20200421030955.114850-7-rebecca@bsdio.com>;;;hst=in02.mta.xmission.com;;;ip=166.70.13.68;;;frm=rebecca@bsdio.com;;;spf=pass X-SA-Exim-Connect-IP: 166.70.13.68 X-SA-Exim-Mail-From: rebecca@bsdio.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa04.xmission.com X-Spam-Level: X-Spam-Status: No, score=-0.2 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE autolearn=disabled version=3.4.2 X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa04 1397; IP=ok Body=1 Fuz1=1] [Fuz2=1] X-Spam-DCC: XMission; sa04 1397; IP=ok Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: ;devel@edk2.groups.io X-Spam-Relay-Country: X-Spam-Timing: total 1473 ms - load_scoreonly_sql: 0.05 (0.0%), signal_user_changed: 13 (0.9%), b_tie_ro: 11 (0.8%), parse: 3.7 (0.3%), extract_message_metadata: 35 (2.4%), get_uri_detail_list: 15 (1.0%), tests_pri_-1000: 29 (1.9%), tests_pri_-950: 1.45 (0.1%), tests_pri_-900: 1.11 (0.1%), tests_pri_-90: 321 (21.8%), check_bayes: 319 (21.7%), b_tokenize: 42 (2.8%), b_tok_get_all: 190 (12.9%), b_comp_prob: 8 (0.6%), b_tok_touch_all: 74 (5.0%), b_finish: 1.27 (0.1%), tests_pri_0: 1046 (71.0%), check_dkim_signature: 1.23 (0.1%), check_dkim_adsp: 2.5 (0.2%), poll_dns_idle: 0.69 (0.0%), tests_pri_10: 2.6 (0.2%), tests_pri_500: 12 (0.8%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH v3 6/6] BhyvePkg: Add AcpiPlatformDxe X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in02.mta.xmission.com) Content-Transfer-Encoding: 8bit Make a copy of OvmfPkg/AcpiPlatformDxe under BhyvePkg, with the changes needed to support the bhyve hypervisor. Signed-off-by: Rebecca Cran --- 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.
+ 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ACPI_PLATFORM_H_INCLUDED_ +#define _ACPI_PLATFORM_H_INCLUDED_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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.
+# +# 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.
+ * 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 +#include +#include + +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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#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 + +#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