DxeBoardInitLib library provides board-specific initialization functions for the DXE phase.
Cc: Abner Chang <abner.ch...@amd.com> Cc: Paul Grimes <paul.gri...@amd.com> Signed-off-by: Abdul Lateef Attar <abdullateef.at...@amd.com> --- .../AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc | 6 +- .../Library/DxeBoardInitLib/DxeBoardInitLib.c | 253 +++++++++++++++ .../DxeBoardInitLib/DxeBoardInitLib.inf | 51 +++ .../DxeBoardInitLib/DxeBoardInitLibInternal.c | 306 ++++++++++++++++++ .../DxeBoardInitLib/DxeBoardInitLibInternal.h | 159 +++++++++ .../DxeBoardInitLib/MadtAcpiTablePatch.c | 243 ++++++++++++++ 6 files changed, 1017 insertions(+), 1 deletion(-) create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.c create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.c create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.h create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/MadtAcpiTablePatch.c diff --git a/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc b/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc index 335e875f70..e0afe1e755 100644 --- a/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc +++ b/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc @@ -40,6 +40,9 @@ SetCacheMtrrLib|AmdMinBoardPkg/Library/SetCacheMtrrLib/SetCacheMtrrLib.inf BoardInitLib|AmdMinBoardPkg/Library/PeiBoardInitPreMemLib/PeiBoardInitPreMemLib.inf +[LibraryClasses.common.DXE_DRIVER] + BoardInitLib|AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf + [Components] AmdMinBoardPkg/Library/SpcrDeviceLib/SpcrDeviceLib.inf @@ -49,4 +52,5 @@ AmdMinBoardPkg/Library/PeiBoardInitPreMemLib/PeiBoardInitPreMemLib.inf [Components.X64] - AmdMinBoardPkg/PciHotPlug/PciHotPlugInit.inf + AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf + AmdMinBoardPkg/PciHotPlug/PciHotPlugInit.inf \ No newline at end of file diff --git a/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.c b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.c new file mode 100644 index 0000000000..7c41d3e38b --- /dev/null +++ b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.c @@ -0,0 +1,253 @@ +/** @file + BoardInitLib library implementation for DXE phase. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Library/BoardInitLib.h> +#include <Library/PcdLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesTableLib.h> +#include "DxeBoardInitLibInternal.h" + +EFI_HANDLE mImageHandle; +EFI_SYSTEM_TABLE *mSystemTable; + +/** + This board service detects the board type. + + @retval EFI_SUCCESS The board was detected successfully. + @retval EFI_NOT_FOUND The board could not be detected. +**/ +EFI_STATUS +EFIAPI +BoardDetect ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + This board service initializes board-specific debug devices. + + @retval EFI_SUCCESS Board-specific debug initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardDebugInit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + This board service detects the boot mode. + + @retval EFI_BOOT_MODE The boot mode. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_BOOT_MODE +EFIAPI +BoardBootModeDetect ( + VOID + ) +{ + return BOOT_WITH_FULL_CONFIGURATION; +} + +/** + A hook for board-specific initialization prior to memory initialization. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitBeforeMemoryInit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + A hook for board-specific initialization after memory initialization. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitAfterMemoryInit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + A hook for board-specific initialization prior to disabling temporary RAM. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitBeforeTempRamExit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + A hook for board-specific initialization after disabling temporary RAM. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitAfterTempRamExit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + A hook for board-specific initialization prior to silicon initialization. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitBeforeSiliconInit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + A hook for board-specific initialization after silicon initialization. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitAfterSiliconInit ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + A hook for board-specific initialization after PCI enumeration. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitAfterPciEnumeration ( + VOID + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "%a - ENTRY\n", __FUNCTION__)); + + Status = ReserveLegacyVgaIoSpace (); + DEBUG ((DEBUG_INFO, "ReserveLegacyVgaIoSpace...%r.\n", Status)); + + Status = ReservePcieExtendedConfigSpace (mImageHandle, mSystemTable); + DEBUG ((DEBUG_INFO, "ReservePcieExtendedConfigSpace...%r.\n", Status)); + + return Status; +} + +/** + A hook for board-specific functionality for the ReadyToBoot event. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitReadyToBoot ( + VOID + ) +{ + EFI_STATUS Status; + + Status = UpdateReinstallAcpiTable ( + EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + (PATCH_ACPITABLE)FadtAcpiTablePatch + ); + DEBUG ((DEBUG_INFO, "Patching FADT ACPI Table ... Status = %r.\n", Status)); + + Status = UpdateReinstallAcpiTable ( + EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, + (PATCH_ACPITABLE)MadtAcpiTablePatch + ); + DEBUG ((DEBUG_INFO, "Patching MADT ACPI Table ... Status = %r.\n", Status)); + + UpdateReinstallAcpiTable ( + EFI_ACPI_6_5_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + (PATCH_ACPITABLE)AcpiTableAmlUpdate + ); + + UpdateReinstallAcpiTable ( + EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + (PATCH_ACPITABLE)AcpiTableAmlUpdate + ); + + return EFI_SUCCESS; +} + +/** + A hook for board-specific functionality for the ExitBootServices event. + + @retval EFI_SUCCESS The board initialization was successful. + @retval EFI_NOT_READY The board has not been detected yet. +**/ +EFI_STATUS +EFIAPI +BoardInitEndOfFirmware ( + VOID + ) +{ + return EFI_SUCCESS; +} + +/** + The constructor function caches the PCI Express Base Address and creates a + Set Virtual Address Map event to convert physical address to virtual addresses. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor completed successfully. + @retval Other value The constructor did not complete successfully. + +**/ +EFI_STATUS +EFIAPI +DxeBoardInitLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mImageHandle = ImageHandle; + mSystemTable = SystemTable; + return EFI_SUCCESS; +} diff --git a/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf new file mode 100644 index 0000000000..919777d016 --- /dev/null +++ b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf @@ -0,0 +1,51 @@ +## @file +# Implements BoardInitLib Library Class in DXE phase. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = DxeBoardInitLib + FILE_GUID = B3C8F348-B528-4CA0-928E-3193ADEA65E6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = BoardInitLib + CONSTRUCTOR = DxeBoardInitLibConstructor + +[LibraryClasses] + BaseLib + DebugLib + LocalApicLib + PcdLib + PcieConfigLib + PlatformSocLib + SortLib + +[Packages] + AmdPlatformPkg/AmdPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + MinPlatformPkg/MinPlatformPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[Sources] + DxeBoardInitLib.c + DxeBoardInitLibInternal.c + DxeBoardInitLibInternal.h + MadtAcpiTablePatch.c + +[Protocols] + gEfiAcpiSdtProtocolGuid + gEfiAcpiTableProtocolGuid + gEfiMpServiceProtocolGuid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId + gMinPlatformPkgTokenSpaceGuid.PcdMaxCpuSocketCount + +[DEPEX] + gEfiMpServiceProtocolGuid diff --git a/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.c b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.c new file mode 100644 index 0000000000..2ffc249792 --- /dev/null +++ b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.c @@ -0,0 +1,306 @@ +/** @file + BoardInitLib library internal implementation for DXE phase. + +Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "DxeBoardInitLibInternal.h" + +/** + A helper function to uninstall or update the ACPI table. + It searches for ACPI table for provided table signature, + if found then creates a copy of the table and calls the callbackfunction. + + @param[in] Signature ACPI table signature + @param[in] CallbackFunction The function to call to patch the searching ACPI table. + If NULL then uninstalls the table. + + @return EFI_SUCCESS Successfully Re-install the ACPI Table + @return EFI_NOT_FOUND Table not found + @return EFI_STATUS returns non-EFI_SUCCESS value in case of failure + +**/ +EFI_STATUS +EFIAPI +UpdateReinstallAcpiTable ( + IN UINT32 Signature, + IN PATCH_ACPITABLE CallbackFunction + ) +{ + EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol; + EFI_STATUS Status; + UINTN Index; + EFI_ACPI_SDT_HEADER *Table; + EFI_ACPI_TABLE_VERSION Version; + UINTN OriginalTableKey; + EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; + EFI_ACPI_SDT_HEADER *NewTable; + UINTN NewTableKey; + BOOLEAN Found; + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTableProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error(%r): Unable to locate ACPI Table protocol.\n", Status)); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&AcpiSdtProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error(%r): Unable to locate ACPI SDT protocol.\n", Status)); + return Status; + } + + Found = FALSE; + Index = 0; + do { + Status = AcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &OriginalTableKey); + if (EFI_ERROR (Status)) { + goto END_OF_SEARCH; + } + + // Look for given table + if (Table->Signature == Signature) { + if (CallbackFunction == NULL) { + Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, OriginalTableKey); + return Status; + } + + NewTable = AllocateCopyPool (Table->Length, Table); + if (NULL == NewTable) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "Error(%r): Not enough resource to allocate table.\n", Status)); + return Status; + } + + Status = CallbackFunction (NewTable); + if (!EFI_ERROR (Status)) { + // Uninstall the old table + Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, OriginalTableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error(%r): Uninstall old table error.\n", Status)); + FreePool (NewTable); + return Status; + } + + // Install the new table + Status = AcpiTableProtocol->InstallAcpiTable (AcpiTableProtocol, NewTable, NewTable->Length, &NewTableKey); + FreePool (NewTable); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error(%r): Failed to install new table.\n", Status)); + return Status; + } + + // If non SSDT table, then return status + if (Table->Signature != EFI_ACPI_6_5_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { + return Status; + } + + // Atleast one SSDT table update is success + Found = TRUE; + } + + // continue to search next SSDT table. + Status = EFI_SUCCESS; + } + + Index++; + } while (!EFI_ERROR (Status)); + +END_OF_SEARCH: + if (!Found) { + DEBUG ((DEBUG_ERROR, "Error(%r): Unable to locate ACPI Table.\n", Status)); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + A Callback function to patch the ACPI FADT table. + Updates FADT table with AMD specific values, which + are different than MinPlatformPkg. + + @param[in, out] NewTable Pointer to ACPI FADT table + + @return EFI_SUCCESS Always return EFI_SUCCESSe + +**/ +EFI_STATUS +EFIAPI +FadtAcpiTablePatch ( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ) +{ + EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE *NewFadt; + + NewFadt = (EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE *)NewTable; + // Patch the Table + NewFadt->PLvl2Lat = 0x64; + NewFadt->Pm2CntLen = 0; + NewFadt->XGpe0Blk.RegisterBitWidth = 0x40; + NewFadt->FlushSize = 0x400; + NewFadt->FlushStride = 0x10; + NewFadt->XGpe1Blk.AccessSize = 0x01; + + return EFI_SUCCESS; +} + +/** + A Callback function to patch the ACPI DSDT/SSDT table. + Which has ASL code that needs to be updated. + + @param[in, out] NewTable Pointer to ACPI FADT table + + @return EFI_SUCCESS If table is modified. + EFI_NOT_FOUND If table is not modified. + +**/ +EFI_STATUS +EFIAPI +AcpiTableAmlUpdate ( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ) +{ + UINT64 OemTableId; + + if ((AsciiStrnCmp (NewTable->OemTableId, "AmdTable", 8) == 0)) { + DEBUG ((DEBUG_INFO, "Found (D/S)SDT table for patching OemTableId.\n")); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (NewTable->OemTableId, &OemTableId, 8); + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +/** + Reserve Legacy VGA IO space. + + @retval EFI_SUCCESS MMIO at Legacy VGA region has been allocated. + @retval !EFI_SUCCESS Error allocating the legacy VGA region. + +**/ +EFI_STATUS +EFIAPI +ReserveLegacyVgaIoSpace ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS VgaMemAddress; + + VgaMemAddress = (EFI_PHYSICAL_ADDRESS)VGA_MEM_BASE; + Status = gBS->AllocatePages ( + AllocateAddress, + EfiMemoryMappedIO, + EFI_SIZE_TO_PAGES (VGA_MEM_SIZE), + &VgaMemAddress + ); + return Status; +} + +/** + Helper function to get size of MMIO region required for the Bus Range + configured. + + @param[in] BusRange Chipset representation of Bus Range + + @retval Size of MMIO required for bus range +**/ +UINT64 +DecodeMmioBusRange ( + UINT64 BusRange + ) +{ + // Minimum MMIO region required is 1MB (1 Segment - 1 Bus). + // Set Mmio Size to 1MB. + UINT64 MmioSize; + + MmioSize = 0x100000; + + if (BusRange > 0x0E) { + MmioSize = SIZE_32GB; + } else { + MmioSize = (MmioSize << BusRange); + } + + return MmioSize; +} + +/** + Reserve PCIe Extended Config Space MMIO in the GCD and mark it runtime + + @param[in] ImageHandle ImageHandle of the loaded driver. + @param[in] SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS One or more of the drivers returned a success code. + @retval !EFI_SUCCESS Error initializing the Legacy PIC. + +**/ +EFI_STATUS +EFIAPI +ReservePcieExtendedConfigSpace ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + AMD_MMIO_CFG_MSR MmioCfgMsr; + UINT64 MmioCfgBase; + UINT64 MmioCfgSize; + + Status = EFI_SUCCESS; + // + // Reserve MMIO for PCI-Config space + // + MmioCfgMsr.AsUint64 = AsmReadMsr64 (AMD_MMIO_CFG_MSR_ADDR); + MmioCfgBase = MmioCfgMsr.AsUint64 & AMD_MMIO_CFG_ADDR_MASK; + MmioCfgSize = DecodeMmioBusRange (MmioCfgMsr.AsBits.BusRange); + DEBUG ((DEBUG_INFO, "\nMMIO_CFG MSR = 0x%08lX\n", MmioCfgMsr.AsUint64)); + DEBUG ((DEBUG_INFO, " Enable = %d\n", MmioCfgMsr.AsBits.Enable)); + DEBUG ((DEBUG_INFO, " BusRange = %d\n", MmioCfgMsr.AsBits.BusRange)); + DEBUG ((DEBUG_INFO, " MmioCfgBase = 0x%08lX\n", MmioCfgBase)); + DEBUG ((DEBUG_INFO, " MmioCfgSize = 0x%08lX\n", MmioCfgSize)); + + if (MmioCfgMsr.AsBits.Enable) { + // Free Memory if it is allocated (call will likely return Not Found) + Status = gDS->FreeMemorySpace ( + MmioCfgBase, + MmioCfgSize + ); + // Remove Memory Space from GCD map (could return Not Found) + Status = gDS->RemoveMemorySpace ( + MmioCfgBase, + MmioCfgSize + ); + // Make sure Adding memory space succeeds or assert + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeReserved, + MmioCfgBase, + MmioCfgSize, + EFI_MEMORY_RUNTIME | EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR (Status); + // Make sure Allocating memory space succeed or assert + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeReserved, + 0, + MmioCfgSize, + &MmioCfgBase, + ImageHandle, + NULL + ); + ASSERT_EFI_ERROR (Status); + + DEBUG (( + DEBUG_INFO, + "\nReserved PciCfg MMIO: Base = 0x%lX, Size = 0x%lX\n", + MmioCfgBase, + MmioCfgSize + )); + } + + return Status; +} diff --git a/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.h b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.h new file mode 100644 index 0000000000..037328a34c --- /dev/null +++ b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLibInternal.h @@ -0,0 +1,159 @@ +/** @file + +Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef DXE_BOARD_INIT_LIB_INTERNAL_H_ +#define DXE_BOARD_INIT_LIB_INTERNAL_H_ + +#include <Uefi/UefiBaseType.h> +#include <Register/Intel/Cpuid.h> +#include <Protocol/AcpiSystemDescriptionTable.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Protocol/AcpiTable.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <IndustryStandard/Acpi65.h> +#include <Library/SortLib.h> +#include <Library/IoLib.h> +#include <Register/IoApic.h> +#include <Protocol/MpService.h> +#include <Library/BaseLib.h> + +// Define temp buffer length for save IoApic data +#define MAX_IOAPIC_NUM 0x20 + +#define VGA_MEM_BASE 0xA0000 +#define VGA_MEM_SIZE 0x20000 + +// +// 48-bit MMIO space (MB-aligned) +// +#define AMD_MMIO_CFG_MSR_ADDR 0xC0010058UL +#define AMD_MMIO_CFG_ADDR_MASK 0xFFFFFFF00000ULL + +typedef struct { + UINT8 Type; + UINT8 Length; +} STRUCTURE_HEADER; + +#pragma pack(1) +typedef union { + struct { + // HACK-HACK: Use UINT32 to keep compiler from using SHIFT intrinsics on NOOPT build + UINT32 Enable : 1; // [0] + UINT32 Reserved1 : 1; // [1] + UINT32 BusRange : 4; // [5:2] + UINT32 Reserved2 : 14; // [19:6] + UINT32 MmioCfgBaseAddr : 28; // [47:20] + UINT32 Reserved3 : 16; // [63:48] + } AsBits; + + UINT64 AsUint64; +} AMD_MMIO_CFG_MSR; +#pragma pack() + +/** + Reserve PCIe Extended Config Space MMIO in the GCD and mark it runtime + + @param[in] ImageHandle ImageHandle of the loaded driver. + @param[in] SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS One or more of the drivers returned a success code. + @retval !EFI_SUCCESS Error initializing the Legacy PIC. +**/ +EFI_STATUS +EFIAPI +ReservePcieExtendedConfigSpace ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Prototype for callback function to patch ACPI table. + + @param[in, out] NewTable The pointer to ACPI table. + @return EFI_SUCCESS Always return EFI_SUCCESS +**/ +typedef +EFI_STATUS +(EFIAPI *PATCH_ACPITABLE)( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ); + +/** + A helper function to update and re-install ACPI table. + It search for ACPI table for provided table signature, + if found then creates a copy of the table and invokes + the call back function. + + @param[in] Signature ACPI table signature + @param[in] CallbackFunction The function to call to patch the searching ACPI table. + + @return EFI_SUCCESS Successfully Re-install the ACPI Table + @return EFI_NOT_FOUND Table not found + @return EFI_STATUS returns non-EFI_SUCCESS value in case of failure + +**/ +EFI_STATUS +EFIAPI +UpdateReinstallAcpiTable ( + IN UINT32 Signature, + IN PATCH_ACPITABLE CallbackFunction + ); + +/** + A Callback function to patch the ACPI FADT table. + Updates FADT table with AMD specific values, which + are different than MinPlatformPkg. + + @param[in, out] NewTable Pointer to ACPI FADT table + + @return EFI_SUCCESS Always return EFI_SUCCESSe + +**/ +EFI_STATUS +EFIAPI +FadtAcpiTablePatch ( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ); + +EFI_STATUS +EFIAPI +MadtAcpiTablePatch ( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ); + +/** + A Callback function to patch the ACPI DSDT/SSDT table. + Which has ASL code that needs to be updated. + + @param[in, out] NewTable Pointer to ACPI FADT table + + @return EFI_SUCCESS Always return EFI_SUCCESSe + +**/ +EFI_STATUS +EFIAPI +AcpiTableAmlUpdate ( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ); + +/** + Reserve Legacy VGA IO space. + + @retval EFI_SUCCESS MMIO at Legacy VGA region has been allocated. + @retval !EFI_SUCCESS Error allocating the legacy VGA region. + +**/ +EFI_STATUS +EFIAPI +ReserveLegacyVgaIoSpace ( + VOID + ); + +#endif diff --git a/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/MadtAcpiTablePatch.c b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/MadtAcpiTablePatch.c new file mode 100644 index 0000000000..aefb378981 --- /dev/null +++ b/Platform/AMD/AmdMinBoardPkg/Library/DxeBoardInitLib/MadtAcpiTablePatch.c @@ -0,0 +1,243 @@ +/** @file + This file patches the ACPI MADT table for AMD specific values. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "DxeBoardInitLibInternal.h" +#include <Library/AmdPlatformSocLib.h> +#include <Library/LocalApicLib.h> +#define AMD_CPUID_EXTENDED_TOPOLOGY_V2 0x26 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_CCX 0x03 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_CCD 0x04 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE 0x05 + +UINT32 mCcdOrder[16] = { 0, 4, 8, 12, 2, 6, 10, 14, 3, 7, 11, 15, 1, 5, 9, 13 }; + +/** + Callback compare function. + Compares CCD number of provided arguments. + + @param[in] LocalX2ApicLeft Pointer to Left Buffer. + @param[in] LocalX2ApicRight Pointer to Right Buffer. + @return 0 If both are same + -1 If left value is less than righ value. + 1 If left value is greater than righ value. + +**/ +INTN +EFIAPI +SortByCcd ( + CONST VOID *LocalX2ApicLeft, + CONST VOID *LocalX2ApicRight + ) +{ + CONST EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *Left; + CONST EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *Right; + EFI_CPU_PHYSICAL_LOCATION2 LeftLocation; + EFI_CPU_PHYSICAL_LOCATION2 RightLocation; + UINT32 LeftCcdIndex; + UINT32 RightCcdIndex; + UINT32 Index; + + Left = (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)LocalX2ApicLeft; + Right = (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)LocalX2ApicRight; + + GetProcessorLocation2ByApicId ( + Left->X2ApicId, + &LeftLocation.Package, + &LeftLocation.Die, + &LeftLocation.Tile, + &LeftLocation.Module, + &LeftLocation.Core, + &LeftLocation.Thread + ); + + GetProcessorLocation2ByApicId ( + Right->X2ApicId, + &RightLocation.Package, + &RightLocation.Die, + &RightLocation.Tile, + &RightLocation.Module, + &RightLocation.Core, + &RightLocation.Thread + ); + + // Get the CCD Index number + LeftCcdIndex = MAX_UINT32; + for (Index = 0; Index < ARRAY_SIZE (mCcdOrder); Index++) { + if (LeftLocation.Die == mCcdOrder[Index]) { + LeftCcdIndex = Index; + break; + } + } + + RightCcdIndex = MAX_UINT32; + for (Index = 0; Index < ARRAY_SIZE (mCcdOrder); Index++) { + if (RightLocation.Die == mCcdOrder[Index]) { + RightCcdIndex = Index; + break; + } + } + + // Now compare for quick sort + if (LeftCcdIndex < RightCcdIndex) { + return -1; + } + + if (LeftCcdIndex > RightCcdIndex) { + return 1; + } + + return 0; +} + +/** + A Callback function to patch the ACPI MADT table. + Updates MADT table with AMD specific values, which + are different than MinPlatformPkg. + + @param[in, out] NewTable Pointer to ACPI MADT table + + @return EFI_SUCCESS Always return EFI_SUCCESSe + +**/ +EFI_STATUS +EFIAPI +MadtAcpiTablePatch ( + IN OUT EFI_ACPI_SDT_HEADER *NewTable + ) +{ + UINT32 Index; + EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable; + UINT8 *TablePtr; + UINT64 Length; + EFI_ACPI_6_5_IO_APIC_STRUCTURE *NbioIoApic; + UINT8 IoApicCount; + UINTN LapicCount; + EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *LocalX2ApicPtr; + EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *SortedItem; + EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *Src; + EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *Dst; + + // Patch the Table + NewMadtTable = (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)NewTable; + NewMadtTable->Header.Revision = 6; + // Get the IoApic information + NbioIoApic = NULL; + IoApicCount = 0; + LapicCount = 0; + LocalX2ApicPtr = NULL; + GetIoApicInfo (&NbioIoApic, &IoApicCount); + if ((NbioIoApic == NULL) || (IoApicCount == 0)) { + DEBUG ((DEBUG_INFO, "%a:%d Cannot obtain NBIO IOAPIC information.\n", __FUNCTION__, __LINE__)); + return EFI_SUCCESS; + } + + // Create MADT header + TablePtr = (UINT8 *)NewMadtTable; + TablePtr = TablePtr + sizeof (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); + Length = sizeof (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); + + // Get the IOAPIC structure + Index = 0; // now holds the IoApic Index + do { + if (((STRUCTURE_HEADER *)TablePtr)->Type == EFI_ACPI_6_5_IO_APIC) { + // Patch the IoApic Strucure + if (Index >= IoApicCount) { + /// Mark the extra IOAPIC structure Type as reserved, so that OSPM can ignore it. + /// As per ACPI specification 6.5 for MADT table + /// Subtype 0x18-0x7F are reserved, OSPM skips structures of the reserved type. + ((EFI_ACPI_6_5_IO_APIC_STRUCTURE *)TablePtr)->Type = 0x7F; + } else { + ((EFI_ACPI_6_5_IO_APIC_STRUCTURE *)TablePtr)->IoApicId = NbioIoApic[Index].IoApicId; + ((EFI_ACPI_6_5_IO_APIC_STRUCTURE *)TablePtr)->IoApicAddress = NbioIoApic[Index].IoApicAddress; + ((EFI_ACPI_6_5_IO_APIC_STRUCTURE *)TablePtr)->GlobalSystemInterruptBase = NbioIoApic[Index].GlobalSystemInterruptBase; + } + + Index++; + } + + if (((STRUCTURE_HEADER *)TablePtr)->Type == EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE) { + // Patch Flags + ((EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)TablePtr)->Flags = 0xF; + } + + if (((STRUCTURE_HEADER *)TablePtr)->Type == EFI_ACPI_6_5_LOCAL_X2APIC_NMI) { + // Patch Flags - Edge-triggered, Active High + ((EFI_ACPI_6_5_LOCAL_X2APIC_NMI_STRUCTURE *)TablePtr)->Flags = 0x0005; + } + + if (((STRUCTURE_HEADER *)TablePtr)->Type == EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC) { + if (LapicCount == 0) { + // Get the first entry pointer + LocalX2ApicPtr = (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)TablePtr; + } + + LapicCount += 1; + } + + Length += ((STRUCTURE_HEADER *)TablePtr)->Length; + TablePtr += ((STRUCTURE_HEADER *)TablePtr)->Length; + } while (Length < NewMadtTable->Header.Length); + + FreePool (NbioIoApic); + + if (LocalX2ApicPtr != NULL) { + if (FixedPcdGet32 (PcdMaxCpuSocketCount) > 1) { + /// Sort by CCD location + PerformQuickSort (LocalX2ApicPtr, LapicCount/2, sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE), SortByCcd); + PerformQuickSort (LocalX2ApicPtr+(LapicCount/2), LapicCount/2, sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE), SortByCcd); + } else { + /// Sort by CCD location + PerformQuickSort (LocalX2ApicPtr, LapicCount, sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE), SortByCcd); + } + + /// Now allocate the Uid + SortedItem = LocalX2ApicPtr; + for (Index = 0; Index < LapicCount; Index++, SortedItem++) { + SortedItem->AcpiProcessorUid = Index; + } + + // Now separate the second thread list + SortedItem = LocalX2ApicPtr + 1; + if ((SortedItem->X2ApicId & 0x1) == 0x1) { + // It has multi-thread on + SortedItem = NULL; + SortedItem = AllocateZeroPool (sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE) * LapicCount); + if (SortedItem == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Src = LocalX2ApicPtr; + Dst = SortedItem; + for (Index = 0; Index < LapicCount; Index++) { + if ((Src->X2ApicId & 0x1) == 0) { + CopyMem (Dst, Src, sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE)); + Src++; + Dst++; + } else { + Src++; + } + } + + Src = LocalX2ApicPtr; + for (Index = 0; Index < LapicCount; Index++) { + if ((Src->X2ApicId & 0x1) == 1) { + CopyMem (Dst, Src, sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE)); + Src++; + Dst++; + } else { + Src++; + } + } + + CopyMem (LocalX2ApicPtr, SortedItem, sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE) * LapicCount); + FreePool (SortedItem); + } + } + + return EFI_SUCCESS; +} -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118977): https://edk2.groups.io/g/devel/message/118977 Mute This Topic: https://groups.io/mt/106148092/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-