From patchwork Fri Dec 2 20:20:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 86362 Delivered-To: patch@linaro.org Received: by 10.140.20.101 with SMTP id 92csp429083qgi; Fri, 2 Dec 2016 12:21:24 -0800 (PST) X-Received: by 10.98.67.138 with SMTP id l10mr47597085pfi.101.1480710084555; Fri, 02 Dec 2016 12:21:24 -0800 (PST) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id b62si6363900pgc.225.2016.12.02.12.21.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 02 Dec 2016 12:21:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 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 50D5381F66; Fri, 2 Dec 2016 12:21:24 -0800 (PST) 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 D5CEC81F66 for ; Fri, 2 Dec 2016 12:21:22 -0800 (PST) Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (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 5116D19D053; Fri, 2 Dec 2016 20:21:22 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-87.phx2.redhat.com [10.3.116.87]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uB2KL4BJ010188; Fri, 2 Dec 2016 15:21:21 -0500 From: Laszlo Ersek To: edk2-devel-01 Date: Fri, 2 Dec 2016 21:20:59 +0100 Message-Id: <20161202202059.5061-7-lersek@redhat.com> In-Reply-To: <20161202202059.5061-1-lersek@redhat.com> References: <20161202202059.5061-1-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Fri, 02 Dec 2016 20:21:22 +0000 (UTC) Subject: [edk2] [PATCH v2 6/6] OvmfPkg/QemuFwCfgLib: support QEMU's DMA-like fw_cfg access method 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 MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" The benefits of the DMA-like access method are (a) speed, (b) write support in QEMU 2.9+. (IOPort-based write support was discontinued in QEMU 2.4, and the DMA-based one is being added to QEMU 2.9. Write support needs no separate feature detection because writeability is governed on the level of individual fw_cfg files -- if a file meant to be written by the firmware exists in the directory, then it is writeable with the DMA method.) We don't enable this feature for the SEC library instance, because: - the SEC instance remains without clients (I've checked that it builds though), - in SEC, any possible fw_cfg use is expected to be small and read-only. Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jordan Justen --- Notes: v2: - no need to include IndustryStandard/QemuFwCfgDma.h any longer (no such file) - kept Jordan's R-b OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h | 13 ++++ OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c | 72 ++++++++++++++++++++ OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c | 25 ++++++- OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c | 15 ++++ 4 files changed, 124 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/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h index 5b162bf98739..6e87c625102e 100644 --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h @@ -30,4 +30,17 @@ InternalQemuFwCfgIsAvailable ( VOID ); + +/** + Returns a boolean indicating whether QEMU provides the DMA-like access method + for fw_cfg. + + @retval TRUE The DMA-like access method is available. + @retval FALSE The DMA-like access method is unavailable. +**/ +BOOLEAN +InternalQemuFwCfgDmaIsAvailable ( + VOID + ); + #endif diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c index 804d5b0e42be..0bbf121de432 100644 --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c @@ -99,6 +99,70 @@ QemuFwCfgSelectItem ( /** + Transfer an array of bytes using the DMA interface. + + @param[in] Size Size in bytes to transfer. + @param[in,out] Buffer Buffer to read data into or write data from. May be + NULL if Size is zero. + @param[in] Write TRUE if writing to fw_cfg from Buffer, FALSE if + reading from fw_cfg into Buffer. +**/ +VOID +InternalQemuFwCfgDmaBytes ( + IN UINT32 Size, + IN OUT VOID *Buffer OPTIONAL, + IN BOOLEAN Write + ) +{ + volatile FW_CFG_DMA_ACCESS Access; + UINT32 AccessHigh, AccessLow; + UINT32 Status; + + if (Size == 0) { + return; + } + + Access.Control = SwapBytes32 ( + Write ? FW_CFG_DMA_CTL_WRITE : FW_CFG_DMA_CTL_READ + ); + Access.Length = SwapBytes32 (Size); + Access.Address = SwapBytes64 ((UINTN)Buffer); + + // + // Delimit the transfer from (a) modifications to Access, (b) in case of a + // write, from writes to Buffer by the caller. + // + MemoryFence (); + + // + // Start the transfer. + // + AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32); + AccessLow = (UINT32)(UINTN)&Access; + IoWrite32 (0x514, SwapBytes32 (AccessHigh)); + IoWrite32 (0x518, SwapBytes32 (AccessLow)); + + // + // Don't look at Access.Control before starting the transfer. + // + MemoryFence (); + + // + // Wait for the transfer to complete. + // + do { + Status = SwapBytes32 (Access.Control); + ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0); + } while (Status != 0); + + // + // After a read, the caller will want to use Buffer. + // + MemoryFence (); +} + + +/** Reads firmware configuration bytes into a buffer @param[in] Size - Size in bytes to read @@ -112,6 +176,10 @@ InternalQemuFwCfgReadBytes ( IN VOID *Buffer OPTIONAL ) { + if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) { + InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FALSE); + return; + } IoReadFifo8 (0x511, Size, Buffer); } @@ -160,6 +228,10 @@ QemuFwCfgWriteBytes ( ) { if (InternalQemuFwCfgIsAvailable ()) { + if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) { + InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, TRUE); + return; + } IoWriteFifo8 (0x511, Size, Buffer); } } diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c index 88d88c0edf69..ac05f4c347f3 100644 --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c @@ -20,6 +20,7 @@ #include "QemuFwCfgLibInternal.h" STATIC BOOLEAN mQemuFwCfgSupported = FALSE; +STATIC BOOLEAN mQemuFwCfgDmaSupported; /** @@ -53,8 +54,10 @@ QemuFwCfgInitialize ( // // Enable the access routines while probing to see if it is supported. + // For probing we always use the IO Port (IoReadFifo8()) access method. // mQemuFwCfgSupported = TRUE; + mQemuFwCfgDmaSupported = FALSE; QemuFwCfgSelectItem (QemuFwCfgItemSignature); Signature = QemuFwCfgRead32 (); @@ -70,7 +73,12 @@ QemuFwCfgInitialize ( return RETURN_SUCCESS; } - DEBUG ((EFI_D_INFO, "QemuFwCfg interface is supported.\n")); + if ((Revision & FW_CFG_F_DMA) == 0) { + DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n")); + } else { + mQemuFwCfgDmaSupported = TRUE; + DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n")); + } return RETURN_SUCCESS; } @@ -91,3 +99,18 @@ InternalQemuFwCfgIsAvailable ( { return mQemuFwCfgSupported; } + +/** + Returns a boolean indicating whether QEMU provides the DMA-like access method + for fw_cfg. + + @retval TRUE The DMA-like access method is available. + @retval FALSE The DMA-like access method is unavailable. +**/ +BOOLEAN +InternalQemuFwCfgDmaIsAvailable ( + VOID + ) +{ + return mQemuFwCfgDmaSupported; +} diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c index 56c59ca3f01d..465ccbe90dad 100644 --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c @@ -79,3 +79,18 @@ InternalQemuFwCfgIsAvailable ( // return TRUE; } + +/** + Returns a boolean indicating whether QEMU provides the DMA-like access method + for fw_cfg. + + @retval TRUE The DMA-like access method is available. + @retval FALSE The DMA-like access method is unavailable. +**/ +BOOLEAN +InternalQemuFwCfgDmaIsAvailable ( + VOID + ) +{ + return FALSE; +}