]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / VirtioBlkDxe / VirtioBlk.c
index 17b9f71d63beadcb434ea4bda2a0bf632a5e729f..cc094cc4ddb8bf5774aea0d017a6c696e3807018 100644 (file)
     synchronous requests and EFI_BLOCK_IO_PROTOCOL for now.\r
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
-  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\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 <IndustryStandard/Pci.h>\r
 #include <IndustryStandard/VirtioBlk.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 /**\r
 \r
   Convenience macros to read and write region 0 IO space elements of the\r
-  virtio-blk PCI device, for configuration purposes.\r
+  virtio-blk device, for configuration purposes.\r
 \r
   The following macros make it possible to specify only the "core parameters"\r
   for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()\r
   returns, the transaction will have been completed.\r
 \r
-  @param[in] Dev       Pointer to the VBLK_DEV structure whose PCI IO space\r
-                       we're accessing. Dev->PciIo must be valid.\r
+  @param[in] Dev       Pointer to the VBLK_DEV structure whose VirtIo space\r
+                       we're accessing. Dev->VirtIo must be valid.\r
 \r
   @param[in] Field     A field name from VBLK_HDR, identifying the virtio-blk\r
                        configuration item to access.\r
                        one of UINT8, UINT16, UINT32, UINT64.\r
 \r
 \r
-  @return  Status code returned by VirtioWrite() / VirtioRead().\r
+  @return  Status code returned by Virtio->WriteDevice() /\r
+           Virtio->ReadDevice().\r
 \r
 **/\r
 \r
-#define VIRTIO_CFG_WRITE(Dev, Field, Value)  (VirtioWrite (             \\r
-                                                (Dev)->PciIo,           \\r
-                                                OFFSET_OF_VBLK (Field), \\r
-                                                SIZE_OF_VBLK (Field),   \\r
-                                                (Value)                 \\r
+#define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice ( \\r
+                                                (Dev)->VirtIo,             \\r
+                                                OFFSET_OF_VBLK (Field),    \\r
+                                                SIZE_OF_VBLK (Field),      \\r
+                                                (Value)                    \\r
                                                 ))\r
 \r
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead (              \\r
-                                                (Dev)->PciIo,           \\r
-                                                OFFSET_OF_VBLK (Field), \\r
-                                                SIZE_OF_VBLK (Field),   \\r
-                                                sizeof *(Pointer),      \\r
-                                                (Pointer)               \\r
+#define VIRTIO_CFG_READ(Dev, Field, Pointer)  ((Dev)->VirtIo->ReadDevice ( \\r
+                                                (Dev)->VirtIo,             \\r
+                                                OFFSET_OF_VBLK (Field),    \\r
+                                                SIZE_OF_VBLK (Field),      \\r
+                                                sizeof *(Pointer),         \\r
+                                                (Pointer)                  \\r
                                                 ))\r
 \r
-\r
 //\r
 // UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol\r
 // Driver Writer's Guide for UEFI 2.3.1 v1.01,\r
@@ -85,8 +79,8 @@
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkReset (\r
-  IN EFI_BLOCK_IO_PROTOCOL *This,\r
-  IN BOOLEAN               ExtendedVerification\r
+  IN EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN BOOLEAN                ExtendedVerification\r
   )\r
 {\r
   //\r
@@ -148,26 +142,28 @@ STATIC
 EFI_STATUS\r
 EFIAPI\r
 VerifyReadWriteRequest (\r
-  IN  EFI_BLOCK_IO_MEDIA *Media,\r
-  IN  EFI_LBA            Lba,\r
-  IN  UINTN              PositiveBufferSize,\r
-  IN  BOOLEAN            RequestIsWrite\r
+  IN  EFI_BLOCK_IO_MEDIA  *Media,\r
+  IN  EFI_LBA             Lba,\r
+  IN  UINTN               PositiveBufferSize,\r
+  IN  BOOLEAN             RequestIsWrite\r
   )\r
 {\r
-  UINTN BlockCount;\r
+  UINTN  BlockCount;\r
 \r
   ASSERT (PositiveBufferSize > 0);\r
 \r
-  if (PositiveBufferSize > SIZE_1GB ||\r
-      PositiveBufferSize % Media->BlockSize > 0) {\r
+  if ((PositiveBufferSize > SIZE_1GB) ||\r
+      (PositiveBufferSize % Media->BlockSize > 0))\r
+  {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
+\r
   BlockCount = PositiveBufferSize / Media->BlockSize;\r
 \r
   //\r
   // Avoid unsigned wraparound on either side in the second comparison.\r
   //\r
-  if (Lba > Media->LastBlock || BlockCount - 1 > Media->LastBlock - Lba) {\r
+  if ((Lba > Media->LastBlock) || (BlockCount - 1 > Media->LastBlock - Lba)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -178,9 +174,6 @@ VerifyReadWriteRequest (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
-\r
-\r
 /**\r
 \r
   Format a read / write / flush request as three consecutive virtio\r
@@ -229,30 +222,46 @@ VerifyReadWriteRequest (
 \r
   @retval EFI_SUCCESS          Transfer complete.\r
 \r
-  @retval EFI_DEVICE_ERROR     Failed to notify host side via PCI write, or\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
 STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 SynchronousRequest (\r
-  IN              VBLK_DEV *Dev,\r
-  IN              EFI_LBA  Lba,\r
-  IN              UINTN    BufferSize,\r
-  IN OUT volatile VOID     *Buffer,\r
-  IN              BOOLEAN  RequestIsWrite\r
+  IN              VBLK_DEV  *Dev,\r
+  IN              EFI_LBA   Lba,\r
+  IN              UINTN     BufferSize,\r
+  IN OUT volatile VOID      *Buffer,\r
+  IN              BOOLEAN   RequestIsWrite\r
   )\r
 {\r
-  UINT32                  BlockSize;\r
-  volatile VIRTIO_BLK_REQ Request;\r
-  volatile UINT8          HostStatus;\r
-  DESC_INDICES            Indices;\r
+  UINT32                   BlockSize;\r
+  volatile VIRTIO_BLK_REQ  Request;\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
+  EFI_STATUS               UnmapStatus;\r
 \r
   BlockSize = Dev->BlockIoMedia.BlockSize;\r
 \r
+  //\r
+  // Set BufferMapping and BufferDeviceAddress to suppress incorrect\r
+  // compiler/analyzer warnings.\r
+  //\r
+  BufferMapping       = NULL;\r
+  BufferDeviceAddress = 0;\r
+\r
   //\r
   // ensured by VirtioBlkInit()\r
   //\r
@@ -268,18 +277,88 @@ SynchronousRequest (
   // Prepare virtio-blk request header, setting zero size for flush.\r
   // IO Priority is homogeneously 0.\r
   //\r
-  Request.Type   = RequestIsWrite ?\r
-                   (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :\r
-                   VIRTIO_BLK_T_IN;\r
+  Request.Type = RequestIsWrite ?\r
+                 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :\r
+                 VIRTIO_BLK_T_IN;\r
   Request.IoPrio = 0;\r
-  Request.Sector = MultU64x32(Lba, BlockSize / 512);\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
@@ -290,8 +369,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
@@ -310,28 +394,68 @@ 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->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&\r
-      HostStatus == VIRTIO_BLK_S_OK) {\r
-    return EFI_SUCCESS;\r
+  if ((VirtioFlush (\r
+         Dev->VirtIo,\r
+         0,\r
+         &Dev->Ring,\r
+         &Indices,\r
+         NULL\r
+         ) == EFI_SUCCESS) &&\r
+      (*HostStatus == VIRTIO_BLK_S_OK))\r
+  {\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
-  return EFI_DEVICE_ERROR;\r
-}\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);\r
 \r
+UnmapDataBuffer:\r
+  if (BufferSize > 0) {\r
+    UnmapStatus = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);\r
+    if (EFI_ERROR (UnmapStatus) && !RequestIsWrite && !EFI_ERROR (Status)) {\r
+      //\r
+      // Data from the bus master may not reach the caller; fail the request.\r
+      //\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\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
 \r
@@ -350,25 +474,24 @@ SynchronousRequest (
   successfully.\r
 \r
 **/\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkReadBlocks (\r
-  IN  EFI_BLOCK_IO_PROTOCOL *This,\r
-  IN  UINT32                MediaId,\r
-  IN  EFI_LBA               Lba,\r
-  IN  UINTN                 BufferSize,\r
-  OUT VOID                  *Buffer\r
+  IN  EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN  UINT32                 MediaId,\r
+  IN  EFI_LBA                Lba,\r
+  IN  UINTN                  BufferSize,\r
+  OUT VOID                   *Buffer\r
   )\r
 {\r
-  VBLK_DEV   *Dev;\r
-  EFI_STATUS Status;\r
+  VBLK_DEV    *Dev;\r
+  EFI_STATUS  Status;\r
 \r
   if (BufferSize == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
+  Dev    = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
   Status = VerifyReadWriteRequest (\r
              &Dev->BlockIoMedia,\r
              Lba,\r
@@ -405,25 +528,24 @@ VirtioBlkReadBlocks (
   successfully.\r
 \r
 **/\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkWriteBlocks (\r
-  IN EFI_BLOCK_IO_PROTOCOL *This,\r
-  IN UINT32                MediaId,\r
-  IN EFI_LBA               Lba,\r
-  IN UINTN                 BufferSize,\r
-  IN VOID                  *Buffer\r
+  IN EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN UINT32                 MediaId,\r
+  IN EFI_LBA                Lba,\r
+  IN UINTN                  BufferSize,\r
+  IN VOID                   *Buffer\r
   )\r
 {\r
-  VBLK_DEV   *Dev;\r
-  EFI_STATUS Status;\r
+  VBLK_DEV    *Dev;\r
+  EFI_STATUS  Status;\r
 \r
   if (BufferSize == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
+  Dev    = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
   Status = VerifyReadWriteRequest (\r
              &Dev->BlockIoMedia,\r
              Lba,\r
@@ -443,7 +565,6 @@ VirtioBlkWriteBlocks (
            );\r
 }\r
 \r
-\r
 /**\r
 \r
   FlushBlocks() operation for virtio-blk.\r
@@ -460,28 +581,26 @@ VirtioBlkWriteBlocks (
   Should they do nonetheless, we do nothing, successfully.\r
 \r
 **/\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkFlushBlocks (\r
-  IN EFI_BLOCK_IO_PROTOCOL *This\r
+  IN EFI_BLOCK_IO_PROTOCOL  *This\r
   )\r
 {\r
-  VBLK_DEV *Dev;\r
+  VBLK_DEV  *Dev;\r
 \r
   Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
   return Dev->BlockIoMedia.WriteCaching ?\r
-           SynchronousRequest (\r
-             Dev,\r
-             0,    // Lba\r
-             0,    // BufferSize\r
-             NULL, // Buffer\r
-             TRUE  // RequestIsWrite\r
-             ) :\r
-           EFI_SUCCESS;\r
+         SynchronousRequest (\r
+           Dev,\r
+           0,      // Lba\r
+           0,      // BufferSize\r
+           NULL,   // Buffer\r
+           TRUE    // RequestIsWrite\r
+           ) :\r
+         EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
 \r
   Device probe function for this driver.\r
@@ -500,11 +619,6 @@ VirtioBlkFlushBlocks (
       underlying device\r
     - 9 Driver Binding Protocol -- for exporting ourselves\r
 \r
-  Specs relevant in the specific sense:\r
-  - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol\r
-  - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design\r
-    Guidelines, 18.3 PCI drivers.\r
-\r
   @param[in]  This                The EFI_DRIVER_BINDING_PROTOCOL object\r
                                   incorporating this driver (independently of\r
                                   any device).\r
@@ -516,86 +630,68 @@ VirtioBlkFlushBlocks (
 \r
   @retval EFI_SUCCESS      The driver supports the device being probed.\r
 \r
-  @retval EFI_UNSUPPORTED  Based on virtio-blk PCI discovery, we do not support\r
+  @retval EFI_UNSUPPORTED  Based on virtio-blk discovery, we do not support\r
                            the device.\r
 \r
   @return                  Error codes from the OpenProtocol() boot service or\r
-                           the PciIo protocol.\r
+                           the VirtIo protocol.\r
 \r
 **/\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkDriverBindingSupported (\r
-  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
-  IN EFI_HANDLE                  DeviceHandle,\r
-  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   DeviceHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
 {\r
-  EFI_STATUS          Status;\r
-  EFI_PCI_IO_PROTOCOL *PciIo;\r
-  PCI_TYPE00          Pci;\r
+  EFI_STATUS              Status;\r
+  VIRTIO_DEVICE_PROTOCOL  *VirtIo;\r
 \r
   //\r
-  // Attempt to open the device with the PciIo set of interfaces. On success,\r
-  // the protocol is "instantiated" for the PCI device. Covers duplicate open\r
-  // attempts (EFI_ALREADY_STARTED).\r
+  // Attempt to open the device with the VirtIo set of interfaces. On success,\r
+  // the protocol is "instantiated" for the VirtIo device. Covers duplicate\r
+  // open attempts (EFI_ALREADY_STARTED).\r
   //\r
   Status = gBS->OpenProtocol (\r
                   DeviceHandle,               // candidate device\r
-                  &gEfiPciIoProtocolGuid,     // for generic PCI access\r
-                  (VOID **)&PciIo,            // handle to instantiate\r
+                  &gVirtioDeviceProtocolGuid, // for generic VirtIo access\r
+                  (VOID **)&VirtIo,           // handle to instantiate\r
                   This->DriverBindingHandle,  // requestor driver identity\r
                   DeviceHandle,               // ControllerHandle, according to\r
                                               // the UEFI Driver Model\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to\r
                                               // the device; to be released\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  //\r
-  // Read entire PCI configuration header for more extensive check ahead.\r
-  //\r
-  Status = PciIo->Pci.Read (\r
-                        PciIo,                        // (protocol, device)\r
-                                                      // handle\r
-                        EfiPciIoWidthUint32,          // access width & copy\r
-                                                      // mode\r
-                        0,                            // Offset\r
-                        sizeof Pci / sizeof (UINT32), // Count\r
-                        &Pci                          // target buffer\r
-                        );\r
-\r
-  if (Status == EFI_SUCCESS) {\r
-    //\r
-    // virtio-0.9.5, 2.1 PCI Discovery\r
-    //\r
-    Status = (Pci.Hdr.VendorId == 0x1AF4 &&\r
-              Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&\r
-              Pci.Hdr.RevisionID == 0x00 &&\r
-              Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_BLOCK_DEVICE) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
+  if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {\r
+    Status = EFI_UNSUPPORTED;\r
   }\r
 \r
   //\r
-  // We needed PCI IO access only transitorily, to see whether we support the\r
+  // We needed VirtIo access only transitorily, to see whether we support the\r
   // device or not.\r
   //\r
-  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
-         This->DriverBindingHandle, DeviceHandle);\r
+  gBS->CloseProtocol (\r
+         DeviceHandle,\r
+         &gVirtioDeviceProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         DeviceHandle\r
+         );\r
   return Status;\r
 }\r
 \r
-\r
 /**\r
 \r
   Set up all BlockIo and virtio-blk aspects of this driver for the specified\r
   device.\r
 \r
   @param[in out] Dev  The driver instance to configure. The caller is\r
-                      responsible for Dev->PciIo's validity (ie. working IO\r
-                      access to the underlying virtio-blk PCI device).\r
+                      responsible for Dev->VirtIo's validity (ie. working IO\r
+                      access to the underlying virtio-blk device).\r
 \r
   @retval EFI_SUCCESS      Setup complete.\r
 \r
@@ -603,42 +699,58 @@ VirtioBlkDriverBindingSupported (
                            virtio-blk attributes the host provides.\r
 \r
   @return                  Error codes from VirtioRingInit() or\r
-                           VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE().\r
+                           VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE or\r
+                           VirtioRingMap().\r
 \r
 **/\r
-\r
 STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkInit (\r
-  IN OUT VBLK_DEV *Dev\r
+  IN OUT VBLK_DEV  *Dev\r
   )\r
 {\r
-  UINT8      NextDevStat;\r
-  EFI_STATUS Status;\r
-\r
-  UINT32     Features;\r
-  UINT64     NumSectors;\r
-  UINT32     BlockSize;\r
-  UINT16     QueueSize;\r
+  UINT8       NextDevStat;\r
+  EFI_STATUS  Status;\r
+\r
+  UINT64  Features;\r
+  UINT64  NumSectors;\r
+  UINT32  BlockSize;\r
+  UINT8   PhysicalBlockExp;\r
+  UINT8   AlignmentOffset;\r
+  UINT32  OptIoSize;\r
+  UINT16  QueueSize;\r
+  UINT64  RingBaseShift;\r
+\r
+  PhysicalBlockExp = 0;\r
+  AlignmentOffset  = 0;\r
+  OptIoSize        = 0;\r
 \r
   //\r
   // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.\r
   //\r
   NextDevStat = 0;             // step 1 -- reset device\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status      = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
 \r
   NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status       = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
 \r
   NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status       = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Failed;\r
+  }\r
+\r
+  //\r
+  // Set Page Size - MMIO VirtIo Specific\r
+  //\r
+  Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -646,26 +758,30 @@ VirtioBlkInit (
   //\r
   // step 4a -- retrieve and validate features\r
   //\r
-  Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);\r
+  Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
-  Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors);\r
+\r
+  Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
+\r
   if (NumSectors == 0) {\r
     Status = EFI_UNSUPPORTED;\r
     goto Failed;\r
   }\r
 \r
   if (Features & VIRTIO_BLK_F_BLK_SIZE) {\r
-    Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize);\r
+    Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);\r
     if (EFI_ERROR (Status)) {\r
       goto Failed;\r
     }\r
-    if (BlockSize == 0 || BlockSize % 512 != 0 ||\r
-        ModU64x32 (NumSectors, BlockSize / 512) != 0) {\r
+\r
+    if ((BlockSize == 0) || (BlockSize % 512 != 0) ||\r
+        (ModU64x32 (NumSectors, BlockSize / 512) != 0))\r
+    {\r
       //\r
       // We can only handle a logical block consisting of whole sectors,\r
       // and only a disk composed of whole logical blocks.\r
@@ -673,66 +789,137 @@ VirtioBlkInit (
       Status = EFI_UNSUPPORTED;\r
       goto Failed;\r
     }\r
-  }\r
-  else {\r
+  } else {\r
     BlockSize = 512;\r
   }\r
 \r
+  if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
+    Status = VIRTIO_CFG_READ (\r
+               Dev,\r
+               Topology.PhysicalBlockExp,\r
+               &PhysicalBlockExp\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+\r
+    if (PhysicalBlockExp >= 32) {\r
+      Status = EFI_UNSUPPORTED;\r
+      goto Failed;\r
+    }\r
+\r
+    Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+\r
+    Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+  }\r
+\r
+  Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |\r
+              VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |\r
+              VIRTIO_F_IOMMU_PLATFORM;\r
+\r
+  //\r
+  // In virtio-1.0, feature negotiation is expected to complete before queue\r
+  // discovery, and the device can also reject the selected set of features.\r
+  //\r
+  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+  }\r
+\r
   //\r
   // step 4b -- allocate virtqueue\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0);\r
+  Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
-  Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);\r
+\r
+  Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
-  if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors\r
+\r
+  if (QueueSize < 3) {\r
+    // SynchronousRequest() uses at most three descriptors\r
     Status = EFI_UNSUPPORTED;\r
     goto Failed;\r
   }\r
 \r
-  Status = VirtioRingInit (QueueSize, &Dev->Ring);\r
+  Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
 \r
   //\r
-  // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything\r
-  // fails from here on, we must release the ring resources.\r
+  // If anything fails from here on, we must release the ring resources\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,\r
-             (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);\r
+  Status = VirtioRingMap (\r
+             Dev->VirtIo,\r
+             &Dev->Ring,\r
+             &RingBaseShift,\r
+             &Dev->RingMap\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
 \r
   //\r
-  // step 5 -- Report understood features. There are no virtio-blk specific\r
-  // features to negotiate in virtio-0.9.5, plus we do not want any of the\r
-  // device-independent (known or unknown) VIRTIO_F_* capabilities (see\r
-  // Appendix B).\r
+  // Additional steps for MMIO: align the queue appropriately, and set the\r
+  // size. If anything fails from here on, we must unmap the ring resources.\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0);\r
+  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);\r
   if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+    goto UnmapQueue;\r
+  }\r
+\r
+  Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UnmapQueue;\r
+  }\r
+\r
+  //\r
+  // step 4c -- Report GPFN (guest-physical frame number) of queue.\r
+  //\r
+  Status = Dev->VirtIo->SetQueueAddress (\r
+                          Dev->VirtIo,\r
+                          &Dev->Ring,\r
+                          RingBaseShift\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    goto UnmapQueue;\r
+  }\r
+\r
+  //\r
+  // step 5 -- Report understood features.\r
+  //\r
+  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);\r
+    Status    = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
+    if (EFI_ERROR (Status)) {\r
+      goto UnmapQueue;\r
+    }\r
   }\r
 \r
   //\r
   // step 6 -- initialization complete\r
   //\r
   NextDevStat |= VSTAT_DRIVER_OK;\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Status       = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
   if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+    goto UnmapQueue;\r
   }\r
 \r
   //\r
-  // Populate the exported interface's attributes; see UEFI spec v2.3.1 +\r
-  // Errata C, 12.8 EFI Block I/O Protocol. We stick to the lowest possible\r
-  // EFI_BLOCK_IO_PROTOCOL revision for now.\r
+  // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI\r
+  // Block I/O Protocol.\r
   //\r
   Dev->BlockIo.Revision              = 0;\r
   Dev->BlockIo.Media                 = &Dev->BlockIoMedia;\r
@@ -744,29 +931,64 @@ VirtioBlkInit (
   Dev->BlockIoMedia.RemovableMedia   = FALSE;\r
   Dev->BlockIoMedia.MediaPresent     = TRUE;\r
   Dev->BlockIoMedia.LogicalPartition = FALSE;\r
-  Dev->BlockIoMedia.ReadOnly         = !!(Features & VIRTIO_BLK_F_RO);\r
-  Dev->BlockIoMedia.WriteCaching     = !!(Features & VIRTIO_BLK_F_FLUSH);\r
+  Dev->BlockIoMedia.ReadOnly         = (BOOLEAN)((Features & VIRTIO_BLK_F_RO) != 0);\r
+  Dev->BlockIoMedia.WriteCaching     = (BOOLEAN)((Features & VIRTIO_BLK_F_FLUSH) != 0);\r
   Dev->BlockIoMedia.BlockSize        = BlockSize;\r
   Dev->BlockIoMedia.IoAlign          = 0;\r
-  Dev->BlockIoMedia.LastBlock        = DivU64x32 (NumSectors,\r
-                                         BlockSize / 512) - 1;\r
+  Dev->BlockIoMedia.LastBlock        = DivU64x32 (\r
+                                         NumSectors,\r
+                                         BlockSize / 512\r
+                                         ) - 1;\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",\r
+    __FUNCTION__,\r
+    Dev->BlockIoMedia.BlockSize,\r
+    Dev->BlockIoMedia.LastBlock + 1\r
+    ));\r
+\r
+  if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
+    Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;\r
+\r
+    Dev->BlockIoMedia.LowestAlignedLba                 = AlignmentOffset;\r
+    Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock    = 1u << PhysicalBlockExp;\r
+    Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;\r
+\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",\r
+      __FUNCTION__,\r
+      Dev->BlockIoMedia.LowestAlignedLba,\r
+      Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock\r
+      ));\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",\r
+      __FUNCTION__,\r
+      Dev->BlockIoMedia.OptimalTransferLengthGranularity\r
+      ));\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 \r
+UnmapQueue:\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
+\r
 ReleaseQueue:\r
-  VirtioRingUninit (&Dev->Ring);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
 Failed:\r
   //\r
   // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device\r
-  // Status. PCI IO access failure here should not mask the original error.\r
+  // Status. VirtIo access failure here should not mask the original error.\r
   //\r
   NextDevStat |= VSTAT_FAILED;\r
-  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
 \r
   return Status; // reached only via Failed above\r
 }\r
 \r
-\r
 /**\r
 \r
   Uninitialize the internals of a virtio-blk device that has been successfully\r
@@ -775,12 +997,11 @@ Failed:
   @param[in out]  Dev  The device to clean up.\r
 \r
 **/\r
-\r
 STATIC\r
 VOID\r
 EFIAPI\r
 VirtioBlkUninit (\r
-  IN OUT VBLK_DEV *Dev\r
+  IN OUT VBLK_DEV  *Dev\r
   )\r
 {\r
   //\r
@@ -788,20 +1009,51 @@ VirtioBlkUninit (
   // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from\r
   // the old comms area.\r
   //\r
-  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
-  VirtioRingUninit (&Dev->Ring);\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
-  SetMem (&Dev->BlockIo,      sizeof Dev->BlockIo,      0x00);\r
+  SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);\r
   SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);\r
 }\r
 \r
+/**\r
+\r
+  Event notification function enqueued by ExitBootServices().\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+\r
+  @param[in] Context  Pointer to the VBLK_DEV structure.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VirtioBlkExitBoot (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  )\r
+{\r
+  VBLK_DEV  *Dev;\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));\r
+  //\r
+  // Reset the device. This causes the hypervisor to forget about the virtio\r
+  // ring.\r
+  //\r
+  // We allocated said ring in EfiBootServicesData type memory, and code\r
+  // executing after ExitBootServices() is permitted to overwrite it.\r
+  //\r
+  Dev = Context;\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
+}\r
 \r
 /**\r
 \r
   After we've pronounced support for a specific device in\r
   DriverBindingSupported(), we start managing said device (passed in by the\r
-  Driver Exeuction Environment) with the following service.\r
+  Driver Execution Environment) with the following service.\r
 \r
   See DriverBindingSupported() for specification references.\r
 \r
@@ -815,95 +1067,92 @@ VirtioBlkUninit (
 \r
 \r
   @retval EFI_SUCCESS           Driver instance has been created and\r
-                                initialized  for the virtio-blk PCI device, it\r
-                                is now accessibla via EFI_BLOCK_IO_PROTOCOL.\r
+                                initialized  for the virtio-blk device, it\r
+                                is now accessible via EFI_BLOCK_IO_PROTOCOL.\r
 \r
   @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
 \r
   @return                       Error codes from the OpenProtocol() boot\r
-                                service, the PciIo protocol, VirtioBlkInit(),\r
+                                service, the VirtIo protocol, VirtioBlkInit(),\r
                                 or the InstallProtocolInterface() boot service.\r
 \r
 **/\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkDriverBindingStart (\r
-  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
-  IN EFI_HANDLE                  DeviceHandle,\r
-  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   DeviceHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
 {\r
-  VBLK_DEV   *Dev;\r
-  EFI_STATUS Status;\r
+  VBLK_DEV    *Dev;\r
+  EFI_STATUS  Status;\r
 \r
-  Dev = (VBLK_DEV *) AllocateZeroPool (sizeof *Dev);\r
+  Dev = (VBLK_DEV *)AllocateZeroPool (sizeof *Dev);\r
   if (Dev == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
-                  (VOID **)&Dev->PciIo, This->DriverBindingHandle,\r
-                  DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
+  Status = gBS->OpenProtocol (\r
+                  DeviceHandle,\r
+                  &gVirtioDeviceProtocolGuid,\r
+                  (VOID **)&Dev->VirtIo,\r
+                  This->DriverBindingHandle,\r
+                  DeviceHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     goto FreeVirtioBlk;\r
   }\r
 \r
   //\r
-  // We must retain and ultimately restore the original PCI attributes of the\r
-  // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /\r
-  // 18.3.2 Start() and Stop().\r
-  //\r
-  // The third parameter ("Attributes", input) is ignored by the Get operation.\r
-  // The fourth parameter ("Result", output) is ignored by the Enable and Set\r
-  // operations.\r
-  //\r
-  // For virtio-blk we only need IO space access.\r
+  // VirtIo access granted, configure virtio-blk device.\r
   //\r
-  Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,\r
-                         0, &Dev->OriginalPciAttributes);\r
-  if (EFI_ERROR (Status)) {\r
-    goto ClosePciIo;\r
-  }\r
-\r
-  Status = Dev->PciIo->Attributes (Dev->PciIo,\r
-                         EfiPciIoAttributeOperationEnable,\r
-                         EFI_PCI_IO_ATTRIBUTE_IO, NULL);\r
+  Status = VirtioBlkInit (Dev);\r
   if (EFI_ERROR (Status)) {\r
-    goto ClosePciIo;\r
+    goto CloseVirtIo;\r
   }\r
 \r
-  //\r
-  // PCI IO access granted, configure virtio-blk device.\r
-  //\r
-  Status = VirtioBlkInit (Dev);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+                  TPL_CALLBACK,\r
+                  &VirtioBlkExitBoot,\r
+                  Dev,\r
+                  &Dev->ExitBoot\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
-    goto RestorePciAttributes;\r
+    goto UninitDev;\r
   }\r
 \r
   //\r
   // Setup complete, attempt to export the driver instance's BlockIo interface.\r
   //\r
   Dev->Signature = VBLK_SIG;\r
-  Status = gBS->InstallProtocolInterface (&DeviceHandle,\r
-                  &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,\r
-                  &Dev->BlockIo);\r
+  Status         = gBS->InstallProtocolInterface (\r
+                          &DeviceHandle,\r
+                          &gEfiBlockIoProtocolGuid,\r
+                          EFI_NATIVE_INTERFACE,\r
+                          &Dev->BlockIo\r
+                          );\r
   if (EFI_ERROR (Status)) {\r
-    goto UninitDev;\r
+    goto CloseExitBoot;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
+CloseExitBoot:\r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
 UninitDev:\r
   VirtioBlkUninit (Dev);\r
 \r
-RestorePciAttributes:\r
-  Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
-                Dev->OriginalPciAttributes, NULL);\r
-\r
-ClosePciIo:\r
-  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
-         This->DriverBindingHandle, DeviceHandle);\r
+CloseVirtIo:\r
+  gBS->CloseProtocol (\r
+         DeviceHandle,\r
+         &gVirtioDeviceProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         DeviceHandle\r
+         );\r
 \r
 FreeVirtioBlk:\r
   FreePool (Dev);\r
@@ -911,7 +1160,6 @@ FreeVirtioBlk:
   return Status;\r
 }\r
 \r
-\r
 /**\r
 \r
   Stop driving a virtio-blk device and remove its BlockIo interface.\r
@@ -934,19 +1182,18 @@ FreeVirtioBlk:
   @param[in] ChildHandleBuffer  Ignored (corresponding to NumberOfChildren).\r
 \r
 **/\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkDriverBindingStop (\r
-  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
-  IN EFI_HANDLE                  DeviceHandle,\r
-  IN UINTN                       NumberOfChildren,\r
-  IN EFI_HANDLE                  *ChildHandleBuffer\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   DeviceHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
   )\r
 {\r
-  EFI_STATUS            Status;\r
-  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
-  VBLK_DEV              *Dev;\r
+  EFI_STATUS             Status;\r
+  EFI_BLOCK_IO_PROTOCOL  *BlockIo;\r
+  VBLK_DEV               *Dev;\r
 \r
   Status = gBS->OpenProtocol (\r
                   DeviceHandle,                  // candidate device\r
@@ -965,32 +1212,37 @@ VirtioBlkDriverBindingStop (
   //\r
   // Handle Stop() requests for in-use driver instances gracefully.\r
   //\r
-  Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
-                  &gEfiBlockIoProtocolGuid, &Dev->BlockIo);\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  DeviceHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  &Dev->BlockIo\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  VirtioBlkUninit (Dev);\r
+  gBS->CloseEvent (Dev->ExitBoot);\r
 \r
-  Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
-                Dev->OriginalPciAttributes, NULL);\r
+  VirtioBlkUninit (Dev);\r
 \r
-  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
-         This->DriverBindingHandle, DeviceHandle);\r
+  gBS->CloseProtocol (\r
+         DeviceHandle,\r
+         &gVirtioDeviceProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         DeviceHandle\r
+         );\r
 \r
   FreePool (Dev);\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 //\r
 // The static object that groups the Supported() (ie. probe), Start() and\r
 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
 // C, 10.1 EFI Driver Binding Protocol.\r
 //\r
-STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
+STATIC EFI_DRIVER_BINDING_PROTOCOL  gDriverBinding = {\r
   &VirtioBlkDriverBindingSupported,\r
   &VirtioBlkDriverBindingStart,\r
   &VirtioBlkDriverBindingStop,\r
@@ -1000,7 +1252,6 @@ STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
   NULL  // DriverBindingHandle, ditto\r
 };\r
 \r
-\r
 //\r
 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r
 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r
@@ -1014,20 +1265,20 @@ STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
 //\r
 \r
 STATIC\r
-EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
+EFI_UNICODE_STRING_TABLE  mDriverNameTable[] = {\r
   { "eng;en", L"Virtio Block Driver" },\r
   { NULL,     NULL                   }\r
 };\r
 \r
 STATIC\r
-EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
+EFI_COMPONENT_NAME_PROTOCOL  gComponentName;\r
 \r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkGetDriverName (\r
-  IN  EFI_COMPONENT_NAME_PROTOCOL *This,\r
-  IN  CHAR8                       *Language,\r
-  OUT CHAR16                      **DriverName\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
   )\r
 {\r
   return LookupUnicodeString2 (\r
@@ -1042,39 +1293,38 @@ VirtioBlkGetDriverName (
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkGetDeviceName (\r
-  IN  EFI_COMPONENT_NAME_PROTOCOL *This,\r
-  IN  EFI_HANDLE                  DeviceHandle,\r
-  IN  EFI_HANDLE                  ChildHandle,\r
-  IN  CHAR8                       *Language,\r
-  OUT CHAR16                      **ControllerName\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   DeviceHandle,\r
+  IN  EFI_HANDLE                   ChildHandle,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **ControllerName\r
   )\r
 {\r
   return EFI_UNSUPPORTED;\r
 }\r
 \r
 STATIC\r
-EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
+EFI_COMPONENT_NAME_PROTOCOL  gComponentName = {\r
   &VirtioBlkGetDriverName,\r
   &VirtioBlkGetDeviceName,\r
   "eng" // SupportedLanguages, ISO 639-2 language codes\r
 };\r
 \r
 STATIC\r
-EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
-  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &VirtioBlkGetDriverName,\r
-  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioBlkGetDeviceName,\r
+EFI_COMPONENT_NAME2_PROTOCOL  gComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioBlkGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioBlkGetDeviceName,\r
   "en" // SupportedLanguages, RFC 4646 language codes\r
 };\r
 \r
-\r
 //\r
 // Entry point of this driver.\r
 //\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioBlkEntryPoint (\r
-  IN EFI_HANDLE       ImageHandle,\r
-  IN EFI_SYSTEM_TABLE *SystemTable\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
   return EfiLibInstallDriverBindingComponentName2 (\r
@@ -1086,4 +1336,3 @@ VirtioBlkEntryPoint (
            &gComponentName2\r
            );\r
 }\r
-\r