public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: Brijesh Singh <brijesh.singh@amd.com>, edk2-devel@lists.01.org
Cc: 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: Fri, 4 Aug 2017 00:27:46 +0200	[thread overview]
Message-ID: <2b7e7cfb-0006-9dc2-951f-2d1f7d1a3214@redhat.com> (raw)
In-Reply-To: <e5b049d5-fd01-6b25-4cf8-46307e4e8a08@amd.com>

On 08/04/17 00:07, Brijesh Singh wrote:
> 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.

In the coding style, you will find:

https://edk2-docs.gitbooks.io/edk-ii-c-coding-standards-specification/content/5_source_files/#51-general-rules

----------
5 Source Files
5.1 General Rules
5.1.1 Lines shall be 120 columns, or less

Preferably, limit line lengths to 80 columns or less. When this doesn't
leave sufficient space for a good postfix style comment, extend the line
to a total of 120 columns. Having some level of uniformity in the
expected width of the source is useful for viewing and printing the code.
----------

I stick with 79 chars because they don't wrap in any kind of window
sized to 80 columns. (Some terminal emulators / pager programs insert
blank lines or wrap unexpectedly when a line is exactly 80 columns.)
And, I like to size my windows to 80 columns because I use only one
monitor (I dislike using more than one) and with 80 cols/window I can
fit two windows side by side conveniently.

You will find that users of Windows IDEs / multi-monitor setups totally
ignore the 80 columns recommendation, and only stay even within the 120
columns limit as long as it's convenient for them (regardless of
"postfix style comments"). For this reason, reading MdePkg /
MdeModulePkg source code is a constant struggle for me. And, I tend to
rewrap code that's imported to OvmfPkg from those places.

Unfortunately, the very long variable names encouraged in edk2, combined
with the requirement to break every argument of a multi-line function
call to a separate line, provides a really strong incentive to exceed 80
characters. Say you have a protocol member func call with 5 arguments,
and when written on a single line, it ends at column 105. Will you stick
with that -- and drive me nuts, when I have to read it --, or will you
break it into *seven* lines (function name, plus 5 args, plus closing
paren)? Most people will opt to drive me nuts.

Of course the sensible pattern would be to fill lines up to 79 chars as
much as possible, and break the line only when you have to (honoring
this limit), but that style has not been accepted, and I've had to
abandon it.

> Sorry about all those formating errors, and thanks for being so patience.

No problem.

Thanks,
Laszlo

> 
> -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
>>



  reply	other threads:[~2017-08-03 22:25 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
2017-08-03 22:27       ` Laszlo Ersek [this message]
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=2b7e7cfb-0006-9dc2-951f-2d1f7d1a3214@redhat.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