]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioScsiDxe/VirtioScsi.c
OvmfPkg/AmdSevDxe: decrypt the pages of the initial SMRAM save state map
[mirror_edk2.git] / OvmfPkg / VirtioScsiDxe / VirtioScsi.c
index e58dd80df27e6406fd8ddbc8d2917e323e8f5e83..1a68f062106c00132f1c9a32002fb52f1cee3820 100644 (file)
@@ -26,7 +26,8 @@
     unreasonable for now.\r
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
     unreasonable for now.\r
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
-  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2012 - 2014, 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
 \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
@@ -38,7 +39,6 @@
 \r
 **/\r
 \r
 \r
 **/\r
 \r
-#include <IndustryStandard/Pci.h>\r
 #include <IndustryStandard/VirtioScsi.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <IndustryStandard/VirtioScsi.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 \r
 /**\r
 \r
 \r
 /**\r
 \r
-  Convenience macros to read and write region 0 IO space elements of the\r
-  virtio-scsi PCI device, for configuration purposes.\r
+  Convenience macros to read and write configuration elements of the\r
+  virtio-scsi VirtIo device.\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
 \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 VSCSI_DEV structure whose PCI IO space\r
-                       we're accessing. Dev->PciIo must be valid.\r
+  @param[in] Dev       Pointer to the VSCSI_DEV structure.\r
 \r
   @param[in] Field     A field name from VSCSI_HDR, identifying the virtio-scsi\r
                        configuration item to access.\r
 \r
   @param[in] Field     A field name from VSCSI_HDR, identifying the virtio-scsi\r
                        configuration item to access.\r
                        one of UINT8, UINT16, UINT32, UINT64.\r
 \r
 \r
                        one of UINT8, UINT16, UINT32, UINT64.\r
 \r
 \r
-  @return  Status codes returned by VirtioWrite() / VirtioRead().\r
+  @return  Status codes returned by Virtio->WriteDevice() / Virtio->ReadDevice().\r
 \r
 **/\r
 \r
 \r
 **/\r
 \r
-#define VIRTIO_CFG_WRITE(Dev, Field, Value)  (VirtioWrite (              \\r
-                                                (Dev)->PciIo,            \\r
-                                                OFFSET_OF_VSCSI (Field), \\r
-                                                SIZE_OF_VSCSI (Field),   \\r
-                                                (Value)                  \\r
+#define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice (  \\r
+                                                (Dev)->VirtIo,              \\r
+                                                OFFSET_OF_VSCSI (Field),    \\r
+                                                SIZE_OF_VSCSI (Field),      \\r
+                                                (Value)                     \\r
                                                 ))\r
 \r
                                                 ))\r
 \r
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead (               \\r
-                                                (Dev)->PciIo,            \\r
-                                                OFFSET_OF_VSCSI (Field), \\r
-                                                SIZE_OF_VSCSI (Field),   \\r
-                                                sizeof *(Pointer),       \\r
-                                                (Pointer)                \\r
+#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice (   \\r
+                                                (Dev)->VirtIo,              \\r
+                                                OFFSET_OF_VSCSI (Field),    \\r
+                                                SIZE_OF_VSCSI (Field),      \\r
+                                                sizeof *(Pointer),          \\r
+                                                (Pointer)                   \\r
                                                 ))\r
 \r
 \r
                                                 ))\r
 \r
 \r
@@ -98,7 +97,7 @@
 // set some fields in the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET in/out\r
 // parameter on return. The following is a full list of those fields, for\r
 // easier validation of PopulateRequest(), ParseResponse(), and\r
 // set some fields in the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET in/out\r
 // parameter on return. The following is a full list of those fields, for\r
 // easier validation of PopulateRequest(), ParseResponse(), and\r
-// VirtioScsiPassThru() below.\r
+// ReportHostAdapterError() below.\r
 //\r
 // - InTransferLength\r
 // - OutTransferLength\r
 //\r
 // - InTransferLength\r
 // - OutTransferLength\r
@@ -255,7 +254,7 @@ PopulateRequest (
   //\r
   Request->Lun[0] = 1;\r
   Request->Lun[1] = (UINT8) Target;\r
   //\r
   Request->Lun[0] = 1;\r
   Request->Lun[1] = (UINT8) Target;\r
-  Request->Lun[2] = (UINT8) ((Lun >> 8) | 0x40);\r
+  Request->Lun[2] = (UINT8) (((UINT32)Lun >> 8) | 0x40);\r
   Request->Lun[3] = (UINT8) Lun;\r
 \r
   //\r
   Request->Lun[3] = (UINT8) Lun;\r
 \r
   //\r
@@ -389,6 +388,37 @@ ParseResponse (
 }\r
 \r
 \r
 }\r
 \r
 \r
+/**\r
+\r
+  The function can be used to create a fake host adapter error.\r
+\r
+  When VirtioScsiPassThru() is failed due to some reasons then this function\r
+  can be called to construct a host adapter error.\r
+\r
+  @param[out] Packet  The Extended SCSI Pass Thru Protocol packet that the host\r
+                      adapter error shall be placed in.\r
+\r
+\r
+  @retval EFI_DEVICE_ERROR  The function returns this status code\r
+                            unconditionally, to be propagated by\r
+                            VirtioScsiPassThru().\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ReportHostAdapterError (\r
+  OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  )\r
+{\r
+  Packet->InTransferLength  = 0;\r
+  Packet->OutTransferLength = 0;\r
+  Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;\r
+  Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;\r
+  Packet->SenseDataLength   = 0;\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
 //\r
 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL\r
 // for the virtio-scsi HBA. Refer to UEFI Spec 2.3.1 + Errata C, sections\r
 //\r
 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL\r
 // for the virtio-scsi HBA. Refer to UEFI Spec 2.3.1 + Errata C, sections\r
@@ -410,26 +440,157 @@ VirtioScsiPassThru (
   UINT16                    TargetValue;\r
   EFI_STATUS                Status;\r
   volatile VIRTIO_SCSI_REQ  Request;\r
   UINT16                    TargetValue;\r
   EFI_STATUS                Status;\r
   volatile VIRTIO_SCSI_REQ  Request;\r
-  volatile VIRTIO_SCSI_RESP Response;\r
+  volatile VIRTIO_SCSI_RESP *Response;\r
+  VOID                      *ResponseBuffer;\r
   DESC_INDICES              Indices;\r
   DESC_INDICES              Indices;\r
+  VOID                      *RequestMapping;\r
+  VOID                      *ResponseMapping;\r
+  VOID                      *InDataMapping;\r
+  VOID                      *OutDataMapping;\r
+  EFI_PHYSICAL_ADDRESS      RequestDeviceAddress;\r
+  EFI_PHYSICAL_ADDRESS      ResponseDeviceAddress;\r
+  EFI_PHYSICAL_ADDRESS      InDataDeviceAddress;\r
+  EFI_PHYSICAL_ADDRESS      OutDataDeviceAddress;\r
+  VOID                      *InDataBuffer;\r
+  UINTN                     InDataNumPages;\r
+  BOOLEAN                   OutDataBufferIsMapped;\r
 \r
   ZeroMem ((VOID*) &Request, sizeof (Request));\r
 \r
   ZeroMem ((VOID*) &Request, sizeof (Request));\r
-  ZeroMem ((VOID*) &Response, sizeof (Response));\r
 \r
   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);\r
   CopyMem (&TargetValue, Target, sizeof TargetValue);\r
 \r
 \r
   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);\r
   CopyMem (&TargetValue, Target, sizeof TargetValue);\r
 \r
+  InDataBuffer = NULL;\r
+  OutDataBufferIsMapped = FALSE;\r
+  InDataNumPages = 0;\r
+\r
   Status = PopulateRequest (Dev, TargetValue, Lun, Packet, &Request);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   Status = PopulateRequest (Dev, TargetValue, Lun, Packet, &Request);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  VirtioPrepare (&Dev->Ring, &Indices);\r
+  //\r
+  // Map the virtio-scsi Request header buffer\r
+  //\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             Dev->VirtIo,\r
+             VirtioOperationBusMasterRead,\r
+             (VOID *) &Request,\r
+             sizeof Request,\r
+             &RequestDeviceAddress,\r
+             &RequestMapping);\r
+  if (EFI_ERROR (Status)) {\r
+    return ReportHostAdapterError (Packet);\r
+  }\r
+\r
+  //\r
+  // Map the input buffer\r
+  //\r
+  if (Packet->InTransferLength > 0) {\r
+    //\r
+    // Allocate a intermediate input buffer. This is mainly to handle the\r
+    // following case:\r
+    //  * caller submits a bi-directional request\r
+    //  * we perform the request fine\r
+    //  * but we fail to unmap the "InDataMapping"\r
+    //\r
+    // In that case simply returing the EFI_DEVICE_ERROR is not sufficient. In\r
+    // addition to the error code we also need to update Packet fields\r
+    // accordingly so that we report the full loss of the incoming transfer.\r
+    //\r
+    // We allocate a temporary buffer and map it with BusMasterCommonBuffer. If\r
+    // the Virtio request is successful then we copy the data from temporary\r
+    // buffer into Packet->InDataBuffer.\r
+    //\r
+    InDataNumPages = EFI_SIZE_TO_PAGES ((UINTN)Packet->InTransferLength);\r
+    Status = Dev->VirtIo->AllocateSharedPages (\r
+                            Dev->VirtIo,\r
+                            InDataNumPages,\r
+                            &InDataBuffer\r
+                            );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = ReportHostAdapterError (Packet);\r
+      goto UnmapRequestBuffer;\r
+    }\r
+\r
+    ZeroMem (InDataBuffer, Packet->InTransferLength);\r
+\r
+    Status = VirtioMapAllBytesInSharedBuffer (\r
+               Dev->VirtIo,\r
+               VirtioOperationBusMasterCommonBuffer,\r
+               InDataBuffer,\r
+               Packet->InTransferLength,\r
+               &InDataDeviceAddress,\r
+               &InDataMapping\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = ReportHostAdapterError (Packet);\r
+      goto FreeInDataBuffer;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Map the output buffer\r
+  //\r
+  if (Packet->OutTransferLength > 0) {\r
+    Status = VirtioMapAllBytesInSharedBuffer (\r
+               Dev->VirtIo,\r
+               VirtioOperationBusMasterRead,\r
+               Packet->OutDataBuffer,\r
+               Packet->OutTransferLength,\r
+               &OutDataDeviceAddress,\r
+               &OutDataMapping\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = ReportHostAdapterError (Packet);\r
+      goto UnmapInDataBuffer;\r
+    }\r
+\r
+    OutDataBufferIsMapped = TRUE;\r
+  }\r
+\r
+  //\r
+  // Response header is bi-direction (we preset with host status and expect\r
+  // the device to update it). Allocate a response buffer which can be mapped\r
+  // to access equally by both processor and device.\r
+  //\r
+  Status = Dev->VirtIo->AllocateSharedPages (\r
+                          Dev->VirtIo,\r
+                          EFI_SIZE_TO_PAGES (sizeof *Response),\r
+                          &ResponseBuffer\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = ReportHostAdapterError (Packet);\r
+    goto UnmapOutDataBuffer;\r
+  }\r
+\r
+  Response = ResponseBuffer;\r
+\r
+  ZeroMem ((VOID *)Response, sizeof (*Response));\r
 \r
   //\r
   // preset a host status for ourselves that we do not accept as success\r
   //\r
 \r
   //\r
   // preset a host status for ourselves that we do not accept as success\r
   //\r
-  Response.Response = VIRTIO_SCSI_S_FAILURE;\r
+  Response->Response = VIRTIO_SCSI_S_FAILURE;\r
+\r
+  //\r
+  // Map the response buffer with BusMasterCommonBuffer so that response\r
+  // buffer can be accessed by both host and device.\r
+  //\r
+  Status = VirtioMapAllBytesInSharedBuffer (\r
+             Dev->VirtIo,\r
+             VirtioOperationBusMasterCommonBuffer,\r
+             ResponseBuffer,\r
+             sizeof (*Response),\r
+             &ResponseDeviceAddress,\r
+             &ResponseMapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = ReportHostAdapterError (Packet);\r
+    goto FreeResponseBuffer;\r
+  }\r
+\r
+  VirtioPrepare (&Dev->Ring, &Indices);\r
 \r
   //\r
   // ensured by VirtioScsiInit() -- this predicate, in combination with the\r
 \r
   //\r
   // ensured by VirtioScsiInit() -- this predicate, in combination with the\r
@@ -440,48 +601,101 @@ VirtioScsiPassThru (
   //\r
   // enqueue Request\r
   //\r
   //\r
   // enqueue Request\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
   // enqueue "dataout" if any\r
   //\r
   if (Packet->OutTransferLength > 0) {\r
 \r
   //\r
   // enqueue "dataout" if any\r
   //\r
   if (Packet->OutTransferLength > 0) {\r
-    VirtioAppendDesc (&Dev->Ring, (UINTN) Packet->OutDataBuffer,\r
-      Packet->OutTransferLength, VRING_DESC_F_NEXT, &Indices);\r
+    VirtioAppendDesc (\r
+      &Dev->Ring,\r
+      OutDataDeviceAddress,\r
+      Packet->OutTransferLength,\r
+      VRING_DESC_F_NEXT,\r
+      &Indices\r
+      );\r
   }\r
 \r
   //\r
   // enqueue Response, to be written by the host\r
   //\r
   }\r
 \r
   //\r
   // enqueue Response, to be written by the host\r
   //\r
-  VirtioAppendDesc (&Dev->Ring, (UINTN) &Response, sizeof Response,\r
-    VRING_DESC_F_WRITE | (Packet->InTransferLength > 0 ?\r
-                          VRING_DESC_F_NEXT : 0),\r
-    &Indices);\r
+  VirtioAppendDesc (\r
+    &Dev->Ring,\r
+    ResponseDeviceAddress,\r
+    sizeof *Response,\r
+    VRING_DESC_F_WRITE | (Packet->InTransferLength > 0 ? VRING_DESC_F_NEXT : 0),\r
+    &Indices\r
+    );\r
 \r
   //\r
   // enqueue "datain" if any, to be written by the host\r
   //\r
   if (Packet->InTransferLength > 0) {\r
 \r
   //\r
   // enqueue "datain" if any, to be written by the host\r
   //\r
   if (Packet->InTransferLength > 0) {\r
-    VirtioAppendDesc (&Dev->Ring, (UINTN) Packet->InDataBuffer,\r
-      Packet->InTransferLength, VRING_DESC_F_WRITE, &Indices);\r
+    VirtioAppendDesc (\r
+      &Dev->Ring,\r
+      InDataDeviceAddress,\r
+      Packet->InTransferLength,\r
+      VRING_DESC_F_WRITE,\r
+      &Indices\r
+      );\r
   }\r
 \r
   // If kicking the host fails, we must fake a host adapter error.\r
   // EFI_NOT_READY would save us the effort, but it would also suggest that the\r
   // caller retry.\r
   //\r
   }\r
 \r
   // If kicking the host fails, we must fake a host adapter error.\r
   // EFI_NOT_READY would save us the effort, but it would also suggest that the\r
   // caller retry.\r
   //\r
-  if (VirtioFlush (Dev->PciIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,\r
-        &Indices) != EFI_SUCCESS) {\r
-    Packet->InTransferLength  = 0;\r
-    Packet->OutTransferLength = 0;\r
-    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;\r
-    Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;\r
-    Packet->SenseDataLength   = 0;\r
-    return EFI_DEVICE_ERROR;\r
+  if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,\r
+        &Indices, NULL) != EFI_SUCCESS) {\r
+    Status = ReportHostAdapterError (Packet);\r
+    goto UnmapResponseBuffer;\r
   }\r
 \r
   }\r
 \r
-  return ParseResponse (Packet, &Response);\r
+  Status = ParseResponse (Packet, Response);\r
+\r
+  //\r
+  // If virtio request was successful and it was a CPU read request then we\r
+  // have used an intermediate buffer. Copy the data from intermediate buffer\r
+  // to the final buffer.\r
+  //\r
+  if (InDataBuffer != NULL) {\r
+    CopyMem (Packet->InDataBuffer, InDataBuffer, Packet->InTransferLength);\r
+  }\r
+\r
+UnmapResponseBuffer:\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, ResponseMapping);\r
+\r
+FreeResponseBuffer:\r
+  Dev->VirtIo->FreeSharedPages (\r
+                 Dev->VirtIo,\r
+                 EFI_SIZE_TO_PAGES (sizeof *Response),\r
+                 ResponseBuffer\r
+                 );\r
+\r
+UnmapOutDataBuffer:\r
+  if (OutDataBufferIsMapped) {\r
+    Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, OutDataMapping);\r
+  }\r
+\r
+UnmapInDataBuffer:\r
+  if (InDataBuffer != NULL) {\r
+    Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, InDataMapping);\r
+  }\r
+\r
+FreeInDataBuffer:\r
+  if (InDataBuffer != NULL) {\r
+    Dev->VirtIo->FreeSharedPages (Dev->VirtIo, InDataNumPages, InDataBuffer);\r
+  }\r
+\r
+UnmapRequestBuffer:\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);\r
+\r
+  return Status;\r
 }\r
 \r
 \r
 }\r
 \r
 \r
@@ -708,8 +922,8 @@ VirtioScsiInit (
 {\r
   UINT8      NextDevStat;\r
   EFI_STATUS Status;\r
 {\r
   UINT8      NextDevStat;\r
   EFI_STATUS Status;\r
-\r
-  UINT32     Features;\r
+  UINT64     RingBaseShift;\r
+  UINT64     Features;\r
   UINT16     MaxChannel; // for validation only\r
   UINT32     NumQueues;  // for validation only\r
   UINT16     QueueSize;\r
   UINT16     MaxChannel; // for validation only\r
   UINT32     NumQueues;  // for validation only\r
   UINT16     QueueSize;\r
@@ -718,19 +932,27 @@ VirtioScsiInit (
   // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.\r
   //\r
   NextDevStat = 0;             // step 1 -- reset device\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
   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
   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
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -738,13 +960,13 @@ VirtioScsiInit (
   //\r
   // step 4a -- retrieve and validate features\r
   //\r
   //\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
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
-  Dev->InOutSupported = !!(Features & VIRTIO_SCSI_F_INOUT);\r
+  Dev->InOutSupported = (BOOLEAN) ((Features & VIRTIO_SCSI_F_INOUT) != 0);\r
 \r
 \r
-  Status = VIRTIO_CFG_READ (Dev, VhdrMaxChannel, &MaxChannel);\r
+  Status = VIRTIO_CFG_READ (Dev, MaxChannel, &MaxChannel);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -756,7 +978,7 @@ VirtioScsiInit (
     goto Failed;\r
   }\r
 \r
     goto Failed;\r
   }\r
 \r
-  Status = VIRTIO_CFG_READ (Dev, VhdrNumQueues, &NumQueues);\r
+  Status = VIRTIO_CFG_READ (Dev, NumQueues, &NumQueues);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -765,7 +987,7 @@ VirtioScsiInit (
     goto Failed;\r
   }\r
 \r
     goto Failed;\r
   }\r
 \r
-  Status = VIRTIO_CFG_READ (Dev, VhdrMaxTarget, &Dev->MaxTarget);\r
+  Status = VIRTIO_CFG_READ (Dev, MaxTarget, &Dev->MaxTarget);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -773,7 +995,7 @@ VirtioScsiInit (
     Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);\r
   }\r
 \r
     Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);\r
   }\r
 \r
-  Status = VIRTIO_CFG_READ (Dev, VhdrMaxLun, &Dev->MaxLun);\r
+  Status = VIRTIO_CFG_READ (Dev, MaxLun, &Dev->MaxLun);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -781,7 +1003,7 @@ VirtioScsiInit (
     Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);\r
   }\r
 \r
     Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);\r
   }\r
 \r
-  Status = VIRTIO_CFG_READ (Dev, VhdrMaxSectors, &Dev->MaxSectors);\r
+  Status = VIRTIO_CFG_READ (Dev, MaxSectors, &Dev->MaxSectors);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -794,15 +1016,28 @@ VirtioScsiInit (
     goto Failed;\r
   }\r
 \r
     goto Failed;\r
   }\r
 \r
+  Features &= VIRTIO_SCSI_F_INOUT | 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 request virtqueue\r
   //\r
   //\r
   // step 4b -- allocate request virtqueue\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect,\r
-             VIRTIO_SCSI_REQUEST_QUEUE);\r
+  Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
-  Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);\r
+  Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -814,52 +1049,81 @@ VirtioScsiInit (
     goto Failed;\r
   }\r
 \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
   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
   //\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
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
 \r
   //\r
-  // step 5 -- Report understood features and guest-tuneables. We want none of\r
-  // the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see\r
-  // virtio-0.9.5, Appendices B and I), except bidirectional transfers.\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
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits,\r
-             Features & VIRTIO_SCSI_F_INOUT);\r
+  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);\r
   if (EFI_ERROR (Status)) {\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 and guest-tuneables.\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
   // We expect these maximum sizes from the host. Since they are\r
   // guest-negotiable, ask for them rather than just checking them.\r
   //\r
   }\r
 \r
   //\r
   // We expect these maximum sizes from the host. Since they are\r
   // guest-negotiable, ask for them rather than just checking them.\r
   //\r
-  Status = VIRTIO_CFG_WRITE (Dev, VhdrCdbSize, VIRTIO_SCSI_CDB_SIZE);\r
+  Status = VIRTIO_CFG_WRITE (Dev, CdbSize, VIRTIO_SCSI_CDB_SIZE);\r
   if (EFI_ERROR (Status)) {\r
   if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+    goto UnmapQueue;\r
   }\r
   }\r
-  Status = VIRTIO_CFG_WRITE (Dev, VhdrSenseSize, VIRTIO_SCSI_SENSE_SIZE);\r
+  Status = VIRTIO_CFG_WRITE (Dev, SenseSize, VIRTIO_SCSI_SENSE_SIZE);\r
   if (EFI_ERROR (Status)) {\r
   if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+    goto UnmapQueue;\r
   }\r
 \r
   //\r
   // step 6 -- initialization complete\r
   //\r
   NextDevStat |= VSTAT_DRIVER_OK;\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
   if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+    goto UnmapQueue;\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -895,16 +1159,19 @@ VirtioScsiInit (
 \r
   return EFI_SUCCESS;\r
 \r
 \r
   return EFI_SUCCESS;\r
 \r
+UnmapQueue:\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
+\r
 ReleaseQueue:\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
 \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
   //\r
   NextDevStat |= VSTAT_FAILED;\r
-  VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
 \r
   Dev->InOutSupported = FALSE;\r
   Dev->MaxTarget      = 0;\r
 \r
   Dev->InOutSupported = FALSE;\r
   Dev->MaxTarget      = 0;\r
@@ -915,7 +1182,6 @@ Failed:
 }\r
 \r
 \r
 }\r
 \r
 \r
-\r
 STATIC\r
 VOID\r
 EFIAPI\r
 STATIC\r
 VOID\r
 EFIAPI\r
@@ -928,20 +1194,48 @@ VirtioScsiUninit (
   // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from\r
   // the old comms area.\r
   //\r
   // 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
   Dev->InOutSupported = FALSE;\r
   Dev->MaxTarget      = 0;\r
   Dev->MaxLun         = 0;\r
   Dev->MaxSectors     = 0;\r
 \r
 \r
   Dev->InOutSupported = FALSE;\r
   Dev->MaxTarget      = 0;\r
   Dev->MaxLun         = 0;\r
   Dev->MaxSectors     = 0;\r
 \r
-  VirtioRingUninit (&Dev->Ring);\r
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
   SetMem (&Dev->PassThru,     sizeof Dev->PassThru,     0x00);\r
   SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);\r
 }\r
 \r
 \r
 \r
   SetMem (&Dev->PassThru,     sizeof Dev->PassThru,     0x00);\r
   SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);\r
 }\r
 \r
 \r
+//\r
+// Event notification function enqueued by ExitBootServices().\r
+//\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VirtioScsiExitBoot (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  VSCSI_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
 // Probe, start and stop functions of this driver, called by the DXE core for\r
 // specific devices.\r
 //\r
 // Probe, start and stop functions of this driver, called by the DXE core for\r
 // specific devices.\r
@@ -953,11 +1247,8 @@ VirtioScsiUninit (
 // The implementation follows:\r
 // - Driver Writer's Guide for UEFI 2.3.1 v1.01\r
 //   - 5.1.3.4 OpenProtocol() and CloseProtocol()\r
 // The implementation follows:\r
 // - Driver Writer's Guide for UEFI 2.3.1 v1.01\r
 //   - 5.1.3.4 OpenProtocol() and CloseProtocol()\r
-//   - 18      PCI Driver Design Guidelines\r
-//   - 18.3    PCI drivers\r
 // - UEFI Spec 2.3.1 + Errata C\r
 //   -  6.3 Protocol Handler Services\r
 // - UEFI Spec 2.3.1 + Errata C\r
 //   -  6.3 Protocol Handler Services\r
-//   - 13.4 EFI PCI I/O Protocol\r
 //\r
 \r
 EFI_STATUS\r
 //\r
 \r
 EFI_STATUS\r
@@ -968,57 +1259,37 @@ VirtioScsiDriverBindingSupported (
   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
   )\r
 {\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
 \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
+  // Attempt to open the device with the VirtIo set of interfaces. On success,\r
+  // the protocol is "instantiated" for the VirtIo device. Covers duplicate open\r
   // attempts (EFI_ALREADY_STARTED).\r
   //\r
   Status = gBS->OpenProtocol (\r
                   DeviceHandle,               // candidate device\r
   // 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
                   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
                                               // 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 == 0x08) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
+  if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) {\r
+    Status = EFI_UNSUPPORTED;\r
   }\r
 \r
   //\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
   // device or not.\r
   //\r
-  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+  gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
          This->DriverBindingHandle, DeviceHandle);\r
   return Status;\r
 }\r
          This->DriverBindingHandle, DeviceHandle);\r
   return Status;\r
 }\r
@@ -1040,43 +1311,25 @@ VirtioScsiDriverBindingStart (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
-                  (VOID **)&Dev->PciIo, This->DriverBindingHandle,\r
+  Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
+                  (VOID **)&Dev->VirtIo, This->DriverBindingHandle,\r
                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
   if (EFI_ERROR (Status)) {\r
     goto FreeVirtioScsi;\r
   }\r
 \r
   //\r
                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
   if (EFI_ERROR (Status)) {\r
     goto FreeVirtioScsi;\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
+  // VirtIo access granted, configure virtio-scsi device.\r
   //\r
   //\r
-  // For virtio-scsi we only need IO space access.\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 = VirtioScsiInit (Dev);\r
   if (EFI_ERROR (Status)) {\r
   if (EFI_ERROR (Status)) {\r
-    goto ClosePciIo;\r
+    goto CloseVirtIo;\r
   }\r
 \r
   }\r
 \r
-  //\r
-  // PCI IO access granted, configure virtio-scsi device.\r
-  //\r
-  Status = VirtioScsiInit (Dev);\r
+  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
+                  &VirtioScsiExitBoot, Dev, &Dev->ExitBoot);\r
   if (EFI_ERROR (Status)) {\r
   if (EFI_ERROR (Status)) {\r
-    goto RestorePciAttributes;\r
+    goto UninitDev;\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -1088,20 +1341,19 @@ VirtioScsiDriverBindingStart (
                   &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,\r
                   &Dev->PassThru);\r
   if (EFI_ERROR (Status)) {\r
                   &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,\r
                   &Dev->PassThru);\r
   if (EFI_ERROR (Status)) {\r
-    goto UninitDev;\r
+    goto CloseExitBoot;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
+CloseExitBoot:\r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
 UninitDev:\r
   VirtioScsiUninit (Dev);\r
 \r
 UninitDev:\r
   VirtioScsiUninit (Dev);\r
 \r
-RestorePciAttributes:\r
-  Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
-                Dev->OriginalPciAttributes, NULL);\r
-\r
-ClosePciIo:\r
-  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+CloseVirtIo:\r
+  gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
          This->DriverBindingHandle, DeviceHandle);\r
 \r
 FreeVirtioScsi:\r
          This->DriverBindingHandle, DeviceHandle);\r
 \r
 FreeVirtioScsi:\r
@@ -1147,12 +1399,11 @@ VirtioScsiDriverBindingStop (
     return Status;\r
   }\r
 \r
     return Status;\r
   }\r
 \r
-  VirtioScsiUninit (Dev);\r
+  gBS->CloseEvent (Dev->ExitBoot);\r
 \r
 \r
-  Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
-                Dev->OriginalPciAttributes, NULL);\r
+  VirtioScsiUninit (Dev);\r
 \r
 \r
-  gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+  gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
          This->DriverBindingHandle, DeviceHandle);\r
 \r
   FreePool (Dev);\r
          This->DriverBindingHandle, DeviceHandle);\r
 \r
   FreePool (Dev);\r