]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/VirtioLib/VirtioLib.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / VirtioLib / VirtioLib.c
index 54cf225c9885d666944f14718f67fa127e2927f4..28041dbec524f29cd4e59227414944387fe368e4 100644 (file)
@@ -2,28 +2,21 @@
 \r
   Utility functions used by virtio device drivers.\r
 \r
-  Copyright (C) 2012, Red Hat, Inc.\r
+  Copyright (C) 2012-2016, Red Hat, Inc.\r
   Portion of Copyright (C) 2013, ARM Ltd.\r
+  Copyright (C) 2017, AMD Inc, All rights reserved.<BR>\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
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 \r
 #include <Library/VirtioLib.h>\r
 \r
-\r
 /**\r
 \r
   Configure a virtio ring.\r
   - 1.1 Virtqueues,\r
   - 2.3 Virtqueue Configuration.\r
 \r
+  @param[in]  VirtIo            The virtio device which will use the ring.\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
+  @return                       Status codes propagated from\r
+                                VirtIo->AllocateSharedPages().\r
 \r
   @retval EFI_SUCCESS           Allocation and setup successful. Ring->Base\r
                                 (and nothing else) is responsible for\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioRingInit (\r
-  IN  UINT16 QueueSize,\r
-  OUT VRING  *Ring\r
+  IN  VIRTIO_DEVICE_PROTOCOL  *VirtIo,\r
+  IN  UINT16                  QueueSize,\r
+  OUT VRING                   *Ring\r
   )\r
 {\r
-  UINTN          RingSize;\r
-  volatile UINT8 *RingPagesPtr;\r
+  EFI_STATUS      Status;\r
+  UINTN           RingSize;\r
+  volatile UINT8  *RingPagesPtr;\r
 \r
   RingSize = ALIGN_VALUE (\r
                sizeof *Ring->Desc            * QueueSize +\r
@@ -66,59 +62,70 @@ VirtioRingInit (
                sizeof *Ring->Avail.Idx                   +\r
                sizeof *Ring->Avail.Ring      * QueueSize +\r
                sizeof *Ring->Avail.UsedEvent,\r
-               EFI_PAGE_SIZE);\r
+               EFI_PAGE_SIZE\r
+               );\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
+                EFI_PAGE_SIZE\r
+                );\r
 \r
+  //\r
+  // Allocate a shared ring buffer\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
+  Status         = VirtIo->AllocateSharedPages (\r
+                             VirtIo,\r
+                             Ring->NumPages,\r
+                             &Ring->Base\r
+                             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
+\r
   SetMem (Ring->Base, RingSize, 0x00);\r
   RingPagesPtr = Ring->Base;\r
 \r
-  Ring->Desc = (volatile VOID *) RingPagesPtr;\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
+  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
+  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
+  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
+  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
+  RingPagesPtr = (volatile UINT8 *)Ring->Base +\r
+                 ALIGN_VALUE (\r
+                   RingPagesPtr - (volatile UINT8 *)Ring->Base,\r
+                   EFI_PAGE_SIZE\r
+                   );\r
 \r
-  Ring->Used.Flags = (volatile VOID *) RingPagesPtr;\r
-  RingPagesPtr += sizeof *Ring->Used.Flags;\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
+  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
+  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
+  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
@@ -127,20 +134,22 @@ VirtioRingInit (
   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
+  @param[in]  VirtIo  The virtio device which was using the ring.\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
+  IN     VIRTIO_DEVICE_PROTOCOL  *VirtIo,\r
+  IN OUT VRING                   *Ring\r
   )\r
 {\r
-  FreePages (Ring->Base, Ring->NumPages);\r
+  VirtIo->FreeSharedPages (VirtIo, Ring->NumPages, Ring->Base);\r
   SetMem (Ring, sizeof *Ring, 0x00);\r
 }\r
 \r
-\r
 /**\r
 \r
   Turn off interrupt notifications from the host, and prepare for appending\r
@@ -156,15 +165,15 @@ VirtioRingUninit (
 VOID\r
 EFIAPI\r
 VirtioPrepare (\r
-  IN OUT VRING        *Ring,\r
-  OUT    DESC_INDICES *Indices\r
+  IN OUT VRING         *Ring,\r
+  OUT    DESC_INDICES  *Indices\r
   )\r
 {\r
   //\r
   // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.\r
   // We're going to poll the answer, the host should not send an interrupt.\r
   //\r
-  *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;\r
+  *Ring->Avail.Flags = (UINT16)VRING_AVAIL_F_NO_INTERRUPT;\r
 \r
   //\r
   // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.\r
@@ -176,7 +185,6 @@ VirtioPrepare (
   Indices->NextDescIdx = Indices->HeadDescIdx;\r
 }\r
 \r
-\r
 /**\r
 \r
   Append a contiguous buffer for transmission / reception via the virtio ring.\r
@@ -192,48 +200,48 @@ VirtioPrepare (
   The caller is responsible for initializing *Indices with VirtioPrepare()\r
   first.\r
 \r
-  @param[in,out] Ring        The virtio ring to append the buffer to, as a\r
-                             descriptor.\r
+  @param[in,out] Ring               The virtio ring to append the buffer to,\r
+                                    as a descriptor.\r
 \r
-  @param[in] BufferPhysAddr  (Guest pseudo-physical) start address of the\r
-                             transmit / receive buffer.\r
+  @param[in] BufferDeviceAddress    (Bus master device) start address of the\r
+                                    transmit / receive buffer.\r
 \r
-  @param[in] BufferSize      Number of bytes to transmit or receive.\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 to\r
-                             append and transfer direction.\r
-                             VRING_DESC_F_INDIRECT is unsupported. The\r
-                             VRING_DESC.Next field is always set, but the host\r
-                             only interprets it dependent on VRING_DESC_F_NEXT.\r
+  @param[in] Flags                  A bitmask of VRING_DESC_F_* flags. The\r
+                                    caller computes this mask dependent on\r
+                                    further buffers to append and transfer\r
+                                    direction. VRING_DESC_F_INDIRECT is\r
+                                    unsupported. The VRING_DESC.Next field is\r
+                                    always set, but the host only interprets\r
+                                    it dependent on VRING_DESC_F_NEXT.\r
 \r
-  @param[in,out] Indices     Indices->HeadDescIdx is not accessed.\r
-                             On input, Indices->NextDescIdx identifies the next\r
-                             descriptor to carry the buffer. On output,\r
-                             Indices->NextDescIdx is incremented by one, modulo\r
-                             2^16.\r
+  @param[in,out] Indices            Indices->HeadDescIdx is not accessed.\r
+                                    On input, Indices->NextDescIdx identifies\r
+                                    the next descriptor to carry the buffer.\r
+                                    On output, Indices->NextDescIdx is\r
+                                    incremented by one, modulo 2^16.\r
 \r
 **/\r
 VOID\r
 EFIAPI\r
 VirtioAppendDesc (\r
-  IN OUT VRING        *Ring,\r
-  IN     UINTN        BufferPhysAddr,\r
-  IN     UINT32       BufferSize,\r
-  IN     UINT16       Flags,\r
-  IN OUT DESC_INDICES *Indices\r
+  IN OUT VRING         *Ring,\r
+  IN     UINT64        BufferDeviceAddress,\r
+  IN     UINT32        BufferSize,\r
+  IN     UINT16        Flags,\r
+  IN OUT DESC_INDICES  *Indices\r
   )\r
 {\r
-  volatile VRING_DESC *Desc;\r
+  volatile VRING_DESC  *Desc;\r
 \r
   Desc        = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize];\r
-  Desc->Addr  = BufferPhysAddr;\r
+  Desc->Addr  = BufferDeviceAddress;\r
   Desc->Len   = BufferSize;\r
   Desc->Flags = Flags;\r
   Desc->Next  = Indices->NextDescIdx % Ring->QueueSize;\r
 }\r
 \r
-\r
 /**\r
 \r
   Notify the host about the descriptor chain just built, and wait until the\r
@@ -249,6 +257,12 @@ VirtioAppendDesc (
                           Indices->HeadDescIdx identifies the head descriptor\r
                           of the descriptor chain.\r
 \r
+  @param[out] UsedLen     On success, the total number of bytes, consecutively\r
+                          across the buffers linked by the descriptor chain,\r
+                          that the host wrote. May be NULL if the caller\r
+                          doesn't care, or can compute the same information\r
+                          from device-specific request structures linked by the\r
+                          descriptor chain.\r
 \r
   @return              Error code from VirtIo->SetQueueNotify() if it fails.\r
 \r
@@ -258,15 +272,17 @@ VirtioAppendDesc (
 EFI_STATUS\r
 EFIAPI\r
 VirtioFlush (\r
-  IN     VIRTIO_DEVICE_PROTOCOL *VirtIo,\r
-  IN     UINT16                 VirtQueueId,\r
-  IN OUT VRING                  *Ring,\r
-  IN     DESC_INDICES           *Indices\r
+  IN     VIRTIO_DEVICE_PROTOCOL  *VirtIo,\r
+  IN     UINT16                  VirtQueueId,\r
+  IN OUT VRING                   *Ring,\r
+  IN     DESC_INDICES            *Indices,\r
+  OUT    UINT32                  *UsedLen    OPTIONAL\r
   )\r
 {\r
-  UINT16     NextAvailIdx;\r
-  EFI_STATUS Status;\r
-  UINTN      PollPeriodUsecs;\r
+  UINT16      NextAvailIdx;\r
+  UINT16      LastUsedIdx;\r
+  EFI_STATUS  Status;\r
+  UINTN       PollPeriodUsecs;\r
 \r
   //\r
   // virtio-0.9.5, 2.4.1.2 Updating the Available Ring\r
@@ -276,20 +292,25 @@ VirtioFlush (
   // head descriptor of any given descriptor chain.\r
   //\r
   NextAvailIdx = *Ring->Avail.Idx;\r
+  //\r
+  // (Due to our lock-step progress, this is where the host will produce the\r
+  // used element with the head descriptor's index in it.)\r
+  //\r
+  LastUsedIdx                                        = NextAvailIdx;\r
   Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] =\r
     Indices->HeadDescIdx % Ring->QueueSize;\r
 \r
   //\r
   // virtio-0.9.5, 2.4.1.3 Updating the Index Field\r
   //\r
-  MemoryFence();\r
+  MemoryFence ();\r
   *Ring->Avail.Idx = NextAvailIdx;\r
 \r
   //\r
   // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are\r
   // OK.\r
   //\r
-  MemoryFence();\r
+  MemoryFence ();\r
   Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -304,16 +325,229 @@ VirtioFlush (
   // Keep slowing down until we reach a poll period of slightly above 1 ms.\r
   //\r
   PollPeriodUsecs = 1;\r
-  MemoryFence();\r
+  MemoryFence ();\r
   while (*Ring->Used.Idx != NextAvailIdx) {\r
     gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay\r
 \r
     if (PollPeriodUsecs < 1024) {\r
       PollPeriodUsecs *= 2;\r
     }\r
-    MemoryFence();\r
+\r
+    MemoryFence ();\r
+  }\r
+\r
+  MemoryFence ();\r
+\r
+  if (UsedLen != NULL) {\r
+    volatile CONST VRING_USED_ELEM  *UsedElem;\r
+\r
+    UsedElem = &Ring->Used.UsedElem[LastUsedIdx % Ring->QueueSize];\r
+    ASSERT (UsedElem->Id == Indices->HeadDescIdx);\r
+    *UsedLen = UsedElem->Len;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Report the feature bits to the VirtIo 1.0 device that the VirtIo 1.0 driver\r
+  understands.\r
+\r
+  In VirtIo 1.0, a device can reject a self-inconsistent feature bitmap through\r
+  the new VSTAT_FEATURES_OK status bit. (For example if the driver requests a\r
+  higher level feature but clears a prerequisite feature.) This function is a\r
+  small wrapper around VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures() that also\r
+  verifies if the VirtIo 1.0 device accepts the feature bitmap.\r
+\r
+  @param[in]     VirtIo        Report feature bits to this device.\r
+\r
+  @param[in]     Features      The set of feature bits that the driver wishes\r
+                               to report. The caller is responsible to perform\r
+                               any masking before calling this function; the\r
+                               value is directly written with\r
+                               VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures().\r
+\r
+  @param[in,out] DeviceStatus  On input, the status byte most recently written\r
+                               to the device's status register. On output (even\r
+                               on error), DeviceStatus will be updated so that\r
+                               it is suitable for further status bit\r
+                               manipulation and writing to the device's status\r
+                               register.\r
+\r
+  @retval  EFI_SUCCESS      The device accepted the configuration in Features.\r
+\r
+  @return  EFI_UNSUPPORTED  The device rejected the configuration in Features.\r
+\r
+  @retval  EFI_UNSUPPORTED  VirtIo->Revision is smaller than 1.0.0.\r
+\r
+  @return                   Error codes from the SetGuestFeatures(),\r
+                            SetDeviceStatus(), GetDeviceStatus() member\r
+                            functions.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Virtio10WriteFeatures (\r
+  IN     VIRTIO_DEVICE_PROTOCOL  *VirtIo,\r
+  IN     UINT64                  Features,\r
+  IN OUT UINT8                   *DeviceStatus\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = VirtIo->SetGuestFeatures (VirtIo, Features);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *DeviceStatus |= VSTAT_FEATURES_OK;\r
+  Status         = VirtIo->SetDeviceStatus (VirtIo, *DeviceStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = VirtIo->GetDeviceStatus (VirtIo, DeviceStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((*DeviceStatus & VSTAT_FEATURES_OK) == 0) {\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Provides the virtio device address required to access system memory from a\r
+  DMA bus master.\r
+\r
+  The interface follows the same usage pattern as defined in UEFI spec 2.6\r
+  (Section 13.2 PCI Root Bridge I/O Protocol)\r
+\r
+  The VirtioMapAllBytesInSharedBuffer() is similar to VIRTIO_MAP_SHARED\r
+  with exception that NumberOfBytes is IN-only parameter. The function\r
+  maps all the bytes specified in NumberOfBytes param in one consecutive\r
+  range.\r
+\r
+  @param[in]     VirtIo           The virtio device for which the mapping is\r
+                                  requested.\r
+\r
+  @param[in]     Operation        Indicates if the bus master is going to\r
+                                  read or write to system memory.\r
+\r
+  @param[in]     HostAddress      The system memory address to map to shared\r
+                                  buffer address.\r
+\r
+  @param[in]     NumberOfBytes    Number of bytes to map.\r
+\r
+  @param[out]    DeviceAddress    The resulting shared map address for the\r
+                                  bus master to access the hosts HostAddress.\r
+\r
+  @param[out]    Mapping          A resulting token to pass to\r
+                                  VIRTIO_UNMAP_SHARED.\r
+\r
+\r
+  @retval EFI_SUCCESS             The NumberOfBytes is successfully mapped.\r
+  @retval EFI_UNSUPPORTED         The HostAddress cannot be mapped as a\r
+                                  common buffer.\r
+  @retval EFI_INVALID_PARAMETER   One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to\r
+                                  a lack of resources. This includes the case\r
+                                  when NumberOfBytes bytes cannot be mapped\r
+                                  in one consecutive range.\r
+  @retval EFI_DEVICE_ERROR        The system hardware could not map the\r
+                                  requested address.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioMapAllBytesInSharedBuffer (\r
+  IN  VIRTIO_DEVICE_PROTOCOL  *VirtIo,\r
+  IN  VIRTIO_MAP_OPERATION    Operation,\r
+  IN  VOID                    *HostAddress,\r
+  IN  UINTN                   NumberOfBytes,\r
+  OUT EFI_PHYSICAL_ADDRESS    *DeviceAddress,\r
+  OUT VOID                    **Mapping\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  VOID                  *MapInfo;\r
+  UINTN                 Size;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;\r
+\r
+  Size   = NumberOfBytes;\r
+  Status = VirtIo->MapSharedBuffer (\r
+                     VirtIo,\r
+                     Operation,\r
+                     HostAddress,\r
+                     &Size,\r
+                     &PhysicalAddress,\r
+                     &MapInfo\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Size < NumberOfBytes) {\r
+    goto Failed;\r
+  }\r
+\r
+  *Mapping       = MapInfo;\r
+  *DeviceAddress = PhysicalAddress;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Failed:\r
+  VirtIo->UnmapSharedBuffer (VirtIo, MapInfo);\r
+  return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+/**\r
+\r
+  Map the ring buffer so that it can be accessed equally by both guest\r
+  and hypervisor.\r
+\r
+  @param[in]      VirtIo          The virtio device instance.\r
+\r
+  @param[in]      Ring            The virtio ring to map.\r
+\r
+  @param[out]     RingBaseShift   A resulting translation offset, to be\r
+                                  passed to VirtIo->SetQueueAddress().\r
+\r
+  @param[out]     Mapping         A resulting token to pass to\r
+                                  VirtIo->UnmapSharedBuffer().\r
+\r
+  @return         Status code from VirtIo->MapSharedBuffer()\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioRingMap (\r
+  IN  VIRTIO_DEVICE_PROTOCOL  *VirtIo,\r
+  IN  VRING                   *Ring,\r
+  OUT UINT64                  *RingBaseShift,\r
+  OUT VOID                    **Mapping\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;\r
+\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             VirtIo,\r
+             VirtioOperationBusMasterCommonBuffer,\r
+             Ring->Base,\r
+             EFI_PAGES_TO_SIZE (Ring->NumPages),\r
+             &DeviceAddress,\r
+             Mapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
-  MemoryFence();\r
+  *RingBaseShift = DeviceAddress - (UINT64)(UINTN)Ring->Base;\r
   return EFI_SUCCESS;\r
 }\r