/** @file This driver produces Virtio Device Protocol instances for Virtio Mmio devices. Copyright (C) 2013, ARM Ltd. Copyright (C) 2017, AMD Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include "VirtioMmioDevice.h" STATIC CONST VIRTIO_DEVICE_PROTOCOL mMmioDeviceProtocolTemplate = { 0, // Revision 0, // SubSystemDeviceId VirtioMmioGetDeviceFeatures, // GetDeviceFeatures VirtioMmioSetGuestFeatures, // SetGuestFeatures VirtioMmioSetQueueAddress, // SetQueueAddress VirtioMmioSetQueueSel, // SetQueueSel VirtioMmioSetQueueNotify, // SetQueueNotify VirtioMmioSetQueueAlignment, // SetQueueAlign VirtioMmioSetPageSize, // SetPageSize VirtioMmioGetQueueSize, // GetQueueNumMax VirtioMmioSetQueueSize, // SetQueueNum VirtioMmioGetDeviceStatus, // GetDeviceStatus VirtioMmioSetDeviceStatus, // SetDeviceStatus VirtioMmioDeviceWrite, // WriteDevice VirtioMmioDeviceRead, // ReadDevice VirtioMmioAllocateSharedPages, // AllocateSharedPages VirtioMmioFreeSharedPages, // FreeSharedPages VirtioMmioMapSharedBuffer, // MapSharedBuffer VirtioMmioUnmapSharedBuffer // UnmapSharedBuffer }; /** 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; }