diff options
Diffstat (limited to 'OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c')
-rw-r--r-- | OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c new file mode 100644 index 000000000..f763db5fb --- /dev/null +++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c @@ -0,0 +1,204 @@ +/** @file + + This driver produces Virtio Device Protocol instances for Virtio Mmio devices. + + Copyright (C) 2013, ARM Ltd. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include "VirtioMmioDevice.h" + +static VIRTIO_DEVICE_PROTOCOL mMmioDeviceProtocolTemplate = { + 0, // Revision + 0, // SubSystemDeviceId + VirtioMmioGetDeviceFeatures, // GetDeviceFeatures + VirtioMmioSetGuestFeatures, // SetGuestFeatures + VirtioMmioGetQueueAddress, // GetQueueAddress + VirtioMmioSetQueueAddress, // SetQueueAddress + VirtioMmioSetQueueSel, // SetQueueSel + VirtioMmioSetQueueNotify, // SetQueueNotify + VirtioMmioSetQueueAlignment, // SetQueueAlign + VirtioMmioSetPageSize, // SetPageSize + VirtioMmioGetQueueSize, // GetQueueNumMax + VirtioMmioSetQueueSize, // SetQueueNum + VirtioMmioGetDeviceStatus, // GetDeviceStatus + VirtioMmioSetDeviceStatus, // SetDeviceStatus + VirtioMmioDeviceWrite, // WriteDevice + VirtioMmioDeviceRead // ReadDevice +}; + +/** + + Initialize the VirtIo MMIO Device + + @param[in] BaseAddress Base Address of the VirtIo MMIO Device + + @param[in, out] Device The driver instance to configure. + + @retval EFI_SUCCESS Setup complete. + + @retval EFI_UNSUPPORTED The driver is not a VirtIo MMIO device. + +**/ +STATIC +EFI_STATUS +EFIAPI +VirtioMmioInit ( + IN PHYSICAL_ADDRESS BaseAddress, + IN OUT VIRTIO_MMIO_DEVICE *Device + ) +{ + UINT32 MagicValue; + UINT32 VendorId; + UINT32 Version; + + // Initialize VirtIo Mmio Device + CopyMem (&Device->VirtioDevice, &mMmioDeviceProtocolTemplate, + sizeof (VIRTIO_DEVICE_PROTOCOL)); + Device->BaseAddress = BaseAddress; + Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5); + Device->VirtioDevice.SubSystemDeviceId = + MmioRead32 (BaseAddress + VIRTIO_MMIO_OFFSET_DEVICE_ID); + + // Double-check MMIO-specific values + MagicValue = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_MAGIC); + if (MagicValue != VIRTIO_MMIO_MAGIC) { + return EFI_UNSUPPORTED; + } + + Version = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VERSION); + if (Version != 1) { + return EFI_UNSUPPORTED; + } + + // Double-check MMIO-specific values + VendorId = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_VENDOR_ID); + if (VendorId != VIRTIO_VENDOR_ID) { + // The ARM Base and Foundation Models do not report a valid VirtIo VendorId. + // They return a value of 0x0 for the VendorId. + DEBUG((EFI_D_WARN, "VirtioMmioInit: Warning: The VendorId (0x%X) does not " + "match the VirtIo VendorId (0x%X).\n", + VendorId, VIRTIO_VENDOR_ID)); + //return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + +/** + + Uninitialize the internals of a virtio-mmio device that has been successfully + set up with VirtioMmioInit(). + + @param[in, out] Device The device to clean up. + +**/ + +STATIC +VOID +EFIAPI +VirtioMmioUninit ( + IN VIRTIO_MMIO_DEVICE *Device + ) +{ + // Note: This function mirrors VirtioMmioInit() that does not allocate any + // resources - there's nothing to free here. +} + +EFI_STATUS +VirtioMmioInstallDevice ( + IN PHYSICAL_ADDRESS BaseAddress, + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + VIRTIO_MMIO_DEVICE *VirtIo; + + if (!BaseAddress) { + return EFI_INVALID_PARAMETER; + } + if (Handle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Allocate VIRTIO_MMIO_DEVICE + VirtIo = AllocateZeroPool (sizeof (VIRTIO_MMIO_DEVICE)); + if (VirtIo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VirtIo->Signature = VIRTIO_MMIO_DEVICE_SIGNATURE; + + Status = VirtioMmioInit (BaseAddress, VirtIo); + if (EFI_ERROR (Status)) { + goto FreeVirtioMem; + } + + // Install VIRTIO_DEVICE_PROTOCOL to Handle + Status = gBS->InstallProtocolInterface (&Handle, + &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE, + &VirtIo->VirtioDevice); + if (EFI_ERROR (Status)) { + goto UninitVirtio; + } + + return EFI_SUCCESS; + +UninitVirtio: + VirtioMmioUninit (VirtIo); + +FreeVirtioMem: + FreePool (VirtIo); + return Status; +} + +EFI_STATUS +VirtioMmioUninstallDevice ( + IN EFI_HANDLE DeviceHandle + ) +{ + VIRTIO_DEVICE_PROTOCOL *VirtioDevice; + VIRTIO_MMIO_DEVICE *MmioDevice; + EFI_STATUS Status; + + Status = gBS->OpenProtocol ( + DeviceHandle, // candidate device + &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface + (VOID **)&VirtioDevice, // target pointer + DeviceHandle, // requestor driver identity + DeviceHandle, // requesting lookup for dev. + EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the MMIO device from the VirtIo Device instance + MmioDevice = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice); + + // Uninstall the protocol interface + Status = gBS->UninstallProtocolInterface (DeviceHandle, + &gVirtioDeviceProtocolGuid, &MmioDevice->VirtioDevice + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Uninitialize the VirtIo Device + VirtioMmioUninit (MmioDevice); + + return EFI_SUCCESS; +} |