From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id B25D81A1E25 for ; Fri, 19 Aug 2016 05:49:52 -0700 (PDT) Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3CBB421A3; Fri, 19 Aug 2016 12:49:52 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-13.phx2.redhat.com [10.3.116.13]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u7JCnaSn011583; Fri, 19 Aug 2016 08:49:51 -0400 From: Laszlo Ersek To: edk2-devel-01 Cc: Ard Biesheuvel , Jordan Justen Date: Fri, 19 Aug 2016 14:49:29 +0200 Message-Id: <20160819124932.29711-9-lersek@redhat.com> In-Reply-To: <20160819124932.29711-1-lersek@redhat.com> References: <20160819124932.29711-1-lersek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Fri, 19 Aug 2016 12:49:52 +0000 (UTC) Subject: [PATCH 08/11] OvmfPkg/VirtioGpuDxe: initialize and tear down VirtIo GPU device X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Aug 2016 12:49:52 -0000 Content-Transfer-Encoding: quoted-printable This patch implements the steps listed in section "3.1.1 Driver Requirements: Device Initialization" of the Virtio V1.0 Committee Spec 04. The VirtIo GPU is brought up in VirtioGpuDriverBindingStart(), and down in VirtioGpuDriverBindingStop(). We also add an ExitBootServices() callback that resets the device. This ensures that the device model abandons any guest memory areas when we transfer control to the guest OS. Cc: Ard Biesheuvel Cc: Jordan Justen Ref: https://tianocore.acgmultimedia.com/show_bug.cgi?id=3D66 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- OvmfPkg/VirtioGpuDxe/VirtioGpu.inf | 2 + OvmfPkg/VirtioGpuDxe/VirtioGpu.h | 68 +++++++ OvmfPkg/VirtioGpuDxe/Commands.c | 214 ++++++++++++++++++++ OvmfPkg/VirtioGpuDxe/DriverBinding.c | 28 ++- 4 files changed, 311 insertions(+), 1 deletion(-) diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf b/OvmfPkg/VirtioGpuDxe/Virt= ioGpu.inf index 948350dbce21..7a6269eded51 100644 --- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf +++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf @@ -21,12 +21,13 @@ [Defines] FILE_GUID =3D D6099B94-CD97-4CC5-8714-7F6312701A8A= =0D MODULE_TYPE =3D UEFI_DRIVER=0D VERSION_STRING =3D 1.0=0D ENTRY_POINT =3D VirtioGpuEntryPoint=0D =0D [Sources]=0D + Commands.c=0D DriverBinding.c=0D VirtioGpu.h=0D =0D [Packages]=0D MdePkg/MdePkg.dec=0D OvmfPkg/OvmfPkg.dec=0D @@ -37,11 +38,12 @@ [LibraryClasses] DevicePathLib=0D MemoryAllocationLib=0D PrintLib=0D UefiBootServicesTableLib=0D UefiDriverEntryPoint=0D UefiLib=0D + VirtioLib=0D =0D [Protocols]=0D gEfiDevicePathProtocolGuid ## TO_START ## BY_START=0D gEfiPciIoProtocolGuid ## TO_START=0D gVirtioDeviceProtocolGuid ## TO_START=0D diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h b/OvmfPkg/VirtioGpuDxe/Virtio= Gpu.h index ca5805df8442..97767dba709f 100644 --- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h +++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h @@ -46,12 +46,22 @@ typedef struct { // EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName(). It is expressed in = table=0D // form because it can theoretically support several languages. Never NU= LL.=0D //=0D EFI_UNICODE_STRING_TABLE *BusName;=0D =0D //=0D + // VirtIo ring used for VirtIo communication.=0D + //=0D + VRING Ring;=0D +=0D + //=0D + // Event to be signaled at ExitBootServices().=0D + //=0D + EFI_EVENT ExitBoot;=0D +=0D + //=0D // The Child field references the GOP wrapper structure. If this pointer= is=0D // NULL, then the hybrid driver has bound (i.e., started) the=0D // VIRTIO_DEVICE_PROTOCOL controller without producing the child GOP=0D // controller (that is, after Start() was called with RemainingDevicePat= h=0D // pointing to and End of Device Path node). Child can be created and=0D // destroyed, even repeatedly, independently of VGPU_DEV.=0D @@ -100,7 +110,65 @@ struct VGPU_GOP_STRUCT { //=0D // For now it is just a placeholder.=0D //=0D UINT8 Gop;=0D };=0D =0D +//=0D +// VirtIo GPU initialization, and commands (primitives) for the GPU device= .=0D +//=0D +/**=0D + Configure the VirtIo GPU device that underlies VgpuDev.=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object to set up VirtIo messaging f= or.=0D + On input, the caller is responsible for having=0D + initialized VgpuDev->VirtIo. On output, VgpuDev-= >Ring=0D + has been initialized, and synchronous VirtIo GPU= =0D + commands (primitives) can be submitted to the de= vice.=0D +=0D + @retval EFI_SUCCESS VirtIo GPU configuration successful.=0D +=0D + @retval EFI_UNSUPPORTED The host-side configuration of the VirtIo GPU i= s not=0D + supported by this driver.=0D +=0D + @retval Error codes from underlying functions.=0D +**/=0D +EFI_STATUS=0D +VirtioGpuInit (=0D + IN OUT VGPU_DEV *VgpuDev=0D + );=0D +=0D +/**=0D + De-configure the VirtIo GPU device that underlies VgpuDev.=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object to tear down VirtIo messagin= g=0D + for. On input, the caller is responsible for hav= ing=0D + called VirtioGpuInit(). On output, VgpuDev->Ring= has=0D + been uninitialized; VirtIo GPU commands (primiti= ves)=0D + can no longer be submitted to the device.=0D +**/=0D +VOID=0D +VirtioGpuUninit (=0D + IN OUT VGPU_DEV *VgpuDev=0D + );=0D +=0D +/**=0D + EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the= =0D + VirtIo device, causing it to release its resources and to forget its=0D + configuration.=0D +=0D + This function may only be called (that is, VGPU_DEV.ExitBoot may only be= =0D + signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is= =0D + called.=0D +=0D + @param[in] Event Event whose notification function is being invoked.= =0D +=0D + @param[in] Context Pointer to the associated VGPU_DEV object.=0D +**/=0D +VOID=0D +EFIAPI=0D +VirtioGpuExitBoot (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + );=0D +=0D #endif // _VIRTIO_GPU_DXE_H_=0D diff --git a/OvmfPkg/VirtioGpuDxe/Commands.c b/OvmfPkg/VirtioGpuDxe/Command= s.c new file mode 100644 index 000000000000..804de950ff24 --- /dev/null +++ b/OvmfPkg/VirtioGpuDxe/Commands.c @@ -0,0 +1,214 @@ +/** @file=0D +=0D + VirtIo GPU initialization, and commands (primitives) for the GPU device.= =0D +=0D + Copyright (C) 2016, Red Hat, Inc.=0D +=0D + This program and the accompanying materials are licensed and made availa= ble=0D + under the terms and conditions of the BSD License which accompanies this= =0D + distribution. The full text of the license may be found at=0D + http://opensource.org/licenses/bsd-license.php=0D +=0D + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT=0D + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +=0D +#include "VirtioGpu.h"=0D +=0D +/**=0D + Configure the VirtIo GPU device that underlies VgpuDev.=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object to set up VirtIo messaging f= or.=0D + On input, the caller is responsible for having=0D + initialized VgpuDev->VirtIo. On output, VgpuDev-= >Ring=0D + has been initialized, and synchronous VirtIo GPU= =0D + commands (primitives) can be submitted to the de= vice.=0D +=0D + @retval EFI_SUCCESS VirtIo GPU configuration successful.=0D +=0D + @retval EFI_UNSUPPORTED The host-side configuration of the VirtIo GPU i= s not=0D + supported by this driver.=0D +=0D + @retval Error codes from underlying functions.=0D +**/=0D +EFI_STATUS=0D +VirtioGpuInit (=0D + IN OUT VGPU_DEV *VgpuDev=0D + )=0D +{=0D + UINT8 NextDevStat;=0D + EFI_STATUS Status;=0D + UINT64 Features;=0D + UINT16 QueueSize;=0D +=0D + //=0D + // Execute virtio-v1.0-cs04, 3.1.1 Driver Requirements: Device=0D + // Initialization.=0D + //=0D + // 1. Reset the device.=0D + //=0D + NextDevStat =3D 0;=0D + Status =3D VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevSta= t);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D +=0D + //=0D + // 2. Set the ACKNOWLEDGE status bit [...]=0D + //=0D + NextDevStat |=3D VSTAT_ACK;=0D + Status =3D VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevSta= t);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D +=0D + //=0D + // 3. Set the DRIVER status bit [...]=0D + //=0D + NextDevStat |=3D VSTAT_DRIVER;=0D + Status =3D VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevSta= t);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D +=0D + //=0D + // 4. Read device feature bits...=0D + //=0D + Status =3D VgpuDev->VirtIo->GetDeviceFeatures (VgpuDev->VirtIo, &Feature= s);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D + if ((Features & VIRTIO_F_VERSION_1) =3D=3D 0) {=0D + Status =3D EFI_UNSUPPORTED;=0D + goto Failed;=0D + }=0D + //=0D + // We only want the most basic 2D features.=0D + //=0D + Features &=3D VIRTIO_F_VERSION_1;=0D +=0D + //=0D + // ... and write the subset of feature bits understood by the [...] driv= er to=0D + // the device. [...]=0D + // 5. Set the FEATURES_OK status bit.=0D + // 6. Re-read device status to ensure the FEATURES_OK bit is still set [= ...]=0D + //=0D + Status =3D Virtio10WriteFeatures (VgpuDev->VirtIo, Features, &NextDevSta= t);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D +=0D + //=0D + // 7. Perform device-specific setup, including discovery of virtqueues f= or=0D + // the device [...]=0D + //=0D + Status =3D VgpuDev->VirtIo->SetQueueSel (VgpuDev->VirtIo,=0D + VIRTIO_GPU_CONTROL_QUEUE);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D + Status =3D VgpuDev->VirtIo->GetQueueNumMax (VgpuDev->VirtIo, &QueueSize)= ;=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D +=0D + //=0D + // We implement each VirtIo GPU command that we use with two descriptors= :=0D + // request, response.=0D + //=0D + if (QueueSize < 2) {=0D + Status =3D EFI_UNSUPPORTED;=0D + goto Failed;=0D + }=0D +=0D + //=0D + // [...] population of virtqueues [...]=0D + //=0D + Status =3D VirtioRingInit (QueueSize, &VgpuDev->Ring);=0D + if (EFI_ERROR (Status)) {=0D + goto Failed;=0D + }=0D + Status =3D VgpuDev->VirtIo->SetQueueAddress (VgpuDev->VirtIo, &VgpuDev->= Ring);=0D + if (EFI_ERROR (Status)) {=0D + goto ReleaseQueue;=0D + }=0D +=0D + //=0D + // 8. Set the DRIVER_OK status bit.=0D + //=0D + NextDevStat |=3D VSTAT_DRIVER_OK;=0D + Status =3D VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevSta= t);=0D + if (EFI_ERROR (Status)) {=0D + goto ReleaseQueue;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +=0D +ReleaseQueue:=0D + VirtioRingUninit (&VgpuDev->Ring);=0D +=0D +Failed:=0D + //=0D + // If any of these steps go irrecoverably wrong, the driver SHOULD set t= he=0D + // FAILED status bit to indicate that it has given up on the device (it = can=0D + // reset the device later to restart if desired). [...]=0D + //=0D + // VirtIo access failure here should not mask the original error.=0D + //=0D + NextDevStat |=3D VSTAT_FAILED;=0D + VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + De-configure the VirtIo GPU device that underlies VgpuDev.=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object to tear down VirtIo messagin= g=0D + for. On input, the caller is responsible for hav= ing=0D + called VirtioGpuInit(). On output, VgpuDev->Ring= has=0D + been uninitialized; VirtIo GPU commands (primiti= ves)=0D + can no longer be submitted to the device.=0D +**/=0D +VOID=0D +VirtioGpuUninit (=0D + IN OUT VGPU_DEV *VgpuDev=0D + )=0D +{=0D + //=0D + // Resetting the VirtIo device makes it release its resources and forget= its=0D + // configuration.=0D + //=0D + VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);=0D + VirtioRingUninit (&VgpuDev->Ring);=0D +}=0D +=0D +/**=0D + EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the= =0D + VirtIo device, causing it to release its resources and to forget its=0D + configuration.=0D +=0D + This function may only be called (that is, VGPU_DEV.ExitBoot may only be= =0D + signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is= =0D + called.=0D +=0D + @param[in] Event Event whose notification function is being invoked.= =0D +=0D + @param[in] Context Pointer to the associated VGPU_DEV object.=0D +**/=0D +VOID=0D +EFIAPI=0D +VirtioGpuExitBoot (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + VGPU_DEV *VgpuDev;=0D +=0D + VgpuDev =3D Context;=0D + VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);=0D +}=0D diff --git a/OvmfPkg/VirtioGpuDxe/DriverBinding.c b/OvmfPkg/VirtioGpuDxe/Dr= iverBinding.c index b902a07871e0..bdea55ef7dbf 100644 --- a/OvmfPkg/VirtioGpuDxe/DriverBinding.c +++ b/OvmfPkg/VirtioGpuDxe/DriverBinding.c @@ -643,19 +643,31 @@ VirtioGpuDriverBindingStart ( &VgpuDev->BusName, VgpuDevName, FALSE /* Iso639Language */)= ;=0D FreePool (VgpuDevName);=0D if (EFI_ERROR (Status)) {=0D goto FreeVgpuDev;=0D }=0D =0D + Status =3D VirtioGpuInit (VgpuDev);=0D + if (EFI_ERROR (Status)) {=0D + goto FreeVgpuDevBusName;=0D + }=0D +=0D + Status =3D gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBA= CK,=0D + VirtioGpuExitBoot, VgpuDev /* NotifyContext */,=0D + &VgpuDev->ExitBoot);=0D + if (EFI_ERROR (Status)) {=0D + goto UninitGpu;=0D + }=0D +=0D //=0D // Install the VGPU_DEV "protocol interface" on ControllerHandle.=0D //=0D Status =3D gBS->InstallProtocolInterface (&ControllerHandle,=0D &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, VgpuDev);=0D if (EFI_ERROR (Status)) {=0D - goto FreeVgpuDevBusName;=0D + goto CloseExitBoot;=0D }=0D =0D if (RemainingDevicePath !=3D NULL && IsDevicePathEnd (RemainingDeviceP= ath)) {=0D //=0D // No child handle should be produced; we're done.=0D //=0D @@ -690,12 +702,22 @@ VirtioGpuDriverBindingStart ( UninstallVgpuDev:=0D if (VirtIoBoundJustNow) {=0D gBS->UninstallProtocolInterface (ControllerHandle, &gEfiCallerIdGuid,= =0D VgpuDev);=0D }=0D =0D +CloseExitBoot:=0D + if (VirtIoBoundJustNow) {=0D + gBS->CloseEvent (VgpuDev->ExitBoot);=0D + }=0D +=0D +UninitGpu:=0D + if (VirtIoBoundJustNow) {=0D + VirtioGpuUninit (VgpuDev);=0D + }=0D +=0D FreeVgpuDevBusName:=0D if (VirtIoBoundJustNow) {=0D FreeUnicodeStringTable (VgpuDev->BusName);=0D }=0D =0D FreeVgpuDev:=0D @@ -758,12 +780,16 @@ VirtioGpuDriverBindingStop ( (VOID *)VgpuDev->VirtIo));=0D =0D Status =3D gBS->UninstallProtocolInterface (ControllerHandle,=0D &gEfiCallerIdGuid, VgpuDev);=0D ASSERT_EFI_ERROR (Status);=0D =0D + Status =3D gBS->CloseEvent (VgpuDev->ExitBoot);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + VirtioGpuUninit (VgpuDev);=0D FreeUnicodeStringTable (VgpuDev->BusName);=0D FreePool (VgpuDev);=0D =0D Status =3D gBS->CloseProtocol (ControllerHandle, &gVirtioDeviceProtoco= lGuid,=0D This->DriverBindingHandle, ControllerHandle);=0D ASSERT_EFI_ERROR (Status);=0D --=20 2.9.2