From 64df8e85818fc2a8c2ca604a9ec006453a65584c Mon Sep 17 00:00:00 2001 From: Arvean Labib Date: Fri, 13 Mar 2026 14:24:10 -0700 Subject: [PATCH 1/2] Add APMT ACPI table support for guest uncore PMU Add receive and install support for the ARM Performance Monitoring Table (APMT) in the guest UEFI firmware. This enables guest VMs to discover uncore PMU MMIO ranges when the host provides an APMT via the UEFI config blob. Changes: - Add UefiConfigApmt (0x28) enum value and UEFI_CONFIG_APMT struct - Add ARM_ACPI_APMT_TABLE_SIGNATURE definition - Add PcdApmtPtr/PcdApmtSize PCDs (tokens 0x6073/0x6074) - Parse and validate APMT in PEI phase (Config.c) - Install APMT in DXE phase via AcpiInstallApmtTable() - Wire PCDs through both AARCH64 and X64 DSC/INF files The APMT is optional: it is not added to requiredStructures, and the DXE installer gracefully skips when the table is absent. The parsing and installation follow the same pattern as IORT/PPTT/HMAT. --- MsvmPkg/AcpiPlatformDxe/AcpiPlatform.c | 65 +++++++++++++++++++++ MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 2 + MsvmPkg/Include/AcpiTables.h | 1 + MsvmPkg/Include/BiosInterface.h | 7 +++ MsvmPkg/MsvmPkg.dec | 4 ++ MsvmPkg/MsvmPkgAARCH64.dsc | 4 ++ MsvmPkg/MsvmPkgX64.dsc | 4 ++ MsvmPkg/PlatformPei/Config.c | 21 +++++++ MsvmPkg/PlatformPei/PlatformPei.inf | 2 + 9 files changed, 110 insertions(+) diff --git a/MsvmPkg/AcpiPlatformDxe/AcpiPlatform.c b/MsvmPkg/AcpiPlatformDxe/AcpiPlatform.c index f66e3279b6..b97181aba3 100644 --- a/MsvmPkg/AcpiPlatformDxe/AcpiPlatform.c +++ b/MsvmPkg/AcpiPlatformDxe/AcpiPlatform.c @@ -862,6 +862,62 @@ Return Value: } +EFI_STATUS +AcpiInstallApmtTable( + EFI_ACPI_TABLE_PROTOCOL *AcpiTable + ) +/*++ + +Routine Description: + + Retrieves the APMT table from the worker process and installs it. + +Arguments: + + AcpiTable - A pointer to the ACPI table protocol. + +Return Value: + + EFI_STATUS. + +--*/ +{ + EFI_STATUS status; + EFI_ACPI_DESCRIPTION_HEADER *table; + UINTN tableHandle; + UINT32 tableSize; + + // + // Get the table from the config blob parsed in PEI. It may not be present. + // + tableSize = PcdGet32(PcdApmtSize); + + if (tableSize == 0) + { + return EFI_SUCCESS; + } + + table = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) PcdGet64(PcdApmtPtr); + + if (table == NULL) + { + return EFI_NOT_FOUND; + } + + ASSERT(table->Length == tableSize); + + // + // Install it into the published tables. + // + status = AcpiTable->InstallAcpiTable(AcpiTable, + table, + table->Length, + &tableHandle); + + return status; +} + + EFI_STATUS EFIAPI AcpiPlatformInitializeAcpiTables( @@ -1078,6 +1134,15 @@ Return Value: goto Cleanup; } + // + // Add the APMT table if present. + // + status = AcpiInstallApmtTable(acpiTable); + if (EFI_ERROR(status)) + { + goto Cleanup; + } + status = EFI_SUCCESS; Cleanup: diff --git a/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf index c293425634..342a8dafc6 100644 --- a/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -78,6 +78,8 @@ gMsvmPkgTokenSpaceGuid.PcdSsdtSize ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdIortPtr ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdIortSize ## CONSUMES + gMsvmPkgTokenSpaceGuid.PcdApmtPtr ## CONSUMES + gMsvmPkgTokenSpaceGuid.PcdApmtSize ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdNvdimmCount ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdPpttPtr ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdPpttSize ## CONSUMES diff --git a/MsvmPkg/Include/AcpiTables.h b/MsvmPkg/Include/AcpiTables.h index 9394d575fd..edcdebbab2 100644 --- a/MsvmPkg/Include/AcpiTables.h +++ b/MsvmPkg/Include/AcpiTables.h @@ -34,6 +34,7 @@ typedef struct _VM_ACPI_ENTROPY_TABLE #define VM_ACPI_ENTROPY_TABLE_SIGNATURE SIGNATURE_32('O','E','M','0') #define AMD_ACPI_ASPT_TABLE_SIGNATURE SIGNATURE_32('A', 'S', 'P', 'T') +#define ARM_ACPI_APMT_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'M', 'T') // // WDAT table. diff --git a/MsvmPkg/Include/BiosInterface.h b/MsvmPkg/Include/BiosInterface.h index 01efb497db..99098a99be 100644 --- a/MsvmPkg/Include/BiosInterface.h +++ b/MsvmPkg/Include/BiosInterface.h @@ -558,6 +558,7 @@ enum UefiStructureType UefiConfigSsdt = 0x25, UefiConfigHmat = 0x26, UefiConfigIort = 0x27, + UefiConfigApmt = 0x28, }; // @@ -879,6 +880,12 @@ typedef struct _UEFI_CONFIG_IORT UINT8 Iort[]; } UEFI_CONFIG_IORT; +typedef struct _UEFI_CONFIG_APMT +{ + UEFI_CONFIG_HEADER Header; + UINT8 Apmt[]; +} UEFI_CONFIG_APMT; + // // UEFI configuration information for direct parsing of IGVM parameters. // diff --git a/MsvmPkg/MsvmPkg.dec b/MsvmPkg/MsvmPkg.dec index 237f2ae1f7..14d8797e33 100644 --- a/MsvmPkg/MsvmPkg.dec +++ b/MsvmPkg/MsvmPkg.dec @@ -382,3 +382,7 @@ # UEFI_CONFIG_IORT gMsvmPkgTokenSpaceGuid.PcdIortPtr|0x0|UINT64|0x6070 gMsvmPkgTokenSpaceGuid.PcdIortSize|0x0|UINT32|0x6071 + + # UEFI_CONFIG_APMT + gMsvmPkgTokenSpaceGuid.PcdApmtPtr|0x0|UINT64|0x6073 + gMsvmPkgTokenSpaceGuid.PcdApmtSize|0x0|UINT32|0x6074 diff --git a/MsvmPkg/MsvmPkgAARCH64.dsc b/MsvmPkg/MsvmPkgAARCH64.dsc index 0140c79977..89472f3bb5 100644 --- a/MsvmPkg/MsvmPkgAARCH64.dsc +++ b/MsvmPkg/MsvmPkgAARCH64.dsc @@ -557,6 +557,10 @@ gMsvmPkgTokenSpaceGuid.PcdIortPtr|0x0 gMsvmPkgTokenSpaceGuid.PcdIortSize|0x0 + # UEFI_CONFIG_APMT + gMsvmPkgTokenSpaceGuid.PcdApmtPtr|0x0 + gMsvmPkgTokenSpaceGuid.PcdApmtSize|0x0 + # UEFI_CONFIG_MEMORY_MAP gMsvmPkgTokenSpaceGuid.PcdMemoryMapPtr|0x0 gMsvmPkgTokenSpaceGuid.PcdMemoryMapSize|0x0 diff --git a/MsvmPkg/MsvmPkgX64.dsc b/MsvmPkg/MsvmPkgX64.dsc index 26cc229895..984df51aff 100644 --- a/MsvmPkg/MsvmPkgX64.dsc +++ b/MsvmPkg/MsvmPkgX64.dsc @@ -556,6 +556,10 @@ gMsvmPkgTokenSpaceGuid.PcdIortPtr|0x0 gMsvmPkgTokenSpaceGuid.PcdIortSize|0x0 + # UEFI_CONFIG_APMT + gMsvmPkgTokenSpaceGuid.PcdApmtPtr|0x0 + gMsvmPkgTokenSpaceGuid.PcdApmtSize|0x0 + # UEFI_CONFIG_MEMORY_MAP gMsvmPkgTokenSpaceGuid.PcdMemoryMapPtr|0x0 gMsvmPkgTokenSpaceGuid.PcdMemoryMapSize|0x0 diff --git a/MsvmPkg/PlatformPei/Config.c b/MsvmPkg/PlatformPei/Config.c index 75da9e1f07..f578bfc563 100644 --- a/MsvmPkg/PlatformPei/Config.c +++ b/MsvmPkg/PlatformPei/Config.c @@ -590,6 +590,10 @@ DebugDumpUefiConfigStruct( DebugDumpHmat(hmat->Hmat); break; + case UefiConfigApmt: + DEBUG((DEBUG_VERBOSE, "\tAPMT table found.\n")); + break; + case UefiConfigMemoryMap: UEFI_CONFIG_MEMORY_MAP *memMap = (UEFI_CONFIG_MEMORY_MAP*) Header; DebugDumpMemoryMap(memMap->MemoryMap, Header->Length - sizeof(UEFI_CONFIG_HEADER), PcdGetBool(PcdLegacyMemoryMap)); @@ -1065,6 +1069,7 @@ Return Value: 0, //UefiConfigSsdt 0, //UefiConfigHmat 0, //UefiConfigIort + 0, //UefiConfigApmt }; // @@ -1630,6 +1635,22 @@ Return Value: PEI_FAIL_FAST_IF_FAILED(PcdSet64S(PcdIortPtr, (UINT64)iortStructure->Iort)); PEI_FAIL_FAST_IF_FAILED(PcdSet32S(PcdIortSize, iortHdr->Length)); break; + + case UefiConfigApmt: + UEFI_CONFIG_APMT *apmtStructure = (UEFI_CONFIG_APMT*) header; + EFI_ACPI_DESCRIPTION_HEADER *apmtHdr = (EFI_ACPI_DESCRIPTION_HEADER*) apmtStructure->Apmt; + + if (apmtStructure->Header.Length < (sizeof(UEFI_CONFIG_HEADER) + sizeof(EFI_ACPI_DESCRIPTION_HEADER)) || + apmtHdr->Signature != ARM_ACPI_APMT_TABLE_SIGNATURE || + apmtHdr->Length > (apmtStructure->Header.Length - sizeof(UEFI_CONFIG_HEADER))) + { + DEBUG((DEBUG_ERROR, "*** Malformed APMT\n")); + FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); + } + + PEI_FAIL_FAST_IF_FAILED(PcdSet64S(PcdApmtPtr, (UINT64)apmtStructure->Apmt)); + PEI_FAIL_FAST_IF_FAILED(PcdSet32S(PcdApmtSize, apmtHdr->Length)); + break; } calculatedConfigSize += header->Length; diff --git a/MsvmPkg/PlatformPei/PlatformPei.inf b/MsvmPkg/PlatformPei/PlatformPei.inf index 1fd34dc854..bb07c6e83a 100644 --- a/MsvmPkg/PlatformPei/PlatformPei.inf +++ b/MsvmPkg/PlatformPei/PlatformPei.inf @@ -89,6 +89,8 @@ gMsvmPkgTokenSpaceGuid.PcdLegacyMemoryMap gMsvmPkgTokenSpaceGuid.PcdIortPtr gMsvmPkgTokenSpaceGuid.PcdIortSize + gMsvmPkgTokenSpaceGuid.PcdApmtPtr + gMsvmPkgTokenSpaceGuid.PcdApmtSize gMsvmPkgTokenSpaceGuid.PcdMadtPtr gMsvmPkgTokenSpaceGuid.PcdMadtSize gMsvmPkgTokenSpaceGuid.PcdMcfgPtr From 052917555829a5656784b1795704580c155ec74d Mon Sep 17 00:00:00 2001 From: Arvean Labib Date: Fri, 22 May 2026 15:52:22 -0700 Subject: [PATCH 2/2] Address APMT review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- MsvmPkg/MsvmPkg.dec | 1 + MsvmPkg/MsvmPkgX64.dsc | 2 ++ MsvmPkg/PlatformPei/Config.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/MsvmPkg/MsvmPkg.dec b/MsvmPkg/MsvmPkg.dec index 14d8797e33..55d91cb14c 100644 --- a/MsvmPkg/MsvmPkg.dec +++ b/MsvmPkg/MsvmPkg.dec @@ -384,5 +384,6 @@ gMsvmPkgTokenSpaceGuid.PcdIortSize|0x0|UINT32|0x6071 # UEFI_CONFIG_APMT + # 0x6072 is used by PcdAziHsmEnabled above. gMsvmPkgTokenSpaceGuid.PcdApmtPtr|0x0|UINT64|0x6073 gMsvmPkgTokenSpaceGuid.PcdApmtSize|0x0|UINT32|0x6074 diff --git a/MsvmPkg/MsvmPkgX64.dsc b/MsvmPkg/MsvmPkgX64.dsc index 984df51aff..7c82bc8c7c 100644 --- a/MsvmPkg/MsvmPkgX64.dsc +++ b/MsvmPkg/MsvmPkgX64.dsc @@ -557,6 +557,8 @@ gMsvmPkgTokenSpaceGuid.PcdIortSize|0x0 # UEFI_CONFIG_APMT + # AcpiPlatformDxe and PlatformPei are shared modules and consume these + # optional PCDs in X64 builds even though APMT is only supplied on ARM hosts. gMsvmPkgTokenSpaceGuid.PcdApmtPtr|0x0 gMsvmPkgTokenSpaceGuid.PcdApmtSize|0x0 diff --git a/MsvmPkg/PlatformPei/Config.c b/MsvmPkg/PlatformPei/Config.c index f578bfc563..ed7b8dfc22 100644 --- a/MsvmPkg/PlatformPei/Config.c +++ b/MsvmPkg/PlatformPei/Config.c @@ -1637,6 +1637,7 @@ Return Value: break; case UefiConfigApmt: + { UEFI_CONFIG_APMT *apmtStructure = (UEFI_CONFIG_APMT*) header; EFI_ACPI_DESCRIPTION_HEADER *apmtHdr = (EFI_ACPI_DESCRIPTION_HEADER*) apmtStructure->Apmt; @@ -1651,6 +1652,7 @@ Return Value: PEI_FAIL_FAST_IF_FAILED(PcdSet64S(PcdApmtPtr, (UINT64)apmtStructure->Apmt)); PEI_FAIL_FAST_IF_FAILED(PcdSet32S(PcdApmtSize, apmtHdr->Length)); break; + } } calculatedConfigSize += header->Length;