]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg: VirtioBlkDxe: reset device at ExitBootServices()
authorLaszlo Ersek <lersek@redhat.com>
Fri, 16 Oct 2015 19:52:24 +0000 (19:52 +0000)
committerlersek <lersek@Edk2>
Fri, 16 Oct 2015 19:52:24 +0000 (19:52 +0000)
(1) VirtioLib allocates the virtio ring in EfiBootServicesData memory.
    (This is intentional.) Code that executes after ExitBootServices() is
    permitted to reuse such memory.

(2) The hypervisor is allowed to look at, and act upon, a live virtio ring
    at any time, even without explicit virtio kicks from the guest.

Should boot loader code or kernel code, running between ExitBootServices()
and the kernel's own virtio drivers resetting the device, overwrite the
pages that used to contain the virtio ring before ExitBootServices(), QEMU
could theoretically interpret that unrelated data as garbage ring
contents, and abort the guest.

Although we have seen no such reports, better be prudent and reset the
device in an ExitBootServices() event handler. Among other things, this
causes QEMU to forget about the device's virtio ring.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18624 6f19259b-4bc3-4df7-8a09-765794883524

OvmfPkg/VirtioBlkDxe/VirtioBlk.c
OvmfPkg/VirtioBlkDxe/VirtioBlk.h

index 862957ce04448467534c8d4c26e73c768881cd66..75f85ca6e09ad01fdadf8bc3245596c8cac45873 100644 (file)
@@ -841,6 +841,37 @@ VirtioBlkUninit (
 }\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
+\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
+  //\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
@@ -901,6 +932,12 @@ VirtioBlkDriverBindingStart (
     goto CloseVirtIo;\r
   }\r
 \r
+  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
+                  &VirtioBlkExitBoot, Dev, &Dev->ExitBoot);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitDev;\r
+  }\r
+\r
   //\r
   // Setup complete, attempt to export the driver instance's BlockIo interface.\r
   //\r
@@ -909,11 +946,14 @@ VirtioBlkDriverBindingStart (
                   &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,\r
                   &Dev->BlockIo);\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
@@ -987,6 +1027,8 @@ VirtioBlkDriverBindingStop (
     return Status;\r
   }\r
 \r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
   VirtioBlkUninit (Dev);\r
 \r
   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
index 789caf9a37eeaebaa3fd5495da12e3561be9804b..ca4b7a0ca6681e5f52147a36b2a5e91180e7a420 100644 (file)
@@ -37,6 +37,7 @@ typedef struct {
   //                     ---------------------    ------------------  ---------\r
   UINT32                 Signature;            // DriverBindingStart  0\r
   VIRTIO_DEVICE_PROTOCOL *VirtIo;              // DriverBindingStart  0\r
+  EFI_EVENT              ExitBoot;             // DriverBindingStart  0\r
   VRING                  Ring;                 // VirtioRingInit      2\r
   EFI_BLOCK_IO_PROTOCOL  BlockIo;              // VirtioBlkInit       1\r
   EFI_BLOCK_IO_MEDIA     BlockIoMedia;         // VirtioBlkInit       1\r