From fbc80813eeb0cff1c102666046a4483bf44b7414 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Fri, 16 Oct 2015 19:52:18 +0000 Subject: OvmfPkg: VirtioScsiDxe: 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 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18623 6f19259b-4bc3-4df7-8a09-765794883524 --- OvmfPkg/VirtioScsiDxe/VirtioScsi.c | 40 ++++++++++++++++++++++++++++++++++++-- OvmfPkg/VirtioScsiDxe/VirtioScsi.h | 1 + 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'OvmfPkg/VirtioScsiDxe') diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c index 2cb3f43bb0..e1e12039b3 100644 --- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c +++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c @@ -933,7 +933,6 @@ Failed: } - STATIC VOID EFIAPI @@ -960,6 +959,32 @@ VirtioScsiUninit ( } +// +// Event notification function enqueued by ExitBootServices(). +// + +STATIC +VOID +EFIAPI +VirtioScsiExitBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + VSCSI_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); +} + + // // Probe, start and stop functions of this driver, called by the DXE core for // specific devices. @@ -1050,6 +1075,12 @@ VirtioScsiDriverBindingStart ( goto CloseVirtIo; } + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, + &VirtioScsiExitBoot, Dev, &Dev->ExitBoot); + if (EFI_ERROR (Status)) { + goto UninitDev; + } + // // Setup complete, attempt to export the driver instance's PassThru // interface. @@ -1059,11 +1090,14 @@ VirtioScsiDriverBindingStart ( &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE, &Dev->PassThru); if (EFI_ERROR (Status)) { - goto UninitDev; + goto CloseExitBoot; } return EFI_SUCCESS; +CloseExitBoot: + gBS->CloseEvent (Dev->ExitBoot); + UninitDev: VirtioScsiUninit (Dev); @@ -1114,6 +1148,8 @@ VirtioScsiDriverBindingStop ( return Status; } + gBS->CloseEvent (Dev->ExitBoot); + VirtioScsiUninit (Dev); gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.h b/OvmfPkg/VirtioScsiDxe/VirtioScsi.h index 0d3181d140..80840d353e 100644 --- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.h +++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.h @@ -52,6 +52,7 @@ typedef struct { // ---------------- ------------------ ---------- UINT32 Signature; // DriverBindingStart 0 VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0 + EFI_EVENT ExitBoot; // DriverBindingStart 0 BOOLEAN InOutSupported; // VirtioScsiInit 1 UINT16 MaxTarget; // VirtioScsiInit 1 UINT32 MaxLun; // VirtioScsiInit 1 -- cgit v1.2.3