From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 Cc: Ard Biesheuvel , Jordan Justen 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: [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: , X-List-Received-Date: Fri, 19 Aug 2016 12:49:54 -0000 Content-Transfer-Encoding: quoted-printable 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=3D66 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(-) diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h b/OvmfPkg/VirtioGpuDxe/Virtio= Gpu.h index 97767dba709f..f8839922487c 100644 --- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h +++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h @@ -14,12 +14,13 @@ =0D **/=0D =0D #ifndef _VIRTIO_GPU_DXE_H_=0D #define _VIRTIO_GPU_DXE_H_=0D =0D +#include =0D #include =0D #include =0D #include =0D =0D //=0D // Forward declaration of VGPU_GOP.=0D @@ -56,12 +57,17 @@ typedef struct { //=0D // Event to be signaled at ExitBootServices().=0D //=0D EFI_EVENT ExitBoot;=0D =0D //=0D + // Common running counter for all VirtIo GPU requests that ask for fenci= ng.=0D + //=0D + UINT64 FenceId;=0D +=0D + //=0D // The Child field references the GOP wrapper structure. If this pointer= is=0D // NULL, then the hybrid driver has bound (i.e., started) the=0D // VIRTIO_DEVICE_PROTOCOL controller without producing the child GOP=0D // controller (that is, after Start() was called with RemainingDevicePat= h=0D // pointing to and End of Device Path node). Child can be created and=0D // destroyed, even repeatedly, independently of VGPU_DEV.=0D @@ -168,7 +174,94 @@ VOID EFIAPI=0D VirtioGpuExitBoot (=0D IN EFI_EVENT Event,=0D IN VOID *Context=0D );=0D =0D +/**=0D + The following functions send requests to the VirtIo GPU device model, aw= ait=0D + the answer from the host, and return a status. They share the following= =0D + interface details:=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo G= PU=0D + device. The caller is responsible to have=0D + successfully invoked VirtioGpuInit() on VgpuDev= =0D + previously, while VirtioGpuUninit() must not hav= e=0D + been called on VgpuDev.=0D +=0D + @retval EFI_INVALID_PARAMETER Invalid command-specific parameters were= =0D + detected by this driver.=0D +=0D + @retval EFI_SUCCESS Operation successful.=0D +=0D + @retval EFI_DEVICE_ERROR The host rejected the request. The host e= rror=0D + code has been logged on the EFI_D_ERROR l= evel.=0D +=0D + @return Codes for unexpected errors in VirtIo=0D + messaging.=0D +=0D + For the command-specific parameters, please consult the GPU Device secti= on of=0D + the VirtIo 1.0 specification (see references in=0D + "OvmfPkg/Include/IndustryStandard/VirtioGpu.h").=0D +**/=0D +EFI_STATUS=0D +VirtioGpuResourceCreate2d (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId,=0D + IN VIRTIO_GPU_FORMATS Format,=0D + IN UINT32 Width,=0D + IN UINT32 Height=0D + );=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceUnref (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId=0D + );=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceAttachBacking (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId,=0D + IN VOID *FirstBackingPage,=0D + IN UINTN NumberOfPages=0D + );=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceDetachBacking (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId=0D + );=0D +=0D +EFI_STATUS=0D +VirtioGpuSetScanout (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 X,=0D + IN UINT32 Y,=0D + IN UINT32 Width,=0D + IN UINT32 Height,=0D + IN UINT32 ScanoutId,=0D + IN UINT32 ResourceId=0D + );=0D +=0D +EFI_STATUS=0D +VirtioGpuTransferToHost2d (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 X,=0D + IN UINT32 Y,=0D + IN UINT32 Width,=0D + IN UINT32 Height,=0D + IN UINT64 Offset,=0D + IN UINT32 ResourceId=0D + );=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceFlush (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 X,=0D + IN UINT32 Y,=0D + IN UINT32 Width,=0D + IN UINT32 Height,=0D + IN UINT32 ResourceId=0D + );=0D +=0D #endif // _VIRTIO_GPU_DXE_H_=0D diff --git a/OvmfPkg/VirtioGpuDxe/Commands.c b/OvmfPkg/VirtioGpuDxe/Command= s.c index 804de950ff24..b369dc3a7abc 100644 --- a/OvmfPkg/VirtioGpuDxe/Commands.c +++ b/OvmfPkg/VirtioGpuDxe/Commands.c @@ -11,13 +11,12 @@ =0D THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WI= THOUT=0D WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.=0D =0D **/=0D =0D -#include =0D #include =0D =0D #include "VirtioGpu.h"=0D =0D /**=0D Configure the VirtIo GPU device that underlies VgpuDev.=0D @@ -209,6 +208,352 @@ VirtioGpuExitBoot ( {=0D VGPU_DEV *VgpuDev;=0D =0D VgpuDev =3D Context;=0D VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);=0D }=0D +=0D +/**=0D + Internal utility function that sends a request to the VirtIo GPU device= =0D + model, awaits the answer from the host, and returns a status.=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo G= PU=0D + device. The caller is responsible to have=0D + successfully invoked VirtioGpuInit() on VgpuDev= =0D + previously, while VirtioGpuUninit() must not hav= e=0D + been called on VgpuDev.=0D +=0D + @param[in] RequestType The type of the request. The caller is responsib= le=0D + for providing a VirtioGpuCmd* RequestType which,= on=0D + success, elicits a VirtioGpuRespOkNodata respons= e=0D + from the host.=0D +=0D + @param[in] Fence Whether to enable fencing for this request. Fenc= ing=0D + forces the host to complete the command before=0D + producing a response. If Fence is TRUE, then=0D + VgpuDev->FenceId is consumed, and incremented.=0D +=0D + @param[in,out] Header Pointer to the caller-allocated request object. = The=0D + request must start with VIRTIO_GPU_CONTROL_HEADE= R.=0D + This function overwrites all fields of Header be= fore=0D + submitting the request to the host:=0D +=0D + - it sets Type from RequestType,=0D +=0D + - it sets Flags and FenceId based on Fence,=0D +=0D + - it zeroes CtxId and Padding.=0D +=0D + @param[in] RequestSize Size of the entire caller-allocated request obje= ct,=0D + including the leading VIRTIO_GPU_CONTROL_HEADER.= =0D +=0D + @retval EFI_SUCCESS Operation successful.=0D +=0D + @retval EFI_DEVICE_ERROR The host rejected the request. The host e= rror=0D + code has been logged on the EFI_D_ERROR l= evel.=0D +=0D + @return Codes for unexpected errors in VirtIo=0D + messaging.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +VirtioGpuSendCommand (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN VIRTIO_GPU_CONTROL_TYPE RequestType,=0D + IN BOOLEAN Fence,=0D + IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Header,=0D + IN UINTN RequestSize=0D + )=0D +{=0D + DESC_INDICES Indices;=0D + volatile VIRTIO_GPU_CONTROL_HEADER Response;=0D + EFI_STATUS Status;=0D + UINT32 ResponseSize;=0D +=0D + //=0D + // Initialize Header.=0D + //=0D + Header->Type =3D RequestType;=0D + if (Fence) {=0D + Header->Flags =3D VIRTIO_GPU_FLAG_FENCE;=0D + Header->FenceId =3D VgpuDev->FenceId++;=0D + } else {=0D + Header->Flags =3D 0;=0D + Header->FenceId =3D 0;=0D + }=0D + Header->CtxId =3D 0;=0D + Header->Padding =3D 0;=0D +=0D + ASSERT (RequestSize >=3D sizeof *Header);=0D +=0D + //=0D + // Compose the descriptor chain.=0D + //=0D + VirtioPrepare (&VgpuDev->Ring, &Indices);=0D + VirtioAppendDesc (&VgpuDev->Ring, (UINTN)Header, RequestSize,=0D + VRING_DESC_F_NEXT, &Indices);=0D + VirtioAppendDesc (&VgpuDev->Ring, (UINTN)&Response, sizeof Response,=0D + VRING_DESC_F_WRITE, &Indices);=0D +=0D + //=0D + // Send the command.=0D + //=0D + Status =3D VirtioFlush (VgpuDev->VirtIo, VIRTIO_GPU_CONTROL_QUEUE,=0D + &VgpuDev->Ring, &Indices, &ResponseSize);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + //=0D + // Parse the response.=0D + //=0D + if (ResponseSize !=3D sizeof Response) {=0D + DEBUG ((EFI_D_ERROR, "%a: malformed response to Request=3D0x%x\n",=0D + __FUNCTION__, (UINT32)RequestType));=0D + return EFI_PROTOCOL_ERROR;=0D + }=0D +=0D + if (Response.Type =3D=3D VirtioGpuRespOkNodata) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + DEBUG ((EFI_D_ERROR, "%a: Request=3D0x%x Response=3D0x%x\n", __FUNCTION_= _,=0D + (UINT32)RequestType, Response.Type));=0D + return EFI_DEVICE_ERROR;=0D +}=0D +=0D +/**=0D + The following functions send requests to the VirtIo GPU device model, aw= ait=0D + the answer from the host, and return a status. They share the following= =0D + interface details:=0D +=0D + @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo G= PU=0D + device. The caller is responsible to have=0D + successfully invoked VirtioGpuInit() on VgpuDev= =0D + previously, while VirtioGpuUninit() must not hav= e=0D + been called on VgpuDev.=0D +=0D + @retval EFI_INVALID_PARAMETER Invalid command-specific parameters were= =0D + detected by this driver.=0D +=0D + @retval EFI_SUCCESS Operation successful.=0D +=0D + @retval EFI_DEVICE_ERROR The host rejected the request. The host e= rror=0D + code has been logged on the EFI_D_ERROR l= evel.=0D +=0D + @return Codes for unexpected errors in VirtIo=0D + messaging.=0D +=0D + For the command-specific parameters, please consult the GPU Device secti= on of=0D + the VirtIo 1.0 specification (see references in=0D + "OvmfPkg/Include/IndustryStandard/VirtioGpu.h").=0D +**/=0D +EFI_STATUS=0D +VirtioGpuResourceCreate2d (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId,=0D + IN VIRTIO_GPU_FORMATS Format,=0D + IN UINT32 Width,=0D + IN UINT32 Height=0D + )=0D +{=0D + volatile VIRTIO_GPU_RESOURCE_CREATE_2D Request;=0D +=0D + if (ResourceId =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Request.ResourceId =3D ResourceId;=0D + Request.Format =3D (UINT32)Format;=0D + Request.Width =3D Width;=0D + Request.Height =3D Height;=0D +=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdResourceCreate2d,=0D + FALSE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceUnref (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId=0D + )=0D +{=0D + volatile VIRTIO_GPU_RESOURCE_UNREF Request;=0D +=0D + if (ResourceId =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Request.ResourceId =3D ResourceId;=0D + Request.Padding =3D 0;=0D +=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdResourceUnref,=0D + FALSE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceAttachBacking (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId,=0D + IN VOID *FirstBackingPage,=0D + IN UINTN NumberOfPages=0D + )=0D +{=0D + volatile VIRTIO_GPU_RESOURCE_ATTACH_BACKING Request;=0D +=0D + if (ResourceId =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Request.ResourceId =3D ResourceId;=0D + Request.NrEntries =3D 1;=0D + Request.Entry.Addr =3D (UINTN)FirstBackingPage;=0D + Request.Entry.Length =3D (UINT32)EFI_PAGES_TO_SIZE (NumberOfPages);=0D + Request.Entry.Padding =3D 0;=0D +=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdResourceAttachBacking,=0D + FALSE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceDetachBacking (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 ResourceId=0D + )=0D +{=0D + volatile VIRTIO_GPU_RESOURCE_DETACH_BACKING Request;=0D +=0D + if (ResourceId =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Request.ResourceId =3D ResourceId;=0D + Request.Padding =3D 0;=0D +=0D + //=0D + // In this case, we set Fence to TRUE, because after this function retur= ns,=0D + // the caller might reasonably want to repurpose the backing pages=0D + // immediately. Thus we should ensure that the host releases all referen= ces=0D + // to the backing pages before we return.=0D + //=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdResourceDetachBacking,=0D + TRUE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +VirtioGpuSetScanout (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 X,=0D + IN UINT32 Y,=0D + IN UINT32 Width,=0D + IN UINT32 Height,=0D + IN UINT32 ScanoutId,=0D + IN UINT32 ResourceId=0D + )=0D +{=0D + volatile VIRTIO_GPU_SET_SCANOUT Request;=0D +=0D + //=0D + // Unlike for most other commands, ResourceId=3D0 is valid; it=0D + // is used to disable a scanout.=0D + //=0D + Request.Rectangle.X =3D X;=0D + Request.Rectangle.Y =3D Y;=0D + Request.Rectangle.Width =3D Width;=0D + Request.Rectangle.Height =3D Height;=0D + Request.ScanoutId =3D ScanoutId;=0D + Request.ResourceId =3D ResourceId;=0D +=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdSetScanout,=0D + FALSE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +VirtioGpuTransferToHost2d (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 X,=0D + IN UINT32 Y,=0D + IN UINT32 Width,=0D + IN UINT32 Height,=0D + IN UINT64 Offset,=0D + IN UINT32 ResourceId=0D + )=0D +{=0D + volatile VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D Request;=0D +=0D + if (ResourceId =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Request.Rectangle.X =3D X;=0D + Request.Rectangle.Y =3D Y;=0D + Request.Rectangle.Width =3D Width;=0D + Request.Rectangle.Height =3D Height;=0D + Request.Offset =3D Offset;=0D + Request.ResourceId =3D ResourceId;=0D + Request.Padding =3D 0;=0D +=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdTransferToHost2d,=0D + FALSE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +VirtioGpuResourceFlush (=0D + IN OUT VGPU_DEV *VgpuDev,=0D + IN UINT32 X,=0D + IN UINT32 Y,=0D + IN UINT32 Width,=0D + IN UINT32 Height,=0D + IN UINT32 ResourceId=0D + )=0D +{=0D + volatile VIRTIO_GPU_RESOURCE_FLUSH Request;=0D +=0D + if (ResourceId =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Request.Rectangle.X =3D X;=0D + Request.Rectangle.Y =3D Y;=0D + Request.Rectangle.Width =3D Width;=0D + Request.Rectangle.Height =3D Height;=0D + Request.ResourceId =3D ResourceId;=0D + Request.Padding =3D 0;=0D +=0D + return VirtioGpuSendCommand (=0D + VgpuDev,=0D + VirtioGpuCmdResourceFlush,=0D + FALSE, // Fence=0D + &Request.Header,=0D + sizeof Request=0D + );=0D +}=0D --=20 2.9.2