diff options
author | Laszlo Ersek <lersek@redhat.com> | 2015-09-24 21:40:41 +0000 |
---|---|---|
committer | lersek <lersek@Edk2> | 2015-09-24 21:40:41 +0000 |
commit | 953bcbcce425f56bf48ef029daea7ec9e6421f4f (patch) | |
tree | d8fb43be29036a76d038543d66e2e90e4e5fae8f /ArmVirtPkg/Library | |
parent | 50b91449a3a073af3a7c87af83002016e7e34cc4 (diff) | |
download | edk2-platforms-953bcbcce425f56bf48ef029daea7ec9e6421f4f.tar.xz |
ArmVirtPkg: QemuFwCfgLib: read bytes from fw-cfg with DMA when available
The protocol is documented in "docs/specs/fw_cfg.txt" in the QEMU tree.
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18545 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ArmVirtPkg/Library')
-rw-r--r-- | ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c | 126 | ||||
-rw-r--r-- | ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf | 2 |
2 files changed, 121 insertions, 7 deletions
diff --git a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c index c62eee3be8..303dc520c6 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
diff --git a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf index 42f21f20c0..298aa6edfb 100644 --- a/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf +++ b/ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf @@ -44,9 +44,11 @@ [LibraryClasses]
BaseLib
BaseMemoryLib
+ DebugLib
IoLib
PcdLib
[Pcd]
gArmVirtTokenSpaceGuid.PcdFwCfgSelectorAddress
gArmVirtTokenSpaceGuid.PcdFwCfgDataAddress
+ gArmVirtTokenSpaceGuid.PcdFwCfgDmaAddress
|