public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@ml01.01.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>,
	Jordan Justen <jordan.l.justen@intel.com>
Subject: [PATCH 08/11] OvmfPkg/VirtioGpuDxe: initialize and tear down VirtIo GPU device
Date: Fri, 19 Aug 2016 14:49:29 +0200	[thread overview]
Message-ID: <20160819124932.29711-9-lersek@redhat.com> (raw)
In-Reply-To: <20160819124932.29711-1-lersek@redhat.com>

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 <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Ref: https://tianocore.acgmultimedia.com/show_bug.cgi?id=66
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 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/VirtioGpu.inf
index 948350dbce21..7a6269eded51 100644
--- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
+++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
@@ -21,12 +21,13 @@ [Defines]
   FILE_GUID                      = D6099B94-CD97-4CC5-8714-7F6312701A8A
   MODULE_TYPE                    = UEFI_DRIVER
   VERSION_STRING                 = 1.0
   ENTRY_POINT                    = VirtioGpuEntryPoint
 
 [Sources]
+  Commands.c
   DriverBinding.c
   VirtioGpu.h
 
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
@@ -37,11 +38,12 @@ [LibraryClasses]
   DevicePathLib
   MemoryAllocationLib
   PrintLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
+  VirtioLib
 
 [Protocols]
   gEfiDevicePathProtocolGuid     ## TO_START ## BY_START
   gEfiPciIoProtocolGuid          ## TO_START
   gVirtioDeviceProtocolGuid      ## TO_START
diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h b/OvmfPkg/VirtioGpuDxe/VirtioGpu.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
   // form because it can theoretically support several languages. Never NULL.
   //
   EFI_UNICODE_STRING_TABLE *BusName;
 
   //
+  // VirtIo ring used for VirtIo communication.
+  //
+  VRING                    Ring;
+
+  //
+  // Event to be signaled at ExitBootServices().
+  //
+  EFI_EVENT                ExitBoot;
+
+  //
   // The Child field references the GOP wrapper structure. If this pointer is
   // NULL, then the hybrid driver has bound (i.e., started) the
   // VIRTIO_DEVICE_PROTOCOL controller without producing the child GOP
   // controller (that is, after Start() was called with RemainingDevicePath
   // pointing to and End of Device Path node). Child can be created and
   // destroyed, even repeatedly, independently of VGPU_DEV.
@@ -100,7 +110,65 @@ struct VGPU_GOP_STRUCT {
   //
   // For now it is just a placeholder.
   //
   UINT8                                Gop;
 };
 
+//
+// VirtIo GPU initialization, and commands (primitives) for the GPU device.
+//
+/**
+  Configure the VirtIo GPU device that underlies VgpuDev.
+
+  @param[in,out] VgpuDev  The VGPU_DEV object to set up VirtIo messaging for.
+                          On input, the caller is responsible for having
+                          initialized VgpuDev->VirtIo. On output, VgpuDev->Ring
+                          has been initialized, and synchronous VirtIo GPU
+                          commands (primitives) can be submitted to the device.
+
+  @retval EFI_SUCCESS      VirtIo GPU configuration successful.
+
+  @retval EFI_UNSUPPORTED  The host-side configuration of the VirtIo GPU is not
+                           supported by this driver.
+
+  @retval                  Error codes from underlying functions.
+**/
+EFI_STATUS
+VirtioGpuInit (
+  IN OUT VGPU_DEV *VgpuDev
+  );
+
+/**
+  De-configure the VirtIo GPU device that underlies VgpuDev.
+
+  @param[in,out] VgpuDev  The VGPU_DEV object to tear down VirtIo messaging
+                          for. On input, the caller is responsible for having
+                          called VirtioGpuInit(). On output, VgpuDev->Ring has
+                          been uninitialized; VirtIo GPU commands (primitives)
+                          can no longer be submitted to the device.
+**/
+VOID
+VirtioGpuUninit (
+  IN OUT VGPU_DEV *VgpuDev
+  );
+
+/**
+  EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the
+  VirtIo device, causing it to release its resources and to forget its
+  configuration.
+
+  This function may only be called (that is, VGPU_DEV.ExitBoot may only be
+  signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is
+  called.
+
+  @param[in] Event    Event whose notification function is being invoked.
+
+  @param[in] Context  Pointer to the associated VGPU_DEV object.
+**/
+VOID
+EFIAPI
+VirtioGpuExitBoot (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  );
+
 #endif // _VIRTIO_GPU_DXE_H_
diff --git a/OvmfPkg/VirtioGpuDxe/Commands.c b/OvmfPkg/VirtioGpuDxe/Commands.c
new file mode 100644
index 000000000000..804de950ff24
--- /dev/null
+++ b/OvmfPkg/VirtioGpuDxe/Commands.c
@@ -0,0 +1,214 @@
+/** @file
+
+  VirtIo GPU initialization, and commands (primitives) for the GPU device.
+
+  Copyright (C) 2016, Red Hat, Inc.
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution. The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/VirtioGpu.h>
+#include <Library/VirtioLib.h>
+
+#include "VirtioGpu.h"
+
+/**
+  Configure the VirtIo GPU device that underlies VgpuDev.
+
+  @param[in,out] VgpuDev  The VGPU_DEV object to set up VirtIo messaging for.
+                          On input, the caller is responsible for having
+                          initialized VgpuDev->VirtIo. On output, VgpuDev->Ring
+                          has been initialized, and synchronous VirtIo GPU
+                          commands (primitives) can be submitted to the device.
+
+  @retval EFI_SUCCESS      VirtIo GPU configuration successful.
+
+  @retval EFI_UNSUPPORTED  The host-side configuration of the VirtIo GPU is not
+                           supported by this driver.
+
+  @retval                  Error codes from underlying functions.
+**/
+EFI_STATUS
+VirtioGpuInit (
+  IN OUT VGPU_DEV *VgpuDev
+  )
+{
+  UINT8      NextDevStat;
+  EFI_STATUS Status;
+  UINT64     Features;
+  UINT16     QueueSize;
+
+  //
+  // Execute virtio-v1.0-cs04, 3.1.1 Driver Requirements: Device
+  // Initialization.
+  //
+  // 1. Reset the device.
+  //
+  NextDevStat = 0;
+  Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  //
+  // 2. Set the ACKNOWLEDGE status bit [...]
+  //
+  NextDevStat |= VSTAT_ACK;
+  Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  //
+  // 3. Set the DRIVER status bit [...]
+  //
+  NextDevStat |= VSTAT_DRIVER;
+  Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  //
+  // 4. Read device feature bits...
+  //
+  Status = VgpuDev->VirtIo->GetDeviceFeatures (VgpuDev->VirtIo, &Features);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+  if ((Features & VIRTIO_F_VERSION_1) == 0) {
+    Status = EFI_UNSUPPORTED;
+    goto Failed;
+  }
+  //
+  // We only want the most basic 2D features.
+  //
+  Features &= VIRTIO_F_VERSION_1;
+
+  //
+  // ... and write the subset of feature bits understood by the [...] driver to
+  // the device. [...]
+  // 5. Set the FEATURES_OK status bit.
+  // 6. Re-read device status to ensure the FEATURES_OK bit is still set [...]
+  //
+  Status = Virtio10WriteFeatures (VgpuDev->VirtIo, Features, &NextDevStat);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  //
+  // 7. Perform device-specific setup, including discovery of virtqueues for
+  // the device [...]
+  //
+  Status = VgpuDev->VirtIo->SetQueueSel (VgpuDev->VirtIo,
+                              VIRTIO_GPU_CONTROL_QUEUE);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+  Status = VgpuDev->VirtIo->GetQueueNumMax (VgpuDev->VirtIo, &QueueSize);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  //
+  // We implement each VirtIo GPU command that we use with two descriptors:
+  // request, response.
+  //
+  if (QueueSize < 2) {
+    Status = EFI_UNSUPPORTED;
+    goto Failed;
+  }
+
+  //
+  // [...] population of virtqueues [...]
+  //
+  Status = VirtioRingInit (QueueSize, &VgpuDev->Ring);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+  Status = VgpuDev->VirtIo->SetQueueAddress (VgpuDev->VirtIo, &VgpuDev->Ring);
+  if (EFI_ERROR (Status)) {
+    goto ReleaseQueue;
+  }
+
+  //
+  // 8. Set the DRIVER_OK status bit.
+  //
+  NextDevStat |= VSTAT_DRIVER_OK;
+  Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
+  if (EFI_ERROR (Status)) {
+    goto ReleaseQueue;
+  }
+
+  return EFI_SUCCESS;
+
+ReleaseQueue:
+  VirtioRingUninit (&VgpuDev->Ring);
+
+Failed:
+  //
+  // If any of these steps go irrecoverably wrong, the driver SHOULD set the
+  // FAILED status bit to indicate that it has given up on the device (it can
+  // reset the device later to restart if desired). [...]
+  //
+  // VirtIo access failure here should not mask the original error.
+  //
+  NextDevStat |= VSTAT_FAILED;
+  VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
+
+  return Status;
+}
+
+/**
+  De-configure the VirtIo GPU device that underlies VgpuDev.
+
+  @param[in,out] VgpuDev  The VGPU_DEV object to tear down VirtIo messaging
+                          for. On input, the caller is responsible for having
+                          called VirtioGpuInit(). On output, VgpuDev->Ring has
+                          been uninitialized; VirtIo GPU commands (primitives)
+                          can no longer be submitted to the device.
+**/
+VOID
+VirtioGpuUninit (
+  IN OUT VGPU_DEV *VgpuDev
+  )
+{
+  //
+  // Resetting the VirtIo device makes it release its resources and forget its
+  // configuration.
+  //
+  VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);
+  VirtioRingUninit (&VgpuDev->Ring);
+}
+
+/**
+  EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the
+  VirtIo device, causing it to release its resources and to forget its
+  configuration.
+
+  This function may only be called (that is, VGPU_DEV.ExitBoot may only be
+  signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is
+  called.
+
+  @param[in] Event    Event whose notification function is being invoked.
+
+  @param[in] Context  Pointer to the associated VGPU_DEV object.
+**/
+VOID
+EFIAPI
+VirtioGpuExitBoot (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  VGPU_DEV *VgpuDev;
+
+  VgpuDev = Context;
+  VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);
+}
diff --git a/OvmfPkg/VirtioGpuDxe/DriverBinding.c b/OvmfPkg/VirtioGpuDxe/DriverBinding.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 */);
     FreePool (VgpuDevName);
     if (EFI_ERROR (Status)) {
       goto FreeVgpuDev;
     }
 
+    Status = VirtioGpuInit (VgpuDev);
+    if (EFI_ERROR (Status)) {
+      goto FreeVgpuDevBusName;
+    }
+
+    Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+                    VirtioGpuExitBoot, VgpuDev /* NotifyContext */,
+                    &VgpuDev->ExitBoot);
+    if (EFI_ERROR (Status)) {
+      goto UninitGpu;
+    }
+
     //
     // Install the VGPU_DEV "protocol interface" on ControllerHandle.
     //
     Status = gBS->InstallProtocolInterface (&ControllerHandle,
                     &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, VgpuDev);
     if (EFI_ERROR (Status)) {
-      goto FreeVgpuDevBusName;
+      goto CloseExitBoot;
     }
 
     if (RemainingDevicePath != NULL && IsDevicePathEnd (RemainingDevicePath)) {
       //
       // No child handle should be produced; we're done.
       //
@@ -690,12 +702,22 @@ VirtioGpuDriverBindingStart (
 UninstallVgpuDev:
   if (VirtIoBoundJustNow) {
     gBS->UninstallProtocolInterface (ControllerHandle, &gEfiCallerIdGuid,
            VgpuDev);
   }
 
+CloseExitBoot:
+  if (VirtIoBoundJustNow) {
+    gBS->CloseEvent (VgpuDev->ExitBoot);
+  }
+
+UninitGpu:
+  if (VirtIoBoundJustNow) {
+    VirtioGpuUninit (VgpuDev);
+  }
+
 FreeVgpuDevBusName:
   if (VirtIoBoundJustNow) {
     FreeUnicodeStringTable (VgpuDev->BusName);
   }
 
 FreeVgpuDev:
@@ -758,12 +780,16 @@ VirtioGpuDriverBindingStop (
       (VOID *)VgpuDev->VirtIo));
 
     Status = gBS->UninstallProtocolInterface (ControllerHandle,
                     &gEfiCallerIdGuid, VgpuDev);
     ASSERT_EFI_ERROR (Status);
 
+    Status = gBS->CloseEvent (VgpuDev->ExitBoot);
+    ASSERT_EFI_ERROR (Status);
+
+    VirtioGpuUninit (VgpuDev);
     FreeUnicodeStringTable (VgpuDev->BusName);
     FreePool (VgpuDev);
 
     Status = gBS->CloseProtocol (ControllerHandle, &gVirtioDeviceProtocolGuid,
                     This->DriverBindingHandle, ControllerHandle);
     ASSERT_EFI_ERROR (Status);
-- 
2.9.2




  parent reply	other threads:[~2016-08-19 12:49 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-19 12:49 [PATCH 00/11] OvmfPkg, ArmVirtPkg: GOP driver for the VirtIo GPU (virtio-gpu-pci) Laszlo Ersek
2016-08-19 12:49 ` [PATCH 01/11] OvmfPkg/QemuVideoDxe: don't incorrectly bind virtio-gpu-pci Laszlo Ersek
2016-08-19 12:49 ` [PATCH 02/11] OvmfPkg/Virtio10Dxe: don't bind virtio-vga Laszlo Ersek
2016-08-19 12:49 ` [PATCH 03/11] OvmfPkg/PlatformBootManagerLib: relax device class requirement for ConOut Laszlo Ersek
2016-08-19 12:49 ` [PATCH 04/11] OvmfPkg/IndustryStandard: add type definitions for the virtio GPU device Laszlo Ersek
2016-08-19 12:49 ` [PATCH 05/11] OvmfPkg/VirtioGpuDxe: introduce with Component Name 2 and Driver Binding Laszlo Ersek
2016-08-19 12:49 ` [PATCH 06/11] OvmfPkg: include VirtioGpuDxe in the platform DSC/FDF files Laszlo Ersek
2016-08-19 12:49 ` [PATCH 07/11] ArmVirtPkg/ArmVirtQemu: " Laszlo Ersek
2016-08-19 13:14   ` Ard Biesheuvel
2016-08-19 12:49 ` Laszlo Ersek [this message]
2016-08-19 12:49 ` [PATCH 09/11] OvmfPkg/VirtioGpuDxe: provide functions for sending VirtIo GPU commands Laszlo Ersek
2016-08-19 12:49 ` [PATCH 10/11] OvmfPkg/VirtioGpuDxe: implement EFI_GRAPHICS_OUTPUT_PROTOCOL Laszlo Ersek
2016-08-19 12:49 ` [PATCH 11/11] ArmVirtPkg: remove PcdKludgeMapPciMmioAsCached Laszlo Ersek
2016-08-19 13:16   ` Ard Biesheuvel
2016-08-19 13:06 ` [PATCH 00/11] OvmfPkg, ArmVirtPkg: GOP driver for the VirtIo GPU (virtio-gpu-pci) Ard Biesheuvel
2016-08-19 14:25   ` Laszlo Ersek
2016-08-31 20:43     ` Jordan Justen
2016-09-01  7:44       ` Ard Biesheuvel
2016-09-01 16:48         ` Laszlo Ersek
2016-09-01 16:29       ` Laszlo Ersek
2016-09-01 18:03         ` Jordan Justen
2016-09-01 18:46           ` Laszlo Ersek
2016-09-01 19:52             ` Jordan Justen
2016-09-01 20:23               ` Ard Biesheuvel
2016-09-01 20:26                 ` Ard Biesheuvel
2016-09-01 20:52                 ` Jordan Justen
2016-09-01 20:44               ` Laszlo Ersek
2016-09-05 14:17               ` Gerd Hoffmann
2016-08-30 15:07 ` Laszlo Ersek
2016-09-01 20:32 ` Jordan Justen
2016-09-01 21:07   ` Laszlo Ersek
2016-09-01 22:02 ` Laszlo Ersek
     [not found]   ` <57CD6463.90903@suse.de>
2016-09-05 12:56     ` Laszlo Ersek
     [not found]       ` <57CD6C25.7000406@suse.de>
2016-09-05 13:17         ` Laszlo Ersek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160819124932.29711-9-lersek@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox