From: Brijesh Singh <brijesh.singh@amd.com>
To: Laszlo Ersek <lersek@redhat.com>, edk2-devel@lists.01.org
Cc: brijesh.singh@amd.com, Tom Lendacky <thomas.lendacky@amd.com>,
Jordan Justen <jordan.l.justen@intel.com>,
Ard Biesheuvel <ard.biesheuvel@linaro.org>
Subject: Re: [PATCH v2 1/1] OvmfPkg : QemuFwCfgLib: Use BusMasterCommandBuffer to map FW_CFG_DMA_ACCESS
Date: Thu, 3 Aug 2017 17:07:26 -0500 [thread overview]
Message-ID: <e5b049d5-fd01-6b25-4cf8-46307e4e8a08@amd.com> (raw)
In-Reply-To: <2517ecce-c92c-b85c-39a7-f454048e6b3d@redhat.com>
Hi Laszlo,
Thanks for the detail review, I will soon send v3 with all your feedback
addressed. I must admit that I have constant struggle with formating issues
in EDKII contributions. While browsing the code, several packages have
code and comment exceeding 79 char. But looking at your previous feedbacks
somehow I was under assumption that comments should be <= 79 chars but code
can exceed 79 char limit. I think my understanding was wrong. I will update
my vi setting to warn me when I exceed 79 char limit.
Sorry about all those formating errors, and thanks for being so patience.
-Brijesh
On 08/03/2017 03:51 PM, Laszlo Ersek wrote:
> 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 <lersek@redhat.com>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>> 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 <Protocol/IoMmu.h>
>>
>> #include <Library/BaseLib.h>
>> +#include <Library/IoLib.h>
>> #include <Library/DebugLib.h>
>> #include <Library/QemuFwCfgLib.h>
>> #include <Library/UefiBootServicesTableLib.h>
>> @@ -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 <Library/BaseLib.h>
>> +#include <Library/IoLib.h>
>> #include <Library/DebugLib.h>
>> #include <Library/QemuFwCfgLib.h>
>> #include <Library/MemEncryptSevLib.h>
>> @@ -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
>
next prev parent reply other threads:[~2017-08-03 22:05 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-03 16:09 [PATCH v2 0/1] OvmfPkg/QemuFwCfgLib: Use BusMasterCommandBuffer to map FW_CFG_DMA_ACCESS Brijesh Singh
2017-08-03 16:10 ` [PATCH v2 1/1] OvmfPkg : QemuFwCfgLib: " Brijesh Singh
2017-08-03 20:51 ` Laszlo Ersek
2017-08-03 22:07 ` Brijesh Singh [this message]
2017-08-03 22:27 ` Laszlo Ersek
2017-08-04 17:08 ` Jordan Justen
2017-08-04 20:25 ` Laszlo Ersek
2017-08-10 18:36 ` Jordan Justen
2017-08-10 19:48 ` Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e5b049d5-fd01-6b25-4cf8-46307e4e8a08@amd.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox