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 8DA6721DF809B for ; Mon, 28 Aug 2017 06:22:03 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8BE7E91FC3; Mon, 28 Aug 2017 13:24:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8BE7E91FC3 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=lersek@redhat.com Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-67.phx2.redhat.com [10.3.116.67]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2FB166061E; Mon, 28 Aug 2017 13:24:41 +0000 (UTC) From: Laszlo Ersek To: edk2-devel-01 Cc: Ard Biesheuvel , Brijesh Singh , Jordan Justen , Tom Lendacky Date: Mon, 28 Aug 2017 15:24:31 +0200 Message-Id: <20170828132436.15933-2-lersek@redhat.com> In-Reply-To: <20170828132436.15933-1-lersek@redhat.com> References: <20170828132436.15933-1-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Mon, 28 Aug 2017 13:24:42 +0000 (UTC) Subject: [PATCH 1/6] OvmfPkg/VirtioGpuDxe: map VRING for bus master common buffer operation X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Aug 2017 13:22:03 -0000 VirtioGpuDxe uses one virtio ring, for VIRTIO_GPU_CONTROL_QUEUE. Map it for bus master common buffer operation with VirtioRingMap(), so that it can be accessed equally by both guest and hypervisor even if an IOMMU is used. (VirtioRingInit() already allocates the ring suitably for this, see commit b0338c53297c, "OvmfPkg/VirtioLib: alloc VRING buffer with AllocateSharedPages()", 2017-08-23). Pass the resultant translation offset ("RingBaseShift"), from system memory address to bus master device address, to VIRTIO_SET_QUEUE_ADDRESS. Unmap the ring in all contexts where the ring becomes unused (these contexts are mutually exclusive): - in VirtioGpuInit(): the ring has been mapped, but we cannot complete the virtio initialization for another reason, - in VirtioGpuUninit(): the virtio initialization has succeeded, but VirtioGpuDriverBindingStart() fails for another reason, or VirtioGpuDriverBindingStop() unbinds the device after use, - in VirtioGpuExitBoot(): ExitBootServices() is called after VirtioGpuDriverBindingStart() has successfully bound the device. (Unmapping the ring does not change the UEFI memory map.) Cc: Ard Biesheuvel Cc: Brijesh Singh Cc: Jordan Justen Cc: Tom Lendacky Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Laszlo Ersek --- OvmfPkg/VirtioGpuDxe/VirtioGpu.h | 6 +++++ OvmfPkg/VirtioGpuDxe/Commands.c | 27 +++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h index 078b7d44d83e..193e932e1430 100644 --- a/OvmfPkg/VirtioGpuDxe/VirtioGpu.h +++ b/OvmfPkg/VirtioGpuDxe/VirtioGpu.h @@ -40,46 +40,52 @@ typedef struct VGPU_GOP_STRUCT VGPU_GOP; typedef struct { // // VirtIo represents access to the Virtio GPU device. Never NULL. // VIRTIO_DEVICE_PROTOCOL *VirtIo; // // BusName carries a customized name for // EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName(). It is expressed in table // form because it can theoretically support several languages. Never NULL. // EFI_UNICODE_STRING_TABLE *BusName; // // VirtIo ring used for VirtIo communication. // VRING Ring; + // + // Token associated with Ring's mapping for bus master common buffer + // operation, from VirtioRingMap(). + // + VOID *RingMap; + // // 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. // // In practice, this field represents the single head (scanout) that we // support. // VGPU_GOP *Child; } VGPU_DEV; // // The Graphics Output Protocol wrapper structure. // #define VGPU_GOP_SIG SIGNATURE_64 ('V', 'G', 'P', 'U', '_', 'G', 'O', 'P') diff --git a/OvmfPkg/VirtioGpuDxe/Commands.c b/OvmfPkg/VirtioGpuDxe/Commands.c index 5cb003161207..4e19bac606ee 100644 --- a/OvmfPkg/VirtioGpuDxe/Commands.c +++ b/OvmfPkg/VirtioGpuDxe/Commands.c @@ -39,119 +39,138 @@ EFI_STATUS VirtioGpuInit ( IN OUT VGPU_DEV *VgpuDev ) { UINT8 NextDevStat; EFI_STATUS Status; UINT64 Features; UINT16 QueueSize; + UINT64 RingBaseShift; // // 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 (VgpuDev->VirtIo, QueueSize, &VgpuDev->Ring); if (EFI_ERROR (Status)) { goto Failed; } + // + // If anything fails from here on, we have to release the ring. + // + Status = VirtioRingMap ( + VgpuDev->VirtIo, + &VgpuDev->Ring, + &RingBaseShift, + &VgpuDev->RingMap + ); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + // + // If anything fails from here on, we have to unmap the ring. + // Status = VgpuDev->VirtIo->SetQueueAddress ( VgpuDev->VirtIo, &VgpuDev->Ring, - 0 + RingBaseShift ); if (EFI_ERROR (Status)) { - goto ReleaseQueue; + goto UnmapQueue; } // // 8. Set the DRIVER_OK status bit. // NextDevStat |= VSTAT_DRIVER_OK; Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) { - goto ReleaseQueue; + goto UnmapQueue; } return EFI_SUCCESS; +UnmapQueue: + VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap); + ReleaseQueue: VirtioRingUninit (VgpuDev->VirtIo, &VgpuDev->Ring); @@ -182,25 +201,26 @@ 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); + VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap); VirtioRingUninit (VgpuDev->VirtIo, &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. **/ @@ -209,53 +229,54 @@ EFIAPI VirtioGpuExitBoot ( IN EFI_EVENT Event, IN VOID *Context ) { VGPU_DEV *VgpuDev; VgpuDev = Context; VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0); + VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap); } /** 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. **/ -- 2.14.1.3.gb7cf6e02401b