blob: 92165de226cf6dc8ac1d292f7459bc65d59fc587 [file] [log] [blame]
/** @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;
}