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

