blob: 31bafa91953fe3b42e39554ec2fce6ae8911e142 [file] [log] [blame]
/** @file
Stateless fw_cfg library implementation.
Clients must call QemuFwCfgIsAvailable() first.
Copyright (C) 2013, Red Hat, Inc.
Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/QemuFwCfgLib.h>
#include <PiPei.h>
#include <WorkArea.h>
#include "QemuFwCfgLibInternal.h"
/**
Returns a boolean indicating if the firmware configuration interface
is available or not.
This function may change fw_cfg state.
@retval TRUE The interface is available
@retval FALSE The interface is not available
**/
BOOLEAN
EFIAPI
QemuFwCfgIsAvailable (
VOID
)
{
UINT32 Signature;
UINT32 Revision;
QemuFwCfgSelectItem (QemuFwCfgItemSignature);
Signature = QemuFwCfgRead32 ();
DEBUG ((DEBUG_INFO, "FW CFG Signature: 0x%x\n", Signature));
QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
Revision = QemuFwCfgRead32 ();
DEBUG ((DEBUG_INFO, "FW CFG Revision: 0x%x\n", Revision));
if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
(Revision < 1)
)
{
DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));
return FALSE;
}
DEBUG ((DEBUG_INFO, "QemuFwCfg interface is supported.\n"));
return TRUE;
}
/**
Returns a boolean indicating if the firmware configuration interface is
available for library-internal purposes.
This function never changes fw_cfg state.
@retval TRUE The interface is available internally.
@retval FALSE The interface is not available internally.
**/
BOOLEAN
InternalQemuFwCfgIsAvailable (
VOID
)
{
//
// We always return TRUE, because the consumer of this library ought to have
// called QemuFwCfgIsAvailable before making other calls which would hit this
// path.
//
return TRUE;
}
/**
Returns a boolean indicating whether QEMU provides the DMA-like access method
for fw_cfg.
@retval TRUE The DMA-like access method is available.
@retval FALSE The DMA-like access method is unavailable.
**/
BOOLEAN
InternalQemuFwCfgDmaIsAvailable (
VOID
)
{
return FALSE;
}
/**
Transfer an array of bytes, or skip a number of bytes, using the DMA
interface.
@param[in] Size Size in bytes to transfer or skip.
@param[in,out] Buffer Buffer to read data into or write data from. Ignored,
and may be NULL, if Size is zero, or Control is
FW_CFG_DMA_CTL_SKIP.
@param[in] Control One of the following:
FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
**/
VOID
InternalQemuFwCfgDmaBytes (
IN UINT32 Size,
IN OUT VOID *Buffer OPTIONAL,
IN UINT32 Control
)
{
//
// We should never reach here
//
ASSERT (FALSE);
CpuDeadLoop ();
}
#ifdef TDX_PEI_LESS_BOOT
/**
Check if the Ovmf work area is built as HobList before invoking Hob services.
@retval TRUE Ovmf work area is not NULL and it is built as HobList.
@retval FALSE Ovmf work area is NULL or it is not built as HobList.
**/
BOOLEAN
InternalQemuFwCfgCheckOvmfWorkArea (
VOID
)
{
TDX_WORK_AREA *TdxWorkArea;
// QemuFwCfgLib might be called in a very early stage
// (at that moment HobList may not be set). So an additional check
// to the HobList is needed.
TdxWorkArea = (TDX_WORK_AREA *)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase);
if ((TdxWorkArea == NULL) || (TdxWorkArea->SecTdxWorkArea.HobList == 0)) {
return FALSE;
} else {
return TRUE;
}
}
/**
Get the pointer to the QEMU_FW_CFG_WORK_AREA. This data is used as the
workarea to record the ongoing fw_cfg item and offset.
@retval QEMU_FW_CFG_WORK_AREA Pointer to the QEMU_FW_CFG_WORK_AREA
@retval NULL QEMU_FW_CFG_WORK_AREA doesn't exist
**/
QEMU_FW_CFG_WORK_AREA *
InternalQemuFwCfgCacheGetWorkArea (
VOID
)
{
EFI_HOB_GUID_TYPE *GuidHob;
EFI_HOB_PLATFORM_INFO *PlatformHobinfo;
if (InternalQemuFwCfgCheckOvmfWorkArea () == FALSE) {
return NULL;
}
GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
if (GuidHob == NULL) {
return NULL;
}
PlatformHobinfo = (EFI_HOB_PLATFORM_INFO *)(VOID *)GET_GUID_HOB_DATA (GuidHob);
return &(PlatformHobinfo->QemuFwCfgWorkArea);
}
/**
OVMF reads configuration data from QEMU via fw_cfg.
For Td-Guest VMM is out of TCB and the configuration data is untrusted.
From the security perpective the configuration data shall be measured
before it is consumed.
This function reads the fw_cfg items and cached them. In the meanwhile these
fw_cfg items are measured as well. This is to avoid changing the order when
reading the fw_cfg process, which depends on multiple factors(depex, order in
the Firmware volume).
@retval RETURN_SUCCESS - Successfully cache with measurement
@retval Others - As the error code indicates
*/
RETURN_STATUS
EFIAPI
QemuFwCfgInitCache (
IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
)
{
if (!QemuFwCfgIsAvailable ()) {
DEBUG ((DEBUG_ERROR, "%a: Qemu Fw_Cfg is not Available! \n", __func__));
return RETURN_UNSUPPORTED;
}
if (InternalQemuFwCfgCheckOvmfWorkArea () == FALSE) {
return RETURN_ABORTED;
}
if (EFI_ERROR (InternalQemuFwCfgInitCache (PlatformInfoHob))) {
return RETURN_ABORTED;
}
DEBUG ((DEBUG_INFO, "QemuFwCfgInitCache Pass!!!\n"));
return RETURN_SUCCESS;
}
#endif