\r
#include <Library/BaseLib.h>\r
#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
#include <Library/IoLib.h>\r
#include <Library/PcdLib.h>\r
#include <Library/QemuFwCfgLib.h>\r
\r
STATIC UINTN mFwCfgSelectorAddress;\r
STATIC UINTN mFwCfgDataAddress;\r
+STATIC UINTN mFwCfgDmaAddress;\r
+\r
+/**\r
+ Reads firmware configuration bytes into a buffer\r
+\r
+ @param[in] Size Size in bytes to read\r
+ @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)\r
+\r
+**/\r
+typedef\r
+VOID (EFIAPI READ_BYTES_FUNCTION) (\r
+ IN UINTN Size,\r
+ IN VOID *Buffer OPTIONAL\r
+ );\r
+\r
+//\r
+// Forward declaration of the two implementations we have.\r
+//\r
+STATIC READ_BYTES_FUNCTION MmioReadBytes;\r
+STATIC READ_BYTES_FUNCTION DmaReadBytes;\r
+\r
+//\r
+// This points to the one we detect at runtime.\r
+//\r
+STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;\r
+\r
+//\r
+// Communication structure for DmaReadBytes(). All fields are encoded in big\r
+// endian.\r
+//\r
+#pragma pack (1)\r
+typedef struct {\r
+ UINT32 Control;\r
+ UINT32 Length;\r
+ UINT64 Address;\r
+} FW_CFG_DMA_ACCESS;\r
+#pragma pack ()\r
+\r
+//\r
+// Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).\r
+//\r
+#define FW_CFG_DMA_CTL_ERROR BIT0\r
+#define FW_CFG_DMA_CTL_READ BIT1\r
+#define FW_CFG_DMA_CTL_SKIP BIT2\r
+#define FW_CFG_DMA_CTL_SELECT BIT3\r
\r
\r
/**\r
\r
QemuFwCfgSelectItem (QemuFwCfgItemSignature);\r
Signature = QemuFwCfgRead32 ();\r
- if (Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
+ if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
+ //\r
+ // For DMA support, we require the DTB to advertise the register, and the\r
+ // feature bitmap (which we read without DMA) to confirm the feature.\r
+ //\r
+ if (PcdGet64 (PcdFwCfgDmaAddress) != 0) {\r
+ UINT32 Features;\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);\r
+ Features = QemuFwCfgRead32 ();\r
+ if ((Features & BIT1) != 0) {\r
+ mFwCfgDmaAddress = PcdGet64 (PcdFwCfgDmaAddress);\r
+ InternalQemuFwCfgReadBytes = DmaReadBytes;\r
+ }\r
+ }\r
+ } else {\r
mFwCfgSelectorAddress = 0;\r
mFwCfgDataAddress = 0;\r
}\r
\r
\r
/**\r
- Reads firmware configuration bytes into a buffer\r
-\r
- @param[in] Size Size in bytes to read\r
- @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)\r
-\r
+ Slow READ_BYTES_FUNCTION.\r
**/\r
STATIC\r
VOID\r
EFIAPI\r
-InternalQemuFwCfgReadBytes (\r
+MmioReadBytes (\r
IN UINTN Size,\r
IN VOID *Buffer OPTIONAL\r
)\r
}\r
\r
\r
+/**\r
+ Fast READ_BYTES_FUNCTION.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+DmaReadBytes (\r
+ IN UINTN Size,\r
+ IN VOID *Buffer OPTIONAL\r
+ )\r
+{\r
+ volatile FW_CFG_DMA_ACCESS Access;\r
+ UINT32 Status;\r
+\r
+ if (Size == 0) {\r
+ return;\r
+ }\r
+\r
+ ASSERT (Size <= MAX_UINT32);\r
+\r
+ Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);\r
+ Access.Length = SwapBytes32 ((UINT32)Size);\r
+ Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);\r
+\r
+ //\r
+ // We shouldn't start the transfer before setting up Access.\r
+ //\r
+ MemoryFence ();\r
+\r
+ //\r
+ // This will fire off the transfer.\r
+ //\r
+#ifdef MDE_CPU_AARCH64\r
+ MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));\r
+#else\r
+ MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));\r
+#endif\r
+\r
+ //\r
+ // We shouldn't look at Access.Control before starting the transfer.\r
+ //\r
+ MemoryFence ();\r
+\r
+ do {\r
+ Status = SwapBytes32 (Access.Control);\r
+ ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
+ } while (Status != 0);\r
+\r
+ //\r
+ // The caller will want to access the transferred data.\r
+ //\r
+ MemoryFence ();\r
+}\r
+\r
+\r
/**\r
Reads firmware configuration bytes into a buffer\r
\r