| /** @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; | |
| } |