<div>Reviewed-by: Chao Li  <lichao@loongson.cn></div><br><div><signature id="local-a67dfd9c-c219"><p style="color:grey;font-size:11px"><br>Thanks,<br>Chao<br>--------<br><br></p></signature></div><div class="gmail_quote_attribution">On 11月 11 2022, at 5:12 δΈ‹εˆ, xianglai li <lixianglai@loongson.cn> wrote:</div><blockquote><div><div>QemuFwCfgLib for PEI phase.</div><br><div>This library obtains the QemuFWCfg base address by</div><br><div>directly parsing the fdt, and reads and writes the data</div><br><div>in the QemuFWCfg by operating on the QemuFWCfg base address.</div><br><br><br><div>REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054</div><br><br><br><div>Cc: Bibo Mao <maobibo@loongson.cn></div><br><div>Cc: Chao Li <lichao@loongson.cn></div><br><div>Cc: Leif Lindholm <quic_llindhol@quicinc.com></div><br><div>Cc: Liming Gao <gaoliming@byosoft.com.cn></div><br><div>Cc: Michael D Kinney <michael.d.kinney@intel.com></div><br><div>Signed-off-by: xianglai li <lixianglai@loongson.cn></div><br><div>---</div><br><div>.../Include/Library/QemuFwCfgLib.h | 174 +++++++</div><br><div>.../QemuFwCfgLib/QemuFwCfgLibInternal.h | 63 +++</div><br><div>.../Library/QemuFwCfgLib/QemuFwCfgPei.c | 117 +++++</div><br><div>.../Library/QemuFwCfgLib/QemuFwCfgPeiLib.c | 463 ++++++++++++++++++</div><br><div>.../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 46 ++</div><br><div>5 files changed, 863 insertions(+)</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf</div><br><br><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h</div><br><div>new file mode 100644</div><br><div>index 0000000000..11da4d0b8a</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h</div><br><div>@@ -0,0 +1,174 @@</div><br><div>+/** @file</div><br><div>+ QEMU/KVM Firmware Configuration access</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+ @par Glossary:</div><br><div>+ - FW or Fw - Firmware</div><br><div>+ - Cfg - Configure</div><br><div>+**/</div><br><div>+</div><br><div>+#ifndef QEMU_FW_CFG_LIB_</div><br><div>+#define QEMU_FW_CFG_LIB_</div><br><div>+</div><br><div>+#include <IndustryStandard/QemuFwCfg.h></div><br><div>+</div><br><div>+typedef enum {</div><br><div>+ EfiAcpiAddressRangeMemory = 1,</div><br><div>+ EfiAcpiAddressRangeReserved = 2,</div><br><div>+ EfiAcpiAddressRangeACPI = 3,</div><br><div>+ EfiAcpiAddressRangeNVS = 4</div><br><div>+} EFI_ACPI_MEMORY_TYPE;</div><br><div>+</div><br><div>+typedef struct {</div><br><div>+ UINT64 BaseAddr;</div><br><div>+ UINT64 Length;</div><br><div>+ UINT32 Type;</div><br><div>+ UINT32 Reserved;</div><br><div>+} LOONGARCH_MEMMAP_ENTRY;</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a boolean indicating if the firmware configuration interface</div><br><div>+ is available or not.</div><br><div>+</div><br><div>+ This function may change fw_cfg state.</div><br><div>+</div><br><div>+ @retval TRUE The interface is available</div><br><div>+ @retval FALSE The interface is not available</div><br><div>+**/</div><br><div>+BOOLEAN</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgIsAvailable (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Selects a firmware configuration item for reading.</div><br><div>+</div><br><div>+ Following this call, any data read from this item will start from</div><br><div>+ the beginning of the configuration item's data.</div><br><div>+</div><br><div>+ @param[in] QemuFwCfgItem - Firmware Configuration item to read</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgSelectItem (</div><br><div>+ IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads firmware configuration bytes into a buffer</div><br><div>+</div><br><div>+ If called multiple times, then the data read will</div><br><div>+ continue at the offset of the firmware configuration</div><br><div>+ item where the previous read ended.</div><br><div>+</div><br><div>+ @param[in] Size - Size in bytes to read</div><br><div>+ @param[in] Buffer - Buffer to store data into</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgReadBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer OPTIONAL</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Writes firmware configuration bytes from a buffer</div><br><div>+</div><br><div>+ If called multiple times, then the data written will</div><br><div>+ continue at the offset of the firmware configuration</div><br><div>+ item where the previous write ended.</div><br><div>+</div><br><div>+ @param[in] Size - Size in bytes to write</div><br><div>+ @param[in] Buffer - Buffer to read data from</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgWriteBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Skip bytes in the firmware configuration item.</div><br><div>+</div><br><div>+ Increase the offset of the firmware configuration item without transferring</div><br><div>+ bytes between the item and a caller-provided buffer. Subsequent read, write</div><br><div>+ or skip operations will commence at the increased offset.</div><br><div>+</div><br><div>+ @param[in] Size Number of bytes to skip.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgSkipBytes (</div><br><div>+ IN UINTN Size</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT8 firmware configuration value</div><br><div>+</div><br><div>+ @retval Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT8</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead8 (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT16 firmware configuration value</div><br><div>+</div><br><div>+ @retval Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT16</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead16 (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT32 firmware configuration value</div><br><div>+</div><br><div>+ @retval Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT32</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead32 (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT64 firmware configuration value</div><br><div>+</div><br><div>+ @retval Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT64</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead64 (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Find the configuration item corresponding to the firmware configuration file.</div><br><div>+</div><br><div>+ @param[in] Name - Name of file to look up.</div><br><div>+ @param[out] Item - Configuration item corresponding to the file, to be passed</div><br><div>+ to QemuFwCfgSelectItem ().</div><br><div>+ @param[out] Size - Number of bytes in the file.</div><br><div>+</div><br><div>+ @retval RETURN_SUCCESS If file is found.</div><br><div>+ RETURN_NOT_FOUND If file is not found.</div><br><div>+ RETURN_UNSUPPORTED If firmware configuration is unavailable.</div><br><div>+**/</div><br><div>+RETURN_STATUS</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgFindFile (</div><br><div>+ IN CONST CHAR8 *Name,</div><br><div>+ OUT FIRMWARE_CONFIG_ITEM *Item,</div><br><div>+ OUT UINTN *Size</div><br><div>+ );</div><br><div>+</div><br><div>+#endif // QEMU_FW_CFG_LIB_</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h</div><br><div>new file mode 100644</div><br><div>index 0000000000..229c080961</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h</div><br><div>@@ -0,0 +1,63 @@</div><br><div>+/** @file</div><br><div>+ fw_cfg library implementation.</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+ @par Glossary:</div><br><div>+ - FwCfg - firmWare Configure</div><br><div>+**/</div><br><div>+</div><br><div>+#ifndef QEMU_FW_CFG_LIB_INTERNAL_H_</div><br><div>+#define QEMU_FW_CFG_LIB_INTERNAL_H_</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a boolean indicating if the firmware configuration interface is</div><br><div>+ available for library-internal purposes.</div><br><div>+</div><br><div>+ This function never changes fw_cfg state.</div><br><div>+</div><br><div>+ @retval TRUE The interface is available internally.</div><br><div>+ @retval FALSE The interface is not available internally.</div><br><div>+**/</div><br><div>+BOOLEAN</div><br><div>+InternalQemuFwCfgIsAvailable (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a boolean indicating whether QEMU provides the DMA-like access method</div><br><div>+ for fw_cfg.</div><br><div>+</div><br><div>+ @retval TRUE The DMA-like access method is available.</div><br><div>+ @retval FALSE The DMA-like access method is unavailable.</div><br><div>+**/</div><br><div>+BOOLEAN</div><br><div>+InternalQemuFwCfgDmaIsAvailable (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ Transfer an array of bytes, or skip a number of bytes, using the DMA</div><br><div>+ interface.</div><br><div>+</div><br><div>+ @param[in] Size Size in bytes to transfer or skip.</div><br><div>+</div><br><div>+ @param[in,out] Buffer Buffer to read data into or write data from. Ignored,</div><br><div>+ and may be NULL, if Size is zero, or Control is</div><br><div>+ FW_CFG_DMA_CTL_SKIP.</div><br><div>+</div><br><div>+ @param[in] Control One of the following:</div><br><div>+ FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.</div><br><div>+ FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.</div><br><div>+ FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+InternalQemuFwCfgDmaBytes (</div><br><div>+ IN UINT32 Size,</div><br><div>+ IN OUT VOID *Buffer OPTIONAL,</div><br><div>+ IN UINT32 Control</div><br><div>+ );</div><br><div>+</div><br><div>+#endif // QEMU_FW_CFG_LIB_INTERNAL_H_</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c</div><br><div>new file mode 100644</div><br><div>index 0000000000..b170c953f3</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c</div><br><div>@@ -0,0 +1,117 @@</div><br><div>+/** @file</div><br><div>+ fw_cfg library implementation.</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+ @par Glossary:</div><br><div>+ - FwCfg - firmWare Configure</div><br><div>+**/</div><br><div>+</div><br><div>+#include <Library/BaseLib.h></div><br><div>+#include <Library/DebugLib.h></div><br><div>+#include <Library/QemuFwCfgLib.h></div><br><div>+</div><br><div>+#include "QemuFwCfgLibInternal.h"</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a boolean indicating if the firmware configuration interface</div><br><div>+ is available or not.</div><br><div>+</div><br><div>+ This function may change fw_cfg state.</div><br><div>+</div><br><div>+ @retval TRUE The interface is available</div><br><div>+ @retval FALSE The interface is not available</div><br><div>+**/</div><br><div>+BOOLEAN</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgIsAvailable (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINT32 Signature;</div><br><div>+ UINT32 Revision;</div><br><div>+</div><br><div>+ QemuFwCfgSelectItem (QemuFwCfgItemSignature);</div><br><div>+ Signature = QemuFwCfgRead32 ();</div><br><div>+ DEBUG ((DEBUG_INFO, "FW CFG Signature: 0x%x\n", Signature));</div><br><div>+ QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);</div><br><div>+ Revision = QemuFwCfgRead32 ();</div><br><div>+ DEBUG ((DEBUG_INFO, "FW CFG Revision: 0x%x\n", Revision));</div><br><div>+ if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U'))</div><br><div>+ || (Revision < 1))</div><br><div>+ {</div><br><div>+ DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));</div><br><div>+ return FALSE;</div><br><div>+ }</div><br><div>+</div><br><div>+ DEBUG ((DEBUG_INFO, "QemuFwCfg interface is supported.\n"));</div><br><div>+ return TRUE;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a boolean indicating if the firmware configuration interface is</div><br><div>+ available for library-internal purposes.</div><br><div>+</div><br><div>+ This function never changes fw_cfg state.</div><br><div>+</div><br><div>+ @retval TRUE The interface is available internally.</div><br><div>+ @retval FALSE The interface is not available internally.</div><br><div>+**/</div><br><div>+BOOLEAN</div><br><div>+InternalQemuFwCfgIsAvailable (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ //</div><br><div>+ // We always return TRUE, because the consumer of this library ought to have</div><br><div>+ // called QemuFwCfgIsAvailable before making other calls which would hit this</div><br><div>+ // path.</div><br><div>+ //</div><br><div>+ return TRUE;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a boolean indicating whether QEMU provides the DMA-like access method</div><br><div>+ for fw_cfg.</div><br><div>+</div><br><div>+ @retval TRUE The DMA-like access method is available.</div><br><div>+ @retval FALSE The DMA-like access method is unavailable.</div><br><div>+**/</div><br><div>+BOOLEAN</div><br><div>+InternalQemuFwCfgDmaIsAvailable (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ return FALSE;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Transfer an array of bytes, or skip a number of bytes, using the DMA</div><br><div>+ interface.</div><br><div>+</div><br><div>+ @param[in] Size Size in bytes to transfer or skip.</div><br><div>+</div><br><div>+ @param[in, out] Buffer Buffer to read data into or write data from. Ignored,</div><br><div>+ and may be NULL, if Size is zero, or Control is</div><br><div>+ FW_CFG_DMA_CTL_SKIP.</div><br><div>+</div><br><div>+ @param[in] Control One of the following:</div><br><div>+ FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.</div><br><div>+ FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.</div><br><div>+ FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+InternalQemuFwCfgDmaBytes (</div><br><div>+ IN UINT32 Size,</div><br><div>+ IN OUT VOID *Buffer OPTIONAL,</div><br><div>+ IN UINT32 Control</div><br><div>+ )</div><br><div>+{</div><br><div>+ //</div><br><div>+ // We should never reach here</div><br><div>+ //</div><br><div>+ ASSERT (FALSE);</div><br><div>+ CpuDeadLoop ();</div><br><div>+}</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c</div><br><div>new file mode 100644</div><br><div>index 0000000000..5593856b82</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c</div><br><div>@@ -0,0 +1,463 @@</div><br><div>+/** @file</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+ @par Glossary:</div><br><div>+ - FwCfg - firmWare Configure</div><br><div>+ - CTL - Control</div><br><div>+**/</div><br><div>+</div><br><div>+#include "Uefi.h"</div><br><div>+#include <Library/BaseLib.h></div><br><div>+#include <Library/BaseMemoryLib.h></div><br><div>+#include <Library/DebugLib.h></div><br><div>+#include <Library/IoLib.h></div><br><div>+#include <Library/QemuFwCfgLib.h></div><br><div>+#include <Library/MemoryAllocationLib.h></div><br><div>+#include <Library/UefiBootServicesTableLib.h></div><br><div>+#include <Library/PcdLib.h></div><br><div>+#include <libfdt.h></div><br><div>+#include "QemuFwCfgLibInternal.h"</div><br><div>+</div><br><div>+STATIC UINTN mFwCfgSelectorAddress;</div><br><div>+STATIC UINTN mFwCfgDataAddress;</div><br><div>+/**</div><br><div>+ To get firmware configure selector address.</div><br><div>+</div><br><div>+ @param VOID</div><br><div>+</div><br><div>+ @retval firmware configure selector address</div><br><div>+**/</div><br><div>+UINTN</div><br><div>+EFIAPI</div><br><div>+QemuGetFwCfgSelectorAddress (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINTN FwCfgSelectorAddress = mFwCfgSelectorAddress;</div><br><div>+ if (FwCfgSelectorAddress == 0) {</div><br><div>+ FwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);</div><br><div>+ }</div><br><div>+ return FwCfgSelectorAddress;</div><br><div>+}</div><br><div>+/**</div><br><div>+ To get firmware configure Data address.</div><br><div>+</div><br><div>+ @param VOID</div><br><div>+</div><br><div>+ @retval firmware configure data address</div><br><div>+**/</div><br><div>+UINTN</div><br><div>+EFIAPI</div><br><div>+QemuGetFwCfgDataAddress (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINTN FwCfgDataAddress = mFwCfgDataAddress;</div><br><div>+ if (FwCfgDataAddress == 0) {</div><br><div>+ FwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);</div><br><div>+ }</div><br><div>+ return FwCfgDataAddress;</div><br><div>+}</div><br><div>+/**</div><br><div>+ Selects a firmware configuration item for reading.</div><br><div>+</div><br><div>+ Following this call, any data read from this item will start from</div><br><div>+ the beginning of the configuration item's data.</div><br><div>+</div><br><div>+ @param[in] QemuFwCfgItem - Firmware Configuration item to read</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgSelectItem (</div><br><div>+ IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINTN FwCfgSelectorAddress;</div><br><div>+ FwCfgSelectorAddress = QemuGetFwCfgSelectorAddress ();</div><br><div>+ MmioWrite16 (FwCfgSelectorAddress, SwapBytes16((UINT16) (UINTN)QemuFwCfgItem));</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Slow READ_BYTES_FUNCTION.</div><br><div>+</div><br><div>+ @param[in] The size of the data to be read.</div><br><div>+ @param[in] Buffer The buffer that stores the readout data.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+MmioReadBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer OPTIONAL</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINTN Left;</div><br><div>+ UINT8 *Ptr;</div><br><div>+ UINT8 *End;</div><br><div>+ UINTN FwCfgDataAddress;</div><br><div>+ Left = Size & 7;</div><br><div>+</div><br><div>+ Size -= Left;</div><br><div>+ Ptr = Buffer;</div><br><div>+ End = Ptr + Size;</div><br><div>+ FwCfgDataAddress = QemuGetFwCfgDataAddress ();</div><br><div>+ while (Ptr < End) {</div><br><div>+ *(UINT64 *)Ptr = MmioRead64 (FwCfgDataAddress);</div><br><div>+ Ptr += 8;</div><br><div>+ }</div><br><div>+ if (Left & 4) {</div><br><div>+ *(UINT32 *)Ptr = MmioRead32 (FwCfgDataAddress);</div><br><div>+ Ptr += 4;</div><br><div>+ }</div><br><div>+ if (Left & 2) {</div><br><div>+ *(UINT16 *)Ptr = MmioRead16 (FwCfgDataAddress);</div><br><div>+ Ptr += 2;</div><br><div>+ }</div><br><div>+ if (Left & 1) {</div><br><div>+ *Ptr = MmioRead8 (FwCfgDataAddress);</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Slow WRITE_BYTES_FUNCTION.</div><br><div>+</div><br><div>+ @param[in] The size of the data to be write.</div><br><div>+ @param[in] Buffer The buffer that stores the writein data.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+MmioWriteBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer OPTIONAL</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINTN Idx;</div><br><div>+ UINTN FwCfgDataAddress;</div><br><div>+ FwCfgDataAddress = QemuGetFwCfgDataAddress ();</div><br><div>+ for (Idx = 0; Idx < Size; ++Idx) {</div><br><div>+ MmioWrite8 (FwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads firmware configuration bytes into a buffer</div><br><div>+</div><br><div>+ @param[in] Size - Size in bytes to read</div><br><div>+ @param[in] Buffer - Buffer to store data into (OPTIONAL if Size is 0)</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+InternalQemuFwCfgReadBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer OPTIONAL</div><br><div>+ )</div><br><div>+{</div><br><div>+ if ((InternalQemuFwCfgDmaIsAvailable ())</div><br><div>+ && (Size <= MAX_UINT32))</div><br><div>+ {</div><br><div>+ InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_READ);</div><br><div>+ return;</div><br><div>+ }</div><br><div>+ MmioReadBytes (Size, Buffer);</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads firmware configuration bytes into a buffer</div><br><div>+</div><br><div>+ If called multiple times, then the data read will</div><br><div>+ continue at the offset of the firmware configuration</div><br><div>+ item where the previous read ended.</div><br><div>+</div><br><div>+ @param[in] Size - Size in bytes to read</div><br><div>+ @param[in] Buffer - Buffer to store data into</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgReadBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer</div><br><div>+ )</div><br><div>+{</div><br><div>+ if (InternalQemuFwCfgIsAvailable ()) {</div><br><div>+ InternalQemuFwCfgReadBytes (Size, Buffer);</div><br><div>+ } else {</div><br><div>+ ZeroMem (Buffer, Size);</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Write firmware configuration bytes from a buffer</div><br><div>+</div><br><div>+ If called multiple times, then the data written will</div><br><div>+ continue at the offset of the firmware configuration</div><br><div>+ item where the previous write ended.</div><br><div>+</div><br><div>+ @param[in] Size - Size in bytes to write</div><br><div>+ @param[in] Buffer - Buffer to read data from</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgWriteBytes (</div><br><div>+ IN UINTN Size,</div><br><div>+ IN VOID *Buffer</div><br><div>+ )</div><br><div>+{</div><br><div>+ if (InternalQemuFwCfgIsAvailable ()) {</div><br><div>+ if ((InternalQemuFwCfgDmaIsAvailable ())</div><br><div>+ && (Size <= MAX_UINT32))</div><br><div>+ {</div><br><div>+ InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_WRITE);</div><br><div>+ return;</div><br><div>+ }</div><br><div>+ MmioWriteBytes (Size, Buffer);</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Skip bytes in the firmware configuration item.</div><br><div>+</div><br><div>+ Increase the offset of the firmware configuration item without transferring</div><br><div>+ bytes between the item and a caller-provided buffer. Subsequent read, write</div><br><div>+ or skip operations will commence at the increased offset.</div><br><div>+</div><br><div>+ @param[in] Size Number of bytes to skip.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgSkipBytes (</div><br><div>+ IN UINTN Size</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINTN ChunkSize;</div><br><div>+ UINT8 SkipBuffer[256];</div><br><div>+</div><br><div>+ if (!InternalQemuFwCfgIsAvailable ()) {</div><br><div>+ return;</div><br><div>+ }</div><br><div>+</div><br><div>+ if ((InternalQemuFwCfgDmaIsAvailable ())</div><br><div>+ && (Size <= MAX_UINT32))</div><br><div>+ {</div><br><div>+ InternalQemuFwCfgDmaBytes ((UINT32)Size, NULL, FW_CFG_DMA_CTL_SKIP);</div><br><div>+ return;</div><br><div>+ }</div><br><div>+</div><br><div>+ //</div><br><div>+ // Emulate the skip by reading data in chunks, and throwing it away. The</div><br><div>+ // implementation below is suitable even for phases where RAM or dynamic</div><br><div>+ // allocation is not available or appropriate. It also doesn't affect the</div><br><div>+ // static data footprint for client modules. Large skips are not expected,</div><br><div>+ // therefore this fallback is not performance critical. The size of</div><br><div>+ // SkipBuffer is thought not to exert a large pressure on the stack in any</div><br><div>+ // phase.</div><br><div>+ //</div><br><div>+ while (Size > 0) {</div><br><div>+ ChunkSize = MIN (Size, sizeof SkipBuffer);</div><br><div>+ MmioReadBytes (ChunkSize, SkipBuffer);</div><br><div>+ Size -= ChunkSize;</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT8 firmware configuration value</div><br><div>+</div><br><div>+ @return Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT8</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead8 (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINT8 Result;</div><br><div>+</div><br><div>+ QemuFwCfgReadBytes (sizeof (Result), &Result);</div><br><div>+</div><br><div>+ return Result;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT16 firmware configuration value</div><br><div>+</div><br><div>+ @return Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT16</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead16 (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINT16 Result;</div><br><div>+</div><br><div>+ QemuFwCfgReadBytes (sizeof (Result), &Result);</div><br><div>+</div><br><div>+ return Result;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT32 firmware configuration value</div><br><div>+</div><br><div>+ @return Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT32</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead32 (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINT32 Result;</div><br><div>+</div><br><div>+ QemuFwCfgReadBytes (sizeof (Result), &Result);</div><br><div>+</div><br><div>+ return Result;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Reads a UINT64 firmware configuration value</div><br><div>+</div><br><div>+ @return Value of Firmware Configuration item read</div><br><div>+**/</div><br><div>+UINT64</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgRead64 (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINT64 Result;</div><br><div>+</div><br><div>+ QemuFwCfgReadBytes (sizeof (Result), &Result);</div><br><div>+</div><br><div>+ return Result;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Find the configuration item corresponding to the firmware configuration file.</div><br><div>+</div><br><div>+ @param[in] Name - Name of file to look up.</div><br><div>+ @param[out] Item - Configuration item corresponding to the file, to be passed</div><br><div>+ to QemuFwCfgSelectItem ().</div><br><div>+ @param[out] Size - Number of bytes in the file.</div><br><div>+</div><br><div>+ @return RETURN_SUCCESS If file is found.</div><br><div>+ RETURN_NOT_FOUND If file is not found.</div><br><div>+ RETURN_UNSUPPORTED If firmware configuration is unavailable.</div><br><div>+**/</div><br><div>+RETURN_STATUS</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgFindFile (</div><br><div>+ IN CONST CHAR8 *Name,</div><br><div>+ OUT FIRMWARE_CONFIG_ITEM *Item,</div><br><div>+ OUT UINTN *Size</div><br><div>+ )</div><br><div>+{</div><br><div>+ UINT32 Count;</div><br><div>+ UINT32 Idx;</div><br><div>+</div><br><div>+ if (!InternalQemuFwCfgIsAvailable ()) {</div><br><div>+ return RETURN_UNSUPPORTED;</div><br><div>+ }</div><br><div>+</div><br><div>+ QemuFwCfgSelectItem (QemuFwCfgItemFileDir);</div><br><div>+ Count = SwapBytes32 (QemuFwCfgRead32 ());</div><br><div>+</div><br><div>+ for (Idx = 0; Idx < Count; ++Idx) {</div><br><div>+ UINT32 FileSize;</div><br><div>+ UINT16 FileSelect;</div><br><div>+ CHAR8 FileName[QEMU_FW_CFG_FNAME_SIZE];</div><br><div>+</div><br><div>+ FileSize = QemuFwCfgRead32 ();</div><br><div>+ FileSelect = QemuFwCfgRead16 ();</div><br><div>+ QemuFwCfgRead16 (); // skip the field called "reserved"</div><br><div>+ InternalQemuFwCfgReadBytes (sizeof (FileName), FileName);</div><br><div>+</div><br><div>+ if (AsciiStrCmp (Name, FileName) == 0) {</div><br><div>+ *Item = SwapBytes16 (FileSelect);</div><br><div>+ *Size = SwapBytes32 (FileSize);</div><br><div>+ return RETURN_SUCCESS;</div><br><div>+ }</div><br><div>+ }</div><br><div>+</div><br><div>+ return RETURN_NOT_FOUND;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ firmware config initialize.</div><br><div>+</div><br><div>+ @param VOID</div><br><div>+</div><br><div>+ @return RETURN_SUCCESS Initialization succeeded.</div><br><div>+**/</div><br><div>+RETURN_STATUS</div><br><div>+EFIAPI</div><br><div>+QemuFwCfgInitialize (</div><br><div>+ VOID</div><br><div>+ )</div><br><div>+{</div><br><div>+ VOID *DeviceTreeBase;</div><br><div>+ INT32 Node;</div><br><div>+ INT32 Prev;</div><br><div>+ CONST CHAR8 *Type;</div><br><div>+ INT32 Len;</div><br><div>+ CONST UINT64 *RegProp;</div><br><div>+ UINT64 FwCfgSelectorAddress;</div><br><div>+ UINT64 FwCfgDataAddress;</div><br><div>+ UINT64 FwCfgDataSize;</div><br><div>+ RETURN_STATUS PcdStatus;</div><br><div>+</div><br><div>+ DeviceTreeBase = (VOID *) (UINTN)PcdGet64 (PcdDeviceTreeBase);</div><br><div>+ ASSERT (DeviceTreeBase != NULL);</div><br><div>+ //</div><br><div>+ // Make sure we have a valid device tree blob</div><br><div>+ //</div><br><div>+ ASSERT (fdt_check_header (DeviceTreeBase) == 0);</div><br><div>+</div><br><div>+ for (Prev = 0;; Prev = Node) {</div><br><div>+ Node = fdt_next_node (DeviceTreeBase, Prev, NULL);</div><br><div>+ if (Node < 0) {</div><br><div>+ break;</div><br><div>+ }</div><br><div>+</div><br><div>+ //</div><br><div>+ // Check for memory node</div><br><div>+ //</div><br><div>+ Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);</div><br><div>+ if ((Type)</div><br><div>+ && (AsciiStrnCmp (Type, "qemu,fw-cfg-mmio", Len) == 0))</div><br><div>+ {</div><br><div>+ //</div><br><div>+ // Get the 'reg' property of this node. For now, we will assume</div><br><div>+ // two 8 byte quantities for base and size, respectively.</div><br><div>+ //</div><br><div>+ RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);</div><br><div>+ if ((RegProp != 0)</div><br><div>+ && (Len == (2 * sizeof (UINT64))))</div><br><div>+ {</div><br><div>+ FwCfgDataAddress = SwapBytes64 (RegProp[0]);</div><br><div>+ FwCfgDataSize = 8;</div><br><div>+ FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;</div><br><div>+</div><br><div>+ mFwCfgSelectorAddress = FwCfgSelectorAddress;</div><br><div>+ mFwCfgDataAddress = FwCfgDataAddress;</div><br><div>+</div><br><div>+ PcdStatus = PcdSet64S (</div><br><div>+ PcdFwCfgSelectorAddress,</div><br><div>+ FwCfgSelectorAddress</div><br><div>+ );</div><br><div>+ ASSERT_RETURN_ERROR (PcdStatus);</div><br><div>+ PcdStatus = PcdSet64S (</div><br><div>+ PcdFwCfgDataAddress,</div><br><div>+ FwCfgDataAddress</div><br><div>+ );</div><br><div>+ ASSERT_RETURN_ERROR (PcdStatus);</div><br><div>+ break;</div><br><div>+ } else {</div><br><div>+ DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT QemuCfg node\n",</div><br><div>+ __FUNCTION__));</div><br><div>+ break;</div><br><div>+ }</div><br><div>+ }</div><br><div>+ }</div><br><div>+ return RETURN_SUCCESS;</div><br><div>+}</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf</div><br><div>new file mode 100644</div><br><div>index 0000000000..8609d615e7</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf</div><br><div>@@ -0,0 +1,46 @@</div><br><div>+## @file</div><br><div>+# initialized fw_cfg library.</div><br><div>+#</div><br><div>+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+#</div><br><div>+# SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+#</div><br><div>+##</div><br><div>+</div><br><div>+[Defines]</div><br><div>+ INF_VERSION = 0x00010005</div><br><div>+ BASE_NAME = QemuFwCfgSecLib</div><br><div>+ FILE_GUID = cdf9a9d5-7422-4dcb-b41d-607151ad320b</div><br><div>+ MODULE_TYPE = BASE</div><br><div>+ VERSION_STRING = 1.0</div><br><div>+ LIBRARY_CLASS = QemuFwCfgLib|PEIM</div><br><div>+ CONSTRUCTOR = QemuFwCfgInitialize</div><br><div>+</div><br><div>+#</div><br><div>+# VALID_ARCHITECTURES = LOONGARCH64</div><br><div>+#</div><br><div>+</div><br><div>+[Sources]</div><br><div>+ QemuFwCfgLibInternal.h</div><br><div>+ QemuFwCfgPeiLib.c</div><br><div>+ QemuFwCfgPei.c</div><br><div>+</div><br><div>+[Packages]</div><br><div>+ EmbeddedPkg/EmbeddedPkg.dec</div><br><div>+ MdePkg/MdePkg.dec</div><br><div>+ OvmfPkg/OvmfPkg.dec</div><br><div>+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec</div><br><div>+</div><br><div>+[LibraryClasses]</div><br><div>+ BaseLib</div><br><div>+ BaseMemoryLib</div><br><div>+ DebugLib</div><br><div>+ IoLib</div><br><div>+ MemoryAllocationLib</div><br><div>+ FdtLib</div><br><div>+ PcdLib</div><br><div>+</div><br><div>+[Pcd]</div><br><div>+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase</div><br><div>+ gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgSelectorAddress</div><br><div>+ gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgDataAddress</div><br><div>--</div><br><div>2.31.1</div></div></blockquote>


 <div width="1" style="color:white;clear:both">_._,_._,_</div> <hr>   Groups.io Links:<p>   You receive all messages sent to this group.    <p> <a target="_blank" href="https://edk2.groups.io/g/devel/message/96289">View/Reply Online (#96289)</a> |    |  <a target="_blank" href="https://groups.io/mt/94955169/1813853">Mute This Topic</a>  | <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>    <a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> | <a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |  <a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>  [edk2-devel-archive@redhat.com]<br> <div width="1" style="color:white;clear:both">_._,_._,_</div>