]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
Ovmfpkg/VirtioBlkDxe: map virtio-blk request and response buffers
[mirror_edk2.git] / OvmfPkg / VirtioBlkDxe / VirtioBlk.c
index 663ba281ab73c7983cac3523ca72925c39790eee..c9c42aa41243b234a66726f52391ab0993128e59 100644 (file)
@@ -232,7 +232,8 @@ VerifyReadWriteRequest (
 \r
   @retval EFI_DEVICE_ERROR     Failed to notify host side via VirtIo write, or\r
                                unable to parse host response, or host response\r
-                               is not VIRTIO_BLK_S_OK.\r
+                               is not VIRTIO_BLK_S_OK or failed to map Buffer\r
+                               for a bus master operation.\r
 \r
 **/\r
 \r
@@ -249,8 +250,16 @@ SynchronousRequest (
 {\r
   UINT32                  BlockSize;\r
   volatile VIRTIO_BLK_REQ Request;\r
-  volatile UINT8          HostStatus;\r
+  volatile UINT8          *HostStatus;\r
+  VOID                    *HostStatusBuffer;\r
   DESC_INDICES            Indices;\r
+  VOID                    *RequestMapping;\r
+  VOID                    *StatusMapping;\r
+  VOID                    *BufferMapping;\r
+  EFI_PHYSICAL_ADDRESS    BufferDeviceAddress;\r
+  EFI_PHYSICAL_ADDRESS    HostStatusDeviceAddress;\r
+  EFI_PHYSICAL_ADDRESS    RequestDeviceAddress;\r
+  EFI_STATUS              Status;\r
 \r
   BlockSize = Dev->BlockIoMedia.BlockSize;\r
 \r
@@ -275,12 +284,82 @@ SynchronousRequest (
   Request.IoPrio = 0;\r
   Request.Sector = MultU64x32(Lba, BlockSize / 512);\r
 \r
-  VirtioPrepare (&Dev->Ring, &Indices);\r
+  //\r
+  // Host status is bi-directional (we preset with a value and expect the\r
+  // device to update it). Allocate a host status buffer which can be mapped\r
+  // to access equally by both processor and the device.\r
+  //\r
+  Status = Dev->VirtIo->AllocateSharedPages (\r
+                          Dev->VirtIo,\r
+                          EFI_SIZE_TO_PAGES (sizeof *HostStatus),\r
+                          &HostStatusBuffer\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  HostStatus = HostStatusBuffer;\r
+\r
+  //\r
+  // Map virtio-blk request header (must be done after request header is\r
+  // populated)\r
+  //\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             Dev->VirtIo,\r
+             VirtioOperationBusMasterRead,\r
+             (VOID *) &Request,\r
+             sizeof Request,\r
+             &RequestDeviceAddress,\r
+             &RequestMapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto FreeHostStatusBuffer;\r
+  }\r
+\r
+  //\r
+  // Map data buffer\r
+  //\r
+  if (BufferSize > 0) {\r
+    Status = VirtioMapAllBytesInSharedBuffer (\r
+               Dev->VirtIo,\r
+               (RequestIsWrite ?\r
+                VirtioOperationBusMasterRead :\r
+                VirtioOperationBusMasterWrite),\r
+               (VOID *) Buffer,\r
+               BufferSize,\r
+               &BufferDeviceAddress,\r
+               &BufferMapping\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto UnmapRequestBuffer;\r
+    }\r
+  }\r
 \r
   //\r
   // preset a host status for ourselves that we do not accept as success\r
   //\r
-  HostStatus = VIRTIO_BLK_S_IOERR;\r
+  *HostStatus = VIRTIO_BLK_S_IOERR;\r
+\r
+  //\r
+  // Map the Status Buffer with VirtioOperationBusMasterCommonBuffer so that\r
+  // both processor and device can access it.\r
+  //\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             Dev->VirtIo,\r
+             VirtioOperationBusMasterCommonBuffer,\r
+             HostStatusBuffer,\r
+             sizeof *HostStatus,\r
+             &HostStatusDeviceAddress,\r
+             &StatusMapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto UnmapDataBuffer;\r
+  }\r
+\r
+  VirtioPrepare (&Dev->Ring, &Indices);\r
 \r
   //\r
   // ensured by VirtioBlkInit() -- this predicate, in combination with the\r
@@ -291,8 +370,13 @@ SynchronousRequest (
   //\r
   // virtio-blk header in first desc\r
   //\r
-  VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request,\r
-    VRING_DESC_F_NEXT, &Indices);\r
+  VirtioAppendDesc (\r
+    &Dev->Ring,\r
+    RequestDeviceAddress,\r
+    sizeof Request,\r
+    VRING_DESC_F_NEXT,\r
+    &Indices\r
+    );\r
 \r
   //\r
   // data buffer for read/write in second desc\r
@@ -311,27 +395,55 @@ SynchronousRequest (
     //\r
     // VRING_DESC_F_WRITE is interpreted from the host's point of view.\r
     //\r
-    VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize,\r
+    VirtioAppendDesc (\r
+      &Dev->Ring,\r
+      BufferDeviceAddress,\r
+      (UINT32) BufferSize,\r
       VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
-      &Indices);\r
+      &Indices\r
+      );\r
   }\r
 \r
   //\r
   // host status in last (second or third) desc\r
   //\r
-  VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus,\r
-    VRING_DESC_F_WRITE, &Indices);\r
+  VirtioAppendDesc (\r
+    &Dev->Ring,\r
+    HostStatusDeviceAddress,\r
+    sizeof *HostStatus,\r
+    VRING_DESC_F_WRITE,\r
+    &Indices\r
+    );\r
 \r
   //\r
   // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
   //\r
   if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices,\r
         NULL) == EFI_SUCCESS &&\r
-      HostStatus == VIRTIO_BLK_S_OK) {\r
-    return EFI_SUCCESS;\r
+      *HostStatus == VIRTIO_BLK_S_OK) {\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
-  return EFI_DEVICE_ERROR;\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);\r
+\r
+UnmapDataBuffer:\r
+  if (BufferSize > 0) {\r
+    Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);\r
+  }\r
+\r
+UnmapRequestBuffer:\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);\r
+\r
+FreeHostStatusBuffer:\r
+  Dev->VirtIo->FreeSharedPages (\r
+                 Dev->VirtIo,\r
+                 EFI_SIZE_TO_PAGES (sizeof *HostStatus),\r
+                 HostStatusBuffer\r
+                 );\r
+\r
+  return Status;\r
 }\r
 \r
 \r