From patchwork Fri Aug 19 12:49:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 74247 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp295741qga; Fri, 19 Aug 2016 05:50:15 -0700 (PDT) X-Received: by 10.66.90.34 with SMTP id bt2mr13277193pab.139.1471611002269; Fri, 19 Aug 2016 05:50:02 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id 62si5036435pfc.60.2016.08.19.05.50.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 Aug 2016 05:50:02 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 1D86F1A1E3B; Fri, 19 Aug 2016 05:49:57 -0700 (PDT) X-Original-To: edk2-devel@ml01.01.org Delivered-To: edk2-devel@ml01.01.org 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 3E9221A1E3B for ; Fri, 19 Aug 2016 05:49:54 -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 A4E74C057FAD; Fri, 19 Aug 2016 12:49:53 +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 u7JCnaSo011583; Fri, 19 Aug 2016 08:49:52 -0400 From: Laszlo Ersek To: edk2-devel-01 Date: Fri, 19 Aug 2016 14:49:30 +0200 Message-Id: <20160819124932.29711-10-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.32]); Fri, 19 Aug 2016 12:49:53 +0000 (UTC) Subject: [edk2] [PATCH 09/11] OvmfPkg/VirtioGpuDxe: provide functions for sending VirtIo GPU commands 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: , Cc: Jordan Justen , Ard Biesheuvel Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" 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 Cc: Jordan Justen Ref: https://tianocore.acgmultimedia.com/show_bug.cgi?id=66 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- OvmfPkg/VirtioGpuDxe/VirtioGpu.h | 93 ++++++ OvmfPkg/VirtioGpuDxe/Commands.c | 347 +++++++++++++++++++- 2 files changed, 439 insertions(+), 1 deletion(-) -- 2.9.2 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel 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 #include #include #include // // 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 #include #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 + ); +}