blob: 4aa81192ab1060610c551c603a71085bb5a9257b [file] [log] [blame]
/** @file
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <IndustryStandard/QemuUefiVars.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/IoLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include "VirtMmCommunication.h"
UINT64 mUefiVarsAddr;
STATIC
EFI_STATUS
VirtMmHwMemAttr (
)
{
EFI_STATUS Status;
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeMemoryMappedIo,
mUefiVarsAddr,
EFI_PAGE_SIZE,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: AddMemorySpace failed: %r\n", __func__, Status));
return RETURN_UNSUPPORTED;
}
Status = gDS->SetMemorySpaceAttributes (
mUefiVarsAddr,
EFI_PAGE_SIZE,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: SetMemorySpaceAttributes failed: %r\n", __func__, Status));
return RETURN_UNSUPPORTED;
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
EFIAPI
VirtMmHwCommand (
UINT32 Cmd
)
{
UINT32 Count;
UINT32 Sts;
MmioWrite16 (mUefiVarsAddr + UEFI_VARS_REG_CMD_STS, Cmd);
for (Count = 0; Count < 100; Count++) {
Sts = MmioRead16 (mUefiVarsAddr + UEFI_VARS_REG_CMD_STS);
DEBUG ((DEBUG_VERBOSE, "%a: Sts: 0x%x\n", __func__, Sts));
switch (Sts) {
case UEFI_VARS_STS_SUCCESS:
return RETURN_SUCCESS;
case UEFI_VARS_STS_BUSY:
CpuPause ();
break;
case UEFI_VARS_STS_ERR_NOT_SUPPORTED:
return RETURN_UNSUPPORTED;
case UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE:
return RETURN_BAD_BUFFER_SIZE;
default:
return RETURN_DEVICE_ERROR;
}
}
return RETURN_TIMEOUT;
}
EFI_STATUS
EFIAPI
VirtMmHwInit (
VOID
)
{
UINT32 Magic, AddrLo, AddrHi, Flags;
EFI_STATUS Status;
Status = VirtMmHwFind ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: VirtMmHwFind() failed: %d\n", __func__, Status));
return Status;
}
VirtMmHwMemAttr ();
Magic = MmioRead16 (mUefiVarsAddr + UEFI_VARS_REG_MAGIC);
if (Magic != UEFI_VARS_MAGIC_VALUE) {
DEBUG ((
DEBUG_ERROR,
"%a: Magic value mismatch (0x%x != 0x%x)\n",
__func__,
Magic,
UEFI_VARS_MAGIC_VALUE
));
return RETURN_DEVICE_ERROR;
}
DEBUG ((DEBUG_INFO, "%a: Magic 0x%x, good\n", __func__, Magic));
Status = VirtMmHwCommand (UEFI_VARS_CMD_RESET);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Reset failed: %d\n", __func__, Status));
return Status;
}
MmioWrite32 (mUefiVarsAddr + UEFI_VARS_REG_BUFFER_SIZE, MAX_BUFFER_SIZE);
Flags = MmioRead32 (mUefiVarsAddr + UEFI_VARS_REG_FLAGS);
if (Flags & UEFI_VARS_FLAG_USE_PIO) {
mUsePioTransfer = TRUE;
DEBUG ((DEBUG_INFO, "%a: using pio transfer mode\n", __func__));
} else {
AddrLo = (UINT32)mCommunicateBufferPhys;
AddrHi = (UINT32)RShiftU64 (mCommunicateBufferPhys, 32);
MmioWrite32 (mUefiVarsAddr + UEFI_VARS_REG_DMA_BUFFER_ADDR_LO, AddrLo);
MmioWrite32 (mUefiVarsAddr + UEFI_VARS_REG_DMA_BUFFER_ADDR_HI, AddrHi);
DEBUG ((DEBUG_INFO, "%a: using dma transfer mode\n", __func__));
}
return RETURN_SUCCESS;
}
EFI_STATUS
EFIAPI
VirtMmHwPioTransfer (
VOID *Buffer,
UINT32 BufferSize,
BOOLEAN ToDevice
)
{
UINT32 *Ptr = Buffer;
UINT32 Bytes = 0;
UINT32 Crc1;
UINT32 Crc2;
EFI_STATUS Status;
Status = VirtMmHwCommand (UEFI_VARS_CMD_PIO_ZERO_OFFSET);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: zero offset failed: %d\n", __func__, Status));
return Status;
}
while (Bytes < BufferSize) {
if (ToDevice) {
MmioWrite32 (mUefiVarsAddr + UEFI_VARS_REG_PIO_BUFFER_TRANSFER, *Ptr);
} else {
*Ptr = MmioRead32 (mUefiVarsAddr + UEFI_VARS_REG_PIO_BUFFER_TRANSFER);
}
Bytes += sizeof (*Ptr);
Ptr++;
}
Crc1 = CalculateCrc32c (Buffer, Bytes, 0);
Crc2 = MmioRead32 (mUefiVarsAddr + UEFI_VARS_REG_PIO_BUFFER_CRC32C);
if (Crc1 != Crc2) {
DEBUG ((DEBUG_ERROR, "%a: crc32c mismatch (0x%08x,0x%08x)\n", __func__, Crc1, Crc2));
return RETURN_DEVICE_ERROR;
}
return RETURN_SUCCESS;
}
EFI_STATUS
EFIAPI
VirtMmHwVirtMap (
VOID
)
{
EFI_STATUS Status;
DEBUG ((DEBUG_VERBOSE, "%a: << %lx\n", __func__, mUefiVarsAddr));
Status = gRT->ConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mUefiVarsAddr);
DEBUG ((DEBUG_VERBOSE, "%a: >> %lx\n", __func__, mUefiVarsAddr));
return Status;
}
EFI_STATUS
EFIAPI
VirtMmHwComm (
VOID
)
{
EFI_STATUS Status;
UINT32 Cmd;
Cmd = mUsePioTransfer ? UEFI_VARS_CMD_PIO_MM : UEFI_VARS_CMD_DMA_MM;
Status = VirtMmHwCommand (Cmd);
DEBUG ((DEBUG_VERBOSE, "%a: Status: %r\n", __func__, Status));
return Status;
}