/** @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_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); | |
FreePool (MmioDevice); | |
return EFI_SUCCESS; | |
} |