summaryrefslogtreecommitdiff
path: root/OvmfPkg
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg')
-rw-r--r--OvmfPkg/VirtioGpuDxe/Commands.c214
-rw-r--r--OvmfPkg/VirtioGpuDxe/DriverBinding.c28
-rw-r--r--OvmfPkg/VirtioGpuDxe/VirtioGpu.h68
-rw-r--r--OvmfPkg/VirtioGpuDxe/VirtioGpu.inf2
4 files changed, 311 insertions, 1 deletions
diff --git a/OvmfPkg/VirtioGpuDxe/Commands.c b/OvmfPkg/VirtioGpuDxe/Commands.c
new file mode 100644
index 0000000..804de95
--- /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 b902a07..bdea55e 100644
--- a/OvmfPkg/VirtioGpuDxe/DriverBinding.c
+++ b/OvmfPkg/VirtioGpuDxe/DriverBinding.c
@@ -646,13 +646,25 @@ VirtioGpuDriverBindingStart (
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)) {
@@ -693,6 +705,16 @@ UninstallVgpuDev:
VgpuDev);
}
+CloseExitBoot:
+ if (VirtIoBoundJustNow) {
+ gBS->CloseEvent (VgpuDev->ExitBoot);
+ }
+
+UninitGpu:
+ if (VirtIoBoundJustNow) {
+ VirtioGpuUninit (VgpuDev);
+ }
+
FreeVgpuDevBusName:
if (VirtIoBoundJustNow) {
FreeUnicodeStringTable (VgpuDev->BusName);
@@ -761,6 +783,10 @@ VirtioGpuDriverBindingStop (
&gEfiCallerIdGuid, VgpuDev);
ASSERT_EFI_ERROR (Status);
+ Status = gBS->CloseEvent (VgpuDev->ExitBoot);
+ ASSERT_EFI_ERROR (Status);
+
+ VirtioGpuUninit (VgpuDev);
FreeUnicodeStringTable (VgpuDev->BusName);
FreePool (VgpuDev);
diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h
index ca5805d..97767db 100644
--- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h
+++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h
@@ -49,6 +49,16 @@ typedef struct {
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
@@ -103,4 +113,62 @@ struct VGPU_GOP_STRUCT {
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/VirtioGpu.inf b/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
index 948350d..7a6269e 100644
--- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
+++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
@@ -24,6 +24,7 @@
ENTRY_POINT = VirtioGpuEntryPoint
[Sources]
+ Commands.c
DriverBinding.c
VirtioGpu.h
@@ -40,6 +41,7 @@
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib
+ VirtioLib
[Protocols]
gEfiDevicePathProtocolGuid ## TO_START ## BY_START