+/**\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