| /** @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; | |
| } |