On 09/24/15 23:10, Ard Biesheuvel wrote: > 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!
Thank you, especially on behalf of the QEMU side designers & implementors of the feature. :) > > Reviewed-by: Ard Biesheuvel <[email protected]> Thank you very much for the quick review. I committed the series to SVN (r18544, r18545). Cheers Laszlo > >> --- >> 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 > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

