On 24 September 2015 at 04:26, Laszlo Ersek <[email protected]> wrote:
> The protocol is documented in "docs/specs/fw_cfg.txt" in the QEMU tree.
>
> Cc: Ard Biesheuvel <[email protected]>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Laszlo Ersek <[email protected]>

Nice feature!

Reviewed-by: Ard Biesheuvel <[email protected]>

> ---
>  ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf |   2 +
>  ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c   | 126 ++++++++++++++++++--
>  2 files changed, 121 insertions(+), 7 deletions(-)
>
> diff --git a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf 
> b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
> index 42f21f2..298aa6e 100644
> --- a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
> +++ b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
> @@ -44,9 +44,11 @@ [Packages]
>  [LibraryClasses]
>    BaseLib
>    BaseMemoryLib
> +  DebugLib
>    IoLib
>    PcdLib
>
>  [Pcd]
>    gArmVirtTokenSpaceGuid.PcdFwCfgSelectorAddress
>    gArmVirtTokenSpaceGuid.PcdFwCfgDataAddress
> +  gArmVirtTokenSpaceGuid.PcdFwCfgDmaAddress
> diff --git a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c 
> b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
> index c62eee3..303dc52 100644
> --- a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
> +++ b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
> @@ -16,12 +16,58 @@
>
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
>  #include <Library/IoLib.h>
>  #include <Library/PcdLib.h>
>  #include <Library/QemuFwCfgLib.h>
>
>  STATIC UINTN mFwCfgSelectorAddress;
>  STATIC UINTN mFwCfgDataAddress;
> +STATIC UINTN mFwCfgDmaAddress;
> +
> +/**
> +  Reads firmware configuration bytes into a buffer
> +
> +  @param[in] Size    Size in bytes to read
> +  @param[in] Buffer  Buffer to store data into  (OPTIONAL if Size is 0)
> +
> +**/
> +typedef
> +VOID (EFIAPI READ_BYTES_FUNCTION) (
> +  IN UINTN Size,
> +  IN VOID  *Buffer OPTIONAL
> +  );
> +
> +//
> +// Forward declaration of the two implementations we have.
> +//
> +STATIC READ_BYTES_FUNCTION MmioReadBytes;
> +STATIC READ_BYTES_FUNCTION DmaReadBytes;
> +
> +//
> +// This points to the one we detect at runtime.
> +//
> +STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;
> +
> +//
> +// Communication structure for DmaReadBytes(). All fields are encoded in big
> +// endian.
> +//
> +#pragma pack (1)
> +typedef struct {
> +  UINT32 Control;
> +  UINT32 Length;
> +  UINT64 Address;
> +} FW_CFG_DMA_ACCESS;
> +#pragma pack ()
> +
> +//
> +// Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).
> +//
> +#define FW_CFG_DMA_CTL_ERROR  BIT0
> +#define FW_CFG_DMA_CTL_READ   BIT1
> +#define FW_CFG_DMA_CTL_SKIP   BIT2
> +#define FW_CFG_DMA_CTL_SELECT BIT3
>
>
>  /**
> @@ -77,7 +123,22 @@ QemuFwCfgInitialize (
>
>      QemuFwCfgSelectItem (QemuFwCfgItemSignature);
>      Signature = QemuFwCfgRead32 ();
> -    if (Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
> +    if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
> +      //
> +      // For DMA support, we require the DTB to advertise the register, and 
> the
> +      // feature bitmap (which we read without DMA) to confirm the feature.
> +      //
> +      if (PcdGet64 (PcdFwCfgDmaAddress) != 0) {
> +        UINT32 Features;
> +
> +        QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
> +        Features = QemuFwCfgRead32 ();
> +        if ((Features & BIT1) != 0) {
> +          mFwCfgDmaAddress = PcdGet64 (PcdFwCfgDmaAddress);
> +          InternalQemuFwCfgReadBytes = DmaReadBytes;
> +        }
> +      }
> +    } else {
>        mFwCfgSelectorAddress = 0;
>        mFwCfgDataAddress     = 0;
>      }
> @@ -108,16 +169,12 @@ QemuFwCfgSelectItem (
>
>
>  /**
> -  Reads firmware configuration bytes into a buffer
> -
> -  @param[in] Size    Size in bytes to read
> -  @param[in] Buffer  Buffer to store data into  (OPTIONAL if Size is 0)
> -
> +  Slow READ_BYTES_FUNCTION.
>  **/
>  STATIC
>  VOID
>  EFIAPI
> -InternalQemuFwCfgReadBytes (
> +MmioReadBytes (
>    IN UINTN Size,
>    IN VOID  *Buffer OPTIONAL
>    )
> @@ -163,6 +220,61 @@ InternalQemuFwCfgReadBytes (
>
>
>  /**
> +  Fast READ_BYTES_FUNCTION.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +DmaReadBytes (
> +  IN UINTN Size,
> +  IN VOID  *Buffer OPTIONAL
> +  )
> +{
> +  volatile FW_CFG_DMA_ACCESS Access;
> +  UINT32                     Status;
> +
> +  if (Size == 0) {
> +    return;
> +  }
> +
> +  ASSERT (Size <= MAX_UINT32);
> +
> +  Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);
> +  Access.Length  = SwapBytes32 ((UINT32)Size);
> +  Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);
> +
> +  //
> +  // We shouldn't start the transfer before setting up Access.
> +  //
> +  MemoryFence ();
> +
> +  //
> +  // This will fire off the transfer.
> +  //
> +#ifdef MDE_CPU_AARCH64
> +  MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));
> +#else
> +  MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 
> ((UINT32)&Access));
> +#endif
> +
> +  //
> +  // We shouldn't look at Access.Control before starting the transfer.
> +  //
> +  MemoryFence ();
> +
> +  do {
> +    Status = SwapBytes32 (Access.Control);
> +    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
> +  } while (Status != 0);
> +
> +  //
> +  // The caller will want to access the transferred data.
> +  //
> +  MemoryFence ();
> +}
> +
> +
> +/**
>    Reads firmware configuration bytes into a buffer
>
>    If called multiple times, then the data read will continue at the offset of
> --
> 1.8.3.1
>
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to