From df73df138d9d53f7f7570f4fe97a6cde941a2656 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 9 Feb 2017 17:32:40 +0100 Subject: OvmfPkg/AcpiPlatformDxe: replay QEMU_LOADER_WRITE_POINTER commands at S3 Ultimately, each QEMU_LOADER_WRITE_POINTER command creates a guest memory reference in some QEMU device. When the virtual machine is reset, the device willfully forgets the guest address, since the guest memory is wholly invalidated during platform reset. ... Unless the reset is part of S3 resume. Then the guest memory is preserved intact, and the firmware must reprogram those devices with the original guest memory allocation addresses. This patch accumulates the fw_cfg select, skip and write operations of ProcessCmdWritePointer() in a validated / condensed form, and turns them into an ACPI S3 Boot Script fragment at the very end of InstallQemuFwCfgTables(). Cc: Jordan Justen Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=359 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jordan Justen --- OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 70 ++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 5 deletions(-) (limited to 'OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c') diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c index de827c2df2..eadd690bef 100644 --- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c +++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c @@ -360,6 +360,11 @@ ProcessCmdAddChecksum ( @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 @@ -369,13 +374,21 @@ ProcessCmdAddChecksum ( does not fit in the given pointer size. @retval EFI_SUCCESS The pointer object inside the writeable fw_cfg - file has been written. + 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 CONST ORDERED_COLLECTION *Tracker, + IN OUT S3_CONTEXT *S3Context OPTIONAL ) { RETURN_STATUS Status; @@ -432,6 +445,25 @@ ProcessCmdWritePointer ( 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); @@ -701,6 +733,7 @@ InstallQemuFwCfgTables ( CONST QEMU_LOADER_ENTRY *WritePointerSubsetEnd; ORIGINAL_ATTRIBUTES *OriginalPciAttributes; UINTN OriginalPciAttributesCount; + S3_CONTEXT *S3Context; ORDERED_COLLECTION *Tracker; UINTN *InstalledKey; INT32 Installed; @@ -726,10 +759,22 @@ InstallQemuFwCfgTables ( RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount); LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry; + 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 FreeLoader; + } + } + Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare); if (Tracker == NULL) { Status = EFI_OUT_OF_RESOURCES; - goto FreeLoader; + goto FreeS3Context; } // @@ -758,7 +803,7 @@ InstallQemuFwCfgTables ( case QemuLoaderCmdWritePointer: Status = ProcessCmdWritePointer (&LoaderEntry->Command.WritePointer, - Tracker); + Tracker, S3Context); if (!EFI_ERROR (Status)) { WritePointerSubsetEnd = LoaderEntry + 1; } @@ -790,11 +835,21 @@ InstallQemuFwCfgTables ( Status = Process2ndPassCmdAddPointer (&LoaderEntry->Command.AddPointer, Tracker, AcpiProtocol, InstalledKey, &Installed); if (EFI_ERROR (Status)) { - break; + 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); + } + +UninstallAcpiTables: if (EFI_ERROR (Status)) { // // roll back partial installation @@ -847,6 +902,11 @@ RollbackWritePointersAndFreeTracker: } OrderedCollectionUninit (Tracker); +FreeS3Context: + if (S3Context != NULL) { + ReleaseS3Context (S3Context); + } + FreeLoader: FreePool (LoaderStart); -- cgit v1.2.3