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