From 64df8e85818fc2a8c2ca604a9ec006453a65584c Mon Sep 17 00:00:00 2001 From: Arvean Labib Date: Fri, 13 Mar 2026 14:24:10 -0700 Subject: [PATCH] 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 f66e327..b97181a 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 c293425..342a8da 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 9394d57..edcdebb 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 01efb49..99098a9 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 237f2ae..14d8797 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 0140c79..89472f3 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 26cc229..984df51 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 75da9e1..f578bfc 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 1fd34dc..bb07c6e 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