From 4115840c282660b071dbd53c08516e437df1ad0b Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 26 May 2021 22:14:16 +0200 Subject: [PATCH] OvmfPkg/XenAcpiPlatformDxe: remove the QEMU ACPI linker/loader client MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The root of the QEMU ACPI linker/loader client in XenAcpiPlatformDxe is the InstallQemuFwCfgTables() function. This function always fails on Xen, due to its top-most QemuFwCfgFindFile() call. Remove the InstallQemuFwCfgTables() function call from XenAcpiPlatformDxe, along with all dependencies that now become unused. Cc: Anthony Perard Cc: Ard Biesheuvel Cc: Jordan Justen Cc: Julien Grall Cc: Philippe Mathieu-Daudé Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2122 Signed-off-by: Laszlo Ersek Message-Id: <20210526201446.12554-14-lersek@redhat.com> Reviewed-by: Ard Biesheuvel Reviewed-by: Philippe Mathieu-Daudé --- OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.c | 2 +- OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.h | 51 - OvmfPkg/XenAcpiPlatformDxe/BootScript.c | 269 ---- OvmfPkg/XenAcpiPlatformDxe/PciDecoding.c | 194 --- OvmfPkg/XenAcpiPlatformDxe/QemuFwCfgAcpi.c | 1196 ----------------- .../XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf | 6 - 6 files changed, 1 insertion(+), 1717 deletions(-) delete mode 100644 OvmfPkg/XenAcpiPlatformDxe/BootScript.c delete mode 100644 OvmfPkg/XenAcpiPlatformDxe/PciDecoding.c delete mode 100644 OvmfPkg/XenAcpiPlatformDxe/QemuFwCfgAcpi.c diff --git a/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.c b/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.c index 2b2dc57675..9c8b1e0fcf 100644 --- a/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.c +++ b/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.c @@ -256,7 +256,7 @@ InstallAcpiTables ( if (XenDetected ()) { Status = InstallXenTables (AcpiTable); } else { - Status = InstallQemuFwCfgTables (AcpiTable); + Status = EFI_UNSUPPORTED; } if (EFI_ERROR (Status)) { diff --git a/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.h b/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.h index 6259697c4b..d35143a00d 100644 --- a/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.h +++ b/OvmfPkg/XenAcpiPlatformDxe/AcpiPlatform.h @@ -11,14 +11,6 @@ #define ACPI_PLATFORM_H_ #include // EFI_ACPI_TABLE_PROTOCOL -#include // EFI_PCI_IO_PROTOCOL - -typedef struct { - EFI_PCI_IO_PROTOCOL *PciIo; - UINT64 PciAttributes; -} ORIGINAL_ATTRIBUTES; - -typedef struct S3_CONTEXT S3_CONTEXT; EFI_STATUS EFIAPI @@ -49,54 +41,11 @@ InstallXenTables ( IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol ); -EFI_STATUS -EFIAPI -InstallQemuFwCfgTables ( - 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 - ); - -EFI_STATUS -AllocateS3Context ( - OUT S3_CONTEXT **S3Context, - IN UINTN WritePointerCount - ); - -VOID -ReleaseS3Context ( - IN S3_CONTEXT *S3Context - ); - -EFI_STATUS -SaveCondensedWritePointerToS3Context ( - IN OUT S3_CONTEXT *S3Context, - IN UINT16 PointerItem, - IN UINT8 PointerSize, - IN UINT32 PointerOffset, - IN UINT64 PointerValue - ); - -EFI_STATUS -TransferS3ContextToBootScript ( - IN S3_CONTEXT *S3Context - ); - #endif diff --git a/OvmfPkg/XenAcpiPlatformDxe/BootScript.c b/OvmfPkg/XenAcpiPlatformDxe/BootScript.c deleted file mode 100644 index 14d1e68694..0000000000 --- a/OvmfPkg/XenAcpiPlatformDxe/BootScript.c +++ /dev/null @@ -1,269 +0,0 @@ -/** @file - Append an ACPI S3 Boot Script fragment from the QEMU_LOADER_WRITE_POINTER - commands of QEMU's fully processed table linker/loader script. - - Copyright (C) 2017-2021, Red Hat, Inc. - - SPDX-License-Identifier: BSD-2-Clause-Patent -**/ - -#include // CpuDeadLoop() -#include // DEBUG() -#include // AllocatePool() -#include // QemuFwCfgS3ScriptSkipBytes() - -#include "AcpiPlatform.h" - - -// -// Condensed structure for capturing the fw_cfg operations -- select, skip, -// write -- inherent in executing a QEMU_LOADER_WRITE_POINTER command. -// -typedef struct { - UINT16 PointerItem; // resolved from QEMU_LOADER_WRITE_POINTER.PointerFile - UINT8 PointerSize; // copied as-is from QEMU_LOADER_WRITE_POINTER - UINT32 PointerOffset; // copied as-is from QEMU_LOADER_WRITE_POINTER - UINT64 PointerValue; // resolved from QEMU_LOADER_WRITE_POINTER.PointeeFile - // and QEMU_LOADER_WRITE_POINTER.PointeeOffset -} CONDENSED_WRITE_POINTER; - - -// -// Context structure to accumulate CONDENSED_WRITE_POINTER objects from -// QEMU_LOADER_WRITE_POINTER commands. -// -// Any pointers in this structure own the pointed-to objects; that is, when the -// context structure is released, all pointed-to objects must be released too. -// -struct S3_CONTEXT { - CONDENSED_WRITE_POINTER *WritePointers; // one array element per processed - // QEMU_LOADER_WRITE_POINTER - // command - UINTN Allocated; // number of elements allocated for - // WritePointers - UINTN Used; // number of elements populated in - // WritePointers -}; - - -// -// Scratch buffer, allocated in EfiReservedMemoryType type memory, for the ACPI -// S3 Boot Script opcodes to work on. -// -#pragma pack (1) -typedef union { - UINT64 PointerValue; // filled in from CONDENSED_WRITE_POINTER.PointerValue -} SCRATCH_BUFFER; -#pragma pack () - - -/** - Allocate an S3_CONTEXT object. - - @param[out] S3Context The allocated S3_CONTEXT object is returned - through this parameter. - - @param[in] WritePointerCount Number of CONDENSED_WRITE_POINTER elements to - allocate room for. WritePointerCount must be - positive. - - @retval EFI_SUCCESS Allocation successful. - - @retval EFI_OUT_OF_RESOURCES Out of memory. - - @retval EFI_INVALID_PARAMETER WritePointerCount is zero. -**/ -EFI_STATUS -AllocateS3Context ( - OUT S3_CONTEXT **S3Context, - IN UINTN WritePointerCount - ) -{ - EFI_STATUS Status; - S3_CONTEXT *Context; - - if (WritePointerCount == 0) { - return EFI_INVALID_PARAMETER; - } - - Context = AllocateZeroPool (sizeof *Context); - if (Context == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - Context->WritePointers = AllocatePool (WritePointerCount * - sizeof *Context->WritePointers); - if (Context->WritePointers == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto FreeContext; - } - - Context->Allocated = WritePointerCount; - *S3Context = Context; - return EFI_SUCCESS; - -FreeContext: - FreePool (Context); - - return Status; -} - - -/** - Release an S3_CONTEXT object. - - @param[in] S3Context The object to release. -**/ -VOID -ReleaseS3Context ( - IN S3_CONTEXT *S3Context - ) -{ - FreePool (S3Context->WritePointers); - FreePool (S3Context); -} - - -/** - Save the information necessary to replicate a QEMU_LOADER_WRITE_POINTER - command during S3 resume, in condensed format. - - This function is to be called from ProcessCmdWritePointer(), after all the - sanity checks have passed, and before the fw_cfg operations are performed. - - @param[in,out] S3Context The S3_CONTEXT object into which the caller wants - to save the information that was derived from - QEMU_LOADER_WRITE_POINTER. - - @param[in] PointerItem The FIRMWARE_CONFIG_ITEM that - QEMU_LOADER_WRITE_POINTER.PointerFile was resolved - to, expressed as a UINT16 value. - - @param[in] PointerSize Copied directly from - QEMU_LOADER_WRITE_POINTER.PointerSize. - - @param[in] PointerOffset Copied directly from - QEMU_LOADER_WRITE_POINTER.PointerOffset. - - @param[in] PointerValue The base address of the allocated / downloaded - fw_cfg blob that is identified by - QEMU_LOADER_WRITE_POINTER.PointeeFile, plus - QEMU_LOADER_WRITE_POINTER.PointeeOffset. - - @retval EFI_SUCCESS The information derived from - QEMU_LOADER_WRITE_POINTER has been successfully - absorbed into S3Context. - - @retval EFI_OUT_OF_RESOURCES No room available in S3Context. -**/ -EFI_STATUS -SaveCondensedWritePointerToS3Context ( - IN OUT S3_CONTEXT *S3Context, - IN UINT16 PointerItem, - IN UINT8 PointerSize, - IN UINT32 PointerOffset, - IN UINT64 PointerValue - ) -{ - CONDENSED_WRITE_POINTER *Condensed; - - if (S3Context->Used == S3Context->Allocated) { - return EFI_OUT_OF_RESOURCES; - } - Condensed = S3Context->WritePointers + S3Context->Used; - Condensed->PointerItem = PointerItem; - Condensed->PointerSize = PointerSize; - Condensed->PointerOffset = PointerOffset; - Condensed->PointerValue = PointerValue; - DEBUG ((DEBUG_VERBOSE, "%a: 0x%04x/[0x%08x+%d] := 0x%Lx (%Lu)\n", - __FUNCTION__, PointerItem, PointerOffset, PointerSize, PointerValue, - (UINT64)S3Context->Used)); - ++S3Context->Used; - return EFI_SUCCESS; -} - - -/** - FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib. -**/ -STATIC -VOID -EFIAPI -AppendFwCfgBootScript ( - IN OUT VOID *Context, OPTIONAL - IN OUT VOID *ExternalScratchBuffer - ) -{ - S3_CONTEXT *S3Context; - SCRATCH_BUFFER *ScratchBuffer; - UINTN Index; - - S3Context = Context; - ScratchBuffer = ExternalScratchBuffer; - - for (Index = 0; Index < S3Context->Used; ++Index) { - CONST CONDENSED_WRITE_POINTER *Condensed; - RETURN_STATUS Status; - - Condensed = &S3Context->WritePointers[Index]; - - Status = QemuFwCfgS3ScriptSkipBytes (Condensed->PointerItem, - Condensed->PointerOffset); - if (RETURN_ERROR (Status)) { - goto FatalError; - } - - ScratchBuffer->PointerValue = Condensed->PointerValue; - Status = QemuFwCfgS3ScriptWriteBytes (-1, Condensed->PointerSize); - if (RETURN_ERROR (Status)) { - goto FatalError; - } - } - - DEBUG ((DEBUG_VERBOSE, "%a: boot script fragment saved\n", __FUNCTION__)); - - ReleaseS3Context (S3Context); - return; - -FatalError: - ASSERT (FALSE); - CpuDeadLoop (); -} - - -/** - Translate and append the information from an S3_CONTEXT object to the ACPI S3 - Boot Script. - - The effects of a successful call to this function cannot be undone. - - @param[in] S3Context The S3_CONTEXT object to translate to ACPI S3 Boot - Script opcodes. If the function returns successfully, - the caller must set the S3Context pointer -- originally - returned by AllocateS3Context() -- immediately to NULL, - because the ownership of S3Context has been transferred. - - @retval EFI_SUCCESS The translation of S3Context to ACPI S3 Boot Script - opcodes has been successfully executed or queued. (This - includes the case when S3Context was empty on input and - no ACPI S3 Boot Script opcodes have been necessary to - produce.) - - @return Error codes from underlying functions. -**/ -EFI_STATUS -TransferS3ContextToBootScript ( - IN S3_CONTEXT *S3Context - ) -{ - RETURN_STATUS Status; - - if (S3Context->Used == 0) { - ReleaseS3Context (S3Context); - return EFI_SUCCESS; - } - - Status = QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript, - S3Context, sizeof (SCRATCH_BUFFER)); - return (EFI_STATUS)Status; -} diff --git a/OvmfPkg/XenAcpiPlatformDxe/PciDecoding.c b/OvmfPkg/XenAcpiPlatformDxe/PciDecoding.c deleted file mode 100644 index 00fc57eb13..0000000000 --- a/OvmfPkg/XenAcpiPlatformDxe/PciDecoding.c +++ /dev/null @@ -1,194 +0,0 @@ -/** @file - Temporarily enable IO and MMIO decoding for all PCI devices while QEMU - regenerates the ACPI tables. - - Copyright (C) 2016-2021, Red Hat, Inc. - - SPDX-License-Identifier: BSD-2-Clause-Patent -**/ - -#include // DEBUG() -#include // AllocatePool() -#include // gBS - -#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); -} diff --git a/OvmfPkg/XenAcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/XenAcpiPlatformDxe/QemuFwCfgAcpi.c deleted file mode 100644 index 521c06cf54..0000000000 --- a/OvmfPkg/XenAcpiPlatformDxe/QemuFwCfgAcpi.c +++ /dev/null @@ -1,1196 +0,0 @@ -/** @file - OVMF ACPI support using QEMU's fw-cfg interface - - Copyright (C) 2012-2021, Red Hat, Inc. - Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include // EFI_ACPI_DESCRIPTION_HEADER -#include // QEMU_LOADER_FNAME_SIZE -#include // AsciiStrCmp() -#include // CopyMem() -#include // DEBUG() -#include // AllocatePool() -#include // OrderedCollectionMin() -#include // QemuFwCfgFindFile() -#include // QemuFwCfgS3Enabled() -#include // gBS - -#include "AcpiPlatform.h" - -// -// The user structure for the ordered collection that will track the fw_cfg -// blobs under processing. -// -typedef struct { - UINT8 File[QEMU_LOADER_FNAME_SIZE]; // NUL-terminated name of the fw_cfg - // blob. This is the ordering / search - // key. - UINTN Size; // The number of bytes in this blob. - UINT8 *Base; // Pointer to the blob data. - BOOLEAN HostsOnlyTableData; // TRUE iff the blob has been found to - // only contain data that is directly - // part of ACPI tables. -} BLOB; - - -/** - Compare a standalone key against a user structure containing an embedded key. - - @param[in] StandaloneKey Pointer to the bare key. - - @param[in] UserStruct Pointer to the user structure with the embedded - key. - - @retval <0 If StandaloneKey compares less than UserStruct's key. - - @retval 0 If StandaloneKey compares equal to UserStruct's key. - - @retval >0 If StandaloneKey compares greater than UserStruct's key. -**/ -STATIC -INTN -EFIAPI -BlobKeyCompare ( - IN CONST VOID *StandaloneKey, - IN CONST VOID *UserStruct - ) -{ - CONST BLOB *Blob; - - Blob = UserStruct; - return AsciiStrCmp (StandaloneKey, (CONST CHAR8 *)Blob->File); -} - - -/** - Comparator function for two user structures. - - @param[in] UserStruct1 Pointer to the first user structure. - - @param[in] UserStruct2 Pointer to the second user structure. - - @retval <0 If UserStruct1 compares less than UserStruct2. - - @retval 0 If UserStruct1 compares equal to UserStruct2. - - @retval >0 If UserStruct1 compares greater than UserStruct2. -**/ -STATIC -INTN -EFIAPI -BlobCompare ( - IN CONST VOID *UserStruct1, - IN CONST VOID *UserStruct2 - ) -{ - CONST BLOB *Blob1; - - Blob1 = UserStruct1; - return BlobKeyCompare (Blob1->File, UserStruct2); -} - - -/** - Comparator function for two opaque pointers, ordering on (unsigned) pointer - value itself. - Can be used as both Key and UserStruct comparator. - - @param[in] Pointer1 First pointer. - - @param[in] Pointer2 Second pointer. - - @retval <0 If Pointer1 compares less than Pointer2. - - @retval 0 If Pointer1 compares equal to Pointer2. - - @retval >0 If Pointer1 compares greater than Pointer2. -**/ -STATIC -INTN -EFIAPI -PointerCompare ( - IN CONST VOID *Pointer1, - IN CONST VOID *Pointer2 - ) -{ - if (Pointer1 == Pointer2) { - return 0; - } - if ((UINTN)Pointer1 < (UINTN)Pointer2) { - return -1; - } - return 1; -} - - -/** - Comparator function for two ASCII strings. Can be used as both Key and - UserStruct comparator. - - This function exists solely so we can avoid casting &AsciiStrCmp to - ORDERED_COLLECTION_USER_COMPARE and ORDERED_COLLECTION_KEY_COMPARE. - - @param[in] AsciiString1 Pointer to the first ASCII string. - - @param[in] AsciiString2 Pointer to the second ASCII string. - - @return The return value of AsciiStrCmp (AsciiString1, AsciiString2). -**/ -STATIC -INTN -EFIAPI -AsciiStringCompare ( - IN CONST VOID *AsciiString1, - IN CONST VOID *AsciiString2 - ) -{ - return AsciiStrCmp (AsciiString1, AsciiString2); -} - - -/** - Release the ORDERED_COLLECTION structure populated by - CollectAllocationsRestrictedTo32Bit() (below). - - This function may be called by CollectAllocationsRestrictedTo32Bit() itself, - on the error path. - - @param[in] AllocationsRestrictedTo32Bit The ORDERED_COLLECTION structure to - release. -**/ -STATIC -VOID -ReleaseAllocationsRestrictedTo32Bit ( - IN ORDERED_COLLECTION *AllocationsRestrictedTo32Bit -) -{ - ORDERED_COLLECTION_ENTRY *Entry, *Entry2; - - for (Entry = OrderedCollectionMin (AllocationsRestrictedTo32Bit); - Entry != NULL; - Entry = Entry2) { - Entry2 = OrderedCollectionNext (Entry); - OrderedCollectionDelete (AllocationsRestrictedTo32Bit, Entry, NULL); - } - OrderedCollectionUninit (AllocationsRestrictedTo32Bit); -} - - -/** - Iterate over the linker/loader script, and collect the names of the fw_cfg - blobs that are referenced by QEMU_LOADER_ADD_POINTER.PointeeFile fields, such - that QEMU_LOADER_ADD_POINTER.PointerSize is less than 8. This means that the - pointee blob's address will have to be patched into a narrower-than-8 byte - pointer field, hence the pointee blob must not be allocated from 64-bit - address space. - - @param[out] AllocationsRestrictedTo32Bit The ORDERED_COLLECTION structure - linking (not copying / owning) such - QEMU_LOADER_ADD_POINTER.PointeeFile - fields that name the blobs - restricted from 64-bit allocation. - - @param[in] LoaderStart Points to the first entry in the - linker/loader script. - - @param[in] LoaderEnd Points one past the last entry in - the linker/loader script. - - @retval EFI_SUCCESS AllocationsRestrictedTo32Bit has been - populated. - - @retval EFI_OUT_OF_RESOURCES Memory allocation failed. - - @retval EFI_PROTOCOL_ERROR Invalid linker/loader script contents. -**/ -STATIC -EFI_STATUS -CollectAllocationsRestrictedTo32Bit ( - OUT ORDERED_COLLECTION **AllocationsRestrictedTo32Bit, - IN CONST QEMU_LOADER_ENTRY *LoaderStart, - IN CONST QEMU_LOADER_ENTRY *LoaderEnd -) -{ - ORDERED_COLLECTION *Collection; - CONST QEMU_LOADER_ENTRY *LoaderEntry; - EFI_STATUS Status; - - Collection = OrderedCollectionInit (AsciiStringCompare, AsciiStringCompare); - if (Collection == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { - CONST QEMU_LOADER_ADD_POINTER *AddPointer; - - if (LoaderEntry->Type != QemuLoaderCmdAddPointer) { - continue; - } - AddPointer = &LoaderEntry->Command.AddPointer; - - if (AddPointer->PointerSize >= 8) { - continue; - } - - if (AddPointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { - DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__)); - Status = EFI_PROTOCOL_ERROR; - goto RollBack; - } - - Status = OrderedCollectionInsert ( - Collection, - NULL, // Entry - (VOID *)AddPointer->PointeeFile - ); - switch (Status) { - case EFI_SUCCESS: - DEBUG (( - DEBUG_VERBOSE, - "%a: restricting blob \"%a\" from 64-bit allocation\n", - __FUNCTION__, - AddPointer->PointeeFile - )); - break; - case EFI_ALREADY_STARTED: - // - // The restriction has been recorded already. - // - break; - case EFI_OUT_OF_RESOURCES: - goto RollBack; - default: - ASSERT (FALSE); - } - } - - *AllocationsRestrictedTo32Bit = Collection; - return EFI_SUCCESS; - -RollBack: - ReleaseAllocationsRestrictedTo32Bit (Collection); - return Status; -} - - -/** - Process a QEMU_LOADER_ALLOCATE command. - - @param[in] Allocate The QEMU_LOADER_ALLOCATE command to - process. - - @param[in,out] Tracker The ORDERED_COLLECTION tracking the - BLOB user structures created thus - far. - - @param[in] AllocationsRestrictedTo32Bit The ORDERED_COLLECTION populated by - the function - CollectAllocationsRestrictedTo32Bit, - naming the fw_cfg blobs that must - not be allocated from 64-bit address - space. - - @retval EFI_SUCCESS An area of whole AcpiNVS pages has been - allocated for the blob contents, and the - contents have been saved. A BLOB object (user - structure) has been allocated from pool memory, - referencing the blob contents. The BLOB user - structure has been linked into Tracker. - - @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name has been found in - Allocate, or the Allocate command references a - file that is already known by Tracker. - - @retval EFI_UNSUPPORTED Unsupported alignment request has been found in - Allocate. - - @retval EFI_OUT_OF_RESOURCES Pool allocation failed. - - @return Error codes from QemuFwCfgFindFile() and - gBS->AllocatePages(). -**/ -STATIC -EFI_STATUS -EFIAPI -ProcessCmdAllocate ( - IN CONST QEMU_LOADER_ALLOCATE *Allocate, - IN OUT ORDERED_COLLECTION *Tracker, - IN ORDERED_COLLECTION *AllocationsRestrictedTo32Bit - ) -{ - FIRMWARE_CONFIG_ITEM FwCfgItem; - UINTN FwCfgSize; - EFI_STATUS Status; - UINTN NumPages; - EFI_PHYSICAL_ADDRESS Address; - BLOB *Blob; - - if (Allocate->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { - DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__)); - return EFI_PROTOCOL_ERROR; - } - - if (Allocate->Alignment > EFI_PAGE_SIZE) { - DEBUG ((DEBUG_ERROR, "%a: unsupported alignment 0x%x\n", __FUNCTION__, - Allocate->Alignment)); - return EFI_UNSUPPORTED; - } - - Status = QemuFwCfgFindFile ((CHAR8 *)Allocate->File, &FwCfgItem, &FwCfgSize); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a: QemuFwCfgFindFile(\"%a\"): %r\n", __FUNCTION__, - Allocate->File, Status)); - return Status; - } - - NumPages = EFI_SIZE_TO_PAGES (FwCfgSize); - Address = MAX_UINT64; - if (OrderedCollectionFind ( - AllocationsRestrictedTo32Bit, - Allocate->File - ) != NULL) { - Address = MAX_UINT32; - } - Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages, - &Address); - if (EFI_ERROR (Status)) { - return Status; - } - - Blob = AllocatePool (sizeof *Blob); - if (Blob == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto FreePages; - } - CopyMem (Blob->File, Allocate->File, QEMU_LOADER_FNAME_SIZE); - Blob->Size = FwCfgSize; - Blob->Base = (VOID *)(UINTN)Address; - Blob->HostsOnlyTableData = TRUE; - - Status = OrderedCollectionInsert (Tracker, NULL, Blob); - if (Status == RETURN_ALREADY_STARTED) { - DEBUG ((DEBUG_ERROR, "%a: duplicated file \"%a\"\n", __FUNCTION__, - Allocate->File)); - Status = EFI_PROTOCOL_ERROR; - } - if (EFI_ERROR (Status)) { - goto FreeBlob; - } - - QemuFwCfgSelectItem (FwCfgItem); - QemuFwCfgReadBytes (FwCfgSize, Blob->Base); - ZeroMem (Blob->Base + Blob->Size, EFI_PAGES_TO_SIZE (NumPages) - Blob->Size); - - DEBUG ((DEBUG_VERBOSE, "%a: File=\"%a\" Alignment=0x%x Zone=%d Size=0x%Lx " - "Address=0x%Lx\n", __FUNCTION__, Allocate->File, Allocate->Alignment, - Allocate->Zone, (UINT64)Blob->Size, (UINT64)(UINTN)Blob->Base)); - return EFI_SUCCESS; - -FreeBlob: - FreePool (Blob); - -FreePages: - gBS->FreePages (Address, NumPages); - - return Status; -} - - -/** - Process a QEMU_LOADER_ADD_POINTER command. - - @param[in] AddPointer The QEMU_LOADER_ADD_POINTER command to process. - - @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user - structures created thus far. - - @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name(s) have been found in - AddPointer, or the AddPointer command references - a file unknown to Tracker, or the pointer to - relocate has invalid location, size, or value, or - the relocated pointer value is not representable - in the given pointer size. - - @retval EFI_SUCCESS The pointer field inside the pointer blob has - been relocated. -**/ -STATIC -EFI_STATUS -EFIAPI -ProcessCmdAddPointer ( - IN CONST QEMU_LOADER_ADD_POINTER *AddPointer, - IN CONST ORDERED_COLLECTION *Tracker - ) -{ - ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2; - BLOB *Blob, *Blob2; - UINT8 *PointerField; - UINT64 PointerValue; - - if (AddPointer->PointerFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0' || - AddPointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { - DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__)); - return EFI_PROTOCOL_ERROR; - } - - TrackerEntry = OrderedCollectionFind (Tracker, AddPointer->PointerFile); - TrackerEntry2 = OrderedCollectionFind (Tracker, AddPointer->PointeeFile); - if (TrackerEntry == NULL || TrackerEntry2 == NULL) { - DEBUG ((DEBUG_ERROR, "%a: invalid blob reference(s) \"%a\" / \"%a\"\n", - __FUNCTION__, AddPointer->PointerFile, AddPointer->PointeeFile)); - return EFI_PROTOCOL_ERROR; - } - - Blob = OrderedCollectionUserStruct (TrackerEntry); - Blob2 = OrderedCollectionUserStruct (TrackerEntry2); - if ((AddPointer->PointerSize != 1 && AddPointer->PointerSize != 2 && - AddPointer->PointerSize != 4 && AddPointer->PointerSize != 8) || - Blob->Size < AddPointer->PointerSize || - Blob->Size - AddPointer->PointerSize < AddPointer->PointerOffset) { - DEBUG ((DEBUG_ERROR, "%a: invalid pointer location or size in \"%a\"\n", - __FUNCTION__, AddPointer->PointerFile)); - return EFI_PROTOCOL_ERROR; - } - - PointerField = Blob->Base + AddPointer->PointerOffset; - PointerValue = 0; - CopyMem (&PointerValue, PointerField, AddPointer->PointerSize); - if (PointerValue >= Blob2->Size) { - DEBUG ((DEBUG_ERROR, "%a: invalid pointer value in \"%a\"\n", __FUNCTION__, - AddPointer->PointerFile)); - return EFI_PROTOCOL_ERROR; - } - - // - // The memory allocation system ensures that the address of the byte past the - // last byte of any allocated object is expressible (no wraparound). - // - ASSERT ((UINTN)Blob2->Base <= MAX_ADDRESS - Blob2->Size); - - PointerValue += (UINT64)(UINTN)Blob2->Base; - if (AddPointer->PointerSize < 8 && - RShiftU64 (PointerValue, AddPointer->PointerSize * 8) != 0) { - DEBUG ((DEBUG_ERROR, "%a: relocated pointer value unrepresentable in " - "\"%a\"\n", __FUNCTION__, AddPointer->PointerFile)); - return EFI_PROTOCOL_ERROR; - } - - CopyMem (PointerField, &PointerValue, AddPointer->PointerSize); - - DEBUG ((DEBUG_VERBOSE, "%a: PointerFile=\"%a\" PointeeFile=\"%a\" " - "PointerOffset=0x%x PointerSize=%d\n", __FUNCTION__, - AddPointer->PointerFile, AddPointer->PointeeFile, - AddPointer->PointerOffset, AddPointer->PointerSize)); - return EFI_SUCCESS; -} - - -/** - Process a QEMU_LOADER_ADD_CHECKSUM command. - - @param[in] AddChecksum The QEMU_LOADER_ADD_CHECKSUM command to process. - - @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user - structures created thus far. - - @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name has been found in - AddChecksum, or the AddChecksum command - references a file unknown to Tracker, or the - range to checksum is invalid. - - @retval EFI_SUCCESS The requested range has been checksummed. -**/ -STATIC -EFI_STATUS -EFIAPI -ProcessCmdAddChecksum ( - IN CONST QEMU_LOADER_ADD_CHECKSUM *AddChecksum, - IN CONST ORDERED_COLLECTION *Tracker - ) -{ - ORDERED_COLLECTION_ENTRY *TrackerEntry; - BLOB *Blob; - - if (AddChecksum->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { - DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__)); - return EFI_PROTOCOL_ERROR; - } - - TrackerEntry = OrderedCollectionFind (Tracker, AddChecksum->File); - if (TrackerEntry == NULL) { - DEBUG ((DEBUG_ERROR, "%a: invalid blob reference \"%a\"\n", __FUNCTION__, - AddChecksum->File)); - return EFI_PROTOCOL_ERROR; - } - - Blob = OrderedCollectionUserStruct (TrackerEntry); - if (Blob->Size <= AddChecksum->ResultOffset || - Blob->Size < AddChecksum->Length || - Blob->Size - AddChecksum->Length < AddChecksum->Start) { - DEBUG ((DEBUG_ERROR, "%a: invalid checksum range in \"%a\"\n", - __FUNCTION__, AddChecksum->File)); - return EFI_PROTOCOL_ERROR; - } - - Blob->Base[AddChecksum->ResultOffset] = CalculateCheckSum8 ( - Blob->Base + AddChecksum->Start, - AddChecksum->Length - ); - DEBUG ((DEBUG_VERBOSE, "%a: File=\"%a\" ResultOffset=0x%x Start=0x%x " - "Length=0x%x\n", __FUNCTION__, AddChecksum->File, - AddChecksum->ResultOffset, AddChecksum->Start, AddChecksum->Length)); - return EFI_SUCCESS; -} - - -/** - Process a QEMU_LOADER_WRITE_POINTER command. - - @param[in] WritePointer The QEMU_LOADER_WRITE_POINTER command to process. - - @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user - structures created thus far. - - @param[in,out] S3Context The S3_CONTEXT object capturing the fw_cfg actions - of successfully processed QEMU_LOADER_WRITE_POINTER - commands, to be replayed at S3 resume. S3Context - may be NULL if S3 is disabled. - - @retval EFI_PROTOCOL_ERROR Malformed fw_cfg file name(s) have been found in - WritePointer. Or, the WritePointer command - references a file unknown to Tracker or the - fw_cfg directory. Or, the pointer object to - rewrite has invalid location, size, or initial - relative value. Or, the pointer value to store - does not fit in the given pointer size. - - @retval EFI_SUCCESS The pointer object inside the writeable fw_cfg - file has been written. If S3Context is not NULL, - then WritePointer has been condensed into - S3Context. - - @return Error codes propagated from - SaveCondensedWritePointerToS3Context(). The - pointer object inside the writeable fw_cfg file - has not been written. -**/ -STATIC -EFI_STATUS -ProcessCmdWritePointer ( - IN CONST QEMU_LOADER_WRITE_POINTER *WritePointer, - IN CONST ORDERED_COLLECTION *Tracker, - IN OUT S3_CONTEXT *S3Context OPTIONAL - ) -{ - RETURN_STATUS Status; - FIRMWARE_CONFIG_ITEM PointerItem; - UINTN PointerItemSize; - ORDERED_COLLECTION_ENTRY *PointeeEntry; - BLOB *PointeeBlob; - UINT64 PointerValue; - - if (WritePointer->PointerFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0' || - WritePointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { - DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__)); - return EFI_PROTOCOL_ERROR; - } - - Status = QemuFwCfgFindFile ((CONST CHAR8 *)WritePointer->PointerFile, - &PointerItem, &PointerItemSize); - PointeeEntry = OrderedCollectionFind (Tracker, WritePointer->PointeeFile); - if (RETURN_ERROR (Status) || PointeeEntry == NULL) { - DEBUG ((DEBUG_ERROR, - "%a: invalid fw_cfg file or blob reference \"%a\" / \"%a\"\n", - __FUNCTION__, WritePointer->PointerFile, WritePointer->PointeeFile)); - return EFI_PROTOCOL_ERROR; - } - - if ((WritePointer->PointerSize != 1 && WritePointer->PointerSize != 2 && - WritePointer->PointerSize != 4 && WritePointer->PointerSize != 8) || - (PointerItemSize < WritePointer->PointerSize) || - (PointerItemSize - WritePointer->PointerSize < - WritePointer->PointerOffset)) { - DEBUG ((DEBUG_ERROR, "%a: invalid pointer location or size in \"%a\"\n", - __FUNCTION__, WritePointer->PointerFile)); - return EFI_PROTOCOL_ERROR; - } - - PointeeBlob = OrderedCollectionUserStruct (PointeeEntry); - PointerValue = WritePointer->PointeeOffset; - if (PointerValue >= PointeeBlob->Size) { - DEBUG ((DEBUG_ERROR, "%a: invalid PointeeOffset\n", __FUNCTION__)); - return EFI_PROTOCOL_ERROR; - } - - // - // The memory allocation system ensures that the address of the byte past the - // last byte of any allocated object is expressible (no wraparound). - // - ASSERT ((UINTN)PointeeBlob->Base <= MAX_ADDRESS - PointeeBlob->Size); - - PointerValue += (UINT64)(UINTN)PointeeBlob->Base; - if (WritePointer->PointerSize < 8 && - RShiftU64 (PointerValue, WritePointer->PointerSize * 8) != 0) { - DEBUG ((DEBUG_ERROR, "%a: pointer value unrepresentable in \"%a\"\n", - __FUNCTION__, WritePointer->PointerFile)); - return EFI_PROTOCOL_ERROR; - } - - // - // If S3 is enabled, we have to capture the below fw_cfg actions in condensed - // form, to be replayed during S3 resume. - // - if (S3Context != NULL) { - EFI_STATUS SaveStatus; - - SaveStatus = SaveCondensedWritePointerToS3Context ( - S3Context, - (UINT16)PointerItem, - WritePointer->PointerSize, - WritePointer->PointerOffset, - PointerValue - ); - if (EFI_ERROR (SaveStatus)) { - return SaveStatus; - } - } - - QemuFwCfgSelectItem (PointerItem); - QemuFwCfgSkipBytes (WritePointer->PointerOffset); - QemuFwCfgWriteBytes (WritePointer->PointerSize, &PointerValue); - - // - // Because QEMU has now learned PointeeBlob->Base, we must mark PointeeBlob - // as unreleasable, for the case when the whole linker/loader script is - // handled successfully. - // - PointeeBlob->HostsOnlyTableData = FALSE; - - DEBUG ((DEBUG_VERBOSE, "%a: PointerFile=\"%a\" PointeeFile=\"%a\" " - "PointerOffset=0x%x PointeeOffset=0x%x PointerSize=%d\n", __FUNCTION__, - WritePointer->PointerFile, WritePointer->PointeeFile, - WritePointer->PointerOffset, WritePointer->PointeeOffset, - WritePointer->PointerSize)); - return EFI_SUCCESS; -} - - -/** - Undo a QEMU_LOADER_WRITE_POINTER command. - - This function revokes (zeroes out) a guest memory reference communicated to - QEMU earlier. The caller is responsible for invoking this function only on - such QEMU_LOADER_WRITE_POINTER commands that have been successfully processed - by ProcessCmdWritePointer(). - - @param[in] WritePointer The QEMU_LOADER_WRITE_POINTER command to undo. -**/ -STATIC -VOID -UndoCmdWritePointer ( - IN CONST QEMU_LOADER_WRITE_POINTER *WritePointer - ) -{ - RETURN_STATUS Status; - FIRMWARE_CONFIG_ITEM PointerItem; - UINTN PointerItemSize; - UINT64 PointerValue; - - Status = QemuFwCfgFindFile ((CONST CHAR8 *)WritePointer->PointerFile, - &PointerItem, &PointerItemSize); - ASSERT_RETURN_ERROR (Status); - - PointerValue = 0; - QemuFwCfgSelectItem (PointerItem); - QemuFwCfgSkipBytes (WritePointer->PointerOffset); - QemuFwCfgWriteBytes (WritePointer->PointerSize, &PointerValue); - - DEBUG ((DEBUG_VERBOSE, - "%a: PointerFile=\"%a\" PointerOffset=0x%x PointerSize=%d\n", __FUNCTION__, - WritePointer->PointerFile, WritePointer->PointerOffset, - WritePointer->PointerSize)); -} - - -// -// We'll be saving the keys of installed tables so that we can roll them back -// in case of failure. 128 tables should be enough for anyone (TM). -// -#define INSTALLED_TABLES_MAX 128 - -/** - Process a QEMU_LOADER_ADD_POINTER command in order to see if its target byte - array is an ACPI table, and if so, install it. - - This function assumes that the entire QEMU linker/loader command file has - been processed successfully in a prior first pass. - - @param[in] AddPointer The QEMU_LOADER_ADD_POINTER command to process. - - @param[in] Tracker The ORDERED_COLLECTION tracking the BLOB user - structures. - - @param[in] AcpiProtocol The ACPI table protocol used to install tables. - - @param[in,out] InstalledKey On input, an array of INSTALLED_TABLES_MAX UINTN - elements, allocated by the caller. On output, - the function will have stored (appended) the - AcpiProtocol-internal key of the ACPI table that - the function has installed, if the AddPointer - command identified an ACPI table that is - different from RSDT and XSDT. - - @param[in,out] NumInstalled On input, the number of entries already used in - InstalledKey; it must be in [0, - INSTALLED_TABLES_MAX] inclusive. On output, the - parameter is incremented if the AddPointer - command identified an ACPI table that is - different from RSDT and XSDT. - - @param[in,out] SeenPointers The ORDERED_COLLECTION tracking the absolute - target addresses that have been pointed-to by - QEMU_LOADER_ADD_POINTER commands thus far. If a - target address is encountered for the first - time, and it identifies an ACPI table that is - different from RDST and XSDT, the table is - installed. If a target address is seen for the - second or later times, it is skipped without - taking any action. - - @retval EFI_INVALID_PARAMETER NumInstalled was outside the allowed range on - input. - - @retval EFI_OUT_OF_RESOURCES The AddPointer command identified an ACPI - table different from RSDT and XSDT, but there - was no more room in InstalledKey. - - @retval EFI_SUCCESS AddPointer has been processed. Either its - absolute target address has been encountered - before, or an ACPI table different from RSDT - and XSDT has been installed (reflected by - InstalledKey and NumInstalled), or RSDT or - XSDT has been identified but not installed, or - the fw_cfg blob pointed-into by AddPointer has - been marked as hosting something else than - just direct ACPI table contents. - - @return Error codes returned by - AcpiProtocol->InstallAcpiTable(). -**/ -STATIC -EFI_STATUS -EFIAPI -Process2ndPassCmdAddPointer ( - IN CONST QEMU_LOADER_ADD_POINTER *AddPointer, - IN CONST ORDERED_COLLECTION *Tracker, - IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol, - IN OUT UINTN InstalledKey[INSTALLED_TABLES_MAX], - IN OUT INT32 *NumInstalled, - IN OUT ORDERED_COLLECTION *SeenPointers - ) -{ - CONST ORDERED_COLLECTION_ENTRY *TrackerEntry; - CONST ORDERED_COLLECTION_ENTRY *TrackerEntry2; - ORDERED_COLLECTION_ENTRY *SeenPointerEntry; - CONST BLOB *Blob; - BLOB *Blob2; - CONST UINT8 *PointerField; - UINT64 PointerValue; - UINTN Blob2Remaining; - UINTN TableSize; - CONST EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; - CONST EFI_ACPI_DESCRIPTION_HEADER *Header; - EFI_STATUS Status; - - if (*NumInstalled < 0 || *NumInstalled > INSTALLED_TABLES_MAX) { - return EFI_INVALID_PARAMETER; - } - - TrackerEntry = OrderedCollectionFind (Tracker, AddPointer->PointerFile); - TrackerEntry2 = OrderedCollectionFind (Tracker, AddPointer->PointeeFile); - Blob = OrderedCollectionUserStruct (TrackerEntry); - Blob2 = OrderedCollectionUserStruct (TrackerEntry2); - PointerField = Blob->Base + AddPointer->PointerOffset; - PointerValue = 0; - CopyMem (&PointerValue, PointerField, AddPointer->PointerSize); - - // - // We assert that PointerValue falls inside Blob2's contents. This is ensured - // by the Blob2->Size check and later checks in ProcessCmdAddPointer(). - // - Blob2Remaining = (UINTN)Blob2->Base; - ASSERT(PointerValue >= Blob2Remaining); - Blob2Remaining += Blob2->Size; - ASSERT (PointerValue < Blob2Remaining); - - Status = OrderedCollectionInsert ( - SeenPointers, - &SeenPointerEntry, // for reverting insertion in error case - (VOID *)(UINTN)PointerValue - ); - if (EFI_ERROR (Status)) { - if (Status == RETURN_ALREADY_STARTED) { - // - // Already seen this pointer, don't try to process it again. - // - DEBUG (( - DEBUG_VERBOSE, - "%a: PointerValue=0x%Lx already processed, skipping.\n", - __FUNCTION__, - PointerValue - )); - Status = EFI_SUCCESS; - } - return Status; - } - - Blob2Remaining -= (UINTN) PointerValue; - DEBUG ((DEBUG_VERBOSE, "%a: checking for ACPI header in \"%a\" at 0x%Lx " - "(remaining: 0x%Lx): ", __FUNCTION__, AddPointer->PointeeFile, - PointerValue, (UINT64)Blob2Remaining)); - - TableSize = 0; - - // - // To make our job simple, the FACS has a custom header. Sigh. - // - if (sizeof *Facs <= Blob2Remaining) { - Facs = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)PointerValue; - - if (Facs->Length >= sizeof *Facs && - Facs->Length <= Blob2Remaining && - Facs->Signature == - EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) { - DEBUG ((DEBUG_VERBOSE, "found \"%-4.4a\" size 0x%x\n", - (CONST CHAR8 *)&Facs->Signature, Facs->Length)); - TableSize = Facs->Length; - } - } - - // - // check for the uniform tables - // - if (TableSize == 0 && sizeof *Header <= Blob2Remaining) { - Header = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)PointerValue; - - if (Header->Length >= sizeof *Header && - Header->Length <= Blob2Remaining && - CalculateSum8 ((CONST UINT8 *)Header, Header->Length) == 0) { - // - // This looks very much like an ACPI table from QEMU: - // - Length field consistent with both ACPI and containing blob size - // - checksum is correct - // - DEBUG ((DEBUG_VERBOSE, "found \"%-4.4a\" size 0x%x\n", - (CONST CHAR8 *)&Header->Signature, Header->Length)); - TableSize = Header->Length; - - // - // Skip RSDT and XSDT because those are handled by - // EFI_ACPI_TABLE_PROTOCOL automatically. - if (Header->Signature == - EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE || - Header->Signature == - EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { - return EFI_SUCCESS; - } - } - } - - if (TableSize == 0) { - DEBUG ((DEBUG_VERBOSE, "not found; marking fw_cfg blob as opaque\n")); - Blob2->HostsOnlyTableData = FALSE; - return EFI_SUCCESS; - } - - if (*NumInstalled == INSTALLED_TABLES_MAX) { - DEBUG ((DEBUG_ERROR, "%a: can't install more than %d tables\n", - __FUNCTION__, INSTALLED_TABLES_MAX)); - Status = EFI_OUT_OF_RESOURCES; - goto RollbackSeenPointer; - } - - Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol, - (VOID *)(UINTN)PointerValue, TableSize, - &InstalledKey[*NumInstalled]); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a: InstallAcpiTable(): %r\n", __FUNCTION__, - Status)); - goto RollbackSeenPointer; - } - ++*NumInstalled; - return EFI_SUCCESS; - -RollbackSeenPointer: - OrderedCollectionDelete (SeenPointers, SeenPointerEntry, NULL); - return Status; -} - - -/** - Download, process, and install ACPI table data from the QEMU loader - interface. - - @param[in] AcpiProtocol The ACPI table protocol used to install tables. - - @retval EFI_UNSUPPORTED Firmware configuration is unavailable, or QEMU - loader command with unsupported parameters - has been found. - - @retval EFI_NOT_FOUND The host doesn't export the required fw_cfg - files. - - @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than - INSTALLED_TABLES_MAX tables found. - - @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents. - - @return Status codes returned by - AcpiProtocol->InstallAcpiTable(). - -**/ -EFI_STATUS -EFIAPI -InstallQemuFwCfgTables ( - IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol - ) -{ - EFI_STATUS Status; - FIRMWARE_CONFIG_ITEM FwCfgItem; - UINTN FwCfgSize; - QEMU_LOADER_ENTRY *LoaderStart; - CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd; - CONST QEMU_LOADER_ENTRY *WritePointerSubsetEnd; - ORIGINAL_ATTRIBUTES *OriginalPciAttributes; - UINTN OriginalPciAttributesCount; - ORDERED_COLLECTION *AllocationsRestrictedTo32Bit; - S3_CONTEXT *S3Context; - ORDERED_COLLECTION *Tracker; - UINTN *InstalledKey; - INT32 Installed; - ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2; - ORDERED_COLLECTION *SeenPointers; - ORDERED_COLLECTION_ENTRY *SeenPointerEntry, *SeenPointerEntry2; - - Status = QemuFwCfgFindFile ("etc/table-loader", &FwCfgItem, &FwCfgSize); - if (EFI_ERROR (Status)) { - return Status; - } - if (FwCfgSize % sizeof *LoaderEntry != 0) { - DEBUG ((DEBUG_ERROR, "%a: \"etc/table-loader\" has invalid size 0x%Lx\n", - __FUNCTION__, (UINT64)FwCfgSize)); - return EFI_PROTOCOL_ERROR; - } - - LoaderStart = AllocatePool (FwCfgSize); - if (LoaderStart == NULL) { - return EFI_OUT_OF_RESOURCES; - } - EnablePciDecoding (&OriginalPciAttributes, &OriginalPciAttributesCount); - QemuFwCfgSelectItem (FwCfgItem); - QemuFwCfgReadBytes (FwCfgSize, LoaderStart); - RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount); - LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry; - - AllocationsRestrictedTo32Bit = NULL; - Status = CollectAllocationsRestrictedTo32Bit ( - &AllocationsRestrictedTo32Bit, - LoaderStart, - LoaderEnd - ); - if (EFI_ERROR (Status)) { - goto FreeLoader; - } - - S3Context = NULL; - if (QemuFwCfgS3Enabled ()) { - // - // Size the allocation pessimistically, assuming that all commands in the - // script are QEMU_LOADER_WRITE_POINTER commands. - // - Status = AllocateS3Context (&S3Context, LoaderEnd - LoaderStart); - if (EFI_ERROR (Status)) { - goto FreeAllocationsRestrictedTo32Bit; - } - } - - Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare); - if (Tracker == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto FreeS3Context; - } - - // - // first pass: process the commands - // - // "WritePointerSubsetEnd" points one past the last successful - // QEMU_LOADER_WRITE_POINTER command. Now when we're about to start the first - // pass, no such command has been encountered yet. - // - WritePointerSubsetEnd = LoaderStart; - for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { - switch (LoaderEntry->Type) { - case QemuLoaderCmdAllocate: - Status = ProcessCmdAllocate ( - &LoaderEntry->Command.Allocate, - Tracker, - AllocationsRestrictedTo32Bit - ); - break; - - case QemuLoaderCmdAddPointer: - Status = ProcessCmdAddPointer (&LoaderEntry->Command.AddPointer, - Tracker); - break; - - case QemuLoaderCmdAddChecksum: - Status = ProcessCmdAddChecksum (&LoaderEntry->Command.AddChecksum, - Tracker); - break; - - case QemuLoaderCmdWritePointer: - Status = ProcessCmdWritePointer (&LoaderEntry->Command.WritePointer, - Tracker, S3Context); - if (!EFI_ERROR (Status)) { - WritePointerSubsetEnd = LoaderEntry + 1; - } - break; - - default: - DEBUG ((DEBUG_VERBOSE, "%a: unknown loader command: 0x%x\n", - __FUNCTION__, LoaderEntry->Type)); - break; - } - - if (EFI_ERROR (Status)) { - goto RollbackWritePointersAndFreeTracker; - } - } - - InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey); - if (InstalledKey == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto RollbackWritePointersAndFreeTracker; - } - - SeenPointers = OrderedCollectionInit (PointerCompare, PointerCompare); - if (SeenPointers == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto FreeKeys; - } - - // - // second pass: identify and install ACPI tables - // - Installed = 0; - for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) { - if (LoaderEntry->Type == QemuLoaderCmdAddPointer) { - Status = Process2ndPassCmdAddPointer ( - &LoaderEntry->Command.AddPointer, - Tracker, - AcpiProtocol, - InstalledKey, - &Installed, - SeenPointers - ); - if (EFI_ERROR (Status)) { - goto UninstallAcpiTables; - } - } - } - - // - // Translating the condensed QEMU_LOADER_WRITE_POINTER commands to ACPI S3 - // Boot Script opcodes has to be the last operation in this function, because - // if it succeeds, it cannot be undone. - // - if (S3Context != NULL) { - Status = TransferS3ContextToBootScript (S3Context); - if (EFI_ERROR (Status)) { - goto UninstallAcpiTables; - } - // - // Ownership of S3Context has been transferred. - // - S3Context = NULL; - } - -UninstallAcpiTables: - if (EFI_ERROR (Status)) { - // - // roll back partial installation - // - while (Installed > 0) { - --Installed; - AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]); - } - } else { - DEBUG ((DEBUG_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed)); - } - - for (SeenPointerEntry = OrderedCollectionMin (SeenPointers); - SeenPointerEntry != NULL; - SeenPointerEntry = SeenPointerEntry2) { - SeenPointerEntry2 = OrderedCollectionNext (SeenPointerEntry); - OrderedCollectionDelete (SeenPointers, SeenPointerEntry, NULL); - } - OrderedCollectionUninit (SeenPointers); - -FreeKeys: - FreePool (InstalledKey); - -RollbackWritePointersAndFreeTracker: - // - // In case of failure, revoke any allocation addresses that were communicated - // to QEMU previously, before we release all the blobs. - // - if (EFI_ERROR (Status)) { - LoaderEntry = WritePointerSubsetEnd; - while (LoaderEntry > LoaderStart) { - --LoaderEntry; - if (LoaderEntry->Type == QemuLoaderCmdWritePointer) { - UndoCmdWritePointer (&LoaderEntry->Command.WritePointer); - } - } - } - - // - // Tear down the tracker infrastructure. Each fw_cfg blob will be left in - // place only if we're exiting with success and the blob hosts data that is - // not directly part of some ACPI table. - // - for (TrackerEntry = OrderedCollectionMin (Tracker); TrackerEntry != NULL; - TrackerEntry = TrackerEntry2) { - VOID *UserStruct; - BLOB *Blob; - - TrackerEntry2 = OrderedCollectionNext (TrackerEntry); - OrderedCollectionDelete (Tracker, TrackerEntry, &UserStruct); - Blob = UserStruct; - - if (EFI_ERROR (Status) || Blob->HostsOnlyTableData) { - DEBUG ((DEBUG_VERBOSE, "%a: freeing \"%a\"\n", __FUNCTION__, - Blob->File)); - gBS->FreePages ((UINTN)Blob->Base, EFI_SIZE_TO_PAGES (Blob->Size)); - } - FreePool (Blob); - } - OrderedCollectionUninit (Tracker); - -FreeS3Context: - if (S3Context != NULL) { - ReleaseS3Context (S3Context); - } - -FreeAllocationsRestrictedTo32Bit: - ReleaseAllocationsRestrictedTo32Bit (AllocationsRestrictedTo32Bit); - -FreeLoader: - FreePool (LoaderStart); - - return Status; -} diff --git a/OvmfPkg/XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf b/OvmfPkg/XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf index 379b5d56d5..72132e397d 100644 --- a/OvmfPkg/XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf +++ b/OvmfPkg/XenAcpiPlatformDxe/XenAcpiPlatformDxe.inf @@ -24,11 +24,8 @@ [Sources] AcpiPlatform.c AcpiPlatform.h - BootScript.c EntryPoint.c - PciDecoding.c Qemu.c - QemuFwCfgAcpi.c Xen.c [Packages] @@ -43,10 +40,8 @@ DebugLib DxeServicesTableLib MemoryAllocationLib - OrderedCollectionLib PcdLib QemuFwCfgLib - QemuFwCfgS3Lib UefiBootServicesTableLib UefiDriverEntryPoint XenPlatformLib @@ -54,7 +49,6 @@ [Protocols] gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED - gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED [Guids] gRootBridgesConnectedEventGroupGuid -- 2.39.2