]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/VirtioGpuDxe: provide functions for sending VirtIo GPU commands
authorLaszlo Ersek <lersek@redhat.com>
Thu, 18 Aug 2016 15:00:03 +0000 (17:00 +0200)
committerLaszlo Ersek <lersek@redhat.com>
Thu, 1 Sep 2016 20:55:53 +0000 (22:55 +0200)
In this patch we add a "workhorse" function called VirtioGpuSendCommand(),
and implement seven simple RPCs atop, for the command types listed in
"OvmfPkg/Include/IndustryStandard/VirtioGpu.h".

These functions will be called by our EFI_GRAPHICS_OUTPUT_PROTOCOL
implementation.

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>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
OvmfPkg/VirtioGpuDxe/Commands.c
OvmfPkg/VirtioGpuDxe/VirtioGpu.h

index 804de950ff24dbf6f386dc8c1aa590608381ffdd..b369dc3a7abc06f77798a47ca156c3a1f930ac3f 100644 (file)
@@ -14,7 +14,6 @@
 \r
 **/\r
 \r
-#include <IndustryStandard/VirtioGpu.h>\r
 #include <Library/VirtioLib.h>\r
 \r
 #include "VirtioGpu.h"\r
@@ -212,3 +211,349 @@ VirtioGpuExitBoot (
   VgpuDev = Context;\r
   VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);\r
 }\r
+\r
+/**\r
+  Internal utility function that sends a request to the VirtIo GPU device\r
+  model, awaits the answer from the host, and returns a status.\r
+\r
+  @param[in,out] VgpuDev  The VGPU_DEV object that represents the VirtIo GPU\r
+                          device. The caller is responsible to have\r
+                          successfully invoked VirtioGpuInit() on VgpuDev\r
+                          previously, while VirtioGpuUninit() must not have\r
+                          been called on VgpuDev.\r
+\r
+  @param[in] RequestType  The type of the request. The caller is responsible\r
+                          for providing a VirtioGpuCmd* RequestType which, on\r
+                          success, elicits a VirtioGpuRespOkNodata response\r
+                          from the host.\r
+\r
+  @param[in] Fence        Whether to enable fencing for this request. Fencing\r
+                          forces the host to complete the command before\r
+                          producing a response. If Fence is TRUE, then\r
+                          VgpuDev->FenceId is consumed, and incremented.\r
+\r
+  @param[in,out] Header   Pointer to the caller-allocated request object. The\r
+                          request must start with VIRTIO_GPU_CONTROL_HEADER.\r
+                          This function overwrites all fields of Header before\r
+                          submitting the request to the host:\r
+\r
+                          - it sets Type from RequestType,\r
+\r
+                          - it sets Flags and FenceId based on Fence,\r
+\r
+                          - it zeroes CtxId and Padding.\r
+\r
+  @param[in] RequestSize  Size of the entire caller-allocated request object,\r
+                          including the leading VIRTIO_GPU_CONTROL_HEADER.\r
+\r
+  @retval EFI_SUCCESS            Operation successful.\r
+\r
+  @retval EFI_DEVICE_ERROR       The host rejected the request. The host error\r
+                                 code has been logged on the EFI_D_ERROR level.\r
+\r
+  @return                        Codes for unexpected errors in VirtIo\r
+                                 messaging.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+VirtioGpuSendCommand (\r
+  IN OUT VGPU_DEV                           *VgpuDev,\r
+  IN     VIRTIO_GPU_CONTROL_TYPE            RequestType,\r
+  IN     BOOLEAN                            Fence,\r
+  IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Header,\r
+  IN     UINTN                              RequestSize\r
+  )\r
+{\r
+  DESC_INDICES                       Indices;\r
+  volatile VIRTIO_GPU_CONTROL_HEADER Response;\r
+  EFI_STATUS                         Status;\r
+  UINT32                             ResponseSize;\r
+\r
+  //\r
+  // Initialize Header.\r
+  //\r
+  Header->Type      = RequestType;\r
+  if (Fence) {\r
+    Header->Flags   = VIRTIO_GPU_FLAG_FENCE;\r
+    Header->FenceId = VgpuDev->FenceId++;\r
+  } else {\r
+    Header->Flags   = 0;\r
+    Header->FenceId = 0;\r
+  }\r
+  Header->CtxId     = 0;\r
+  Header->Padding   = 0;\r
+\r
+  ASSERT (RequestSize >= sizeof *Header);\r
+\r
+  //\r
+  // Compose the descriptor chain.\r
+  //\r
+  VirtioPrepare (&VgpuDev->Ring, &Indices);\r
+  VirtioAppendDesc (&VgpuDev->Ring, (UINTN)Header, RequestSize,\r
+    VRING_DESC_F_NEXT, &Indices);\r
+  VirtioAppendDesc (&VgpuDev->Ring, (UINTN)&Response, sizeof Response,\r
+    VRING_DESC_F_WRITE, &Indices);\r
+\r
+  //\r
+  // Send the command.\r
+  //\r
+  Status = VirtioFlush (VgpuDev->VirtIo, VIRTIO_GPU_CONTROL_QUEUE,\r
+             &VgpuDev->Ring, &Indices, &ResponseSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Parse the response.\r
+  //\r
+  if (ResponseSize != sizeof Response) {\r
+    DEBUG ((EFI_D_ERROR, "%a: malformed response to Request=0x%x\n",\r
+      __FUNCTION__, (UINT32)RequestType));\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  if (Response.Type == VirtioGpuRespOkNodata) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DEBUG ((EFI_D_ERROR, "%a: Request=0x%x Response=0x%x\n", __FUNCTION__,\r
+    (UINT32)RequestType, Response.Type));\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+  The following functions send requests to the VirtIo GPU device model, await\r
+  the answer from the host, and return a status. They share the following\r
+  interface details:\r
+\r
+  @param[in,out] VgpuDev  The VGPU_DEV object that represents the VirtIo GPU\r
+                          device. The caller is responsible to have\r
+                          successfully invoked VirtioGpuInit() on VgpuDev\r
+                          previously, while VirtioGpuUninit() must not have\r
+                          been called on VgpuDev.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid command-specific parameters were\r
+                                 detected by this driver.\r
+\r
+  @retval EFI_SUCCESS            Operation successful.\r
+\r
+  @retval EFI_DEVICE_ERROR       The host rejected the request. The host error\r
+                                 code has been logged on the EFI_D_ERROR level.\r
+\r
+  @return                        Codes for unexpected errors in VirtIo\r
+                                 messaging.\r
+\r
+  For the command-specific parameters, please consult the GPU Device section of\r
+  the VirtIo 1.0 specification (see references in\r
+  "OvmfPkg/Include/IndustryStandard/VirtioGpu.h").\r
+**/\r
+EFI_STATUS\r
+VirtioGpuResourceCreate2d (\r
+  IN OUT VGPU_DEV           *VgpuDev,\r
+  IN     UINT32             ResourceId,\r
+  IN     VIRTIO_GPU_FORMATS Format,\r
+  IN     UINT32             Width,\r
+  IN     UINT32             Height\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_RESOURCE_CREATE_2D Request;\r
+\r
+  if (ResourceId == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Request.ResourceId = ResourceId;\r
+  Request.Format     = (UINT32)Format;\r
+  Request.Width      = Width;\r
+  Request.Height     = Height;\r
+\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdResourceCreate2d,\r
+           FALSE,                        // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceUnref (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   ResourceId\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_RESOURCE_UNREF Request;\r
+\r
+  if (ResourceId == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Request.ResourceId = ResourceId;\r
+  Request.Padding    = 0;\r
+\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdResourceUnref,\r
+           FALSE,                     // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceAttachBacking (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   ResourceId,\r
+  IN     VOID     *FirstBackingPage,\r
+  IN     UINTN    NumberOfPages\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_RESOURCE_ATTACH_BACKING Request;\r
+\r
+  if (ResourceId == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Request.ResourceId    = ResourceId;\r
+  Request.NrEntries     = 1;\r
+  Request.Entry.Addr    = (UINTN)FirstBackingPage;\r
+  Request.Entry.Length  = (UINT32)EFI_PAGES_TO_SIZE (NumberOfPages);\r
+  Request.Entry.Padding = 0;\r
+\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdResourceAttachBacking,\r
+           FALSE,                             // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceDetachBacking (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   ResourceId\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_RESOURCE_DETACH_BACKING Request;\r
+\r
+  if (ResourceId == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Request.ResourceId = ResourceId;\r
+  Request.Padding    = 0;\r
+\r
+  //\r
+  // In this case, we set Fence to TRUE, because after this function returns,\r
+  // the caller might reasonably want to repurpose the backing pages\r
+  // immediately. Thus we should ensure that the host releases all references\r
+  // to the backing pages before we return.\r
+  //\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdResourceDetachBacking,\r
+           TRUE,                              // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+VirtioGpuSetScanout (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   X,\r
+  IN     UINT32   Y,\r
+  IN     UINT32   Width,\r
+  IN     UINT32   Height,\r
+  IN     UINT32   ScanoutId,\r
+  IN     UINT32   ResourceId\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_SET_SCANOUT Request;\r
+\r
+  //\r
+  // Unlike for most other commands, ResourceId=0 is valid; it\r
+  // is used to disable a scanout.\r
+  //\r
+  Request.Rectangle.X      = X;\r
+  Request.Rectangle.Y      = Y;\r
+  Request.Rectangle.Width  = Width;\r
+  Request.Rectangle.Height = Height;\r
+  Request.ScanoutId        = ScanoutId;\r
+  Request.ResourceId       = ResourceId;\r
+\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdSetScanout,\r
+           FALSE,                  // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+VirtioGpuTransferToHost2d (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   X,\r
+  IN     UINT32   Y,\r
+  IN     UINT32   Width,\r
+  IN     UINT32   Height,\r
+  IN     UINT64   Offset,\r
+  IN     UINT32   ResourceId\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D Request;\r
+\r
+  if (ResourceId == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Request.Rectangle.X      = X;\r
+  Request.Rectangle.Y      = Y;\r
+  Request.Rectangle.Width  = Width;\r
+  Request.Rectangle.Height = Height;\r
+  Request.Offset           = Offset;\r
+  Request.ResourceId       = ResourceId;\r
+  Request.Padding          = 0;\r
+\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdTransferToHost2d,\r
+           FALSE,                        // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceFlush (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   X,\r
+  IN     UINT32   Y,\r
+  IN     UINT32   Width,\r
+  IN     UINT32   Height,\r
+  IN     UINT32   ResourceId\r
+  )\r
+{\r
+  volatile VIRTIO_GPU_RESOURCE_FLUSH Request;\r
+\r
+  if (ResourceId == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Request.Rectangle.X      = X;\r
+  Request.Rectangle.Y      = Y;\r
+  Request.Rectangle.Width  = Width;\r
+  Request.Rectangle.Height = Height;\r
+  Request.ResourceId       = ResourceId;\r
+  Request.Padding          = 0;\r
+\r
+  return VirtioGpuSendCommand (\r
+           VgpuDev,\r
+           VirtioGpuCmdResourceFlush,\r
+           FALSE,                     // Fence\r
+           &Request.Header,\r
+           sizeof Request\r
+           );\r
+}\r
index 97767dba709f9e9eef43221207ef7d72921deba2..f8839922487ca07d44572abae27ba30271afc821 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef _VIRTIO_GPU_DXE_H_\r
 #define _VIRTIO_GPU_DXE_H_\r
 \r
+#include <IndustryStandard/VirtioGpu.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Protocol/VirtioDevice.h>\r
@@ -58,6 +59,11 @@ typedef struct {
   //\r
   EFI_EVENT                ExitBoot;\r
 \r
+  //\r
+  // Common running counter for all VirtIo GPU requests that ask for fencing.\r
+  //\r
+  UINT64                   FenceId;\r
+\r
   //\r
   // The Child field references the GOP wrapper structure. If this pointer is\r
   // NULL, then the hybrid driver has bound (i.e., started) the\r
@@ -171,4 +177,91 @@ VirtioGpuExitBoot (
   IN VOID      *Context\r
   );\r
 \r
+/**\r
+  The following functions send requests to the VirtIo GPU device model, await\r
+  the answer from the host, and return a status. They share the following\r
+  interface details:\r
+\r
+  @param[in,out] VgpuDev  The VGPU_DEV object that represents the VirtIo GPU\r
+                          device. The caller is responsible to have\r
+                          successfully invoked VirtioGpuInit() on VgpuDev\r
+                          previously, while VirtioGpuUninit() must not have\r
+                          been called on VgpuDev.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid command-specific parameters were\r
+                                 detected by this driver.\r
+\r
+  @retval EFI_SUCCESS            Operation successful.\r
+\r
+  @retval EFI_DEVICE_ERROR       The host rejected the request. The host error\r
+                                 code has been logged on the EFI_D_ERROR level.\r
+\r
+  @return                        Codes for unexpected errors in VirtIo\r
+                                 messaging.\r
+\r
+  For the command-specific parameters, please consult the GPU Device section of\r
+  the VirtIo 1.0 specification (see references in\r
+  "OvmfPkg/Include/IndustryStandard/VirtioGpu.h").\r
+**/\r
+EFI_STATUS\r
+VirtioGpuResourceCreate2d (\r
+  IN OUT VGPU_DEV           *VgpuDev,\r
+  IN     UINT32             ResourceId,\r
+  IN     VIRTIO_GPU_FORMATS Format,\r
+  IN     UINT32             Width,\r
+  IN     UINT32             Height\r
+  );\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceUnref (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   ResourceId\r
+  );\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceAttachBacking (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   ResourceId,\r
+  IN     VOID     *FirstBackingPage,\r
+  IN     UINTN    NumberOfPages\r
+  );\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceDetachBacking (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   ResourceId\r
+  );\r
+\r
+EFI_STATUS\r
+VirtioGpuSetScanout (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   X,\r
+  IN     UINT32   Y,\r
+  IN     UINT32   Width,\r
+  IN     UINT32   Height,\r
+  IN     UINT32   ScanoutId,\r
+  IN     UINT32   ResourceId\r
+  );\r
+\r
+EFI_STATUS\r
+VirtioGpuTransferToHost2d (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   X,\r
+  IN     UINT32   Y,\r
+  IN     UINT32   Width,\r
+  IN     UINT32   Height,\r
+  IN     UINT64   Offset,\r
+  IN     UINT32   ResourceId\r
+  );\r
+\r
+EFI_STATUS\r
+VirtioGpuResourceFlush (\r
+  IN OUT VGPU_DEV *VgpuDev,\r
+  IN     UINT32   X,\r
+  IN     UINT32   Y,\r
+  IN     UINT32   Width,\r
+  IN     UINT32   Height,\r
+  IN     UINT32   ResourceId\r
+  );\r
+\r
 #endif // _VIRTIO_GPU_DXE_H_\r