123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- /** @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, Red Hat, Inc.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Library/BaseLib.h> // CpuDeadLoop()
- #include <Library/DebugLib.h> // DEBUG()
- #include <Library/MemoryAllocationLib.h> // AllocatePool()
- #include <Library/QemuFwCfgS3Lib.h> // 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;
- }
|