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 17AE921AEB0D4 for ; Thu, 3 Aug 2017 13:49:35 -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 72C22C058EA9; Thu, 3 Aug 2017 20:51:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 72C22C058EA9 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=lersek@redhat.com Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-72.phx2.redhat.com [10.3.116.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id 999D760BF0; Thu, 3 Aug 2017 20:51:44 +0000 (UTC) To: Brijesh Singh , edk2-devel@lists.01.org Cc: Tom Lendacky , Jordan Justen , Ard Biesheuvel References: <1501776600-16369-1-git-send-email-brijesh.singh@amd.com> <1501776600-16369-2-git-send-email-brijesh.singh@amd.com> From: Laszlo Ersek Message-ID: <2517ecce-c92c-b85c-39a7-f454048e6b3d@redhat.com> Date: Thu, 3 Aug 2017 22:51:43 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.2.1 MIME-Version: 1.0 In-Reply-To: <1501776600-16369-2-git-send-email-brijesh.singh@amd.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.32]); Thu, 03 Aug 2017 20:51:46 +0000 (UTC) Subject: Re: [PATCH v2 1/1] OvmfPkg : QemuFwCfgLib: Use BusMasterCommandBuffer to map FW_CFG_DMA_ACCESS 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: Thu, 03 Aug 2017 20:49:35 -0000 Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit On 08/03/17 18:10, Brijesh Singh wrote: > Commit 09719a01b11b (OvmfPkg/QemuFwCfgLib: Implement SEV internal function for Dxe phase) > uses IOMMU protocol to allocate and free FW_CFG_DMA_ACCESS buffer > when SEV is active. During initial commits we made assumption that > IOMMU.AllocateBuffer() will provide PlainTextAddress (i.e C-bit > cleared). This assumption was wrong, the AllocateBuffer() protocol > member is not expected to produce a buffer that is immediatly usable, > and client is required to call Map() uncondtionally with BusMasterCommonBuffer[64] > to get a mapping which is accessable by both host and device. > > The patch refactors code a bit and add the support to Map() > FW_CFG_DMA_ACCESS buffer using BusMasterCommonBuffer operation > after allocation and Unamp() before free. > > The complete discussion about this and recommendation from Laszlo > can be found here [1] > > [1] https://lists.01.org/pipermail/edk2-devel/2017-July/012652.html > > Suggested-by: Laszlo Ersek > Cc: Jordan Justen > Cc: Laszlo Ersek > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Brijesh Singh > --- > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h | 42 ++-- > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c | 247 ++++++++++++++++---- > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c | 130 ----------- > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 101 +++++--- > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c | 56 ++--- > 5 files changed, 292 insertions(+), 284 deletions(-) (1) please remove the space characters in front of the colons (":") in the subject. (2) Still for the subject, it is "CommonBuffer", not "CommandBuffer". So the subject should be OvmfPkg: QemuFwCfgLib: Use BusMasterCommonBuffer to map FW_CFG_DMA_ACCESS (3) Please rewrap the commit message to 74 characters. > > diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h > index 8cfa7913ffae..327f1d37e17d 100644 > --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h > +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h > @@ -45,39 +45,25 @@ InternalQemuFwCfgDmaIsAvailable ( > ); > > /** > - Returns a boolean indicating whether SEV support is enabled > + Transfer an array of bytes, or skip a number of bytes, using the DMA > + interface. > > - @retval TRUE SEV is enabled > - @retval FALSE SEV is disabled > -**/ > -BOOLEAN > -InternalQemuFwCfgSevIsEnabled ( > - VOID > - ); > + @param[in] Size Size in bytes to transfer or skip. > > -/** > - Allocate a bounce buffer for SEV DMA. > - > - @param[out] Buffer Allocated DMA Buffer pointer > - @param[in] NumPage Number of pages. > + @param[in,out] Buffer Buffer to read data into or write data from. Ignored, > + and may be NULL, if Size is zero, or Control is > + FW_CFG_DMA_CTL_SKIP. > > + @param[in] Control One of the following: > + FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. > + FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. > + FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. > **/ > VOID > -InternalQemuFwCfgSevDmaAllocateBuffer ( > - OUT VOID **Buffer, > - IN UINT32 NumPages > +InternalQemuFwCfgDmaBytes ( > + IN UINT32 Size, > + IN OUT VOID *Buffer OPTIONAL, > + IN UINT32 Control > ); > > -/** > - Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer > - > - @param[in] NumPage Number of pages. > - @param[in] Buffer DMA Buffer pointer > - > -**/ > -VOID > -InternalQemuFwCfgSevDmaFreeBuffer ( > - IN VOID *Buffer, > - IN UINT32 NumPages > - ); > #endif > diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c (4) You forgot to remove the InternalQemuFwCfgSevIsEnabled() function from this file. > index f8eb03bc3a9a..e03647bae3bd 100644 > --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c > +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c > @@ -20,6 +20,7 @@ > #include > > #include > +#include > #include > #include > #include > @@ -157,74 +158,228 @@ InternalQemuFwCfgDmaIsAvailable ( > } > > /** > - Allocate a bounce buffer for SEV DMA. > - > - @param[in] NumPage Number of pages. > - @param[out] Buffer Allocated DMA Buffer pointer > + Function is used for allocating a bi-directional FW_CFG_DMA_ACCESS used > + between Host and device to exchange the information. The buffer must be free'd > + using FreeFwCfgDmaAccessBuffer (). > > **/ > -VOID > -InternalQemuFwCfgSevDmaAllocateBuffer ( > - OUT VOID **Buffer, > - IN UINT32 NumPages > +STATIC > +EFI_STATUS > +AllocFwCfgDmaAccessBuffer ( > + OUT VOID **Access, > + OUT VOID **Mapping > ) > { > - EFI_STATUS Status; > + UINTN Size; > + UINTN NumPages; > + EFI_STATUS Status; > + VOID *HostAddress; > + EFI_PHYSICAL_ADDRESS DmaAddress; > > - ASSERT (mIoMmuProtocol != NULL); > + Size = sizeof (FW_CFG_DMA_ACCESS); > + NumPages = EFI_SIZE_TO_PAGES (Size); > > + // > + // As per UEFI spec, in order to map a host address with BusMasterCommomBuffer64, (5) This line is too long. Also, you have one too many space chars in front of the comma. > + // the buffer must be allocated using the IOMMU AllocateBuffer() > + // > Status = mIoMmuProtocol->AllocateBuffer ( > - mIoMmuProtocol, > - 0, > - EfiBootServicesData, > - NumPages, > - Buffer, > - EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED > + mIoMmuProtocol, > + AllocateAnyPages, > + EfiBootServicesData, > + NumPages, > + &HostAddress, > + EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED (6) Please OR this attribute with EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE, so that the buffer can be allocated from 64-bit memory. > ); (7) The closing paren should be aligned with the arguments. (8) Please handle any errors returned by AllocateBuffer(), by propagating the error. > + > + // > + // Map the host buffer with BusMasterCommonBuffer64 > + // > + Status = mIoMmuProtocol->Map ( > + mIoMmuProtocol, > + EdkiiIoMmuOperationBusMasterCommonBuffer64, > + HostAddress, > + &Size, > + &DmaAddress, > + Mapping > + ); (9) Please add a check here that, on success, Size is still equal to sizeof(FW_CFG_DMA_ACCESS). (Theoretically it could be smaller, even on success.) If it is smaller, then both the map and allocate operations should be rolled back, and we should return EFI_OUT_OF_RESOURCES. For this, error handling labels at the end of the function are likely the best. (10) We should only set the output parameters Mapping and Access only if the entire function succeeds. > if (EFI_ERROR (Status)) { > - DEBUG ((DEBUG_ERROR, > - "%a:%a failed to allocate %u pages\n", gEfiCallerBaseName, __FUNCTION__, > - NumPages)); > - ASSERT (FALSE); > - CpuDeadLoop (); > + mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress); > } > > - DEBUG ((DEBUG_VERBOSE, > - "%a:%a buffer 0x%Lx Pages %u\n", gEfiCallerBaseName, __FUNCTION__, > - (UINT64)(UINTN)Buffer, NumPages)); > + *Access = HostAddress; > + return Status; > +} > + > +/** > + Function is to used for freeing the Access buffer allocated using > + AllocFwCfgDmaAccessBuffer() > + > +**/ > +STATIC > +VOID > +FreeFwCfgDmaAccessBuffer ( > + IN VOID *Access, > + IN VOID *Mapping > + ) > +{ > + UINTN NumPages; > + > + NumPages = EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS)); > + > + mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping); > + > + mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, Access); > +} > + > +/** > + Function is used for mapping host address to device address. The buffer must > + be unmapped with UnmapDmaDataBuffer (). > + > +**/ > +STATIC > +EFI_STATUS > +MapFwCfgDmaDataBuffer ( > + IN BOOLEAN IsWrite, > + IN VOID *HostAddress, > + IN UINT32 Size, > + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, > + OUT VOID **Mapping > + ) > +{ > + EFI_STATUS Status; > + UINTN NumberOfBytes; > + > + NumberOfBytes = Size; > + Status = mIoMmuProtocol->Map ( > + mIoMmuProtocol, > + IsWrite ? EdkiiIoMmuOperationBusMasterRead64 : EdkiiIoMmuOperationBusMasterWrite64, (11) Please make sure that the file is not wider than 80 characters -- the above can be broken up like (IsWrite ? EdkiiIoMmuOperationBusMasterRead64 : EdkiiIoMmuOperationBusMasterWrite64) And if that's still too wide, then a separate variable should be used. > + HostAddress, > + &NumberOfBytes, > + DeviceAddress, > + Mapping > + ); (12) Same comment as (9): on success, we should check that NumberOfBytes has the original value (i.e., Size). Otherwise, roll back the Map(), and return EFI_OUT_OF_RESOURCES. (13) Same comment as (10): we should only set the output parameters (DeviceAddress and Mapping) if the entire function succeeds. (14) Here's an alternative to the explicit / cascading error handling recommended above: given that all of these functions will be called from InternalQemuFwCfgSevDmaFreeBuffer(), which cannot propagate errors anyway, you might as well hang immediately upon error. For this, please preserve the following triplet, used earlier in InternalQemuFwCfgSevDmaAllocateBuffer(): - DEBUG_ERROR message with gEfiCallerBaseName, - ASSERT (FALSE), - CpuDeadLoop(). Correspondingly, none of the helper functions would have to return EFI_STATUS. > + return Status; > +} > + > +EFI_STATUS > +UnmapFwCfgDmaDataBuffer ( > + IN VOID *Mapping > + ) > +{ > + return mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping); > } (15) I think it's fine if we ignore (don't propagate) the error here -- please change the return type to VOID (similarly to FreeFwCfgDmaAccessBuffer()). (16) Please make this function STATIC. > > /** > - Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer > + Transfer an array of bytes, or skip a number of bytes, using the DMA > + interface. > > - @param[in] NumPage Number of pages. > - @param[in] Buffer DMA Buffer pointer > + @param[in] Size Size in bytes to transfer or skip. > > + @param[in,out] Buffer Buffer to read data into or write data from. Ignored, > + and may be NULL, if Size is zero, or Control is > + FW_CFG_DMA_CTL_SKIP. > + > + @param[in] Control One of the following: > + FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. > + FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. > + FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. > **/ > VOID > -InternalQemuFwCfgSevDmaFreeBuffer ( > - IN VOID *Buffer, > - IN UINT32 NumPages > +InternalQemuFwCfgDmaBytes ( > + IN UINT32 Size, > + IN OUT VOID *Buffer OPTIONAL, > + IN UINT32 Control > ) > { > - EFI_STATUS Status; > + volatile FW_CFG_DMA_ACCESS LocalAccess; > + volatile FW_CFG_DMA_ACCESS *Access; > + UINT32 AccessHigh, AccessLow; > + UINT32 Status; > + VOID *AccessMapping, *DataMapping; > > - ASSERT (mIoMmuProtocol != NULL); > + ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ || > + Control == FW_CFG_DMA_CTL_SKIP); > > - Status = mIoMmuProtocol->FreeBuffer ( > - mIoMmuProtocol, > - NumPages, > - Buffer > - ); > - if (EFI_ERROR (Status)) { > - DEBUG ((DEBUG_ERROR, > - "%a:%a failed to free buffer 0x%Lx pages %u\n", gEfiCallerBaseName, > - __FUNCTION__, (UINT64)(UINTN)Buffer, NumPages)); > - ASSERT (FALSE); > - CpuDeadLoop (); > + if (Size == 0) { > + return; > } > > - DEBUG ((DEBUG_VERBOSE, > - "%a:%a buffer 0x%Lx Pages %u\n", gEfiCallerBaseName,__FUNCTION__, > - (UINT64)(UINTN)Buffer, NumPages)); > + // > + // When SEV is enabled, map Buffer to DMA address before issuing the DMA request (17) This line is too long. > + // > + if (MemEncryptSevIsEnabled ()) { > + VOID *AccessBuffer; > + EFI_PHYSICAL_ADDRESS DataBuffer; > + > + // > + // Allocate DMA Access buffer > + // > + Status = AllocFwCfgDmaAccessBuffer (&AccessBuffer, &AccessMapping); > + ASSERT_EFI_ERROR (Status); (18) You can drop the assert according to cmment (14). > + > + Access = AccessBuffer; > + > + // > + // Map actual data buffer > + // > + if (Buffer) { (19) Please don't rely on Buffer being NULL for SKIP operations; that may or may not be true. Instead, please check for (Control != FW_CFG_DMA_CTL_SKIP) > + Status = MapFwCfgDmaDataBuffer (Control == FW_CFG_DMA_CTL_WRITE ? 1 : 0, > + Buffer, Size, &DataBuffer, &DataMapping); (20) Please break every argument to a separate line. (21) The following expression: Control == FW_CFG_DMA_CTL_WRITE ? 1 : 0 should be simplified as: Control == FW_CFG_DMA_CTL_WRITE > + ASSERT_EFI_ERROR (Status); (22) You can drop this, according to (14). > + > + Buffer = (VOID *) (UINTN) DataBuffer; (23) Ugh, please don't overwrite a function parameter. Instead, please introduce an additional variable. For example, you could rename "DataBuffer" to "DataBufferAddress", and introduce "DataBuffer" as a (VOID*). In the non-SEV case, you could set DataBuffer to Buffer, and in the SEV case, you could set DataBuffer to (VOID*)(UINTN)DataBufferAddress. Then use DataBuffer for setting Access->Address. > + } > + } else { > + Access = &LocalAccess; > + AccessMapping = NULL; > + DataMapping = NULL; > + } > + > + Access->Control = SwapBytes32 (Control); > + 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 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh)); > + IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, 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 (); > + > + // > + // If Access buffer was dynamically allocated then free it. > + // > + if (AccessMapping) { > + FreeFwCfgDmaAccessBuffer ((VOID *)Access, AccessMapping); > + } > + > + if (DataMapping) { > + UnmapFwCfgDmaDataBuffer (DataMapping); > + } (24) The DataMapping check is not valid. You have a code path where DataMapping is not set: Buffer==NULL (i.e., SKIP operation) with SEV enabled. I guess the simplest way to fix this is to eliminate the non-SEV branch near the top, and make all those assignments unconditional: Access = &LocalAccess; AccessMapping = NULL; DataMapping = NULL; DataBuffer = Buffer; // // When SEV is enabled... // if (MemEncryptSevIsEnabled ()) { ... > } > diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c > index d3bf75498d60..7f42f38d1c05 100644 > --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c > +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c > @@ -45,136 +45,6 @@ QemuFwCfgSelectItem ( > IoWrite16 (FW_CFG_IO_SELECTOR, (UINT16)(UINTN) QemuFwCfgItem); > } > > - > -/** > - Transfer an array of bytes, or skip a number of bytes, using the DMA > - interface. > - > - @param[in] Size Size in bytes to transfer or skip. > - > - @param[in,out] Buffer Buffer to read data into or write data from. Ignored, > - and may be NULL, if Size is zero, or Control is > - FW_CFG_DMA_CTL_SKIP. > - > - @param[in] Control One of the following: > - FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. > - FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. > - FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. > -**/ > -VOID > -InternalQemuFwCfgDmaBytes ( > - IN UINT32 Size, > - IN OUT VOID *Buffer OPTIONAL, > - IN UINT32 Control > - ) > -{ > - volatile FW_CFG_DMA_ACCESS LocalAccess; > - volatile FW_CFG_DMA_ACCESS *Access; > - UINT32 AccessHigh, AccessLow; > - UINT32 Status; > - UINT32 NumPages; > - VOID *DmaBuffer, *BounceBuffer; > - > - ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ || > - Control == FW_CFG_DMA_CTL_SKIP); > - > - if (Size == 0) { > - return; > - } > - > - // > - // set NumPages to suppress incorrect compiler/analyzer warnings > - // > - NumPages = 0; > - > - // > - // When SEV is enabled then allocate DMA bounce buffer > - // > - if (InternalQemuFwCfgSevIsEnabled ()) { > - UINTN TotalSize; > - > - TotalSize = sizeof (*Access); > - // > - // Skip operation does not need buffer > - // > - if (Control != FW_CFG_DMA_CTL_SKIP) { > - TotalSize += Size; > - } > - > - // > - // Allocate SEV DMA buffer > - // > - NumPages = (UINT32)EFI_SIZE_TO_PAGES (TotalSize); > - InternalQemuFwCfgSevDmaAllocateBuffer (&BounceBuffer, NumPages); > - > - Access = BounceBuffer; > - DmaBuffer = (UINT8*)BounceBuffer + sizeof (*Access); > - > - // > - // Decrypt data from encrypted guest buffer into DMA buffer > - // > - if (Control == FW_CFG_DMA_CTL_WRITE) { > - CopyMem (DmaBuffer, Buffer, Size); > - } > - } else { > - Access = &LocalAccess; > - DmaBuffer = Buffer; > - BounceBuffer = NULL; > - } > - > - Access->Control = SwapBytes32 (Control); > - Access->Length = SwapBytes32 (Size); > - Access->Address = SwapBytes64 ((UINTN)DmaBuffer); > - > - // > - // 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 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh)); > - IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, 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 (); > - > - // > - // If Bounce buffer was allocated then copy the data into guest buffer and > - // free the bounce buffer > - // > - if (BounceBuffer != NULL) { > - // > - // Encrypt the data from DMA buffer into guest buffer > - // > - if (Control == FW_CFG_DMA_CTL_READ) { > - CopyMem (Buffer, DmaBuffer, Size); > - } > - > - InternalQemuFwCfgSevDmaFreeBuffer (BounceBuffer, NumPages); > - } > -} > - > - > /** > Reads firmware configuration bytes into a buffer > > diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c > index 40f89c3b53e2..bc649b40aec3 100644 > --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c > +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c > @@ -16,6 +16,7 @@ > **/ > > #include > +#include > #include > #include > #include > @@ -85,7 +86,7 @@ QemuFwCfgInitialize ( > // (which need to allocate dynamic memory and allocating a PAGE size'd > // buffer can be challenge in PEI phase) > // > - if (InternalQemuFwCfgSevIsEnabled ()) { > + if (MemEncryptSevIsEnabled ()) { > DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n")); > } else { > mQemuFwCfgDmaSupported = TRUE; > @@ -129,56 +130,80 @@ InternalQemuFwCfgDmaIsAvailable ( > } > > /** > + Transfer an array of bytes, or skip a number of bytes, using the DMA > + interface. > > - Returns a boolean indicating whether SEV is enabled > + @param[in] Size Size in bytes to transfer or skip. > > - @retval TRUE SEV is enabled > - @retval FALSE SEV is disabled > + @param[in,out] Buffer Buffer to read data into or write data from. Ignored, > + and may be NULL, if Size is zero, or Control is > + FW_CFG_DMA_CTL_SKIP. > + > + @param[in] Control One of the following: > + FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. > + FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. > + FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. > **/ > -BOOLEAN > -InternalQemuFwCfgSevIsEnabled ( > - VOID > +VOID > +InternalQemuFwCfgDmaBytes ( > + IN UINT32 Size, > + IN OUT VOID *Buffer OPTIONAL, > + IN UINT32 Control > ) > { > - return MemEncryptSevIsEnabled (); > -} > + volatile FW_CFG_DMA_ACCESS Access; > + UINT32 AccessHigh, AccessLow; > + UINT32 Status; > > -/** > - Allocate a bounce buffer for SEV DMA. > + ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ || > + Control == FW_CFG_DMA_CTL_SKIP); > > - @param[in] NumPage Number of pages. > - @param[out] Buffer Allocated DMA Buffer pointer > + if (Size == 0) { > + return; > + } > + > + if (MemEncryptSevIsEnabled ()) { > + // > + // SEV does not support DMA operations in PEI stage, we should > + // not have reached here. > + // > + ASSERT (FALSE); > + } (25) This is good; you are basically restoring / copying the pre-7cfe445d7f4b state of the InternalQemuFwCfgDmaBytes() function, plus adding this assert. But, it can be written better like this: // // ... keep the same comment ... // ASSERT (!MemEncryptSevIsEnabled ()); > + > + Access.Control = SwapBytes32 (Control); > + Access.Length = SwapBytes32 (Size); > + Access.Address = SwapBytes64 ((UINTN)Buffer); > > -**/ > -VOID > -InternalQemuFwCfgSevDmaAllocateBuffer ( > - OUT VOID **Buffer, > - IN UINT32 NumPages > - ) > -{ > // > - // We should never reach here > + // Delimit the transfer from (a) modifications to Access, (b) in case of a > + // write, from writes to Buffer by the caller. > // > - ASSERT (FALSE); > - CpuDeadLoop (); > -} > + MemoryFence (); > + > + // > + // Start the transfer. > + // > + AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32); > + AccessLow = (UINT32)(UINTN)&Access; > + IoWrite32 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh)); > + IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow)); > > -/** > - Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer > + // > + // Don't look at Access.Control before starting the transfer. > + // > + MemoryFence (); > > - @param[in] NumPage Number of pages. > - @param[in] Buffer DMA Buffer pointer > + // > + // Wait for the transfer to complete. > + // > + do { > + Status = SwapBytes32 (Access.Control); > + ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0); > + } while (Status != 0); > > -**/ > -VOID > -InternalQemuFwCfgSevDmaFreeBuffer ( > - IN VOID *Buffer, > - IN UINT32 NumPages > - ) > -{ > // > - // We should never reach here > + // After a read, the caller will want to use Buffer. > // > - ASSERT (FALSE); > - CpuDeadLoop (); > + MemoryFence (); > } > + > diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c > index 071b8d9b91d4..62ddb69d3b4d 100644 > --- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c > +++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c > @@ -97,53 +97,25 @@ InternalQemuFwCfgDmaIsAvailable ( > } > > /** > + Transfer an array of bytes, or skip a number of bytes, using the DMA > + interface. > > - Returns a boolean indicating whether SEV is enabled > + @param[in] Size Size in bytes to transfer or skip. > > - @retval TRUE SEV is enabled > - @retval FALSE SEV is disabled > -**/ > -BOOLEAN > -InternalQemuFwCfgSevIsEnabled ( > - VOID > - ) > -{ > - // > - // DMA is not supported in SEC phase hence SEV support is irrelevant > - // > - return FALSE; > -} > - > -/** > - Allocate a bounce buffer for SEV DMA. > - > - @param[in] NumPage Number of pages. > - @param[out] Buffer Allocated DMA Buffer pointer > - > -**/ > -VOID > -InternalQemuFwCfgSevDmaAllocateBuffer ( > - OUT VOID **Buffer, > - IN UINT32 NumPages > - ) > -{ > - // > - // We should never reach here > - // > - ASSERT (FALSE); > -} > - > -/** > - Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer > - > - @param[in] NumPage Number of pages. > - @param[in] Buffer DMA Buffer pointer > + @param[in,out] Buffer Buffer to read data into or write data from. Ignored, > + and may be NULL, if Size is zero, or Control is > + FW_CFG_DMA_CTL_SKIP. > > + @param[in] Control One of the following: > + FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. > + FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. > + FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. > **/ > VOID > -InternalQemuFwCfgSevDmaFreeBuffer ( > - IN VOID *Buffer, > - IN UINT32 NumPages > +InternalQemuFwCfgDmaBytes ( > + IN UINT32 Size, > + IN OUT VOID *Buffer OPTIONAL, > + IN UINT32 Control > ) > { > // > (26) Can you add a CpuDeadLoop() here as well (i.e., in the SEC instance), after the ASSERT()? I know the previous version of the SEC instance doesn't use CpuDeadLoop(), but I mentioned it here: http://mid.mail-archive.com/2b9361cc-03f9-a403-98aa-c1cf5bfd17c0@redhat.com Thanks! Laszlo