summaryrefslogtreecommitdiffstats
path: root/ArmVirtPkg
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2015-09-24 21:40:41 +0000
committerlersek <lersek@Edk2>2015-09-24 21:40:41 +0000
commit953bcbcce425f56bf48ef029daea7ec9e6421f4f (patch)
treed8fb43be29036a76d038543d66e2e90e4e5fae8f /ArmVirtPkg
parent50b91449a3a073af3a7c87af83002016e7e34cc4 (diff)
downloadedk2-953bcbcce425f56bf48ef029daea7ec9e6421f4f.tar.gz
edk2-953bcbcce425f56bf48ef029daea7ec9e6421f4f.tar.bz2
edk2-953bcbcce425f56bf48ef029daea7ec9e6421f4f.zip
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')
-rw-r--r--ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c126
-rw-r--r--ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf2
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