summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/Library/VirtioLib
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2012-10-12 18:53:58 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2012-10-12 18:53:58 +0000
commit263559b87232826552c9e42c1652d9f9488c9870 (patch)
treef0d9f786a62b29531ba232de46abd9548c9a7075 /OvmfPkg/Library/VirtioLib
parent6b28fe9ee8957c98b4c70c83560734196f43f92f (diff)
downloadedk2-263559b87232826552c9e42c1652d9f9488c9870.tar.gz
edk2-263559b87232826552c9e42c1652d9f9488c9870.tar.bz2
edk2-263559b87232826552c9e42c1652d9f9488c9870.zip
OvmfPkg: extract VirtioLib from VirtioBlkDxe
Introduce a new library called VirtioLib, for now only collecting the following reusable functions with as little changes as possible: - VirtioWrite() - VirtioRead() - VirtioRingInit() - VirtioRingUninit() - AppendDesc() Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13842 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'OvmfPkg/Library/VirtioLib')
-rw-r--r--OvmfPkg/Library/VirtioLib/VirtioLib.c335
-rw-r--r--OvmfPkg/Library/VirtioLib/VirtioLib.inf34
2 files changed, 369 insertions, 0 deletions
diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.c b/OvmfPkg/Library/VirtioLib/VirtioLib.c
new file mode 100644
index 0000000000..580824261c
--- /dev/null
+++ b/OvmfPkg/Library/VirtioLib/VirtioLib.c
@@ -0,0 +1,335 @@
+/** @file
+
+ Utility functions used by virtio device drivers.
+
+ Copyright (C) 2012, Red Hat, Inc.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/Pci22.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Library/VirtioLib.h>
+
+
+/**
+
+ Write a word into Region 0 of the device specified by PciIo.
+
+ Region 0 must be an iomem region. This is an internal function for the
+ driver-specific VIRTIO_CFG_WRITE() macros.
+
+ @param[in] PciIo Target PCI device.
+
+ @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().
+
+**/
+EFIAPI
+EFI_STATUS
+VirtioWrite (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN FieldOffset,
+ IN UINTN FieldSize,
+ IN UINT64 Value
+ )
+{
+ UINTN Count;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ Count = 1;
+ switch (FieldSize) {
+ case 1:
+ Width = EfiPciIoWidthUint8;
+ break;
+
+ case 2:
+ Width = EfiPciIoWidthUint16;
+ break;
+
+ case 8:
+ Count = 2;
+ // fall through
+
+ case 4:
+ Width = EfiPciIoWidthUint32;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return PciIo->Io.Write (
+ PciIo,
+ Width,
+ PCI_BAR_IDX0,
+ FieldOffset,
+ Count,
+ &Value
+ );
+}
+
+
+/**
+
+ Read a word from Region 0 of the device specified by PciIo.
+
+ Region 0 must be an iomem region. This is an internal function for the
+ driver-specific VIRTIO_CFG_READ() macros.
+
+ @param[in] PciIo Source PCI device.
+
+ @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().
+
+**/
+EFIAPI
+EFI_STATUS
+VirtioRead (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN FieldOffset,
+ IN UINTN FieldSize,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN Count;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ ASSERT (FieldSize == BufferSize);
+
+ Count = 1;
+ switch (FieldSize) {
+ case 1:
+ Width = EfiPciIoWidthUint8;
+ break;
+
+ case 2:
+ Width = EfiPciIoWidthUint16;
+ break;
+
+ case 8:
+ Count = 2;
+ // fall through
+
+ case 4:
+ Width = EfiPciIoWidthUint32;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return PciIo->Io.Read (
+ PciIo,
+ Width,
+ PCI_BAR_IDX0,
+ FieldOffset,
+ Count,
+ Buffer
+ );
+}
+
+
+/**
+
+ Configure a virtio ring.
+
+ This function sets up internal storage (the guest-host communication area)
+ and lays out several "navigation" (ie. no-ownership) pointers to parts of
+ that storage.
+
+ Relevant sections from the virtio-0.9.5 spec:
+ - 1.1 Virtqueues,
+ - 2.3 Virtqueue Configuration.
+
+ @param[in] The number of descriptors to allocate for the
+ virtio ring, as requested by the host.
+
+ @param[out] Ring The virtio ring to set up.
+
+ @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous
+ pages for the requested QueueSize. Fields of
+ Ring have indeterminate value.
+
+ @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
+ (and nothing else) is responsible for
+ deallocation.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtioRingInit (
+ IN UINT16 QueueSize,
+ OUT VRING *Ring
+ )
+{
+ UINTN RingSize;
+ volatile UINT8 *RingPagesPtr;
+
+ RingSize = ALIGN_VALUE (
+ sizeof *Ring->Desc * QueueSize +
+ sizeof *Ring->Avail.Flags +
+ sizeof *Ring->Avail.Idx +
+ sizeof *Ring->Avail.Ring * QueueSize +
+ sizeof *Ring->Avail.UsedEvent,
+ EFI_PAGE_SIZE);
+
+ RingSize += ALIGN_VALUE (
+ sizeof *Ring->Used.Flags +
+ sizeof *Ring->Used.Idx +
+ sizeof *Ring->Used.UsedElem * QueueSize +
+ sizeof *Ring->Used.AvailEvent,
+ EFI_PAGE_SIZE);
+
+ Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);
+ Ring->Base = AllocatePages (Ring->NumPages);
+ if (Ring->Base == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SetMem (Ring->Base, RingSize, 0x00);
+ RingPagesPtr = Ring->Base;
+
+ Ring->Desc = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Desc * QueueSize;
+
+ Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Avail.Flags;
+
+ Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Avail.Idx;
+
+ Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;
+
+ Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Avail.UsedEvent;
+
+ RingPagesPtr = (volatile UINT8 *) Ring->Base +
+ ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,
+ EFI_PAGE_SIZE);
+
+ Ring->Used.Flags = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Used.Flags;
+
+ Ring->Used.Idx = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Used.Idx;
+
+ Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
+
+ Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
+ RingPagesPtr += sizeof *Ring->Used.AvailEvent;
+
+ Ring->QueueSize = QueueSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Tear down the internal resources of a configured virtio ring.
+
+ The caller is responsible to stop the host from using this ring before
+ invoking this function: the VSTAT_DRIVER_OK bit must be clear in
+ VhdrDeviceStatus.
+
+ @param[out] Ring The virtio ring to clean up.
+
+**/
+VOID
+EFIAPI
+VirtioRingUninit (
+ IN OUT VRING *Ring
+ )
+{
+ FreePages (Ring->Base, Ring->NumPages);
+ SetMem (Ring, sizeof *Ring, 0x00);
+}
+
+
+/**
+
+ Append a contiguous buffer for transmission / reception via the virtio ring.
+
+ This function implements the following sections from virtio-0.9.5:
+ - 2.4.1.1 Placing Buffers into the Descriptor Table
+ - 2.4.1.2 Updating the Available Ring
+
+ Free space is taken as granted, since the individual drivers support only
+ synchronous requests and host side status is processed in lock-step with
+ request submission. It is the calling driver's responsibility to verify the
+ ring size in advance.
+
+ @param[in out] Ring The virtio ring to append the buffer to, as a
+ descriptor.
+
+ @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the
+ transmit / receive buffer.
+
+ @param [in] BufferSize Number of bytes to transmit or receive.
+
+ @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller
+ computes this mask dependent on further buffers
+ to append and transfer direction.
+ VRING_DESC_F_INDIRECT is unsupported. The
+ VRING_DESC.Next field is always set, but the
+ host only interprets it dependent on
+ VRING_DESC_F_NEXT.
+
+ @param [in] HeadIdx The index identifying the head buffer (first
+ buffer appended) belonging to this same
+ request.
+
+ @param [in out] NextAvailIdx On input, the index identifying the next
+ descriptor available to carry the buffer. On
+ output, incremented by one, modulo 2^16.
+
+**/
+VOID
+EFIAPI
+AppendDesc (
+ IN OUT VRING *Ring,
+ IN UINTN BufferPhysAddr,
+ IN UINT32 BufferSize,
+ IN UINT16 Flags,
+ IN UINT16 HeadIdx,
+ IN OUT UINT16 *NextAvailIdx
+ )
+{
+ volatile VRING_DESC *Desc;
+
+ Desc = &Ring->Desc[*NextAvailIdx % Ring->QueueSize];
+ Desc->Addr = BufferPhysAddr;
+ Desc->Len = BufferSize;
+ Desc->Flags = Flags;
+ Ring->Avail.Ring[(*NextAvailIdx)++ % Ring->QueueSize] =
+ HeadIdx % Ring->QueueSize;
+ Desc->Next = *NextAvailIdx % Ring->QueueSize;
+}
diff --git a/OvmfPkg/Library/VirtioLib/VirtioLib.inf b/OvmfPkg/Library/VirtioLib/VirtioLib.inf
new file mode 100644
index 0000000000..cfd93a2c2c
--- /dev/null
+++ b/OvmfPkg/Library/VirtioLib/VirtioLib.inf
@@ -0,0 +1,34 @@
+## @file
+# Library of virtio utility functions.
+#
+# Copyright (C) 2012, Red Hat, Inc.
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VirtioLib
+ FILE_GUID = 90CED1D9-18F2-47CC-BF24-41EC29406637
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VirtioLib
+
+[Sources]
+ VirtioLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib