/** @file | |
This driver produces Virtio Device Protocol instances for Virtio PCI devices. | |
Copyright (C) 2012, Red Hat, Inc. | |
Copyright (c) 2012, Intel Corporation. All rights reserved.<BR> | |
Copyright (C) 2013, ARM Ltd. | |
Copyright (C) 2017, AMD Inc, All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/UefiLib.h> | |
#include "VirtioPciDevice.h" | |
/** | |
Read a word from Region 0 of the device specified by VirtIo Device protocol. | |
The function implements the ReadDevice protocol member of | |
VIRTIO_DEVICE_PROTOCOL. | |
@param[in] This VirtIo Device protocol. | |
@param[in] FieldOffset Source offset. | |
@param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }. | |
@param[in] BufferSize Number of bytes available in the target buffer. Must | |
equal FieldSize. | |
@param[out] Buffer Target buffer. | |
@return Status code returned by PciIo->Io.Read(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VirtioPciDeviceRead ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINTN FieldOffset, | |
IN UINTN FieldSize, | |
IN UINTN BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoRead ( | |
Dev, | |
Dev->DeviceSpecificConfigurationOffset + FieldOffset, | |
FieldSize, | |
BufferSize, | |
Buffer | |
); | |
} | |
/** | |
Write a word into Region 0 of the device specified by VirtIo Device protocol. | |
@param[in] This VirtIo Device protocol. | |
@param[in] FieldOffset Destination offset. | |
@param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }. | |
@param[in] Value Little endian value to write, converted to UINT64. | |
The least significant FieldSize bytes will be used. | |
@return Status code returned by PciIo->Io.Write(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
VirtioPciDeviceWrite ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINTN FieldOffset, | |
IN UINTN FieldSize, | |
IN UINT64 Value | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoWrite ( | |
Dev, | |
Dev->DeviceSpecificConfigurationOffset + FieldOffset, | |
FieldSize, | |
Value | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciGetDeviceFeatures ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
OUT UINT64 *DeviceFeatures | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
EFI_STATUS Status; | |
UINT32 Features32; | |
if (DeviceFeatures == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
Status = VirtioPciIoRead ( | |
Dev, | |
VIRTIO_PCI_OFFSET_DEVICE_FEATURES, | |
sizeof (UINT32), | |
sizeof (UINT32), | |
&Features32 | |
); | |
if (!EFI_ERROR (Status)) { | |
*DeviceFeatures = Features32; | |
} | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciGetQueueSize ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
OUT UINT16 *QueueNumMax | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
if (QueueNumMax == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoRead ( | |
Dev, | |
VIRTIO_PCI_OFFSET_QUEUE_SIZE, | |
sizeof (UINT16), | |
sizeof (UINT16), | |
QueueNumMax | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciGetDeviceStatus ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
OUT UINT8 *DeviceStatus | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
if (DeviceStatus == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoRead ( | |
Dev, | |
VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS, | |
sizeof (UINT8), | |
sizeof (UINT8), | |
DeviceStatus | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetGuestFeatures ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT64 Features | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
if (Features > MAX_UINT32) { | |
return EFI_UNSUPPORTED; | |
} | |
return VirtioPciIoWrite ( | |
Dev, | |
VIRTIO_PCI_OFFSET_GUEST_FEATURES, | |
sizeof (UINT32), | |
Features | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetQueueAddress ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN VRING *Ring, | |
IN UINT64 RingBaseShift | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
ASSERT (RingBaseShift == 0); | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoWrite ( | |
Dev, | |
VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, | |
sizeof (UINT32), | |
(UINT32)((UINTN)Ring->Base >> EFI_PAGE_SHIFT) | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetQueueSel ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT16 Sel | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoWrite ( | |
Dev, | |
VIRTIO_PCI_OFFSET_QUEUE_SELECT, | |
sizeof (UINT16), | |
Sel | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetQueueAlignment ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT32 Alignment | |
) | |
{ | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetPageSize ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT32 PageSize | |
) | |
{ | |
return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED; | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetQueueNotify ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT16 Index | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoWrite ( | |
Dev, | |
VIRTIO_PCI_OFFSET_QUEUE_NOTIFY, | |
sizeof (UINT16), | |
Index | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetQueueSize ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT16 Size | |
) | |
{ | |
// | |
// This function is only applicable in Virtio-MMIO. | |
// (The QueueSize field is read-only in Virtio proper (PCI)) | |
// | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciSetDeviceStatus ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINT8 DeviceStatus | |
) | |
{ | |
VIRTIO_PCI_DEVICE *Dev; | |
Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This); | |
return VirtioPciIoWrite ( | |
Dev, | |
VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS, | |
sizeof (UINT8), | |
DeviceStatus | |
); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciAllocateSharedPages ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINTN NumPages, | |
OUT VOID **HostAddress | |
) | |
{ | |
VOID *Buffer; | |
Buffer = AllocatePages (NumPages); | |
if (Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
*HostAddress = Buffer; | |
return EFI_SUCCESS; | |
} | |
VOID | |
EFIAPI | |
VirtioPciFreeSharedPages ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN UINTN NumPages, | |
IN VOID *HostAddress | |
) | |
{ | |
FreePages (HostAddress, NumPages); | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciMapSharedBuffer ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN VIRTIO_MAP_OPERATION Operation, | |
IN VOID *HostAddress, | |
IN OUT UINTN *NumberOfBytes, | |
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
OUT VOID **Mapping | |
) | |
{ | |
*DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; | |
*Mapping = NULL; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioPciUnmapSharedBuffer ( | |
IN VIRTIO_DEVICE_PROTOCOL *This, | |
IN VOID *Mapping | |
) | |
{ | |
return EFI_SUCCESS; | |
} |