SbsaQemu can configure with numa-related arguments, but OS cannot identify the numa architecture without SRAT tables. We add supporting for generating SRAT tables at runtime to solve this issue.
Changes in v2: - get the information of numa via SMC calls rather than parse DT.
Changes in v3 - Considering the combination of CPU and memory nodes when counting numa nodes.
Xiong Yining (1): SbsaQemu: AcpiDxe: Create SRAT table at runtime
.../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c | 91 +++++++++++++++++++ .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.h | 28 ++++++ .../SbsaQemu/Include/Library/QemuSbsaSmc.h | 10 ++ .../Library/SbsaQemuSmc/SbsaQemuSmc.c | 31 +++++++ .../Library/SbsaQemuSmc/SbsaQemuSmc.inf | 1 + 5 files changed, 161 insertions(+)
Add support to create SRAT(System resource affinity table) for sbsa platform at runtime.
Signed-off-by: Xiong Yining xiongyining1480@phytium.com.cn Signed-off-by: Chen Baozi chenbaozi@phytium.com.cn --- .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c | 91 +++++++++++++++++++ .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.h | 28 ++++++ .../SbsaQemu/Include/Library/QemuSbsaSmc.h | 10 ++ .../Library/SbsaQemuSmc/SbsaQemuSmc.c | 31 +++++++ .../Library/SbsaQemuSmc/SbsaQemuSmc.inf | 1 + 5 files changed, 161 insertions(+)
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c index 89c4b797d2..8c79e0ca3a 100644 --- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c +++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c @@ -748,6 +748,90 @@ DisableXhciOnOlderPlatVer ( return Status; }
+/* + * A function that adds the SRAT ACPI table. + */ +EFI_STATUS +AddSratTable ( + IN EFI_ACPI_TABLE_PROTOCOL *AcpiTable + ) +{ + EFI_STATUS Status; + UINT8 *New; + EFI_PHYSICAL_ADDRESS PageAddress; + UINTN TableHandle; + UINT32 TableSize; + UINT32 Index; + UINT32 NodeId; + UINT32 NumMemNodes; + MemoryNode MemNode; + UINT32 NumCores = PcdGet32 (PcdCoreCount); + + // Initialize SRAT ACPI Header + EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER Header = { + SBSAQEMU_ACPI_HEADER (EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE, + EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER, + EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION), + 1, 0 }; + + NumMemNodes = SbsaQemuGetMemNodeCount(); + + // Calculate the new table size based on the number of cores + TableSize = sizeof (EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER) + + (sizeof (EFI_ACPI_6_4_MEMORY_AFFINITY_STRUCTURE) * NumMemNodes ) + + (sizeof (EFI_ACPI_6_4_GICC_AFFINITY_STRUCTURE) * NumCores); + + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIReclaimMemory, + EFI_SIZE_TO_PAGES (TableSize), + &PageAddress + ); + + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate pages for SRAT table\n")); + return EFI_OUT_OF_RESOURCES; + } + + New = (UINT8 *)(UINTN) PageAddress; + ZeroMem (New, TableSize); + + // Add the ACPI Description table header + CopyMem (New, &Header, sizeof (EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER)); + ((EFI_ACPI_DESCRIPTION_HEADER*) New)->Length = TableSize; + New += sizeof (EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER); + + // Add memory structures + for (Index = 0; Index < NumMemNodes ; Index++) { + MemNode = SbsaQemuGetMemInfo (Index); + EFI_ACPI_6_4_MEMORY_AFFINITY_STRUCTURE memory = SBSAQEMU_ACPI_MEMORY_AFFINITY_STRUCTURE_INIT (MemNode.NodeId, MemNode.AddressBase, MemNode.AddressSize, 1); + CopyMem (New, &memory, sizeof (EFI_ACPI_6_4_MEMORY_AFFINITY_STRUCTURE)); + New += sizeof (EFI_ACPI_6_4_MEMORY_AFFINITY_STRUCTURE); + } + + // Add processor structures for the cores + for (Index = 0; Index < NumCores; Index++) { + NodeId = SbsaQemuGetCpuNumaNode(Index); + EFI_ACPI_6_4_GICC_AFFINITY_STRUCTURE gicc = SBSAQEMU_ACPI_GICC_AFFINITY_STRUCTURE_INIT(NodeId, Index, 1, 0); + CopyMem (New, &gicc, sizeof (EFI_ACPI_6_4_GICC_AFFINITY_STRUCTURE)); + New += sizeof (EFI_ACPI_6_4_GICC_AFFINITY_STRUCTURE); + } + + // Perform Checksum + AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize); + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + (EFI_ACPI_COMMON_HEADER *)PageAddress, + TableSize, + &TableHandle + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to install SRAT table\n")); + } + + return Status; +}
EFI_STATUS EFIAPI @@ -799,6 +883,13 @@ InitializeSbsaQemuAcpiDxe ( DEBUG ((DEBUG_ERROR, "Failed to add GTDT table\n")); }
+ if (SbsaQemuGetNumNumaNode() > 0){ + Status = AddSratTable (AcpiTable); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to add SRAT table\n")); + } + } + Status = DisableXhciOnOlderPlatVer (); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to handle XHCI enablement\n")); diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.h b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.h index 7595df4c8a..1cf14952e5 100644 --- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.h +++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.h @@ -39,6 +39,34 @@ typedef struct { EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE mGwdt; } GENERIC_TIMER_DESCRIPTION_TABLES;
+#define SBSAQEMU_ACPI_MEMORY_AFFINITY_STRUCTURE_INIT( \ + ProximityDomain, Base, Length, Flags) \ + { \ + 1, /* Type */ \ + sizeof (EFI_ACPI_6_4_MEMORY_AFFINITY_STRUCTURE), /* Length */ \ + ProximityDomain, /* Proximity Domain */ \ + 0, /* Reserved */ \ + (Base) & 0xffffffff, /* Base Address Low */ \ + ((Base) >> 32) & 0xffffffff , /* Base Address High */ \ + (Length) & 0xffffffff, /* Length Low */ \ + ((Length) >> 32) & 0xffffffff, /* Length High */ \ + 0, /* Reserved */ \ + Flags, /* Flags */ \ + 0 /* Reserved */ \ + } + + +#define SBSAQEMU_ACPI_GICC_AFFINITY_STRUCTURE_INIT( \ + ProximityDomain, ACPIProcessorUID, Flags, ClockDomain) \ + { \ + 3, /* Type */ \ + sizeof (EFI_ACPI_6_4_GICC_AFFINITY_STRUCTURE), /* Length */ \ + ProximityDomain, /* Proximity Domain */ \ + ACPIProcessorUID, /* ACPI Processor UID */ \ + Flags, /* Flags */ \ + ClockDomain /* Clock Domain */ \ + } + #ifndef SYSTEM_TIMER_BASE_ADDRESS #define SYSTEM_TIMER_BASE_ADDRESS MAX_ADDRESS #endif diff --git a/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h b/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h index 61b354a3bf..b150f2c1e0 100644 --- a/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h +++ b/Silicon/Qemu/SbsaQemu/Include/Library/QemuSbsaSmc.h @@ -82,4 +82,14 @@ SbsaQemuGetMemInfo ( IN UINTN MemoryId );
+/** + Get the number of numa node from device tree passed by Qemu. + + @retval the number of numa node. +**/ +UINT64 +SbsaQemuGetNumNumaNode ( + VOID + ); + #endif /* QEMU_SBSA_SMC_ */ diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c index 060e834a4f..23771edb2b 100644 --- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c +++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.c @@ -190,3 +190,34 @@ SbsaQemuGetMemInfo (
return MemNode; } + +UINT64 +SbsaQemuGetNumNumaNode ( + VOID +) +{ + UINT64 Arg; + UINT32 Index; + UINT32 NumNumaNodes; + UINT32 NumMemNodes; + UINT32 NumCores = PcdGet32 (PcdCoreCount); + MemoryNode MemInfo; + + NumNumaNodes = 0; + for (Index = 0; Index < NumCores; Index ++){ + Arg = SbsaQemuGetCpuNumaNode(Index); + if (NumNumaNodes == 0 || NumNumaNodes < (Arg + 1)){ + NumNumaNodes = Arg + 1; + } + } + + NumMemNodes = SbsaQemuGetMemNodeCount(); + for (Index = 0; Index < NumMemNodes; Index ++){ + MemInfo = SbsaQemuGetMemInfo(Index); + if (NumNumaNodes == 0 || NumNumaNodes < (MemInfo.NodeId + 1)){ + NumNumaNodes = MemInfo.NodeId + 1; + } + } + + return NumNumaNodes; +} diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf index c021818f2c..e1f4e292d3 100644 --- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf +++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuSmc/SbsaQemuSmc.inf @@ -31,6 +31,7 @@ PcdLib
[Pcd] + gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdCoreCount gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdMemoryNodeSize gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdFdtFirstMemOffset