/** @file
  S3 support for QEMU fw_cfg

  This library class enables driver modules (a) to query whether S3 support was
  enabled on the QEMU command line, (b) to produce fw_cfg DMA operations that
  are to be replayed at S3 resume time.

  Copyright (C) 2017, Red Hat, Inc.

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef __FW_CFG_S3_LIB__
#define __FW_CFG_S3_LIB__

#include <Base.h>

/**
  Determine if S3 support is explicitly enabled.

  @retval  TRUE   If S3 support is explicitly enabled. Other functions in this
                  library may be called (subject to their individual
                  restrictions).

           FALSE  Otherwise. This includes unavailability of the firmware
                  configuration interface. No other function in this library
                  must be called.
**/
BOOLEAN
EFIAPI
QemuFwCfgS3Enabled (
  VOID
  );

/**
  Prototype for the callback function that the client module provides.

  In the callback function, the client module calls the
  QemuFwCfgS3ScriptWriteBytes(), QemuFwCfgS3ScriptReadBytes(),
  QemuFwCfgS3ScriptSkipBytes(), and QemuFwCfgS3ScriptCheckValue() functions.
  Those functions produce ACPI S3 Boot Script opcodes that will perform fw_cfg
  DMA operations, and will check any desired values that were read, during S3
  resume.

  The callback function is invoked when the production of ACPI S3 Boot Script
  opcodes becomes possible. This may occur directly on the call stack of
  QemuFwCfgS3CallWhenBootScriptReady() (see below), or after
  QemuFwCfgS3CallWhenBootScriptReady() has successfully returned.

  The callback function must not return if it fails -- in the general case,
  there is noone to propagate any errors to. Therefore, on error, an error
  message should be logged, and CpuDeadLoop() must be called.

  @param[in,out] Context        Carries information from the client module
                                itself (i.e., from the invocation of
                                QemuFwCfgS3CallWhenBootScriptReady()) to the
                                callback function.

                                If Context points to dynamically allocated
                                storage, then the callback function must
                                release it.

  @param[in,out] ScratchBuffer  Points to reserved memory, allocated by
                                QemuFwCfgS3CallWhenBootScriptReady()
                                internally.

                                ScratchBuffer is typed and sized by the client
                                module when it calls
                                QemuFwCfgS3CallWhenBootScriptReady(). The
                                client module defines a union type of
                                structures for ScratchBuffer such that the
                                union can hold client data for any desired
                                fw_cfg DMA read and write operations, and value
                                checking.

                                The callback function casts ScratchBuffer to
                                the union type described above. It passes union
                                member sizes as NumberOfBytes to
                                QemuFwCfgS3ScriptReadBytes() and
                                QemuFwCfgS3ScriptWriteBytes(). It passes field
                                addresses and sizes in structures in the union
                                as ScratchData and ValueSize to
                                QemuFwCfgS3ScriptCheckValue().

                                ScratchBuffer is aligned at 8 bytes.
**/
typedef
VOID(EFIAPI FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION)(
  IN OUT VOID *Context       OPTIONAL,
  IN OUT VOID *ScratchBuffer
  );

/**
  Install the client module's FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION callback for
  when the production of ACPI S3 Boot Script opcodes becomes possible.

  Take ownership of the client-provided Context, and pass it to the callback
  function, when the latter is invoked.

  Allocate scratch space for those ACPI S3 Boot Script opcodes to work upon
  that the client will produce in the callback function.

  @param[in] Callback           FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION to invoke
                                when the production of ACPI S3 Boot Script
                                opcodes becomes possible. Callback() may be
                                called immediately from
                                QemuFwCfgS3CallWhenBootScriptReady().

  @param[in,out] Context        Client-provided data structure for the
                                Callback() callback function to consume.

                                If Context points to dynamically allocated
                                memory, then Callback() must release it.

                                If Context points to dynamically allocated
                                memory, and
                                QemuFwCfgS3CallWhenBootScriptReady() returns
                                successfully, then the caller of
                                QemuFwCfgS3CallWhenBootScriptReady() must
                                neither dereference nor even evaluate Context
                                any longer, as ownership of the referenced area
                                has been transferred to Callback().

  @param[in] ScratchBufferSize  The size of the scratch buffer that will hold,
                                in reserved memory, all client data read,
                                written, and checked by the ACPI S3 Boot Script
                                opcodes produced by Callback().

  @retval RETURN_UNSUPPORTED       The library instance does not support this
                                   function.

  @retval RETURN_NOT_FOUND         The fw_cfg DMA interface to QEMU is
                                   unavailable.

  @retval RETURN_BAD_BUFFER_SIZE   ScratchBufferSize is too large.

  @retval RETURN_OUT_OF_RESOURCES  Memory allocation failed.

  @retval RETURN_SUCCESS           Callback() has been installed, and the
                                   ownership of Context has been transferred.
                                   Reserved memory has been allocated for the
                                   scratch buffer.

                                   A successful invocation of
                                   QemuFwCfgS3CallWhenBootScriptReady() cannot
                                   be rolled back.

  @return                          Error codes from underlying functions.
**/
RETURN_STATUS
EFIAPI
QemuFwCfgS3CallWhenBootScriptReady (
  IN     FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION  *Callback,
  IN OUT VOID                                  *Context           OPTIONAL,
  IN     UINTN                                 ScratchBufferSize
  );

/**
  Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
  and transfer data to it.

  The opcodes produced by QemuFwCfgS3ScriptWriteBytes() will first restore
  NumberOfBytes bytes in ScratchBuffer in-place, in reserved memory, then write
  them to fw_cfg using DMA.

  If the operation fails during S3 resume, the boot script will hang.

  This function may only be called from the client module's
  FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
  QemuFwCfgS3CallWhenBootScriptReady() as Callback.

  @param[in] FirmwareConfigItem  The UINT16 selector key of the firmware config
                                 item to write, expressed as INT32. If
                                 FirmwareConfigItem is -1, no selection is
                                 made, the write will occur to the currently
                                 selected item, at its currently selected
                                 offset. Otherwise, the specified item will be
                                 selected, and the write will occur at offset
                                 0.

  @param[in] NumberOfBytes       Size of the data to restore in ScratchBuffer,
                                 and to write from ScratchBuffer, during S3
                                 resume. NumberOfBytes must not exceed
                                 ScratchBufferSize, which was passed to
                                 QemuFwCfgS3CallWhenBootScriptReady().

  @retval RETURN_SUCCESS            The opcodes were appended to the ACPI S3
                                    Boot Script successfully. There is no way
                                    to undo this action.

  @retval RETURN_INVALID_PARAMETER  FirmwareConfigItem is invalid.

  @retval RETURN_BAD_BUFFER_SIZE    NumberOfBytes is larger than
                                    ScratchBufferSize.

  @return                           Error codes from underlying functions.
**/
RETURN_STATUS
EFIAPI
QemuFwCfgS3ScriptWriteBytes (
  IN INT32  FirmwareConfigItem,
  IN UINTN  NumberOfBytes
  );

/**
  Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
  and transfer data from it.

  The opcodes produced by QemuFwCfgS3ScriptReadBytes() will read NumberOfBytes
  bytes from fw_cfg using DMA, storing the result in ScratchBuffer, in reserved
  memory.

  If the operation fails during S3 resume, the boot script will hang.

  This function may only be called from the client module's
  FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
  QemuFwCfgS3CallWhenBootScriptReady() as Callback.

  @param[in] FirmwareConfigItem  The UINT16 selector key of the firmware config
                                 item to read, expressed as INT32. If
                                 FirmwareConfigItem is -1, no selection is
                                 made, the read will occur from the currently
                                 selected item, from its currently selected
                                 offset. Otherwise, the specified item will be
                                 selected, and the read will occur from offset
                                 0.

  @param[in] NumberOfBytes       Size of the data to read during S3 resume.
                                 NumberOfBytes must not exceed
                                 ScratchBufferSize, which was passed to
                                 QemuFwCfgS3CallWhenBootScriptReady().

  @retval RETURN_SUCCESS            The opcodes were appended to the ACPI S3
                                    Boot Script successfully. There is no way
                                    to undo this action.

  @retval RETURN_INVALID_PARAMETER  FirmwareConfigItem is invalid.

  @retval RETURN_BAD_BUFFER_SIZE    NumberOfBytes is larger than
                                    ScratchBufferSize.

  @return                           Error codes from underlying functions.
**/
RETURN_STATUS
EFIAPI
QemuFwCfgS3ScriptReadBytes (
  IN INT32  FirmwareConfigItem,
  IN UINTN  NumberOfBytes
  );

/**
  Produce ACPI S3 Boot Script opcodes that (optionally) select an fw_cfg item,
  and increase its offset.

  If the operation fails during S3 resume, the boot script will hang.

  This function may only be called from the client module's
  FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
  QemuFwCfgS3CallWhenBootScriptReady() as Callback.

  @param[in] FirmwareConfigItem  The UINT16 selector key of the firmware config
                                 item to advance the offset of, expressed as
                                 INT32. If FirmwareConfigItem is -1, no
                                 selection is made, and the offset for the
                                 currently selected item is increased.
                                 Otherwise, the specified item will be
                                 selected, and the offset increment will occur
                                 from offset 0.

  @param[in] NumberOfBytes       The number of bytes to skip in the subject
                                 fw_cfg item.

  @retval RETURN_SUCCESS            The opcodes were appended to the ACPI S3
                                    Boot Script successfully. There is no way
                                    to undo this action.

  @retval RETURN_INVALID_PARAMETER  FirmwareConfigItem is invalid.

  @retval RETURN_BAD_BUFFER_SIZE    NumberOfBytes is too large.

  @return                           Error codes from underlying functions.
**/
RETURN_STATUS
EFIAPI
QemuFwCfgS3ScriptSkipBytes (
  IN INT32  FirmwareConfigItem,
  IN UINTN  NumberOfBytes
  );

/**
  Produce ACPI S3 Boot Script opcodes that check a value in ScratchBuffer.

  If the check fails during S3 resume, the boot script will hang.

  This function may only be called from the client module's
  FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION, which was passed to
  QemuFwCfgS3CallWhenBootScriptReady() as Callback.

  @param[in] ScratchData  Pointer to the UINT8, UINT16, UINT32 or UINT64 field
                          in ScratchBuffer that should be checked. The caller
                          is responsible for populating the field during S3
                          resume, by calling QemuFwCfgS3ScriptReadBytes() ahead
                          of QemuFwCfgS3ScriptCheckValue().

                          ScratchData must point into ScratchBuffer, which was
                          allocated, and passed to Callback(), by
                          QemuFwCfgS3CallWhenBootScriptReady().

                          ScratchData must be aligned at ValueSize bytes.

  @param[in] ValueSize    One of 1, 2, 4 or 8, specifying the size of the field
                          to check.

  @param[in] ValueMask    The value read from ScratchData is binarily AND-ed
                          with ValueMask, and the result is compared against
                          Value. If the masked data equals Value, the check
                          passes, and the boot script can proceed. Otherwise,
                          the check fails, and the boot script hangs.

  @param[in] Value        Refer to ValueMask.

  @retval RETURN_SUCCESS            The opcodes were appended to the ACPI S3
                                    Boot Script successfully. There is no way
                                    to undo this action.

  @retval RETURN_INVALID_PARAMETER  ValueSize is invalid.

  @retval RETURN_INVALID_PARAMETER  ValueMask or Value cannot be represented in
                                    ValueSize bytes.

  @retval RETURN_INVALID_PARAMETER  ScratchData is not aligned at ValueSize
                                    bytes.

  @retval RETURN_BAD_BUFFER_SIZE    The ValueSize bytes at ScratchData aren't
                                    wholly contained in the ScratchBufferSize
                                    bytes at ScratchBuffer.

  @return                           Error codes from underlying functions.
**/
RETURN_STATUS
EFIAPI
QemuFwCfgS3ScriptCheckValue (
  IN VOID    *ScratchData,
  IN UINT8   ValueSize,
  IN UINT64  ValueMask,
  IN UINT64  Value
  );

#endif
