From 5a118a61d12215dc1a984c4bec76fb59c6efa2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corvin=20K=C3=B6hne?= Date: Wed, 21 Jun 2023 09:31:15 +0200 Subject: OvmfPkg: move QemuFwCfgAcpi into AcpiPlatformLib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the InstallQemuFwcfgTables function reusable by bhyve. Signed-off-by: Corvin Köhne Acked-by: Peter Grehan --- OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c | 3 + OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h | 6 - OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 3 - OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 1407 --------------------------- 4 files changed, 3 insertions(+), 1416 deletions(-) delete mode 100644 OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c (limited to 'OvmfPkg/AcpiPlatformDxe') diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c index b446bb4872..20c98bb67f 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.c @@ -9,6 +9,9 @@ #include // CLOUDHV_DEVICE_ID #include + +#include + #include "AcpiPlatform.h" /** diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h index c9f2755014..f4ae84b5a1 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatform.h @@ -23,12 +23,6 @@ InstallCloudHvTables ( IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol ); -EFI_STATUS -EFIAPI -InstallQemuFwCfgTables ( - IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol - ); - EFI_STATUS EFIAPI InstallAcpiTables ( diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf index 6001b96269..622589e607 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -25,7 +25,6 @@ AcpiPlatform.h CloudHvAcpi.c EntryPoint.c - QemuFwCfgAcpi.c [Packages] MdeModulePkg/MdeModulePkg.dec @@ -41,12 +40,10 @@ QemuFwCfgLib UefiDriverEntryPoint HobLib - TpmMeasurementLib [Protocols] gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED - gQemuAcpiTableNotifyProtocolGuid # PROTOCOL PRODUCES [Guids] gRootBridgesConnectedEventGroupGuid diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c deleted file mode 100644 index 3de039d574..0000000000 --- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c +++ /dev/null @@ -1,1407 +0,0 @@ -/** @file - OVMF ACPI support using QEMU's fw-cfg interface - - Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
- Copyright (C) 2012-2014, Red Hat, Inc. - - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include // EFI_ACPI_DESCRIPTION_HEADER -#include // QEMU_LOADER_FNAME_SIZE -#include -#include -#include // AsciiStrCmp() -#include // CopyMem() -#include // DEBUG() -#include // AllocatePool() -#include // OrderedCollectionMin() -#include // QemuFwCfgFindFile() -#include // QemuFwCfgS3Enabled() -#include // gBS -#include - -#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", __func__)); - 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", - __func__, - 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", __func__)); - return EFI_PROTOCOL_ERROR; - } - - if (Allocate->Alignment > EFI_PAGE_SIZE) { - DEBUG (( - DEBUG_ERROR, - "%a: unsupported alignment 0x%x\n", - __func__, - Allocate->Alignment - )); - return EFI_UNSUPPORTED; - } - - Status = QemuFwCfgFindFile ((CHAR8 *)Allocate->File, &FwCfgItem, &FwCfgSize); - if (EFI_ERROR (Status)) { - DEBUG (( - DEBUG_ERROR, - "%a: QemuFwCfgFindFile(\"%a\"): %r\n", - __func__, - 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", - __func__, - 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", - __func__, - Allocate->File, - Allocate->Alignment, - Allocate->Zone, - (UINT64)Blob->Size, - (UINT64)(UINTN)Blob->Base - )); - - // - // Measure the data which is downloaded from QEMU. - // It has to be done before it is consumed. Because the data will - // be updated in the following operations. - // - TpmMeasureAndLogData ( - 1, - EV_PLATFORM_CONFIG_FLAGS, - EV_POSTCODE_INFO_ACPI_DATA, - ACPI_DATA_LEN, - (VOID *)(UINTN)Blob->Base, - Blob->Size - ); - - 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", __func__)); - 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", - __func__, - 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", - __func__, - 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", - __func__, - 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", - __func__, - 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", - __func__, - 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", __func__)); - return EFI_PROTOCOL_ERROR; - } - - TrackerEntry = OrderedCollectionFind (Tracker, AddChecksum->File); - if (TrackerEntry == NULL) { - DEBUG (( - DEBUG_ERROR, - "%a: invalid blob reference \"%a\"\n", - __func__, - 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", - __func__, - 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", - __func__, - 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", __func__)); - 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", - __func__, - 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", - __func__, - WritePointer->PointerFile - )); - return EFI_PROTOCOL_ERROR; - } - - PointeeBlob = OrderedCollectionUserStruct (PointeeEntry); - PointerValue = WritePointer->PointeeOffset; - if (PointerValue >= PointeeBlob->Size) { - DEBUG ((DEBUG_ERROR, "%a: invalid PointeeOffset\n", __func__)); - 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", - __func__, - 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", - __func__, - 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", - __func__, - 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", - __func__, - 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): ", - __func__, - 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", - __func__, - 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", - __func__, - 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; - EFI_HANDLE QemuAcpiHandle; - - 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", - __func__, - (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); - - // - // Measure the "etc/table-loader" which is downloaded from QEMU. - // It has to be done before it is consumed. Because it would be - // updated in the following operations. - // - TpmMeasureAndLogData ( - 1, - EV_PLATFORM_CONFIG_FLAGS, - EV_POSTCODE_INFO_ACPI_DATA, - ACPI_DATA_LEN, - (VOID *)(UINTN)LoaderStart, - FwCfgSize - ); - - 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", - __func__, - 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; - } - } - } - - // - // Install a protocol to notify that the ACPI table provided by Qemu is - // ready. - // - QemuAcpiHandle = NULL; - Status = gBS->InstallProtocolInterface ( - &QemuAcpiHandle, - &gQemuAcpiTableNotifyProtocolGuid, - EFI_NATIVE_INTERFACE, - NULL - ); - 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 UninstallQemuAcpiTableNotifyProtocol; - } - - // - // Ownership of S3Context has been transferred. - // - S3Context = NULL; - } - - DEBUG ((DEBUG_INFO, "%a: installed %d tables\n", __func__, Installed)); - -UninstallQemuAcpiTableNotifyProtocol: - if (EFI_ERROR (Status)) { - gBS->UninstallProtocolInterface ( - QemuAcpiHandle, - &gQemuAcpiTableNotifyProtocolGuid, - NULL - ); - } - -UninstallAcpiTables: - if (EFI_ERROR (Status)) { - // - // roll back partial installation - // - while (Installed > 0) { - --Installed; - AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[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", - __func__, - 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; -} -- cgit v1.2.3