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.biesheu...@linaro.org> Cc: Jordan Justen <jordan.l.jus...@intel.com> Ref: https://tianocore.acgmultimedia.com/show_bug.cgi?id=66 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <ler...@redhat.com> --- OvmfPkg/VirtioGpuDxe/VirtioGpu.h | 93 ++++++ OvmfPkg/VirtioGpuDxe/Commands.c | 347 +++++++++++++++++++- 2 files changed, 439 insertions(+), 1 deletion(-) diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h index 97767dba709f..f8839922487c 100644 --- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h +++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h @@ -14,12 +14,13 @@ **/ #ifndef _VIRTIO_GPU_DXE_H_ #define _VIRTIO_GPU_DXE_H_ +#include <IndustryStandard/VirtioGpu.h> #include <Library/DebugLib.h> #include <Library/UefiLib.h> #include <Protocol/VirtioDevice.h> // // Forward declaration of VGPU_GOP. @@ -56,12 +57,17 @@ typedef struct { // // Event to be signaled at ExitBootServices(). // EFI_EVENT ExitBoot; // + // Common running counter for all VirtIo GPU requests that ask for fencing. + // + UINT64 FenceId; + + // // 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. @@ -168,7 +174,94 @@ VOID EFIAPI VirtioGpuExitBoot ( IN EFI_EVENT Event, IN VOID *Context ); +/** + The following functions send requests to the VirtIo GPU device model, await + the answer from the host, and return a status. They share the following + interface details: + + @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU + device. The caller is responsible to have + successfully invoked VirtioGpuInit() on VgpuDev + previously, while VirtioGpuUninit() must not have + been called on VgpuDev. + + @retval EFI_INVALID_PARAMETER Invalid command-specific parameters were + detected by this driver. + + @retval EFI_SUCCESS Operation successful. + + @retval EFI_DEVICE_ERROR The host rejected the request. The host error + code has been logged on the EFI_D_ERROR level. + + @return Codes for unexpected errors in VirtIo + messaging. + + For the command-specific parameters, please consult the GPU Device section of + the VirtIo 1.0 specification (see references in + "OvmfPkg/Include/IndustryStandard/VirtioGpu.h"). +**/ +EFI_STATUS +VirtioGpuResourceCreate2d ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId, + IN VIRTIO_GPU_FORMATS Format, + IN UINT32 Width, + IN UINT32 Height + ); + +EFI_STATUS +VirtioGpuResourceUnref ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId + ); + +EFI_STATUS +VirtioGpuResourceAttachBacking ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId, + IN VOID *FirstBackingPage, + IN UINTN NumberOfPages + ); + +EFI_STATUS +VirtioGpuResourceDetachBacking ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId + ); + +EFI_STATUS +VirtioGpuSetScanout ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 X, + IN UINT32 Y, + IN UINT32 Width, + IN UINT32 Height, + IN UINT32 ScanoutId, + IN UINT32 ResourceId + ); + +EFI_STATUS +VirtioGpuTransferToHost2d ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 X, + IN UINT32 Y, + IN UINT32 Width, + IN UINT32 Height, + IN UINT64 Offset, + IN UINT32 ResourceId + ); + +EFI_STATUS +VirtioGpuResourceFlush ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 X, + IN UINT32 Y, + IN UINT32 Width, + IN UINT32 Height, + IN UINT32 ResourceId + ); + #endif // _VIRTIO_GPU_DXE_H_ diff --git a/OvmfPkg/VirtioGpuDxe/Commands.c b/OvmfPkg/VirtioGpuDxe/Commands.c index 804de950ff24..b369dc3a7abc 100644 --- a/OvmfPkg/VirtioGpuDxe/Commands.c +++ b/OvmfPkg/VirtioGpuDxe/Commands.c @@ -11,13 +11,12 @@ 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. @@ -209,6 +208,352 @@ VirtioGpuExitBoot ( { VGPU_DEV *VgpuDev; VgpuDev = Context; VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0); } + +/** + Internal utility function that sends a request to the VirtIo GPU device + model, awaits the answer from the host, and returns a status. + + @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU + device. The caller is responsible to have + successfully invoked VirtioGpuInit() on VgpuDev + previously, while VirtioGpuUninit() must not have + been called on VgpuDev. + + @param[in] RequestType The type of the request. The caller is responsible + for providing a VirtioGpuCmd* RequestType which, on + success, elicits a VirtioGpuRespOkNodata response + from the host. + + @param[in] Fence Whether to enable fencing for this request. Fencing + forces the host to complete the command before + producing a response. If Fence is TRUE, then + VgpuDev->FenceId is consumed, and incremented. + + @param[in,out] Header Pointer to the caller-allocated request object. The + request must start with VIRTIO_GPU_CONTROL_HEADER. + This function overwrites all fields of Header before + submitting the request to the host: + + - it sets Type from RequestType, + + - it sets Flags and FenceId based on Fence, + + - it zeroes CtxId and Padding. + + @param[in] RequestSize Size of the entire caller-allocated request object, + including the leading VIRTIO_GPU_CONTROL_HEADER. + + @retval EFI_SUCCESS Operation successful. + + @retval EFI_DEVICE_ERROR The host rejected the request. The host error + code has been logged on the EFI_D_ERROR level. + + @return Codes for unexpected errors in VirtIo + messaging. +**/ +STATIC +EFI_STATUS +VirtioGpuSendCommand ( + IN OUT VGPU_DEV *VgpuDev, + IN VIRTIO_GPU_CONTROL_TYPE RequestType, + IN BOOLEAN Fence, + IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Header, + IN UINTN RequestSize + ) +{ + DESC_INDICES Indices; + volatile VIRTIO_GPU_CONTROL_HEADER Response; + EFI_STATUS Status; + UINT32 ResponseSize; + + // + // Initialize Header. + // + Header->Type = RequestType; + if (Fence) { + Header->Flags = VIRTIO_GPU_FLAG_FENCE; + Header->FenceId = VgpuDev->FenceId++; + } else { + Header->Flags = 0; + Header->FenceId = 0; + } + Header->CtxId = 0; + Header->Padding = 0; + + ASSERT (RequestSize >= sizeof *Header); + + // + // Compose the descriptor chain. + // + VirtioPrepare (&VgpuDev->Ring, &Indices); + VirtioAppendDesc (&VgpuDev->Ring, (UINTN)Header, RequestSize, + VRING_DESC_F_NEXT, &Indices); + VirtioAppendDesc (&VgpuDev->Ring, (UINTN)&Response, sizeof Response, + VRING_DESC_F_WRITE, &Indices); + + // + // Send the command. + // + Status = VirtioFlush (VgpuDev->VirtIo, VIRTIO_GPU_CONTROL_QUEUE, + &VgpuDev->Ring, &Indices, &ResponseSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Parse the response. + // + if (ResponseSize != sizeof Response) { + DEBUG ((EFI_D_ERROR, "%a: malformed response to Request=0x%x\n", + __FUNCTION__, (UINT32)RequestType)); + return EFI_PROTOCOL_ERROR; + } + + if (Response.Type == VirtioGpuRespOkNodata) { + return EFI_SUCCESS; + } + + DEBUG ((EFI_D_ERROR, "%a: Request=0x%x Response=0x%x\n", __FUNCTION__, + (UINT32)RequestType, Response.Type)); + return EFI_DEVICE_ERROR; +} + +/** + The following functions send requests to the VirtIo GPU device model, await + the answer from the host, and return a status. They share the following + interface details: + + @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU + device. The caller is responsible to have + successfully invoked VirtioGpuInit() on VgpuDev + previously, while VirtioGpuUninit() must not have + been called on VgpuDev. + + @retval EFI_INVALID_PARAMETER Invalid command-specific parameters were + detected by this driver. + + @retval EFI_SUCCESS Operation successful. + + @retval EFI_DEVICE_ERROR The host rejected the request. The host error + code has been logged on the EFI_D_ERROR level. + + @return Codes for unexpected errors in VirtIo + messaging. + + For the command-specific parameters, please consult the GPU Device section of + the VirtIo 1.0 specification (see references in + "OvmfPkg/Include/IndustryStandard/VirtioGpu.h"). +**/ +EFI_STATUS +VirtioGpuResourceCreate2d ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId, + IN VIRTIO_GPU_FORMATS Format, + IN UINT32 Width, + IN UINT32 Height + ) +{ + volatile VIRTIO_GPU_RESOURCE_CREATE_2D Request; + + if (ResourceId == 0) { + return EFI_INVALID_PARAMETER; + } + + Request.ResourceId = ResourceId; + Request.Format = (UINT32)Format; + Request.Width = Width; + Request.Height = Height; + + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdResourceCreate2d, + FALSE, // Fence + &Request.Header, + sizeof Request + ); +} + +EFI_STATUS +VirtioGpuResourceUnref ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId + ) +{ + volatile VIRTIO_GPU_RESOURCE_UNREF Request; + + if (ResourceId == 0) { + return EFI_INVALID_PARAMETER; + } + + Request.ResourceId = ResourceId; + Request.Padding = 0; + + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdResourceUnref, + FALSE, // Fence + &Request.Header, + sizeof Request + ); +} + +EFI_STATUS +VirtioGpuResourceAttachBacking ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId, + IN VOID *FirstBackingPage, + IN UINTN NumberOfPages + ) +{ + volatile VIRTIO_GPU_RESOURCE_ATTACH_BACKING Request; + + if (ResourceId == 0) { + return EFI_INVALID_PARAMETER; + } + + Request.ResourceId = ResourceId; + Request.NrEntries = 1; + Request.Entry.Addr = (UINTN)FirstBackingPage; + Request.Entry.Length = (UINT32)EFI_PAGES_TO_SIZE (NumberOfPages); + Request.Entry.Padding = 0; + + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdResourceAttachBacking, + FALSE, // Fence + &Request.Header, + sizeof Request + ); +} + +EFI_STATUS +VirtioGpuResourceDetachBacking ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 ResourceId + ) +{ + volatile VIRTIO_GPU_RESOURCE_DETACH_BACKING Request; + + if (ResourceId == 0) { + return EFI_INVALID_PARAMETER; + } + + Request.ResourceId = ResourceId; + Request.Padding = 0; + + // + // In this case, we set Fence to TRUE, because after this function returns, + // the caller might reasonably want to repurpose the backing pages + // immediately. Thus we should ensure that the host releases all references + // to the backing pages before we return. + // + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdResourceDetachBacking, + TRUE, // Fence + &Request.Header, + sizeof Request + ); +} + +EFI_STATUS +VirtioGpuSetScanout ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 X, + IN UINT32 Y, + IN UINT32 Width, + IN UINT32 Height, + IN UINT32 ScanoutId, + IN UINT32 ResourceId + ) +{ + volatile VIRTIO_GPU_SET_SCANOUT Request; + + // + // Unlike for most other commands, ResourceId=0 is valid; it + // is used to disable a scanout. + // + Request.Rectangle.X = X; + Request.Rectangle.Y = Y; + Request.Rectangle.Width = Width; + Request.Rectangle.Height = Height; + Request.ScanoutId = ScanoutId; + Request.ResourceId = ResourceId; + + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdSetScanout, + FALSE, // Fence + &Request.Header, + sizeof Request + ); +} + +EFI_STATUS +VirtioGpuTransferToHost2d ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 X, + IN UINT32 Y, + IN UINT32 Width, + IN UINT32 Height, + IN UINT64 Offset, + IN UINT32 ResourceId + ) +{ + volatile VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D Request; + + if (ResourceId == 0) { + return EFI_INVALID_PARAMETER; + } + + Request.Rectangle.X = X; + Request.Rectangle.Y = Y; + Request.Rectangle.Width = Width; + Request.Rectangle.Height = Height; + Request.Offset = Offset; + Request.ResourceId = ResourceId; + Request.Padding = 0; + + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdTransferToHost2d, + FALSE, // Fence + &Request.Header, + sizeof Request + ); +} + +EFI_STATUS +VirtioGpuResourceFlush ( + IN OUT VGPU_DEV *VgpuDev, + IN UINT32 X, + IN UINT32 Y, + IN UINT32 Width, + IN UINT32 Height, + IN UINT32 ResourceId + ) +{ + volatile VIRTIO_GPU_RESOURCE_FLUSH Request; + + if (ResourceId == 0) { + return EFI_INVALID_PARAMETER; + } + + Request.Rectangle.X = X; + Request.Rectangle.Y = Y; + Request.Rectangle.Width = Width; + Request.Rectangle.Height = Height; + Request.ResourceId = ResourceId; + Request.Padding = 0; + + return VirtioGpuSendCommand ( + VgpuDev, + VirtioGpuCmdResourceFlush, + FALSE, // Fence + &Request.Header, + sizeof Request + ); +} -- 2.9.2 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel