summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2015-10-16 19:52:24 +0000
committerlersek <lersek@Edk2>2015-10-16 19:52:24 +0000
commitfcb636ea4244cb29d3f6a6d938dd9f7692ecfa7c (patch)
tree47edee84837f0496e5bfc1d28e497d74199e15c4
parentfbc80813eeb0cff1c102666046a4483bf44b7414 (diff)
downloadedk2-platforms-fcb636ea4244cb29d3f6a6d938dd9f7692ecfa7c.tar.xz
OvmfPkg: VirtioBlkDxe: reset device at ExitBootServices()
(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
-rw-r--r--OvmfPkg/VirtioBlkDxe/VirtioBlk.c44
-rw-r--r--OvmfPkg/VirtioBlkDxe/VirtioBlk.h1
2 files changed, 44 insertions, 1 deletions
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
index 862957ce04..75f85ca6e0 100644
--- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
+++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
@@ -843,6 +843,37 @@ VirtioBlkUninit (
/**
+ Event notification function enqueued by ExitBootServices().
+
+ @param[in] Event Event whose notification function is being invoked.
+
+ @param[in] Context Pointer to the VBLK_DEV structure.
+
+**/
+
+STATIC
+VOID
+EFIAPI
+VirtioBlkExitBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VBLK_DEV *Dev;
+
+ //
+ // Reset the device. This causes the hypervisor to forget about the virtio
+ // ring.
+ //
+ // We allocated said ring in EfiBootServicesData type memory, and code
+ // executing after ExitBootServices() is permitted to overwrite it.
+ //
+ Dev = Context;
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
+}
+
+/**
+
After we've pronounced support for a specific device in
DriverBindingSupported(), we start managing said device (passed in by the
Driver Exeuction Environment) with the following service.
@@ -901,6 +932,12 @@ VirtioBlkDriverBindingStart (
goto CloseVirtIo;
}
+ Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+ &VirtioBlkExitBoot, Dev, &Dev->ExitBoot);
+ if (EFI_ERROR (Status)) {
+ goto UninitDev;
+ }
+
//
// Setup complete, attempt to export the driver instance's BlockIo interface.
//
@@ -909,11 +946,14 @@ VirtioBlkDriverBindingStart (
&gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,
&Dev->BlockIo);
if (EFI_ERROR (Status)) {
- goto UninitDev;
+ goto CloseExitBoot;
}
return EFI_SUCCESS;
+CloseExitBoot:
+ gBS->CloseEvent (Dev->ExitBoot);
+
UninitDev:
VirtioBlkUninit (Dev);
@@ -987,6 +1027,8 @@ VirtioBlkDriverBindingStop (
return Status;
}
+ gBS->CloseEvent (Dev->ExitBoot);
+
VirtioBlkUninit (Dev);
gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.h b/OvmfPkg/VirtioBlkDxe/VirtioBlk.h
index 789caf9a37..ca4b7a0ca6 100644
--- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.h
+++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.h
@@ -37,6 +37,7 @@ typedef struct {
// --------------------- ------------------ ---------
UINT32 Signature; // DriverBindingStart 0
VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0
+ EFI_EVENT ExitBoot; // DriverBindingStart 0
VRING Ring; // VirtioRingInit 2
EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1
EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1