We submit a patch in TF-A which is armed at reporting the information of through SMC. Cooperating with that patch, we can get thecinformation of memory in EDK2 via SMC calls.
Changes in v2: - Align with the latest version. - modify language and formatting errors.
Changes in v3: - read the information of memory in SbsaQemuSmc.c.
Changes in v4: - add DT fallback when SMC failed.
Xiong Yining (1): SbsaQemu: get the information of memory form TF-A
Platform/Qemu/SbsaQemu/SbsaQemu.dsc | 2 + .../Include/IndustryStandard/SbsaQemuSmc.h | 2 + .../SbsaQemu/Include/Library/QemuSbsaSmc.h | 49 +++++++ .../Library/SbsaQemuLib/SbsaQemuLib.inf | 2 +- .../Library/SbsaQemuLib/SbsaQemuMem.c | 52 ++----- .../Library/SbsaQemuSmc/SbsaQemuSmc.c | 137 ++++++++++++++++++ .../Library/SbsaQemuSmc/SbsaQemuSmc.inf | 10 ++ Silicon/Qemu/SbsaQemu/SbsaQemu.dec | 3 + 8 files changed, 216 insertions(+), 41 deletions(-)
we can get the information of memory via SMC calls during platform initialization.
Handled are: - memory node-id - the base and size of the memory address
Signed-off-by: Xiong Yining xiongyining1480@phytium.com.cn Signed-off-by: Chen Baozi chenbaozi@phytium.com.cn --- Platform/Qemu/SbsaQemu/SbsaQemu.dsc | 2 + .../Include/IndustryStandard/SbsaQemuSmc.h | 2 + .../SbsaQemu/Include/Library/QemuSbsaSmc.h | 49 +++++++ .../Library/SbsaQemuLib/SbsaQemuLib.inf | 2 +- .../Library/SbsaQemuLib/SbsaQemuMem.c | 52 ++----- .../Library/SbsaQemuSmc/SbsaQemuSmc.c | 137 ++++++++++++++++++ .../Library/SbsaQemuSmc/SbsaQemuSmc.inf | 10 ++ Silicon/Qemu/SbsaQemu/SbsaQemu.dec | 3 + 8 files changed, 216 insertions(+), 41 deletions(-)
diff --git a/Platform/Qemu/SbsaQemu/SbsaQemu.dsc b/Platform/Qemu/SbsaQemu/SbsaQemu.dsc index 9164172c8b..2ff0292ed9 100644 --- a/Platform/Qemu/SbsaQemu/SbsaQemu.dsc +++ b/Platform/Qemu/SbsaQemu/SbsaQemu.dsc @@ -568,6 +568,8 @@ DEFINE NETWORK_HTTP_BOOT_ENABLE = FALSE gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPlatformVersionMajor|0x0 gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPlatformVersionMinor|0x0
+ gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdMemoryNodeSize|0 + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdFdtFirstMemOffset|0 ################################################################################ # # Components Section - list of all EDK II Modules needed by this Platform diff --git a/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h b/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h index e33648ee14..31dd699b0b 100644 --- a/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h +++ b/Silicon/Qemu/SbsaQemu/Include/IndustryStandard/SbsaQemuSmc.h @@ -16,5 +16,7 @@ #define SIP_SVC_GET_GIC_ITS SMC_SIP_FUNCTION_ID(101) #define SIP_SVC_GET_CPU_COUNT SMC_SIP_FUNCTION_ID(200) #define SIP_SVC_GET_CPU_NODE SMC_SIP_FUNCTION_ID(201) +#define SIP_SVC_GET_MEMORYNODE_COUNT SMC_SIP_FUNCTION_ID(300) +#define SIP_SVC_GET_MEMORY SMC_SIP_FUNCTION_ID(301)
#endif /* SBSA_QEMU_SMC_H_ */ diff --git a/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h b/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h index e87e966d39..61b354a3bf 100644 --- a/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h +++ b/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h @@ -33,4 +33,53 @@ SbsaQemuGetCpuNumaNode ( IN UINTN CpuId );
+typedef struct{ + UINT32 NodeId; + UINT64 AddressBase; + UINT64 AddressSize; +} MemoryNode; + +/** + Walks through the Device Tree created by Qemu and counts the number of Memory node present in it. + + @retval the number of memory nodes. +**/ +UINT32 +FdtGetMemNodeCount ( + VOID + ); + +/** Walks through the Device Tree created by Qemu and counts the adress、size and node-id of the Memory node present in it. + + @param [in] MemoryId Index of memory to retrieve memory information. + + @retval memory infomation for given memory node. +**/ +MemoryNode +FdtGetMemInfo ( + IN UINTN MemoryId + ); + +/** + Get the number of memory node from device tree passed by Qemu. + + @retval the number of memory nodes. +**/ +UINT32 +SbsaQemuGetMemNodeCount ( + VOID + ); + +/** + Get memory infomation(node-id, addressbase, addresssize) for a given memory node from device tree passed by Qemu. + + @param [in] MemNode Index of memory to retrieve memory information. + + @retval memory infomation for given memory node. +**/ +MemoryNode +SbsaQemuGetMemInfo ( + IN UINTN MemoryId + ); + #endif /* QEMU_SBSA_SMC_ */ diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuLib.inf b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuLib.inf index c067a80cc7..3a4fff7bc7 100644 --- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuLib.inf +++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuLib.inf @@ -32,9 +32,9 @@ ArmLib BaseMemoryLib DebugLib - FdtLib MemoryAllocationLib PcdLib + SbsaQemuSmc
[Pcd] gArmTokenSpaceGuid.PcdSystemMemoryBase diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuMem.c b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuMem.c index 8c2eb0b6a0..9161e1039e 100644 --- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuMem.c +++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuLib/SbsaQemuMem.c @@ -12,7 +12,7 @@ #include <Library/DebugLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/PcdLib.h> -#include <libfdt.h> +#include <Library/QemuSbsaSmc.h>
// Number of Virtual Memory Map Descriptors #define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 4 @@ -23,53 +23,25 @@ SbsaQemuLibConstructor ( VOID ) { - VOID *DeviceTreeBase; - INT32 Node, Prev; UINT64 NewBase, CurBase; UINT64 NewSize, CurSize; - CONST CHAR8 *Type; - INT32 Len; - CONST UINT64 *RegProp; + UINT32 NumMemNodes; + UINT32 Index; + MemoryNode MemNode; RETURN_STATUS PcdStatus;
NewBase = 0; NewSize = 0;
- DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeBaseAddress); - ASSERT (DeviceTreeBase != NULL); + NumMemNodes = SbsaQemuGetMemNodeCount(); + for(Index = 0; Index < NumMemNodes; Index++){ + MemNode = SbsaQemuGetMemInfo(Index); + CurBase = MemNode.AddressBase; + CurSize = MemNode.AddressSize;
- // Make sure we have a valid device tree blob - ASSERT (fdt_check_header (DeviceTreeBase) == 0); - - // Look for the lowest memory node - 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, "device_type", &Len); - if (Type && AsciiStrnCmp (Type, "memory", 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))) { - - CurBase = fdt64_to_cpu (ReadUnaligned64 (RegProp)); - CurSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1)); - - DEBUG ((DEBUG_INFO, "%a: System RAM @ 0x%lx - 0x%lx\n", - __FUNCTION__, CurBase, CurBase + CurSize - 1)); - - if (NewBase > CurBase || NewBase == 0) { - NewBase = CurBase; - NewSize = CurSize; - } - } else { - DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT memory node\n", - __FUNCTION__)); - } + if (NewBase > CurBase || NewBase == 0) { + NewBase = CurBase; + NewSize = CurSize; } }
diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c index 41df610f52..060e834a4f 100644 --- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c +++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c @@ -8,6 +8,9 @@
#include <Library/ArmSmcLib.h> #include <Library/DebugLib.h> +#include <Library/QemuSbsaSmc.h> +#include <libfdt.h> +#include <Library/PcdLib.h> #include <IndustryStandard/SbsaQemuSmc.h>
UINT64 @@ -53,3 +56,137 @@ SbsaQemuGetCpuNumaNode (
return Arg0; } + +UINT32 +FdtGetMemNodeCount ( + VOID + ) +{ + VOID *DeviceTreeBase; + CONST CHAR8 *Type; + UINT32 NumMemNodes; + UINT32 FdtFirstMemOffset; + UINT32 FdtMemNodeSize; + INT32 Node; + INT32 Prev; + INT32 Len; + + DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeBaseAddress); + ASSERT (DeviceTreeBase != NULL); + + // Make sure we have a valid device tree blob + ASSERT (fdt_check_header (DeviceTreeBase) == 0); + + NumMemNodes = 0; + FdtFirstMemOffset = 0; + for (Prev = 0;; Prev = Node) { + Node = fdt_next_node (DeviceTreeBase, Prev, NULL); + if (Node < 0){ + break; + } + + Type = fdt_getprop (DeviceTreeBase, Node, "device_type", &Len); + if (Type && AsciiStrnCmp (Type, "memory", Len) == 0) { + if (FdtFirstMemOffset > Node || FdtFirstMemOffset == 0){ + FdtFirstMemOffset = Node ; + } + + NumMemNodes++; + if (NumMemNodes > 1){ + FdtMemNodeSize = Node - Prev; + } + } + } + + PcdSet32S (PcdMemoryNodeSize, FdtMemNodeSize); + PcdSet32S (PcdFdtFirstMemOffset, FdtFirstMemOffset); + + return NumMemNodes; +} + +MemoryNode +FdtGetMemInfo ( + IN UINTN MemoryId +) +{ + VOID *DeviceTreeBase; + CONST UINT64 *RegProp; + CONST UINT32 *NodeProp; + UINT32 FdtMemNodeSize; + UINT32 FdtFirstMemOffset; + INT32 Len; + MemoryNode MemNode; + + DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeBaseAddress); + ASSERT (DeviceTreeBase != NULL); + + // Make sure we have a valid device tree blob + ASSERT (fdt_check_header (DeviceTreeBase) == 0); + + FdtMemNodeSize = PcdGet32(PcdMemoryNodeSize); + FdtFirstMemOffset = PcdGet32(PcdFdtFirstMemOffset); + + RegProp = fdt_getprop (DeviceTreeBase, FdtFirstMemOffset + (MemoryId * FdtMemNodeSize), "reg", &Len); + if (RegProp != 0 && Len == (2 * sizeof (UINT64))) { + MemNode.AddressBase = fdt64_to_cpu (ReadUnaligned64 (RegProp)); + MemNode.AddressSize= fdt64_to_cpu (ReadUnaligned64 (RegProp + 1)); + } else { + DEBUG ((DEBUG_ERROR, "Failed to find the address and size of the memory")); + } + + NodeProp= fdt_getprop (DeviceTreeBase, FdtFirstMemOffset + (MemoryId * FdtMemNodeSize), "numa-node-id", &Len); + if (NodeProp){ + MemNode.NodeId= fdt32_to_cpu (ReadUnaligned32 (NodeProp)); + } + + return MemNode; +} + +UINT32 +SbsaQemuGetMemNodeCount ( + VOID + ) +{ + UINTN SmcResult; + UINTN Arg0; + + SmcResult = ArmCallSmc0 (SIP_SVC_GET_MEMORYNODE_COUNT, &Arg0, NULL, NULL); + if (SmcResult != SMC_ARCH_CALL_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Couldn't find the information of memory\n")); + Arg0 = FdtGetMemNodeCount(); + } + + DEBUG(( DEBUG_INFO, "The number of the memory nodes is %ld\n", Arg0)); + return (UINT32)Arg0; +} + +MemoryNode +SbsaQemuGetMemInfo ( + IN UINTN MemoryId + ) +{ + UINTN SmcResult; + UINTN Arg0; + UINTN Arg1; + UINTN Arg2; + MemoryNode MemNode; + + Arg0 = MemoryId; + + SmcResult = ArmCallSmc1 (SIP_SVC_GET_MEMORY, &Arg0, &Arg1, &Arg2); + if (SmcResult != SMC_ARCH_CALL_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Couldn't find the number of memry nodes.\n")); + MemNode = FdtGetMemInfo(MemoryId); + } else { + MemNode.NodeId = Arg0; + MemNode.AddressBase = Arg1; + MemNode.AddressSize = Arg2; + } + + DEBUG(( DEBUG_INFO, "System RAM@%d: 0x%lx - 0x%lx\n", + MemNode.NodeId, + MemNode.AddressBase, + MemNode.AddressBase + MemNode.AddressSize -1 )); + + return MemNode; +} diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf index 3eae73650e..c021818f2c 100644 --- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf +++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf @@ -20,9 +20,19 @@ [Packages] ArmPkg/ArmPkg.dec MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec Silicon/Qemu/SbsaQemu/SbsaQemu.dec
[LibraryClasses] ArmSmcLib BaseMemoryLib DebugLib + FdtLib + PcdLib + +[Pcd] + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdMemoryNodeSize + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdFdtFirstMemOffset + +[FixedPcd] + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdDeviceTreeBaseAddress diff --git a/Silicon/Qemu/SbsaQemu/SbsaQemu.dec b/Silicon/Qemu/SbsaQemu/SbsaQemu.dec index 913d1d75ef..dcedf1cfa7 100644 --- a/Silicon/Qemu/SbsaQemu/SbsaQemu.dec +++ b/Silicon/Qemu/SbsaQemu/SbsaQemu.dec @@ -74,3 +74,6 @@ # ARM Generic Interrupt Controller ITS gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdGicItsBase|0|UINT64|0x00000120 gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdSmmuBase|0|UINT64|0x00000121 + + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdMemoryNodeSize|0x0|UINT32|0x00000122 + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdFdtFirstMemOffset|0x0|UINT32|0x00000123