From patchwork Sat Aug 9 02:08:59 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 35175 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f70.google.com (mail-qa0-f70.google.com [209.85.216.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id C11642118A for ; Sat, 9 Aug 2014 02:09:27 +0000 (UTC) Received: by mail-qa0-f70.google.com with SMTP id j7sf16451540qaq.1 for ; Fri, 08 Aug 2014 19:09:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:subject:precedence:reply-to:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version :errors-to:x-original-sender:x-original-authentication-results :mailing-list:content-type:content-transfer-encoding; bh=bn89qTKYPXxGC7pvwhNsNTDm0DWjKPjgytY4aajEKl4=; b=eQOESzoMR88LLLweBZJUPU/IlPtsgHaama4kgNGRr8J5FDw7f6RQ1kqMksKu4qGsTc ycwLb+LYteDO2WqX5RMI3tm/RZmdQ0ydh77XgizMmQpZgyxPqXJCvw1Di8ejPhSBoMOF 8ZOJSsgLFwU3lVwW73sTHCLl7ujuYpDFZSsEjHDT0ahu1dDAxqaY+tKqdvLDsL6yWHuw +n14fW93jNV76bhIt1XpFi+lUppN2r1K5h5D8vL5vcOc+ywWo48pB0d+B+g58Z6Ns8oE m3BbRKdMGIfSK55pyLip6AFK3DA+iayOlGSgSJZ+8irro9hU7jkBMt6Y4nP0IK5QBi7E zZ9Q== X-Gm-Message-State: ALoCoQlgOu36Ip70qVSRLrgzZn03EhQOhexn8VDufs2/XOKCDdn3XdNqOQK1Rb1whu6rAd/Rl86k X-Received: by 10.224.127.6 with SMTP id e6mr14549003qas.3.1407550167652; Fri, 08 Aug 2014 19:09:27 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.38.80 with SMTP id s74ls810356qgs.64.gmail; Fri, 08 Aug 2014 19:09:27 -0700 (PDT) X-Received: by 10.52.136.196 with SMTP id qc4mr9163754vdb.22.1407550167508; Fri, 08 Aug 2014 19:09:27 -0700 (PDT) Received: from mail-vc0-f179.google.com (mail-vc0-f179.google.com [209.85.220.179]) by mx.google.com with ESMTPS id g6si3470918veh.96.2014.08.08.19.09.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 08 Aug 2014 19:09:27 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.179 as permitted sender) client-ip=209.85.220.179; Received: by mail-vc0-f179.google.com with SMTP id hq11so9353573vcb.10 for ; Fri, 08 Aug 2014 19:09:27 -0700 (PDT) X-Received: by 10.220.181.196 with SMTP id bz4mr24800589vcb.36.1407550167359; Fri, 08 Aug 2014 19:09:27 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.37.5 with SMTP id tc5csp169380vcb; Fri, 8 Aug 2014 19:09:26 -0700 (PDT) X-Received: by 10.43.69.202 with SMTP id yd10mr16205201icb.36.1407550165941; Fri, 08 Aug 2014 19:09:25 -0700 (PDT) Received: from lists.sourceforge.net (lists.sourceforge.net. [216.34.181.88]) by mx.google.com with ESMTPS id nu4si17871615icc.81.2014.08.08.19.09.25 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 08 Aug 2014 19:09:25 -0700 (PDT) Received-SPF: pass (google.com: domain of edk2-devel-bounces@lists.sourceforge.net designates 216.34.181.88 as permitted sender) client-ip=216.34.181.88; Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1XFw5t-00043t-LG; Sat, 09 Aug 2014 02:09:17 +0000 Received: from sog-mx-2.v43.ch3.sourceforge.com ([172.29.43.192] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1XFw5r-00043o-OV for edk2-devel@lists.sourceforge.net; Sat, 09 Aug 2014 02:09:15 +0000 Received-SPF: pass (sog-mx-2.v43.ch3.sourceforge.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=lersek@redhat.com; helo=mx1.redhat.com; Received: from mx1.redhat.com ([209.132.183.28]) by sog-mx-2.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) id 1XFw5q-0001r9-4w for edk2-devel@lists.sourceforge.net; Sat, 09 Aug 2014 02:09:15 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s79298qn021247 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 8 Aug 2014 22:09:08 -0400 Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-98.ams2.redhat.com [10.36.116.98]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s79291UG014215; Fri, 8 Aug 2014 22:09:06 -0400 From: Laszlo Ersek To: edk2-devel@lists.sourceforge.net, "Michael S. Tsirkin" Date: Sat, 9 Aug 2014 04:08:59 +0200 Message-Id: <1407550139-25313-5-git-send-email-lersek@redhat.com> In-Reply-To: <1407550139-25313-1-git-send-email-lersek@redhat.com> References: <1407550139-25313-1-git-send-email-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Spam-Score: -2.2 (--) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -1.5 SPF_CHECK_PASS SPF reports sender host as permitted sender for sender-domain -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain X-Headers-End: 1XFw5q-0001r9-4w Subject: [edk2] [PATCH 4/4] OvmfPkg: AcpiPlatformDxe: implement QEMU's full ACPI table loader interface X-BeenThere: edk2-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list Reply-To: edk2-devel@lists.sourceforge.net List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.sourceforge.net X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lersek@redhat.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.179 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Recent changes in the QEMU ACPI table generator have shown that our limited client for that interface is insufficient and/or brittle. Implement the full interface utilizing OrderedCollectionLib for addressing fw_cfg blobs by name. In addition, we stop using EFI_ACPI_TABLE_PROTOCOL in the QEMU loader client, because: - splitting the blobs for EFI_ACPI_TABLE_PROTOCOL is just untenable short of a complete ACPI parser, - and it is fully sufficient to install the RSD PTR as an EFI configuration table for the guest OS to see everything. In short, for this interface, EFI_ACPI_TABLE_PROTOCOL is an unwanted and restrictive convenience; let's stop using it. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jordan Justen --- OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 3 + OvmfPkg/AcpiPlatformDxe/Qemu.c | 415 ++++++++++++++++++++++++++-- 2 files changed, 398 insertions(+), 20 deletions(-) diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf index 90178e0..02eaf23 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -51,12 +51,15 @@ MemoryAllocationLib BaseLib DxeServicesTableLib + OrderedCollectionLib [Protocols] gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED [Guids] gEfiXenInfoGuid + gEfiAcpi10TableGuid + gEfiAcpi20TableGuid [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile diff --git a/OvmfPkg/AcpiPlatformDxe/Qemu.c b/OvmfPkg/AcpiPlatformDxe/Qemu.c index 333766e..4663ecb 100644 --- a/OvmfPkg/AcpiPlatformDxe/Qemu.c +++ b/OvmfPkg/AcpiPlatformDxe/Qemu.c @@ -17,12 +17,15 @@ #include "AcpiPlatform.h" #include "QemuLoader.h" -#include -#include -#include -#include -#include -#include +#include // CopyMem() +#include // AllocatePool() +#include // QemuFwCfgFindFile() +#include // gDS +#include // PcdGet16() +#include // EfiGetSystemConfigurationTable() +#include // OrderedCollectionInit() +#include // EFI_ACPI_DESCRIPTION_HEADER +#include // gEfiAcpi10TableGuid BOOLEAN QemuDetected ( @@ -518,7 +521,8 @@ QemuInstallAcpiTable ( /** - Check if an array of bytes starts with an RSD PTR structure. + Check if an array of bytes starts with an RSD PTR structure, and if so, + return the EFI ACPI table GUID that corresponds to its version. Checksum is ignored. @@ -526,8 +530,9 @@ QemuInstallAcpiTable ( @param[in] Size Number of bytes in Buffer. - @param[out] RsdpSize If the function returns EFI_SUCCESS, this parameter - contains the size of the detected RSD PTR structure. + @param[out] AcpiTableGuid On successful exit, pointer to the EFI ACPI table + GUID in statically allocated storage that + corresponds to the detected RSD PTR version. @retval EFI_SUCCESS RSD PTR structure detected at the beginning of Buffer, and its advertised size does not exceed @@ -545,7 +550,7 @@ EFI_STATUS CheckRsdp ( IN CONST VOID *Buffer, IN UINTN Size, - OUT UINTN *RsdpSize + OUT EFI_GUID **AcpiTableGuid ) { CONST UINT64 *Signature; @@ -574,7 +579,7 @@ CheckRsdp ( // // ACPI 1.0 doesn't include the Length field // - *RsdpSize = sizeof *Rsdp1; + *AcpiTableGuid = &gEfiAcpi10TableGuid; return EFI_SUCCESS; } @@ -587,27 +592,99 @@ CheckRsdp ( return EFI_PROTOCOL_ERROR; } - *RsdpSize = Rsdp2->Length; + *AcpiTableGuid = &gEfiAcpi20TableGuid; return EFI_SUCCESS; } +// +// 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. +} 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); +} + /** - Download all ACPI table data files from QEMU and interpret them. + 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. - @param[in] AcpiProtocol The ACPI table protocol used to install tables. + @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); +} + +/** + Download, process, and install ACPI table data from the QEMU loader + interface. - @retval EFI_UNSUPPORTED Firmware configuration is unavailable. + @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_OUT_OF_RESOURCES Memory allocation failed. @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents. - @return Status codes returned by - AcpiProtocol->InstallAcpiTable(). + @retval EFI_ALREADY_STARTED One of the ACPI TABLE GUIDs has been found in + the EFI Configuration Table, indicating the + presence of a preexistent RSD PTR table, and + therefore that of another module installing + ACPI tables. + + @retval EFI_SUCCESS Installation of ACPI tables succeeded. **/ @@ -617,5 +694,303 @@ InstallAllQemuLinkedTables ( VOID ) { - return CheckRsdp (NULL, 0, NULL); + EFI_STATUS Status; + FIRMWARE_CONFIG_ITEM FwCfgItem; + UINTN FwCfgSize; + VOID *Rsdp; + UINTN RsdpBufferSize; + UINT8 *Loader; + CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd; + ORDERED_COLLECTION *Tracker; + ORDERED_COLLECTION_ENTRY *TrackerEntry, *TrackerEntry2; + BLOB *Blob; + EFI_GUID *AcpiTableGuid; + + // + // This function allocates memory on four levels. From lowest to highest: + // - Areas consisting of whole pages, of type EfiACPIMemoryNVS, for + // (processed) ACPI payload, + // - BLOB structures referencing the above, tracking their names, sizes, and + // addresses, + // - ORDERED_COLLECTION_ENTRY objects internal to OrderedCollectionLib, + // linking the BLOB structures, + // - an ORDERED_COLLECTION organizing the ORDERED_COLLECTION_ENTRY entries. + // + // On exit, the last three levels are torn down unconditionally. If we exit + // with success, then the first (lowest) level is left in place, constituting + // the ACPI tables for the guest. If we exit with error, then even the first + // (lowest) level is torn down. + // + + Status = QemuFwCfgFindFile ("etc/table-loader", &FwCfgItem, &FwCfgSize); + if (EFI_ERROR (Status)) { + return Status; + } + if (FwCfgSize % sizeof *LoaderEntry != 0) { + DEBUG ((EFI_D_ERROR, "%a: \"etc/table-loader\" has invalid size 0x%Lx\n", + __FUNCTION__, (UINT64)FwCfgSize)); + return EFI_PROTOCOL_ERROR; + } + + if (!EFI_ERROR (EfiGetSystemConfigurationTable ( + &gEfiAcpi10TableGuid, &Rsdp)) || + !EFI_ERROR (EfiGetSystemConfigurationTable ( + &gEfiAcpi20TableGuid, &Rsdp))) { + DEBUG ((EFI_D_ERROR, "%a: RSD PTR already present\n", __FUNCTION__)); + return EFI_ALREADY_STARTED; + } + + Loader = AllocatePool (FwCfgSize); + if (Loader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + QemuFwCfgSelectItem (FwCfgItem); + QemuFwCfgReadBytes (FwCfgSize, Loader); + + Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare); + if (Tracker == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeLoader; + } + + Rsdp = NULL; + RsdpBufferSize = 0; + + LoaderEntry = (QEMU_LOADER_ENTRY *)Loader; + LoaderEnd = (QEMU_LOADER_ENTRY *)(Loader + FwCfgSize); + while (LoaderEntry < LoaderEnd) { + switch (LoaderEntry->Type) { + case QemuLoaderCmdAllocate: { + CONST QEMU_LOADER_ALLOCATE *Allocate; + UINTN NumPages; + EFI_PHYSICAL_ADDRESS Address; + + Allocate = &LoaderEntry->Command.Allocate; + if (Allocate->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { + DEBUG ((EFI_D_ERROR, "%a: malformed file name in Allocate command\n", + __FUNCTION__)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + if (Allocate->Alignment > EFI_PAGE_SIZE) { + DEBUG ((EFI_D_ERROR, "%a: unsupported alignment 0x%x in Allocate " + "command\n", __FUNCTION__, Allocate->Alignment)); + Status = EFI_UNSUPPORTED; + goto FreeTracker; + } + Status = QemuFwCfgFindFile ((CHAR8 *)Allocate->File, &FwCfgItem, + &FwCfgSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a: nonexistent file \"%a\" in Allocate " + "command\n", __FUNCTION__, Allocate->File)); + goto FreeTracker; + } + + NumPages = EFI_SIZE_TO_PAGES (FwCfgSize); + Address = 0xFFFFFFFF; + Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, + NumPages, &Address); + if (EFI_ERROR (Status)) { + goto FreeTracker; + } + + 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; + + if (Allocate->Zone == QemuLoaderAllocFSeg) { + if (Rsdp == NULL) { + Rsdp = Blob->Base; + RsdpBufferSize = Blob->Size; + } else { + DEBUG ((EFI_D_ERROR, "%a: duplicate RSD PTR candidate in Allocate " + "command\n", __FUNCTION__)); + Status = EFI_PROTOCOL_ERROR; + goto FreeBlob; + } + } + + Status = OrderedCollectionInsert (Tracker, NULL, Blob); + if (Status == RETURN_ALREADY_STARTED) { + DEBUG ((EFI_D_ERROR, "%a: duplicated file \"%a\" in Allocate " + "command\n", __FUNCTION__, Allocate->File)); + Status = EFI_PROTOCOL_ERROR; + goto FreeBlob; + } + 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 ((EFI_D_VERBOSE, "%a: Allocate: 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)); + break; + +FreeBlob: + FreePool (Blob); +FreePages: + gBS->FreePages (Address, NumPages); + goto FreeTracker; + } + + case QemuLoaderCmdAddPointer: { + CONST QEMU_LOADER_ADD_POINTER *AddPointer; + CONST BLOB *Blob2; + UINT8 *PointerField; + + AddPointer = &LoaderEntry->Command.AddPointer; + if (AddPointer->PointerFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0' || + AddPointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { + DEBUG ((EFI_D_ERROR, "%a: malformed file name in AddPointer command\n", + __FUNCTION__)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + TrackerEntry = OrderedCollectionFind (Tracker, AddPointer->PointerFile); + TrackerEntry2 = OrderedCollectionFind (Tracker, AddPointer->PointeeFile); + if (TrackerEntry == NULL || TrackerEntry2 == NULL) { + DEBUG ((EFI_D_ERROR, "%a: invalid blob reference(s) \"%a\" / \"%a\" " + "in AddPointer command\n", __FUNCTION__, AddPointer->PointerFile, + AddPointer->PointeeFile)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + 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 ((EFI_D_ERROR, "%a: invalid pointer location in \"%a\" in " + "AddPointer command\n", __FUNCTION__, AddPointer->PointerFile)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + PointerField = Blob->Base + AddPointer->PointerOffset; + switch (AddPointer->PointerSize) { + case 1: + *PointerField += (UINT8)(UINTN)Blob2->Base; + break; + + case 2: + *(UINT16 *)PointerField += (UINT16)(UINTN)Blob2->Base; + break; + + case 4: + *(UINT32 *)PointerField += (UINT32)(UINTN)Blob2->Base; + break; + + case 8: + *(UINT64 *)PointerField += (UINT64)(UINTN)Blob2->Base; + break; + } + + DEBUG ((EFI_D_VERBOSE, "%a: AddPointer: PointerFile=\"%a\" " + "PointeeFile=\"%a\" PointerOffset=0x%x PointerSize=%d\n", __FUNCTION__, + AddPointer->PointerFile, AddPointer->PointeeFile, + AddPointer->PointerOffset, AddPointer->PointerSize)); + break; + } + + case QemuLoaderCmdAddChecksum: { + CONST QEMU_LOADER_ADD_CHECKSUM *AddChecksum; + + AddChecksum = &LoaderEntry->Command.AddChecksum; + if (AddChecksum->File[QEMU_LOADER_FNAME_SIZE - 1] != '\0') { + DEBUG ((EFI_D_ERROR, "%a: malformed file name in AddChecksum " + "command\n", __FUNCTION__)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + TrackerEntry = OrderedCollectionFind (Tracker, AddChecksum->File); + if (TrackerEntry == NULL) { + DEBUG ((EFI_D_ERROR, "%a: invalid blob reference \"%a\" in " + "AddChecksum command\n", __FUNCTION__, AddChecksum->File)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + Blob = OrderedCollectionUserStruct (TrackerEntry); + if (Blob->Size <= AddChecksum->ResultOffset || + Blob->Size < AddChecksum->Length || + Blob->Size - AddChecksum->Length < AddChecksum->Start) { + DEBUG ((EFI_D_ERROR, "%a: invalid checksum location or range in " + "\"%a\" in AddChecksum command\n", __FUNCTION__, AddChecksum->File)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + Blob->Base[AddChecksum->ResultOffset] = CalculateCheckSum8 ( + Blob->Base + AddChecksum->Start, + AddChecksum->Length + ); + DEBUG ((EFI_D_VERBOSE, "%a: AddChecksum: File=\"%a\" ResultOffset=0x%x " + "Start=0x%x Length=0x%x\n", __FUNCTION__, AddChecksum->File, + AddChecksum->ResultOffset, AddChecksum->Start, AddChecksum->Length)); + break; + } + + default: + DEBUG ((EFI_D_VERBOSE, "%a: unknown loader command: 0x%x\n", + __FUNCTION__, LoaderEntry->Type)); + break; + } + + ++LoaderEntry; + } + + if (Rsdp == NULL) { + DEBUG ((EFI_D_ERROR, "%a: no RSD PTR candidate\n", __FUNCTION__)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + AcpiTableGuid = NULL; + if (EFI_ERROR (CheckRsdp (Rsdp, RsdpBufferSize, &AcpiTableGuid))) { + DEBUG ((EFI_D_ERROR, "%a: RSD PTR not found in candidate\n", + __FUNCTION__)); + Status = EFI_PROTOCOL_ERROR; + goto FreeTracker; + } + + Status = gBS->InstallConfigurationTable (AcpiTableGuid, Rsdp); + +FreeTracker: + // + // Tear down the tracker structure, and if we're exiting with an error, the + // pages holding the blob data (ie. the processed ACPI payload) as well. + // + for (TrackerEntry = OrderedCollectionMin (Tracker); TrackerEntry != NULL; + TrackerEntry = TrackerEntry2) { + VOID *UserStruct; + + TrackerEntry2 = OrderedCollectionNext (TrackerEntry); + OrderedCollectionDelete (Tracker, TrackerEntry, &UserStruct); + if (EFI_ERROR (Status)) { + Blob = UserStruct; + gBS->FreePages ((UINTN)Blob->Base, EFI_SIZE_TO_PAGES (Blob->Size)); + } + FreePool (UserStruct); + } + OrderedCollectionUninit (Tracker); + +FreeLoader: + FreePool (Loader); + return Status; }