summaryrefslogtreecommitdiff
path: root/OvmfPkg/VirtMmCommunicationDxe/QemuMmio.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/VirtMmCommunicationDxe/QemuMmio.c')
-rw-r--r--OvmfPkg/VirtMmCommunicationDxe/QemuMmio.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/OvmfPkg/VirtMmCommunicationDxe/QemuMmio.c b/OvmfPkg/VirtMmCommunicationDxe/QemuMmio.c
new file mode 100644
index 0000000..4aa8119
--- /dev/null
+++ b/OvmfPkg/VirtMmCommunicationDxe/QemuMmio.c
@@ -0,0 +1,207 @@
+/** @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;
+}