--- /dev/null
+/** @file\r
+\r
+ Declarations of utility functions used by virtio device drivers.\r
+\r
+ Copyright (C) 2012, Red Hat, Inc.\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _VIRTIO_LIB_H_\r
+#define _VIRTIO_LIB_H_\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <IndustryStandard/Virtio.h>\r
+\r
+/**\r
+\r
+ Write a word into Region 0 of the device specified by PciIo.\r
+\r
+ Region 0 must be an iomem region. This is an internal function for the\r
+ driver-specific VIRTIO_CFG_WRITE() macros.\r
+\r
+ @param[in] PciIo Target PCI device.\r
+\r
+ @param[in] FieldOffset Destination offset.\r
+\r
+ @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.\r
+\r
+ @param[in] Value Little endian value to write, converted to UINT64.\r
+ The least significant FieldSize bytes will be used.\r
+\r
+\r
+ @return Status code returned by PciIo->Io.Write().\r
+\r
+**/\r
+EFIAPI\r
+EFI_STATUS\r
+VirtioWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINT64 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Read a word from Region 0 of the device specified by PciIo.\r
+\r
+ Region 0 must be an iomem region. This is an internal function for the\r
+ driver-specific VIRTIO_CFG_READ() macros.\r
+\r
+ @param[in] PciIo Source PCI device.\r
+\r
+ @param[in] FieldOffset Source offset.\r
+\r
+ @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.\r
+\r
+ @param[in] BufferSize Number of bytes available in the target buffer. Must\r
+ equal FieldSize.\r
+\r
+ @param[out] Buffer Target buffer.\r
+\r
+\r
+ @return Status code returned by PciIo->Io.Read().\r
+\r
+**/\r
+EFIAPI\r
+EFI_STATUS\r
+VirtioRead (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Configure a virtio ring.\r
+\r
+ This function sets up internal storage (the guest-host communication area)\r
+ and lays out several "navigation" (ie. no-ownership) pointers to parts of\r
+ that storage.\r
+\r
+ Relevant sections from the virtio-0.9.5 spec:\r
+ - 1.1 Virtqueues,\r
+ - 2.3 Virtqueue Configuration.\r
+\r
+ @param[in] The number of descriptors to allocate for the\r
+ virtio ring, as requested by the host.\r
+\r
+ @param[out] Ring The virtio ring to set up.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous\r
+ pages for the requested QueueSize. Fields of\r
+ Ring have indeterminate value.\r
+\r
+ @retval EFI_SUCCESS Allocation and setup successful. Ring->Base\r
+ (and nothing else) is responsible for\r
+ deallocation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioRingInit (\r
+ IN UINT16 QueueSize,\r
+ OUT VRING *Ring\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Tear down the internal resources of a configured virtio ring.\r
+\r
+ The caller is responsible to stop the host from using this ring before\r
+ invoking this function: the VSTAT_DRIVER_OK bit must be clear in\r
+ VhdrDeviceStatus.\r
+\r
+ @param[out] Ring The virtio ring to clean up.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VirtioRingUninit (\r
+ IN OUT VRING *Ring\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Append a contiguous buffer for transmission / reception via the virtio ring.\r
+\r
+ This function implements the following sections from virtio-0.9.5:\r
+ - 2.4.1.1 Placing Buffers into the Descriptor Table\r
+ - 2.4.1.2 Updating the Available Ring\r
+\r
+ Free space is taken as granted, since the individual drivers support only\r
+ synchronous requests and host side status is processed in lock-step with\r
+ request submission. It is the calling driver's responsibility to verify the\r
+ ring size in advance.\r
+\r
+ @param[in out] Ring The virtio ring to append the buffer to, as a\r
+ descriptor.\r
+\r
+ @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the\r
+ transmit / receive buffer.\r
+\r
+ @param [in] BufferSize Number of bytes to transmit or receive.\r
+\r
+ @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller\r
+ computes this mask dependent on further buffers\r
+ to append and transfer direction.\r
+ VRING_DESC_F_INDIRECT is unsupported. The\r
+ VRING_DESC.Next field is always set, but the\r
+ host only interprets it dependent on\r
+ VRING_DESC_F_NEXT.\r
+\r
+ @param [in] HeadIdx The index identifying the head buffer (first\r
+ buffer appended) belonging to this same\r
+ request.\r
+\r
+ @param [in out] NextAvailIdx On input, the index identifying the next\r
+ descriptor available to carry the buffer. On\r
+ output, incremented by one, modulo 2^16.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AppendDesc (\r
+ IN OUT VRING *Ring,\r
+ IN UINTN BufferPhysAddr,\r
+ IN UINT32 BufferSize,\r
+ IN UINT16 Flags,\r
+ IN UINT16 HeadIdx,\r
+ IN OUT UINT16 *NextAvailIdx\r
+ );\r
+\r
+#endif // _VIRTIO_LIB_H_\r
--- /dev/null
+/** @file\r
+\r
+ Utility functions used by virtio device drivers.\r
+\r
+ Copyright (C) 2012, Red Hat, Inc.\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Pci22.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <Library/VirtioLib.h>\r
+\r
+\r
+/**\r
+\r
+ Write a word into Region 0 of the device specified by PciIo.\r
+\r
+ Region 0 must be an iomem region. This is an internal function for the\r
+ driver-specific VIRTIO_CFG_WRITE() macros.\r
+\r
+ @param[in] PciIo Target PCI device.\r
+\r
+ @param[in] FieldOffset Destination offset.\r
+\r
+ @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.\r
+\r
+ @param[in] Value Little endian value to write, converted to UINT64.\r
+ The least significant FieldSize bytes will be used.\r
+\r
+\r
+ @return Status code returned by PciIo->Io.Write().\r
+\r
+**/\r
+EFIAPI\r
+EFI_STATUS\r
+VirtioWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ UINTN Count;\r
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+\r
+ Count = 1;\r
+ switch (FieldSize) {\r
+ case 1:\r
+ Width = EfiPciIoWidthUint8;\r
+ break;\r
+\r
+ case 2:\r
+ Width = EfiPciIoWidthUint16;\r
+ break;\r
+\r
+ case 8:\r
+ Count = 2;\r
+ // fall through\r
+\r
+ case 4:\r
+ Width = EfiPciIoWidthUint32;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return PciIo->Io.Write (\r
+ PciIo,\r
+ Width,\r
+ PCI_BAR_IDX0,\r
+ FieldOffset,\r
+ Count,\r
+ &Value\r
+ );\r
+}\r
+\r
+\r
+/**\r
+\r
+ Read a word from Region 0 of the device specified by PciIo.\r
+\r
+ Region 0 must be an iomem region. This is an internal function for the\r
+ driver-specific VIRTIO_CFG_READ() macros.\r
+\r
+ @param[in] PciIo Source PCI device.\r
+\r
+ @param[in] FieldOffset Source offset.\r
+\r
+ @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.\r
+\r
+ @param[in] BufferSize Number of bytes available in the target buffer. Must\r
+ equal FieldSize.\r
+\r
+ @param[out] Buffer Target buffer.\r
+\r
+\r
+ @return Status code returned by PciIo->Io.Read().\r
+\r
+**/\r
+EFIAPI\r
+EFI_STATUS\r
+VirtioRead (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINTN FieldOffset,\r
+ IN UINTN FieldSize,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ UINTN Count;\r
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+\r
+ ASSERT (FieldSize == BufferSize);\r
+\r
+ Count = 1;\r
+ switch (FieldSize) {\r
+ case 1:\r
+ Width = EfiPciIoWidthUint8;\r
+ break;\r
+\r
+ case 2:\r
+ Width = EfiPciIoWidthUint16;\r
+ break;\r
+\r
+ case 8:\r
+ Count = 2;\r
+ // fall through\r
+\r
+ case 4:\r
+ Width = EfiPciIoWidthUint32;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return PciIo->Io.Read (\r
+ PciIo,\r
+ Width,\r
+ PCI_BAR_IDX0,\r
+ FieldOffset,\r
+ Count,\r
+ Buffer\r
+ );\r
+}\r
+\r
+\r
+/**\r
+\r
+ Configure a virtio ring.\r
+\r
+ This function sets up internal storage (the guest-host communication area)\r
+ and lays out several "navigation" (ie. no-ownership) pointers to parts of\r
+ that storage.\r
+\r
+ Relevant sections from the virtio-0.9.5 spec:\r
+ - 1.1 Virtqueues,\r
+ - 2.3 Virtqueue Configuration.\r
+\r
+ @param[in] The number of descriptors to allocate for the\r
+ virtio ring, as requested by the host.\r
+\r
+ @param[out] Ring The virtio ring to set up.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous\r
+ pages for the requested QueueSize. Fields of\r
+ Ring have indeterminate value.\r
+\r
+ @retval EFI_SUCCESS Allocation and setup successful. Ring->Base\r
+ (and nothing else) is responsible for\r
+ deallocation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioRingInit (\r
+ IN UINT16 QueueSize,\r
+ OUT VRING *Ring\r
+ )\r
+{\r
+ UINTN RingSize;\r
+ volatile UINT8 *RingPagesPtr;\r
+\r
+ RingSize = ALIGN_VALUE (\r
+ sizeof *Ring->Desc * QueueSize +\r
+ sizeof *Ring->Avail.Flags +\r
+ sizeof *Ring->Avail.Idx +\r
+ sizeof *Ring->Avail.Ring * QueueSize +\r
+ sizeof *Ring->Avail.UsedEvent,\r
+ EFI_PAGE_SIZE);\r
+\r
+ RingSize += ALIGN_VALUE (\r
+ sizeof *Ring->Used.Flags +\r
+ sizeof *Ring->Used.Idx +\r
+ sizeof *Ring->Used.UsedElem * QueueSize +\r
+ sizeof *Ring->Used.AvailEvent,\r
+ EFI_PAGE_SIZE);\r
+\r
+ Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);\r
+ Ring->Base = AllocatePages (Ring->NumPages);\r
+ if (Ring->Base == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ SetMem (Ring->Base, RingSize, 0x00);\r
+ RingPagesPtr = Ring->Base;\r
+\r
+ Ring->Desc = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Desc * QueueSize;\r
+\r
+ Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Avail.Flags;\r
+\r
+ Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Avail.Idx;\r
+\r
+ Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;\r
+\r
+ Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Avail.UsedEvent;\r
+\r
+ RingPagesPtr = (volatile UINT8 *) Ring->Base +\r
+ ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,\r
+ EFI_PAGE_SIZE);\r
+\r
+ Ring->Used.Flags = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Used.Flags;\r
+\r
+ Ring->Used.Idx = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Used.Idx;\r
+\r
+ Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;\r
+\r
+ Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;\r
+ RingPagesPtr += sizeof *Ring->Used.AvailEvent;\r
+\r
+ Ring->QueueSize = QueueSize;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Tear down the internal resources of a configured virtio ring.\r
+\r
+ The caller is responsible to stop the host from using this ring before\r
+ invoking this function: the VSTAT_DRIVER_OK bit must be clear in\r
+ VhdrDeviceStatus.\r
+\r
+ @param[out] Ring The virtio ring to clean up.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VirtioRingUninit (\r
+ IN OUT VRING *Ring\r
+ )\r
+{\r
+ FreePages (Ring->Base, Ring->NumPages);\r
+ SetMem (Ring, sizeof *Ring, 0x00);\r
+}\r
+\r
+\r
+/**\r
+\r
+ Append a contiguous buffer for transmission / reception via the virtio ring.\r
+\r
+ This function implements the following sections from virtio-0.9.5:\r
+ - 2.4.1.1 Placing Buffers into the Descriptor Table\r
+ - 2.4.1.2 Updating the Available Ring\r
+\r
+ Free space is taken as granted, since the individual drivers support only\r
+ synchronous requests and host side status is processed in lock-step with\r
+ request submission. It is the calling driver's responsibility to verify the\r
+ ring size in advance.\r
+\r
+ @param[in out] Ring The virtio ring to append the buffer to, as a\r
+ descriptor.\r
+\r
+ @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the\r
+ transmit / receive buffer.\r
+\r
+ @param [in] BufferSize Number of bytes to transmit or receive.\r
+\r
+ @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller\r
+ computes this mask dependent on further buffers\r
+ to append and transfer direction.\r
+ VRING_DESC_F_INDIRECT is unsupported. The\r
+ VRING_DESC.Next field is always set, but the\r
+ host only interprets it dependent on\r
+ VRING_DESC_F_NEXT.\r
+\r
+ @param [in] HeadIdx The index identifying the head buffer (first\r
+ buffer appended) belonging to this same\r
+ request.\r
+\r
+ @param [in out] NextAvailIdx On input, the index identifying the next\r
+ descriptor available to carry the buffer. On\r
+ output, incremented by one, modulo 2^16.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AppendDesc (\r
+ IN OUT VRING *Ring,\r
+ IN UINTN BufferPhysAddr,\r
+ IN UINT32 BufferSize,\r
+ IN UINT16 Flags,\r
+ IN UINT16 HeadIdx,\r
+ IN OUT UINT16 *NextAvailIdx\r
+ )\r
+{\r
+ volatile VRING_DESC *Desc;\r
+\r
+ Desc = &Ring->Desc[*NextAvailIdx % Ring->QueueSize];\r
+ Desc->Addr = BufferPhysAddr;\r
+ Desc->Len = BufferSize;\r
+ Desc->Flags = Flags;\r
+ Ring->Avail.Ring[(*NextAvailIdx)++ % Ring->QueueSize] =\r
+ HeadIdx % Ring->QueueSize;\r
+ Desc->Next = *NextAvailIdx % Ring->QueueSize;\r
+}\r
--- /dev/null
+## @file\r
+# Library of virtio utility functions.\r
+#\r
+# Copyright (C) 2012, Red Hat, Inc.\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = VirtioLib\r
+ FILE_GUID = 90CED1D9-18F2-47CC-BF24-41EC29406637\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = VirtioLib\r
+\r
+[Sources]\r
+ VirtioLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ OvmfPkg/OvmfPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseMemoryLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf\r
SerializeVariablesLib|OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf\r
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf\r
+ VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf\r
LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf\r
\r
!ifdef $(SOURCE_DEBUG_ENABLE)\r
UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf\r
SerializeVariablesLib|OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf\r
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf\r
+ VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf\r
LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf\r
\r
!ifdef $(SOURCE_DEBUG_ENABLE)\r
UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf\r
SerializeVariablesLib|OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf\r
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf\r
+ VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf\r
LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf\r
\r
!ifdef $(SOURCE_DEBUG_ENABLE)\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/UefiLib.h>\r
+#include <Library/VirtioLib.h>\r
\r
#include "VirtioBlk.h"\r
\r
-/**\r
-\r
- Write a word into Region 0 of the device specified by PciIo.\r
-\r
- Region 0 must be an iomem region. This is an internal function for the\r
- VIRTIO_CFG_WRITE() macro below.\r
-\r
- @param[in] PciIo Target PCI device.\r
-\r
- @param[in] FieldOffset Destination offset.\r
-\r
- @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.\r
-\r
- @param[in] Value Little endian value to write, converted to UINT64.\r
- The least significant FieldSize bytes will be used.\r
-\r
-\r
- @return Status code returned by PciIo->Io.Write().\r
-\r
-**/\r
-STATIC\r
-EFIAPI\r
-EFI_STATUS\r
-VirtioWrite (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINTN FieldOffset,\r
- IN UINTN FieldSize,\r
- IN UINT64 Value\r
- )\r
-{\r
- UINTN Count;\r
- EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
-\r
- Count = 1;\r
- switch (FieldSize) {\r
- case 1:\r
- Width = EfiPciIoWidthUint8;\r
- break;\r
-\r
- case 2:\r
- Width = EfiPciIoWidthUint16;\r
- break;\r
-\r
- case 8:\r
- Count = 2;\r
- // fall through\r
-\r
- case 4:\r
- Width = EfiPciIoWidthUint32;\r
- break;\r
-\r
- default:\r
- ASSERT (FALSE);\r
- }\r
-\r
- return PciIo->Io.Write (\r
- PciIo,\r
- Width,\r
- PCI_BAR_IDX0,\r
- FieldOffset,\r
- Count,\r
- &Value\r
- );\r
-}\r
-\r
-\r
-/**\r
-\r
- Read a word from Region 0 of the device specified by PciIo.\r
-\r
- Region 0 must be an iomem region. This is an internal function for the\r
- VIRTIO_CFG_READ() macro below.\r
-\r
- @param[in] PciIo Source PCI device.\r
-\r
- @param[in] FieldOffset Source offset.\r
-\r
- @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.\r
-\r
- @param[in] BufferSize Number of bytes available in the target buffer. Must\r
- equal FieldSize.\r
-\r
- @param[out] Buffer Target buffer.\r
-\r
-\r
- @return Status code returned by PciIo->Io.Read().\r
-\r
-**/\r
-STATIC\r
-EFIAPI\r
-EFI_STATUS\r
-VirtioRead (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINTN FieldOffset,\r
- IN UINTN FieldSize,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
- )\r
-{\r
- UINTN Count;\r
- EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
-\r
- ASSERT (FieldSize == BufferSize);\r
-\r
- Count = 1;\r
- switch (FieldSize) {\r
- case 1:\r
- Width = EfiPciIoWidthUint8;\r
- break;\r
-\r
- case 2:\r
- Width = EfiPciIoWidthUint16;\r
- break;\r
-\r
- case 8:\r
- Count = 2;\r
- // fall through\r
-\r
- case 4:\r
- Width = EfiPciIoWidthUint32;\r
- break;\r
-\r
- default:\r
- ASSERT (FALSE);\r
- }\r
-\r
- return PciIo->Io.Read (\r
- PciIo,\r
- Width,\r
- PCI_BAR_IDX0,\r
- FieldOffset,\r
- Count,\r
- Buffer\r
- );\r
-}\r
-\r
-\r
/**\r
\r
Convenience macros to read and write region 0 IO space elements of the\r
}\r
\r
\r
-/**\r
-\r
- Append a contiguous buffer for transmission / reception via the virtio ring.\r
-\r
- This function implements the following sections from virtio-0.9.5:\r
- - 2.4.1.1 Placing Buffers into the Descriptor Table\r
- - 2.4.1.2 Updating the Available Ring\r
-\r
- Free space is taken as granted, since this driver supports only synchronous\r
- requests and host side status is processed in lock-step with request\r
- submission. VirtioBlkInit() verifies the ring size in advance.\r
-\r
- @param[in out] Ring The virtio ring to append the buffer to, as a\r
- descriptor.\r
-\r
- @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the\r
- transmit / receive buffer\r
-\r
- @param [in] BufferSize Number of bytes to transmit or receive.\r
-\r
- @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller\r
- computes this mask dependent on further buffers\r
- to append and transfer direction.\r
- VRING_DESC_F_INDIRECT is unsupported. The\r
- VRING_DESC.Next field is always set, but the\r
- host only interprets it dependent on\r
- VRING_DESC_F_NEXT.\r
-\r
- @param [in] HeadIdx The index identifying the head buffer (first\r
- buffer appended) belonging to this same\r
- request.\r
-\r
- @param [in out] NextAvailIdx On input, the index identifying the next\r
- descriptor available to carry the buffer. On\r
- output, incremented by one, modulo 2^16.\r
-\r
-**/\r
-\r
-STATIC\r
-VOID\r
-EFIAPI\r
-AppendDesc (\r
- IN OUT VRING *Ring,\r
- IN UINTN BufferPhysAddr,\r
- IN UINT32 BufferSize,\r
- IN UINT16 Flags,\r
- IN UINT16 HeadIdx,\r
- IN OUT UINT16 *NextAvailIdx\r
- )\r
-{\r
- volatile VRING_DESC *Desc;\r
-\r
- Desc = &Ring->Desc[*NextAvailIdx % Ring->QueueSize];\r
- Desc->Addr = BufferPhysAddr;\r
- Desc->Len = BufferSize;\r
- Desc->Flags = Flags;\r
- Ring->Avail.Ring[(*NextAvailIdx)++ % Ring->QueueSize] =\r
- HeadIdx % Ring->QueueSize;\r
- Desc->Next = *NextAvailIdx % Ring->QueueSize;\r
-}\r
\r
\r
/**\r
}\r
\r
\r
-/**\r
-\r
- Configure a virtio ring.\r
-\r
- This function sets up internal storage (the guest-host communication area)\r
- and lays out several "navigation" (ie. no-ownership) pointers to parts of\r
- that storage.\r
-\r
- Relevant sections from the virtio-0.9.5 spec:\r
- - 1.1 Virtqueues,\r
- - 2.3 Virtqueue Configuration.\r
-\r
- @param[in] The number of descriptors to allocate for the\r
- virtio ring, as requested by the host.\r
-\r
- @param[out] Ring The virtio ring to set up.\r
-\r
- @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous\r
- pages for the requested QueueSize. Fields of\r
- Ring have indeterminate value.\r
-\r
- @retval EFI_SUCCESS Allocation and setup successful. Ring->Base\r
- (and nothing else) is responsible for\r
- deallocation.\r
-\r
-**/\r
-\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-VirtioRingInit (\r
- IN UINT16 QueueSize,\r
- OUT VRING *Ring\r
- )\r
-{\r
- UINTN RingSize;\r
- volatile UINT8 *RingPagesPtr;\r
-\r
- RingSize = ALIGN_VALUE (\r
- sizeof *Ring->Desc * QueueSize +\r
- sizeof *Ring->Avail.Flags +\r
- sizeof *Ring->Avail.Idx +\r
- sizeof *Ring->Avail.Ring * QueueSize +\r
- sizeof *Ring->Avail.UsedEvent,\r
- EFI_PAGE_SIZE);\r
-\r
- RingSize += ALIGN_VALUE (\r
- sizeof *Ring->Used.Flags +\r
- sizeof *Ring->Used.Idx +\r
- sizeof *Ring->Used.UsedElem * QueueSize +\r
- sizeof *Ring->Used.AvailEvent,\r
- EFI_PAGE_SIZE);\r
-\r
- Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);\r
- Ring->Base = AllocatePages (Ring->NumPages);\r
- if (Ring->Base == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- SetMem (Ring->Base, RingSize, 0x00);\r
- RingPagesPtr = Ring->Base;\r
-\r
- Ring->Desc = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Desc * QueueSize;\r
-\r
- Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Avail.Flags;\r
-\r
- Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Avail.Idx;\r
-\r
- Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;\r
-\r
- Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Avail.UsedEvent;\r
-\r
- RingPagesPtr = (volatile UINT8 *) Ring->Base +\r
- ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,\r
- EFI_PAGE_SIZE);\r
-\r
- Ring->Used.Flags = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Used.Flags;\r
-\r
- Ring->Used.Idx = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Used.Idx;\r
-\r
- Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;\r
-\r
- Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;\r
- RingPagesPtr += sizeof *Ring->Used.AvailEvent;\r
-\r
- Ring->QueueSize = QueueSize;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-\r
- Tear down the internal resources of a configured virtio ring.\r
-\r
- The caller is responsible to stop the host from using this ring before\r
- invoking this function: the VSTAT_DRIVER_OK bit must be clear in\r
- VhdrDeviceStatus.\r
-\r
- @param[out] Ring The virtio ring to clean up.\r
-\r
-**/\r
-\r
-\r
-STATIC\r
-VOID\r
-EFIAPI\r
-VirtioRingUninit (\r
- IN OUT VRING *Ring\r
- )\r
-{\r
- FreePages (Ring->Base, Ring->NumPages);\r
- SetMem (Ring, sizeof *Ring, 0x00);\r
-}\r
-\r
-\r
/**\r
\r
Set up all BlockIo and virtio-blk aspects of this driver for the specified\r
UefiBootServicesTableLib\r
UefiDriverEntryPoint\r
UefiLib\r
+ VirtioLib\r
\r
[Protocols]\r
gEfiBlockIoProtocolGuid ## BY_START\r