From: Duke Zhai <duke.z...@amd.com>
BZ #:4640 Initial PlatformInitPei module. This is the Platform module to initialize whole platform on PEI phase. Signed-off-by: Ken Yao <ken....@amd.com> Cc: Eric Xing <eric.x...@amd.com> Cc: Duke Zhai <duke.z...@amd.com> Cc: Igniculus Fu <igniculus...@amd.com> Cc: Abner Chang <abner.ch...@amd.com> --- .../Universal/PlatformInitPei/BootMode.c | 287 ++++++ .../Universal/PlatformInitPei/CommonHeader.h | 244 +++++ .../PlatformInitPei/MemoryCallback.c | 308 ++++++ .../Universal/PlatformInitPei/MemoryInstall.c | 953 ++++++++++++++++++ .../Universal/PlatformInitPei/MemoryInstall.h | 229 +++++ .../Universal/PlatformInitPei/MemoryPeim.c | 385 +++++++ .../Universal/PlatformInitPei/PlatformInit.c | 176 ++++ .../PlatformInitPei/PlatformInit.inf | 114 +++ .../Universal/PlatformInitPei/Stall.c | 122 +++ 9 files changed, 2818 insertions(+) create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/BootMode.c create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/CommonHeader.h create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryCallback.c create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.c create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.h create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryPeim.c create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.c create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.inf create mode 100644 Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/Stall.c diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/BootMode.c b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/BootMode.c new file mode 100644 index 0000000000..9102ae2b86 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/BootMode.c @@ -0,0 +1,287 @@ +/** @file + Implements BootMode.C + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file +This file provide the function to detect boot mode + +Copyright (c) 2013 Intel Corporation. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CommonHeader.h" + +EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiBootInRecoveryModePpiGuid, + NULL +}; +STATIC EFI_PEI_PPI_DESCRIPTOR CapsulePpi = { + EFI_PEI_PPI_DESCRIPTOR_PPI|EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gCapsuleUpdateDetectedPpiGuid, + NULL +}; + +/** + +Routine Description: + + This function is used to verify if the FV header is validate. + + @param FwVolHeader - The FV header that to be verified. + + @retval EFI_SUCCESS - The Fv header is valid. + @retval EFI_NOT_FOUND - The Fv header is invalid. + +**/ +EFI_STATUS +ValidateFvHeader ( + EFI_BOOT_MODE *BootMode + ) +{ + UINT16 *Ptr; + UINT16 HeaderLength; + UINT16 Checksum; + + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + + if (BOOT_IN_RECOVERY_MODE == *BootMode) { + DEBUG ((EFI_D_INFO, "Boot mode recovery\n")); + return EFI_SUCCESS; + } + + // + // Let's check whether FvMain header is valid, if not enter into recovery mode + // + // + // Verify the header revision, header signature, length + // Length of FvBlock cannot be 2**64-1 + // HeaderLength cannot be an odd number + // + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdFlashFvMainBase); + if ((FwVolHeader->Revision != EFI_FVH_REVISION) || + (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength == ((UINT64)-1)) || + ((FwVolHeader->HeaderLength & 0x01) != 0) + ) + { + return EFI_NOT_FOUND; + } + + // + // Verify the header checksum + // + HeaderLength = (UINT16)(FwVolHeader->HeaderLength / 2); + Ptr = (UINT16 *)FwVolHeader; + Checksum = 0; + while (HeaderLength > 0) { + Checksum = Checksum +*Ptr; + Ptr++; + HeaderLength--; + } + + if (Checksum != 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + Peform the boot mode determination logic + + @param PeiServices General purpose services available to every PEIM. + + @param BootMode The detected boot mode. + + @retval EFI_SUCCESS if the boot mode could be set +**/ +EFI_STATUS +UpdateBootMode ( + IN CONST EFI_PEI_SERVICES **PeiServices, + OUT EFI_BOOT_MODE *BootMode + ) +{ + EFI_STATUS Status; + UINT16 SleepType; + CHAR16 *strBootMode; + EFI_BOOT_MODE NewBootMode; + EFI_PEI_CAPSULE_PPI *Capsule; + BOOLEAN IsFirstBoot; + + // + // Let's assume things are OK if not told otherwise + // + NewBootMode = BOOT_WITH_FULL_CONFIGURATION; + + // + // When this boot is WDT reset, the system needs booting with CrashDump function eanbled. + // Check Power Button, click the power button, the system will boot in fast boot mode, + // if it is pressed and hold for a second, it will boot in FullConfiguration/setup mode. + // + IsFirstBoot = PcdGetBool (PcdBootState); + + if (!IsFirstBoot) { + NewBootMode = BOOT_WITH_MINIMAL_CONFIGURATION; + } + + // + // Check if we need to boot in forced recovery mode + // + if (ValidateFvHeader (&NewBootMode) != EFI_SUCCESS) { + NewBootMode = BOOT_IN_RECOVERY_MODE; + DEBUG ((EFI_D_ERROR, "RECOVERY from corrupt FV\n")); + } + + if (NewBootMode == BOOT_IN_RECOVERY_MODE) { + Status = (*PeiServices)->InstallPpi ( + PeiServices, + &mPpiListRecoveryBootMode + ); + ASSERT_EFI_ERROR (Status); + } else { + if (GetSleepTypeAfterWakeup (PeiServices, &SleepType)) { + switch (SleepType) { + case V_SLP_TYPE_S3: + NewBootMode = BOOT_ON_S3_RESUME; + break; + + case V_SLP_TYPE_S4: + NewBootMode = BOOT_ON_S4_RESUME; + break; + + case V_SLP_TYPE_S5: + NewBootMode = BOOT_ON_S5_RESUME; + break; + } // switch (SleepType) + } + + // + // Determine if we're in capsule update mode + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gEfiPeiCapsulePpiGuid, + 0, + NULL, + (void **)&Capsule + ); + + if (Status == EFI_SUCCESS) { + if (Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES **)PeiServices) == EFI_SUCCESS) { + NewBootMode = BOOT_ON_FLASH_UPDATE; + DEBUG ((EFI_D_ERROR, "Setting BootMode to %x\n", BOOT_ON_FLASH_UPDATE)); + + (*PeiServices)->InstallPpi (PeiServices, &CapsulePpi); + } + } + + // + // Check for Safe Mode + // + } + + switch (NewBootMode) { + case BOOT_WITH_FULL_CONFIGURATION: + strBootMode = L"BOOT_WITH_FULL_CONFIGURATION"; + break; + case BOOT_WITH_MINIMAL_CONFIGURATION: + strBootMode = L"BOOT_WITH_MINIMAL_CONFIGURATION"; + break; + case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: + strBootMode = L"BOOT_ASSUMING_NO_CONFIGURATION_CHANGES"; + break; + case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: + strBootMode = L"BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS"; + break; + case BOOT_WITH_DEFAULT_SETTINGS: + strBootMode = L"BOOT_WITH_DEFAULT_SETTINGS"; + break; + case BOOT_ON_S4_RESUME: + strBootMode = L"BOOT_ON_S4_RESUME"; + break; + case BOOT_ON_S5_RESUME: + strBootMode = L"BOOT_ON_S5_RESUME"; + break; + case BOOT_ON_S2_RESUME: + strBootMode = L"BOOT_ON_S2_RESUME"; + break; + case BOOT_ON_S3_RESUME: + strBootMode = L"BOOT_ON_S3_RESUME"; + break; + case BOOT_ON_FLASH_UPDATE: + strBootMode = L"BOOT_ON_FLASH_UPDATE"; + break; + case BOOT_IN_RECOVERY_MODE: + strBootMode = L"BOOT_IN_RECOVERY_MODE"; + break; + default: + strBootMode = L"Unknown boot mode"; + } // switch (BootMode) + + DEBUG ((EFI_D_INFO, "Setting BootMode to %s\n", strBootMode)); + Status = (*PeiServices)->SetBootMode ( + PeiServices, + NewBootMode + ); + ASSERT_EFI_ERROR (Status); + + *BootMode = NewBootMode; + + return Status; +} + +/** + Get sleep type after wakeup + + @param PeiServices Pointer to the PEI Service Table. + @param SleepType Sleep type to be returned. + + @retval TRUE A wake event occured without power failure. + @retval FALSE Power failure occured or not a wakeup. + +**/ +BOOLEAN +GetSleepTypeAfterWakeup ( + IN CONST EFI_PEI_SERVICES **PeiServices, + OUT UINT16 *SleepType + ) + +{ + UINTN AcpiPm1CntBlk; + UINT16 Pm1Cnt; + + AcpiPm1CntBlk = MmioRead16 (ACPI_MMIO_BASE + PMIO_BASE + FCH_PMIOA_REG62); + + Pm1Cnt = IoRead16 (AcpiPm1CntBlk); + // + // check power failur/loss when in S3 resume type. + // Get sleep type if a wake event occurred and there is no power failure + // + if ((Pm1Cnt & B_SLP_TYPE) == V_SLP_TYPE_S3) { + *SleepType = Pm1Cnt & B_SLP_TYPE; + return TRUE; + } else if ((Pm1Cnt & B_SLP_TYPE) == V_SLP_TYPE_S4) { + *SleepType = Pm1Cnt & B_SLP_TYPE; + return TRUE; + } + + *SleepType = 0; + Pm1Cnt &= (~B_SLP_TYPE); + IoWrite16 (AcpiPm1CntBlk, Pm1Cnt); + return FALSE; +} diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/CommonHeader.h b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/CommonHeader.h new file mode 100644 index 0000000000..ffc53cec00 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/CommonHeader.h @@ -0,0 +1,244 @@ +/** @file + Implements CommonHeader.h + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013 - 2016 Intel Corporation. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + +#include <PiPei.h> +#include <Ppi/Stall.h> +#include <Ppi/MasterBootMode.h> +#include <Ppi/MemoryDiscovered.h> +#include <Ppi/Capsule.h> +#include <Library/IoLib.h> +#include <Guid/DebugMask.h> +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PeimEntryPoint.h> +#include <Library/PcdLib.h> +#include <Library/PeiServicesTablePointerLib.h> +#include <Library/PciExpressLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MtrrLib.h> +#include <Guid/MemoryTypeInformation.h> +#include <Guid/SmramMemoryReserve.h> +#include <Ppi/ReadOnlyVariable2.h> +#include <Guid/AmdMemoryInfoHob.h> +#include <Guid/AcpiS3Context.h> +#include "MemoryInstall.h" + +#define B_SLP_TYPE (BIT10 + BIT11 + BIT12) +#define V_SLP_TYPE_S0 (0 << 10) +#define V_SLP_TYPE_S1 (1 << 10) +#define V_SLP_TYPE_S3 (3 << 10) +#define V_SLP_TYPE_S4 (4 << 10) +#define V_SLP_TYPE_S5 (5 << 10) +#define B_ACPI_SLP_EN BIT13 +#define V_ACPI_SLP_EN BIT13 +#define SPI_BASE 0xFEC10000ul +#define EFI_CPUID_EXTENDED_FUNCTION 0x80000000 +#define EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE 0x80000008 + +#define ACPI_MMIO_BASE 0xFED80000ul +#define SMI_BASE 0x200 // DWORD +#define FCH_PMIOA_REG60 0x60 // AcpiPm1EvtBlk +#define FCH_PMIOA_REG62 0x62 // AcpiPm1CntBlk +#define FCH_PMIOA_REG64 0x64 // AcpiPmTmrBlk +#define PMIO_BASE 0x300 // DWORD +#define FCH_SMI_REGA0 0xA0 +#define FCH_SMI_REGC4 0xC4 +#define R_FCH_ACPI_PM_CONTROL 0x04 + +/** + + This function set different memory range cache attribute. + + @param PeiServices Pointer to the PEI Service Table. + +**/ +EFI_STATUS +EFIAPI +SetPeiCacheMode ( + IN CONST EFI_PEI_SERVICES **PeiServices + ); + +/** + + Waits for at least the given number of microseconds. + + @param PeiServices General purpose services available to every PEIM. + @param This PPI instance structure. + @param Microseconds Desired length of time to wait. + + @retval EFI_SUCCESS If the desired amount of time was passed. + +*/ +EFI_STATUS +EFIAPI +Stall ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_STALL_PPI *This, + IN UINTN Microseconds + ); + +/** + Peform the boot mode determination logic + + @param PeiServices General purpose services available to every PEIM. + + @param BootMode The detected boot mode. + + @retval EFI_SUCCESS if the boot mode could be set +**/ +EFI_STATUS +EFIAPI +UpdateBootMode ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE *BootMode + ); + +/** + + This function returns the different avaiable memory length. + + @param PeiServices Pointer to the PEI Service Table. + @param LowMemoryLength Avaiable memory length below 4G address. + @param HighMemoryLength Avaiable memory length above 4G address. + @param GraphicMemoryBase Avaiable UMA base address. + @param GraphicMemoryLength Avaiable UMA length. + + @retval LowMemoryLength Avaiable memory length below 4G address. + @retval HighMemoryLength Avaiable memory length above 4G address. + @retval GraphicMemoryBase Avaiable UMA base address. + @retval GraphicMemoryLength Avaiable UMA length. + +**/ +EFI_STATUS +GetMemorySize ( + IN CONST EFI_PEI_SERVICES **PeiServices, + OUT UINT64 *LowMemoryLength, + OUT UINT64 *HighMemoryLength, + OUT UINT64 *GraphicMemoryBase OPTIONAL, + OUT UINT64 *GraphicMemoryLength OPTIONAL + ); + +/** + + This function returns the memory ranges to be enabled, along with information + describing how the range should be used. + + @param MemoryMap Buffer to record details of the memory ranges. + @param NumRanges On input, this contains the maximum number of memory ranges that can be described + in the MemoryMap buffer. + + @retval MemoryMap The buffer will be filled in + @retval NumRanges will contain the actual number of memory ranges that are to be anabled. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetAvailableMemoryRanges ( + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ); + +/** + + This function returns the memory ranges to be reserved, along with information + describing how the range should be used. + + @param MemoryMap Buffer to record details of the memory ranges. + @param NumRanges On input, this contains the maximum number of memory ranges that can be described + in the MemoryMap buffer. + + @retval MemoryMap The buffer will be filled in + @retval NumRanges will contain the actual number of memory ranges that are to be reserved. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetReservedMemoryRanges ( + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ); + +/** + + Callback function after Memory discovered. + + @param PeiServices PEI Services table. + @param NotifyDescriptor Notify Descriptor. + @param Ppi Ppi + + @return EFI_STATUS If the function completed successfully. + +**/ +EFI_STATUS +EFIAPI +MemoryDiscoveredPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + + Callback function after Memory Info Hob Installed. + + @param PeiServices PEI Services table. + @param NotifyDescriptor Notify Descriptor. + @param Ppi Ppi + + @retval EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +MemoryInfoHobPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Get sleep type after wakeup + + @param PeiServices Pointer to the PEI Service Table. + @param SleepType Sleep type to be returned. + + @retval TRUE A wake event occured without power failure. + @retval FALSE Power failure occured or not a wakeup. + +**/ +BOOLEAN +GetSleepTypeAfterWakeup ( + IN CONST EFI_PEI_SERVICES **PeiServices, + OUT UINT16 *SleepType + ); + +#endif diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryCallback.c b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryCallback.c new file mode 100644 index 0000000000..9ab78b7135 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryCallback.c @@ -0,0 +1,308 @@ +/** @file + Implements MemoryCallback.C + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file +This file includes a memory call back function notified when MRC is done, +following action is performed in this file, + 1. ICH initialization after MRC. + 2. SIO initialization. + 3. Install ResetSystem and FinvFv PPI. + 4. Set MTRR for PEI + 5. Create FV HOB and Flash HOB + +Copyright (c) 2013 - 2016, Intel Corporation. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CommonHeader.h" +#include <Ppi/SmmControl.h> + +EFI_STATUS +EFIAPI +S3PostScriptTableCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_STATUS +EFIAPI +S3EndOfPeiSignalCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnS3ResumeList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gPeiPostScriptTablePpiGuid, + S3PostScriptTableCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + S3EndOfPeiSignalCallback + } +}; + +/** + + Trigger the S3 PostScriptTable notify SW SMI + + @param PeiServices PEI Services table. + @param NotifyDescriptor Notify Descriptor. + @param Ppi Ppi + + @return EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +S3PostScriptTableCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + PEI_SMM_CONTROL_PPI *SmmControl; + UINT16 SmiCommand; + UINTN SmiCommandSize; + + Status = PeiServicesLocatePpi ( + &gPeiSmmControlPpiGuid, + 0, + NULL, + (VOID **)&SmmControl + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiServicesLocatePpi gPeiSmmControlPpiGuid: %r \n", Status)); + return Status; + } + + SmiCommand = PcdGet8 (PcdFchOemBeforePciRestoreSwSmi); + DEBUG ((EFI_D_INFO, "Trigger SW SMI PcdFchOemBeforePciRestoreSwSmi: 0x%X\n", SmiCommand)); + SmiCommandSize = sizeof (SmiCommand); + Status = SmmControl->Trigger ( + (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), + SmmControl, + (INT8 *)&SmiCommand, + &SmiCommandSize, + FALSE, + 0 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + + Trigger the S3 EndOfPeiSignal notify SW SMI + + @param PeiServices PEI Services table. + @param NotifyDescriptor Notify Descriptor. + @param Ppi Ppi + + @return EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +EFIAPI +S3EndOfPeiSignalCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + PEI_SMM_CONTROL_PPI *SmmControl; + UINT16 SmiCommand; + UINTN SmiCommandSize; + + Status = PeiServicesLocatePpi ( + &gPeiSmmControlPpiGuid, + 0, + NULL, + (VOID **)&SmmControl + ); + + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiServicesLocatePpi gPeiSmmControlPpiGuid: %r \n", Status)); + return Status; + } + + SmiCommand = PcdGet8 (AcpiRestoreSwSmi); + DEBUG ((EFI_D_INFO, "Trigger SW SMI AcpiRestoreSwSmi: 0x%X\n", SmiCommand)); + SmiCommandSize = sizeof (SmiCommand); + Status = SmmControl->Trigger ( + (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), + SmmControl, + (INT8 *)&SmiCommand, + &SmiCommandSize, + FALSE, + 0 + ); + ASSERT_EFI_ERROR (Status); + + SmiCommand = PcdGet8 (PcdFchOemAfterPciRestoreSwSmi); + DEBUG ((EFI_D_INFO, "Trigger SW SMI PcdFchOemAfterPciRestoreSwSmi: 0x%X\n", SmiCommand)); + SmiCommandSize = sizeof (SmiCommand); + Status = SmmControl->Trigger ( + (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), + SmmControl, + (INT8 *)&SmiCommand, + &SmiCommandSize, + FALSE, + 0 + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + + Callback function after Memory discovered. + + @param PeiServices PEI Services table. + @param NotifyDescriptor Notify Descriptor. + @param Ppi Ppi + + @return EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +MemoryDiscoveredPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + UINT8 CpuAddressWidth; + UINT32 RegEax; + + #ifndef FV_RECOVERY_MAIN_COMBINE_SUPPORT + UINT32 Pages; + VOID *Memory; + #endif + + // + // Get boot mode + // + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + if (BootMode == BOOT_ON_S3_RESUME) { + Status = PeiServicesNotifyPpi (&mNotifyOnS3ResumeList[0]); + ASSERT_EFI_ERROR (Status); + } + + if (PcdGet8 (PcdFspModeSelection) == 0) { + // Dispatch Mode + SetPeiCacheMode ((const struct _EFI_PEI_SERVICES **)PeiServices); + } + + BuildResourceDescriptorHob ( + EFI_RESOURCE_MEMORY_MAPPED_IO, + (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), + SPI_BASE, + 0x1000 + ); + + // + // Local APIC + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_MEMORY_MAPPED_IO, + (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), + PcdGet32 (PcdCpuLocalApicBaseAddress), + 0x1000 + ); + + // + // IO APIC + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_MEMORY_MAPPED_IO, + (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), + PcdGet32 (PcdIoApicBaseAddress), + 0x1000 + ); + + AsmCpuid (0x80000001, &RegEax, NULL, NULL, NULL); + if (((RegEax >> 20) & 0xFF) == 0x8) { + // For F17: Reserved memory from BootFvBase - (BootFvBase+BootFvSize-1) + DEBUG ((EFI_D_INFO, "Family 17: Reserved memory for BFV\n")); + BuildMemoryAllocationHob ( + PcdGet32 (PcdMemoryFvRecoveryBase), + PcdGet32 (PcdFlashFvRecoverySize), + EfiReservedMemoryType + ); + } + + DEBUG ((EFI_D_INFO, "PcdMemoryFvRecoveryBase: %x,PcdFlashFvMainBase: %x\n", PcdGet32 (PcdMemoryFvRecoveryBase), PcdGet32 (PcdFlashFvMainBase))); + + if ((BootMode != BOOT_ON_S3_RESUME) && (BootMode != BOOT_IN_RECOVERY_MODE)) { + #ifndef FV_RECOVERY_MAIN_COMBINE_SUPPORT + Pages = PcdGet32 (PcdFlashFvMainSize)/0x1000; + Memory = AllocatePages (Pages); + CopyMem (Memory, (VOID *)PcdGet32 (PcdFlashFvMainBase), PcdGet32 (PcdFlashFvMainSize)); + #endif + // + // DXE FV + // + PeiServicesInstallFvInfoPpi ( + NULL, + #ifdef FV_RECOVERY_MAIN_COMBINE_SUPPORT + (VOID *)PcdGet32 (PcdFlashFvMainBase), + #else + (VOID *)Memory, + #endif + PcdGet32 (PcdFlashFvMainSize), + NULL, + NULL + ); + } + + // + // Adding the Flashpart to the E820 memory table as type 2 memory. + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_FIRMWARE_DEVICE, + (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), + FixedPcdGet32 (PcdFlashAreaBaseAddress), + FixedPcdGet32 (PcdFlashAreaSize) + ); + DEBUG ((EFI_D_INFO, "FLASH_BASE_ADDRESS : 0x%x\n", FixedPcdGet32 (PcdFlashAreaBaseAddress))); + + // + // Create a CPU hand-off information + // + CpuAddressWidth = 36; + + BuildCpuHob (CpuAddressWidth, 16); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.c b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.c new file mode 100644 index 0000000000..f58645f2cd --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.c @@ -0,0 +1,953 @@ +/** @file + Implements MemoryInstall.C + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file +Framework PEIM to initialize memory on a Quark Memory Controller. + +Copyright (c) 2013 - 2016, Intel Corporation. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CommonHeader.h" + +EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { + { EfiACPIReclaimMemory, 0x80 }, + { EfiACPIMemoryNVS, 0x3000 }, + { EfiReservedMemoryType, 0x1000 }, + { EfiMemoryMappedIO, 0 }, + { EfiMemoryMappedIOPortSpace, 0 }, + { EfiPalCode, 0 }, + { EfiRuntimeServicesCode, 0x800 }, + { EfiRuntimeServicesData, 0x1000 }, + { EfiLoaderCode, 0x200 }, + { EfiLoaderData, 0 }, + { EfiBootServicesCode, 0x2000 }, + { EfiBootServicesData, 0xA000 }, + { EfiConventionalMemory, 0x0 }, + { EfiUnusableMemory, 0 }, + { EfiMaxMemoryType, 0 } +}; + +/** + + This function returns the memory ranges to be enabled, along with information + describing how the range should be used. + + @param PeiServices PEI Services Table. + @param MemoryMap Buffer to record details of the memory ranges tobe enabled. + @param NumRanges On input, this contains the maximum number of memory ranges that can be described + in the MemoryMap buffer. + + @retval MemoryMap The buffer will be filled in + @retval NumRanges will contain the actual number of memory ranges that are to be anabled. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetMemoryMap ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ) +{ + EFI_PHYSICAL_ADDRESS MemorySize; + EFI_PHYSICAL_ADDRESS RowLength; + PEI_MEMORY_RANGE_SMRAM SmramMask; + PEI_MEMORY_RANGE_SMRAM TsegMask; + UINT32 BlockNum; + UINT8 ExtendedMemoryIndex; + UINT8 Index; + UINT64 SmRamTsegBase; + UINT64 SmRamTsegLength; + UINT64 SmRamTsegMask; + UINT64 LowMemoryLength; + PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE TemMemoryMap[MAX_RANGES]; + UINT8 TemNumRanges; + + if ((*NumRanges) < MAX_RANGES) { + return EFI_BUFFER_TOO_SMALL; + } + + // + // Get the Memory Map + // + TemNumRanges = MAX_RANGES; + LowMemoryLength = 0; + *NumRanges = 0; + ZeroMem (TemMemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * MAX_RANGES); + + GetAvailableMemoryRanges (TemMemoryMap, &TemNumRanges); + + for (Index = 0; Index < TemNumRanges; Index++) { + if (TemMemoryMap[Index].CpuAddress < SIZE_4GB) { + LowMemoryLength += TemMemoryMap[Index].RangeLength; + } else { + // + // Memory Map information Upper than 4G + // + MemoryMap[*NumRanges].PhysicalAddress = TemMemoryMap[Index].PhysicalAddress; + MemoryMap[*NumRanges].CpuAddress = TemMemoryMap[Index].CpuAddress; + MemoryMap[*NumRanges].RangeLength = TemMemoryMap[Index].RangeLength; + MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory; + (*NumRanges)++; + } + } + + TemNumRanges = MAX_RANGES; + ZeroMem (TemMemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * MAX_RANGES); + + GetReservedMemoryRanges (TemMemoryMap, &TemNumRanges); + for (Index = 0; Index < TemNumRanges; Index++) { + MemoryMap[*NumRanges].PhysicalAddress = TemMemoryMap[Index].PhysicalAddress; + MemoryMap[*NumRanges].CpuAddress = TemMemoryMap[Index].CpuAddress; + MemoryMap[*NumRanges].RangeLength = TemMemoryMap[Index].RangeLength; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + (*NumRanges)++; + } + + // + // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks + // + SmramMask = PEI_MR_SMRAM_ABSEG_128K_NOCACHE | PEI_MR_SMRAM_TSEG_4096K_CACHE; + + // + // Generate Memory ranges for the memory map. + // + MemorySize = 0; + + RowLength = LowMemoryLength; + + // + // Add memory below 640KB to the memory map. Make sure memory between + // 640KB and 1MB are reserved, even if not used for SMRAM + // + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[*NumRanges].RangeLength = 0xA0000; + MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory; + (*NumRanges)++; + + // Reserve ABSEG or HSEG SMRAM if needed + // + if (SmramMask & (PEI_MR_SMRAM_ABSEG_MASK | PEI_MR_SMRAM_HSEG_MASK)) { + MemoryMap[*NumRanges].PhysicalAddress = MC_ABSEG_HSEG_PHYSICAL_START; + MemoryMap[*NumRanges].RangeLength = MC_ABSEG_HSEG_LENGTH; + MemoryMap[*NumRanges].CpuAddress = (SmramMask & PEI_MR_SMRAM_ABSEG_MASK) ? + MC_ABSEG_CPU_START : MC_HSEG_CPU_START; + // + // Chipset only supports cacheable SMRAM + // + MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable; + } else { + // + // Just mark this range reserved + // + MemoryMap[*NumRanges].PhysicalAddress = 0xA0000; + MemoryMap[*NumRanges].CpuAddress = 0xA0000; + MemoryMap[*NumRanges].RangeLength = 0x60000; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + } + + (*NumRanges)++; + + RowLength -= (0x100000 - MemorySize); + MemorySize = 0x100000; + + // + // Add remaining memory to the memory map + // + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[*NumRanges].RangeLength = RowLength; + MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory; + (*NumRanges)++; + MemorySize += RowLength; + + ExtendedMemoryIndex = (UINT8)(*NumRanges - 1); + + // See if we need to trim TSEG out of the highest memory range + // + if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) { + // pcd + // + // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range + // + TsegMask = (SmramMask & PEI_MR_SMRAM_SIZE_MASK); + + BlockNum = 1; + while (TsegMask) { + TsegMask >>= 1; + BlockNum <<= 1; + } + + BlockNum >>= 1; + + if (BlockNum) { + SmRamTsegBase = MemorySize; + SmRamTsegLength = (UINT64)(BlockNum * 128 * 1024); + MemoryMap[*NumRanges].RangeLength = SmRamTsegLength; + MemorySize -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength; + + // + // Turn On Smram + // + SmRamTsegMask = (0x0000010000000000L-SmRamTsegLength) & 0xFFFFFFFE0000UL; // TSegMask[47:17] + SmRamTsegMask |= 0x4403; // enable both ASeg and TSeg, and both address range memory type set to write through + AsmWriteMsr64 (0xC0010112, SmRamTsegBase); + AsmWriteMsr64 (0xC0010113, SmRamTsegMask); // enable + } + + // + // Chipset only supports non-cacheable SMRAM + // + MemoryMap[*NumRanges].Type = DualChannelDdrSmramNonCacheable; + + (*NumRanges)++; + } + + return EFI_SUCCESS; +} + +/** + + This function installs memory. + + @param PeiServices PEI Services table. + @param BootMode The specific boot path that is being followed + @param Mch Pointer to the DualChannelDdrMemoryInit PPI + @param RowConfArray Row configuration information for each row in the system. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED An error occurred. + +**/ +EFI_STATUS +InstallEfiMemory ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress; + EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock; + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES]; + UINT8 Index; + UINT8 NumRanges; + UINT8 SmramIndex; + UINT8 SmramRanges; + UINT64 PeiMemoryLength; + UINTN BufferSize; + UINTN PeiMemoryIndex; + EFI_RESOURCE_ATTRIBUTE_TYPE Attribute; + EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable; + VOID *CapsuleBuffer; + UINTN CapsuleBufferLength; + EFI_PEI_CAPSULE_PPI *Capsule; + VOID *LargeMemRangeBuf; + UINTN LargeMemRangeBufLen; + + // + // Get the Memory Map + // + NumRanges = MAX_RANGES; + + ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges); + + Status = GetMemoryMap ( + PeiServices, + (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *)MemoryMap, + &NumRanges + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "NumRanges: %d\n", NumRanges)); + + DEBUG ((EFI_D_INFO, "GetMemoryMap:\n")); + for (Index = 0; Index < NumRanges; Index++) { + DEBUG ((EFI_D_INFO, "Index: %d ", Index)); + DEBUG ((EFI_D_INFO, "RangeLength: 0x%016lX\t", MemoryMap[Index].RangeLength)); + DEBUG ((EFI_D_INFO, "PhysicalAddress: 0x%016lX\t", MemoryMap[Index].PhysicalAddress)); + DEBUG ((EFI_D_INFO, "CpuAddress: 0x%016lX\t", MemoryMap[Index].CpuAddress)); + DEBUG ((EFI_D_INFO, "Type: %d\n", MemoryMap[Index].Type)); + } + + // + // Find the highest memory range in processor native address space to give to + // PEI. Then take the top. + // + PeiMemoryBaseAddress = 0; + + // + // Query the platform for the minimum memory size + // + + Status = GetPlatformMemorySize ( + PeiServices, + BootMode, + &PeiMemoryLength + ); + ASSERT_EFI_ERROR (Status); + PeiMemoryLength = (PeiMemoryLength > PEI_MIN_MEMORY_SIZE) ? PeiMemoryLength : PEI_MIN_MEMORY_SIZE; + // + + PeiMemoryIndex = 0; + + for (Index = 0; Index < NumRanges; Index++) { + DEBUG ((EFI_D_INFO, "Found 0x%lx bytes at ", MemoryMap[Index].RangeLength)); + DEBUG ((EFI_D_INFO, "0x%lx.\t", MemoryMap[Index].PhysicalAddress)); + DEBUG ((EFI_D_INFO, "Type: %d.\n", MemoryMap[Index].Type)); + + if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) && + (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS) && + (MemoryMap[Index].PhysicalAddress >= PeiMemoryBaseAddress) && + (MemoryMap[Index].RangeLength >= PeiMemoryLength)) + { + PeiMemoryBaseAddress = MemoryMap[Index].PhysicalAddress + + MemoryMap[Index].RangeLength - + PeiMemoryLength; + PeiMemoryIndex = Index; + } + } + + // + // Find the largest memory range excluding that given to PEI. + // + LargeMemRangeBuf = NULL; + LargeMemRangeBufLen = 0; + for (Index = 0; Index < NumRanges; Index++) { + if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) && + (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS)) + { + if (Index != PeiMemoryIndex) { + if (MemoryMap[Index].RangeLength > LargeMemRangeBufLen) { + LargeMemRangeBuf = (VOID *)((UINTN)MemoryMap[Index].PhysicalAddress); + LargeMemRangeBufLen = (UINTN)MemoryMap[Index].RangeLength; + } + } else { + if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= LargeMemRangeBufLen) { + LargeMemRangeBuf = (VOID *)((UINTN)MemoryMap[Index].PhysicalAddress); + LargeMemRangeBufLen = (UINTN)(MemoryMap[Index].RangeLength - PeiMemoryLength); + } + } + } + } + + Capsule = NULL; + CapsuleBuffer = NULL; + CapsuleBufferLength = 0; + if (BootMode == BOOT_ON_FLASH_UPDATE) { + Status = PeiServicesLocatePpi ( + &gEfiPeiCapsulePpiGuid, // GUID + 0, // INSTANCE + NULL, // EFI_PEI_PPI_DESCRIPTOR + (VOID **)&Capsule // PPI + ); + ASSERT_EFI_ERROR (Status); + + if (Status == EFI_SUCCESS) { + CapsuleBuffer = LargeMemRangeBuf; + CapsuleBufferLength = LargeMemRangeBufLen; + DEBUG ((EFI_D_INFO, "CapsuleBuffer: %x, CapsuleBufferLength: %x\n", CapsuleBuffer, CapsuleBufferLength)); + + // + // Call the Capsule PPI Coalesce function to coalesce the capsule data. + // + Status = Capsule->Coalesce ( + PeiServices, + &CapsuleBuffer, + &CapsuleBufferLength + ); + // + // If it failed, then NULL out our capsule PPI pointer so that the capsule + // HOB does not get created below. + // + if (Status != EFI_SUCCESS) { + Capsule = NULL; + } + } + } + + // + // Carve out the top memory reserved for PEI + // + Status = PeiServicesInstallPeiMemory (PeiMemoryBaseAddress, PeiMemoryLength); + ASSERT_EFI_ERROR (Status); + + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + PeiMemoryBaseAddress, // MemoryBegin + PeiMemoryLength // MemoryLength + ); + + // Report first 640KB of system memory + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + (EFI_PHYSICAL_ADDRESS)(0), + (UINT64)(0xA0000) + ); + + // + // Install physical memory descriptor hobs for each memory range. + // + SmramRanges = 0; + for (Index = 0; Index < NumRanges; Index++) { + Attribute = 0; + if (MemoryMap[Index].Type == DualChannelDdrMainMemory) { + if (Index == PeiMemoryIndex) { + // + // This is a partially tested Main Memory range, give it to EFI + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + MemoryMap[Index].PhysicalAddress, + MemoryMap[Index].RangeLength - PeiMemoryLength + ); + } else { + // + // This is an untested Main Memory range, give it to EFI + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + MemoryMap[Index].PhysicalAddress, // MemoryBegin + MemoryMap[Index].RangeLength // MemoryLength + ); + } + } else { + // + // Only report TSEG range to align AcpiVariableHobOnSmramReserveHobThunk + // + if ((MemoryMap[Index].PhysicalAddress > 0x100000) && + ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable))) + { + SmramRanges++; + } + + // + // AMD CPU has different flow to SMM and normal mode cache attribute. + // SmmIPL will set TSEG and HSEG as UC when exit SMM. + // the Attribute only support 0 then it will fail to set them to UC + // otherwise the SmmIPL will hang at set memory attribute. + // + if (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable) { + Attribute |= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE; + } + + if (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryCacheable) { + Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE; + } + + if (MemoryMap[Index].Type == DualChannelDdrReservedMemory) { + Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE; + } + + // + // Make sure non-system memory is marked as reserved + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_MEMORY_RESERVED, // MemoryType, + Attribute, // MemoryAttribute + MemoryMap[Index].PhysicalAddress, // MemoryBegin + MemoryMap[Index].RangeLength // MemoryLength + ); + } + } + + // + // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer + // to the SMM Services Table that is required on the S3 resume path + // + ASSERT (SmramRanges > 0); + BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK); + if (SmramRanges > 0) { + BufferSize += ((SmramRanges) * sizeof (EFI_SMRAM_DESCRIPTOR)); + } + + Hob.Raw = BuildGuidHob ( + &gEfiSmmPeiSmramMemoryReserveGuid, + BufferSize + ); + ASSERT (Hob.Raw); + + SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)(Hob.Raw); + SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges + 1; + + SmramIndex = 0; + for (Index = 0; Index < NumRanges; Index++) { + if ((MemoryMap[Index].PhysicalAddress > 0x100000) && + ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable))) + { + // + // This is an SMRAM range, create an SMRAM descriptor + // + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress; + SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress; + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength; + if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) { + SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE; + } else { + SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED; + } + + if ( SmramIndex == SmramRanges - 1) { + // + // one extra EFI_SMRAM_DESCRIPTOR for a page of SMRAM memory + // + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = EFI_PAGE_SIZE; + SmramIndex++; + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress + EFI_PAGE_SIZE; + SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress + EFI_PAGE_SIZE; + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength - EFI_PAGE_SIZE; + SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = SmramHobDescriptorBlock->Descriptor[SmramIndex-1].RegionState; + SmramHobDescriptorBlock->Descriptor[SmramIndex-1].RegionState |= EFI_ALLOCATED; + } + + SmramIndex++; + } + } + + // + // Build a HOB with the location of the reserved memory range. + // + CopyMem (&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof (EFI_SMRAM_DESCRIPTOR)); + DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET; + DEBUG ((EFI_D_INFO, "gEfiAcpiVariableGuid CpuStart: 0x%X\n", (UINTN)DescriptorAcpiVariable.CpuStart)); + BuildGuidDataHob ( + &gEfiAcpiVariableGuid, + &DescriptorAcpiVariable, + sizeof (EFI_SMRAM_DESCRIPTOR) + ); + + // + // If we found the capsule PPI (and we didn't have errors), then + // call the capsule PEIM to allocate memory for the capsule. + // + if (Capsule != NULL) { + Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength); + } + + return EFI_SUCCESS; +} + +/** + + Find memory that is reserved so PEI has some to use. + + @param PeiServices PEI Services table. + @param VariableSevices Variable PPI instance. + + @retval EFI_SUCCESS The function completed successfully. + Error value from LocatePpi() + +**/ +EFI_STATUS +InstallS3Memory ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_STATUS Status; + UINTN S3MemoryBase; + UINTN S3MemorySize; + UINT8 SmramRanges; + UINT8 NumRanges; + UINT8 Index; + UINT8 SmramIndex; + UINTN BufferSize; + EFI_PEI_HOB_POINTERS Hob; + EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock; + PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES]; + RESERVED_ACPI_S3_RANGE *S3MemoryRangeData; + EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable; + + // + // Get the Memory Map + // + NumRanges = MAX_RANGES; + + ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges); + + Status = GetMemoryMap ( + PeiServices, + (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *)MemoryMap, + &NumRanges + ); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "NumRanges = 0x%x\n", NumRanges)); + + // + // Install physical memory descriptor hobs for each memory range. + // + SmramRanges = 0; + DEBUG ((EFI_D_INFO, "GetMemoryMap:\n")); + for (Index = 0; Index < NumRanges; Index++) { + DEBUG ((EFI_D_INFO, "Index: %d ", Index)); + DEBUG ((EFI_D_INFO, "RangeLength: 0x%016lX\t", MemoryMap[Index].RangeLength)); + DEBUG ((EFI_D_INFO, "PhysicalAddress: 0x%016lX\t", MemoryMap[Index].PhysicalAddress)); + DEBUG ((EFI_D_INFO, "CpuAddress: 0x%016lX\t", MemoryMap[Index].CpuAddress)); + DEBUG ((EFI_D_INFO, "Type: %d\n", MemoryMap[Index].Type)); + if ((MemoryMap[Index].PhysicalAddress > 0x100000) && + ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable))) + { + SmramRanges++; + } + } + + ASSERT (SmramRanges > 0); + DEBUG ((EFI_D_INFO, "SmramRanges = 0x%x\n", SmramRanges)); + + // + // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer + // to the SMM Services Table that is required on the S3 resume path + // + BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK); + if (SmramRanges > 0) { + BufferSize += ((SmramRanges) * sizeof (EFI_SMRAM_DESCRIPTOR)); + } + + DEBUG ((EFI_D_INFO, "BufferSize = 0x%x\n", BufferSize)); + + Hob.Raw = BuildGuidHob ( + &gEfiSmmPeiSmramMemoryReserveGuid, + BufferSize + ); + ASSERT (Hob.Raw); + DEBUG ((EFI_D_INFO, "gEfiSmmPeiSmramMemoryReserveGuid/SmramHobDescriptorBlock: 0x%X \n", (UINTN)Hob.Raw)); + + SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)(Hob.Raw); + SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges + 1; + + SmramIndex = 0; + for (Index = 0; Index < NumRanges; Index++) { + DEBUG ((EFI_D_INFO, "Index: 0x%X \t", Index)); + DEBUG ((EFI_D_INFO, "SmramIndex: 0x%X \n", SmramIndex)); + if ((MemoryMap[Index].PhysicalAddress > 0x100000) && + ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) + ) + { + // + // This is an SMRAM range, create an SMRAM descriptor + // + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress; + SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress; + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength; + if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) { + SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE; + } else { + SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED; + } + + DEBUG ((EFI_D_INFO, "SmramIndex: 0x%X \n", SmramIndex)); + DEBUG ((EFI_D_INFO, "PhysicalStart: 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart)); + DEBUG ((EFI_D_INFO, "CpuStart : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart)); + DEBUG ((EFI_D_INFO, "PhysicalSize : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize)); + DEBUG ((EFI_D_INFO, "RegionState : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState)); + if ( SmramIndex == SmramRanges - 1) { + // + // one extra EFI_SMRAM_DESCRIPTOR for a page of SMRAM memory + // + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = EFI_PAGE_SIZE; + SmramIndex++; + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress + EFI_PAGE_SIZE; + SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress + EFI_PAGE_SIZE; + SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength - EFI_PAGE_SIZE; + SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = SmramHobDescriptorBlock->Descriptor[SmramIndex-1].RegionState; + SmramHobDescriptorBlock->Descriptor[SmramIndex-1].RegionState |= EFI_ALLOCATED; + DEBUG ((EFI_D_INFO, "SmramIndex: 0x%X \n", SmramIndex)); + DEBUG ((EFI_D_INFO, "PhysicalStart: 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart)); + DEBUG ((EFI_D_INFO, "CpuStart : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart)); + DEBUG ((EFI_D_INFO, "PhysicalSize : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize)); + DEBUG ((EFI_D_INFO, "RegionState : 0x%X\n\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState)); + + DEBUG ((EFI_D_INFO, "PhysicalSize : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex-1].PhysicalSize)); + DEBUG ((EFI_D_INFO, "RegionState : 0x%X\n", (UINTN)SmramHobDescriptorBlock->Descriptor[SmramIndex-1].RegionState)); + } + + SmramIndex++; + } + } + + // + // Build a HOB with the location of the reserved memory range. + // + CopyMem (&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof (EFI_SMRAM_DESCRIPTOR)); + DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET; + DEBUG ((EFI_D_INFO, "gEfiAcpiVariableGuid CpuStart: 0x%X\n", (UINTN)DescriptorAcpiVariable.CpuStart)); + BuildGuidDataHob ( + &gEfiAcpiVariableGuid, + &DescriptorAcpiVariable, + sizeof (EFI_SMRAM_DESCRIPTOR) + ); + + // + // Get the location and size of the S3 memory range in the reserved page and + // install it as PEI Memory. + // + + DEBUG ((EFI_D_INFO, "TSEG Base = 0x%08x\n", SmramHobDescriptorBlock->Descriptor[SmramRanges].PhysicalStart)); + DEBUG ((EFI_D_INFO, "SmramRanges = 0x%x\n", SmramRanges)); + S3MemoryRangeData = (RESERVED_ACPI_S3_RANGE *)(UINTN) + (SmramHobDescriptorBlock->Descriptor[SmramRanges].PhysicalStart + RESERVED_ACPI_S3_RANGE_OFFSET); + DEBUG ((EFI_D_INFO, "S3MemoryRangeData = 0x%08x\n", (UINTN)S3MemoryRangeData)); + + DEBUG ((EFI_D_INFO, "S3MemoryRangeData->AcpiReservedMemoryBase = 0x%X\n", (UINTN)S3MemoryRangeData->AcpiReservedMemoryBase)); + DEBUG ((EFI_D_INFO, "S3MemoryRangeData->AcpiReservedMemorySize = 0x%X\n", (UINTN)S3MemoryRangeData->AcpiReservedMemorySize)); + DEBUG ((EFI_D_INFO, "S3MemoryRangeData->SystemMemoryLength = 0x%X\n", (UINTN)S3MemoryRangeData->SystemMemoryLength)); + + S3MemoryBase = (UINTN)(S3MemoryRangeData->AcpiReservedMemoryBase); + DEBUG ((EFI_D_INFO, "S3MemoryBase = 0x%08x\n", S3MemoryBase)); + S3MemorySize = (UINTN)(S3MemoryRangeData->AcpiReservedMemorySize); + DEBUG ((EFI_D_INFO, "S3MemorySize = 0x%08x\n", S3MemorySize)); + + Status = PeiServicesInstallPeiMemory (S3MemoryBase, S3MemorySize); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve the system memory length and build memory hob for the system + // memory above 1MB. So Memory Callback can set cache for the system memory + // correctly on S3 boot path, just like it does on Normal boot path. + // + ASSERT ((S3MemoryRangeData->SystemMemoryLength - 0x100000) > 0); + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + 0x100000, + S3MemoryRangeData->SystemMemoryLength - 0x100000 + ); + + DEBUG ((EFI_D_INFO, "MemoryBegin: 0x%lX, MemoryLength: 0x%lX\n", 0x100000, S3MemoryRangeData->SystemMemoryLength - 0x100000)); + + for (Index = 0; Index < NumRanges; Index++) { + if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) && + (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < 0x100000)) + { + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + MemoryMap[Index].PhysicalAddress, + MemoryMap[Index].RangeLength + ); + DEBUG ((EFI_D_INFO, "MemoryBegin: 0x%lX, MemoryLength: 0x%lX\n", MemoryMap[Index].PhysicalAddress, MemoryMap[Index].RangeLength)); + + DEBUG ((EFI_D_INFO, "Build resource HOB for Legacy Region on S3 patch :")); + DEBUG ((EFI_D_INFO, " Memory Base:0x%lX Length:0x%lX\n", MemoryMap[Index].PhysicalAddress, MemoryMap[Index].RangeLength)); + } + } + + return EFI_SUCCESS; +} + +/** + + This function Get Platform Memory Size. + + @param PeiServices PEI Services table. + @param BootMode The specific boot path that is being followed + @param MemorySize Size of Memory used by Platform + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetPlatformMemorySize ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode, + IN OUT UINT64 *MemorySize + ) +{ + EFI_STATUS Status; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; + UINTN DataSize; + EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1]; + UINTN Index; + + DataSize = sizeof (MemoryData); + + if (BootMode == BOOT_IN_RECOVERY_MODE) { + // + // // Treat recovery as if variable not found (eg 1st boot). + // + Status = EFI_NOT_FOUND; + } else { + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **)&Variable + ); + + ASSERT_EFI_ERROR (Status); + + DataSize = sizeof (MemoryData); + Status = Variable->GetVariable ( + Variable, + EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, + &gEfiMemoryTypeInformationGuid, + NULL, + &DataSize, + &MemoryData + ); + } + + // + // Accumulate maximum amount of memory needed + // + if (EFI_ERROR (Status)) { + // + // Start with minimum memory + // + *MemorySize = PEI_MIN_MEMORY_SIZE; + + for (Index = 0; Index < sizeof (mDefaultMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) { + *MemorySize += mDefaultMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE; + } + + // + // Build the GUID'd HOB for DXE + // + BuildGuidDataHob ( + &gEfiMemoryTypeInformationGuid, + mDefaultMemoryTypeInformation, + sizeof (mDefaultMemoryTypeInformation) + ); + } else { + // + // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack + // + + *MemorySize = PEI_MIN_MEMORY_SIZE; + for (Index = 0; Index < DataSize / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) { + DEBUG ((EFI_D_INFO, "Index %d, Page: %d\n", Index, MemoryData[Index].NumberOfPages)); + *MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE; + } + + // + // Build the GUID'd HOB for DXE + // + BuildGuidDataHob ( + &gEfiMemoryTypeInformationGuid, + MemoryData, + DataSize + ); + } + + DEBUG ((EFI_D_INFO, "GetPlatformMemorySize, MemorySize: 0x%lX\n", *MemorySize)); + return EFI_SUCCESS; +} + +/** + + Callback function after Memory Info Hob Installed. + + @param PeiServices PEI Services table. + @param NotifyDescriptor Notify Descriptor. + @param Ppi Ppi + + @retval EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +MemoryInfoHobPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + + // + // Get boot mode + // + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + if (BootMode == BOOT_ON_S3_RESUME) { + DEBUG ((EFI_D_INFO, "Following BOOT_ON_S3_RESUME boot path.\n")); + + Status = InstallS3Memory (PeiServices, BootMode); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + PeiServicesResetSystem (); + } + + return EFI_SUCCESS; + } + + Status = InstallEfiMemory (PeiServices, BootMode); + return Status; +} diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.h b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.h new file mode 100644 index 0000000000..a9a24677ad --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryInstall.h @@ -0,0 +1,229 @@ +/** @file + Implements MemoryInstall.h + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file +Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller. + +Copyright (c) 2013 - 2016 Intel Corporation. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _MRC_WRAPPER_H +#define _MRC_WRAPPER_H + +// +// Maximum number of memory ranges supported by the memory controller +// +#define MAX_RANGES (4 + 5) + +// +// Min. of 48MB PEI phase +// +#define PEI_MIN_MEMORY_SIZE (8 * 0x800000) +#define PEI_RECOVERY_MIN_MEMORY_SIZE (8 * 0x800000) + +// +// SMRAM Memory Range +// +#define PEI_MEMORY_RANGE_SMRAM UINT32 +#define PEI_MR_SMRAM_ALL 0xFFFFFFFF +#define PEI_MR_SMRAM_NONE 0x00000000 +#define PEI_MR_SMRAM_CACHEABLE_MASK 0x80000000 +#define PEI_MR_SMRAM_SEGTYPE_MASK 0x00FF0000 +#define PEI_MR_SMRAM_ABSEG_MASK 0x00010000 +#define PEI_MR_SMRAM_HSEG_MASK 0x00020000 +#define PEI_MR_SMRAM_TSEG_MASK 0x00040000 + +// +// SMRAM range definitions +// +#define MC_ABSEG_HSEG_PHYSICAL_START 0x000A0000 +#define MC_ABSEG_HSEG_LENGTH 0x00020000 +#define MC_ABSEG_CPU_START 0x000A0000 +#define MC_HSEG_CPU_START 0xFEDA0000 + +// +// If adding additional entries, SMRAM Size +// is a multiple of 128KB. +// +#define PEI_MR_SMRAM_SIZE_MASK 0x0000FFFF +#define PEI_MR_SMRAM_SIZE_128K_MASK 0x00000001 +#define PEI_MR_SMRAM_SIZE_256K_MASK 0x00000002 +#define PEI_MR_SMRAM_SIZE_512K_MASK 0x00000004 +#define PEI_MR_SMRAM_SIZE_1024K_MASK 0x00000008 +#define PEI_MR_SMRAM_SIZE_2048K_MASK 0x00000010 +#define PEI_MR_SMRAM_SIZE_4096K_MASK 0x00000020 +#define PEI_MR_SMRAM_SIZE_8192K_MASK 0x00000040 + +#define PEI_MR_SMRAM_ABSEG_128K_NOCACHE 0x00010001 +#define PEI_MR_SMRAM_HSEG_128K_CACHE 0x80020001 +#define PEI_MR_SMRAM_HSEG_128K_NOCACHE 0x00020001 +#define PEI_MR_SMRAM_TSEG_128K_CACHE 0x80040001 +#define PEI_MR_SMRAM_TSEG_128K_NOCACHE 0x00040001 +#define PEI_MR_SMRAM_TSEG_256K_CACHE 0x80040002 +#define PEI_MR_SMRAM_TSEG_256K_NOCACHE 0x00040002 +#define PEI_MR_SMRAM_TSEG_512K_CACHE 0x80040004 +#define PEI_MR_SMRAM_TSEG_512K_NOCACHE 0x00040004 +#define PEI_MR_SMRAM_TSEG_1024K_CACHE 0x80040008 +#define PEI_MR_SMRAM_TSEG_1024K_NOCACHE 0x00040008 +#define PEI_MR_SMRAM_TSEG_2048K_CACHE 0x80040010 +#define PEI_MR_SMRAM_TSEG_2048K_NOCACHE 0x00040010 +#define PEI_MR_SMRAM_TSEG_4096K_CACHE 0x80040020 +#define PEI_MR_SMRAM_TSEG_4096K_NOCACHE 0x00040020 +#define PEI_MR_SMRAM_TSEG_8192K_CACHE 0x80040040 +#define PEI_MR_SMRAM_TSEG_8192K_NOCACHE 0x00040040 + +// +// Pci Memory Hole +// +#define PEI_MEMORY_RANGE_PCI_MEMORY UINT32 + +typedef enum { + Ignore, + Quick, + Sparse, + Extensive +} PEI_MEMORY_TEST_OP; + +// Memory range types +// +typedef enum { + DualChannelDdrMainMemory, + DualChannelDdrSmramCacheable, + DualChannelDdrSmramNonCacheable, + DualChannelDdrGraphicsMemoryCacheable, + DualChannelDdrGraphicsMemoryNonCacheable, + DualChannelDdrReservedMemory, + DualChannelDdrMaxMemoryRangeType +} PEI_DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE; + +// +// Memory map range information +// +typedef struct { + EFI_PHYSICAL_ADDRESS PhysicalAddress; + EFI_PHYSICAL_ADDRESS CpuAddress; + EFI_PHYSICAL_ADDRESS RangeLength; + PEI_DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE Type; +} PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE; + +// +// This structure stores the base and size of the ACPI reserved memory used when +// resuming from S3. This region must be allocated by the platform code. +// +typedef struct { + UINT32 AcpiReservedMemoryBase; + UINT32 AcpiReservedMemorySize; + UINT32 SystemMemoryLength; +} RESERVED_ACPI_S3_RANGE; + +#define RESERVED_ACPI_S3_RANGE_OFFSET (EFI_PAGE_SIZE - sizeof (RESERVED_ACPI_S3_RANGE)) + +// +// ------------------------ TSEG Base +// +// ------------------------ RESERVED_CPU_S3_SAVE_OFFSET +// CPU S3 data +// ------------------------ RESERVED_ACPI_S3_RANGE_OFFSET +// S3 Memory base structure +// ------------------------ TSEG + 1 page + +#define RESERVED_CPU_S3_SAVE_OFFSET (RESERVED_ACPI_S3_RANGE_OFFSET - sizeof (SMM_S3_RESUME_STATE)) + +// +// Function prototypes. +// + +/** + + This function installs memory. + + @param PeiServices PEI Services table. + @param BootMode The specific boot path that is being followed + @param Mch Pointer to the DualChannelDdrMemoryInit PPI + @param RowConfArray Row configuration information for each row in the system. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED An error occurred. + +**/ +EFI_STATUS +InstallEfiMemory ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode + ); + +/** + + Find memory that is reserved so PEI has some to use. + + @param PeiServices PEI Services table. + @param VariableSevices Variable PPI instance. + + @retval EFI_SUCCESS The function completed successfully. + Error value from LocatePpi() + +**/ +EFI_STATUS +InstallS3Memory ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode + ); + +/** + + This function returns the memory ranges to be enabled, along with information + describing how the range should be used. + + @param PeiServices PEI Services Table. + @param MemoryMap Buffer to record details of the memory ranges tobe enabled. + @param NumRanges On input, this contains the maximum number of memory ranges that can be described + in the MemoryMap buffer. + + @retval MemoryMap The buffer will be filled in + @retval NumRanges will contain the actual number of memory ranges that are to be anabled. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetMemoryMap ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ); + +/** + + This function Get Platform Memory Size. + + @param PeiServices PEI Services table. + @param BootMode The specific boot path that is being followed + @param MemorySize Size of Memory used by Platform + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetPlatformMemorySize ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE BootMode, + IN OUT UINT64 *MemorySize + ); + +#endif diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryPeim.c b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryPeim.c new file mode 100644 index 0000000000..5f6aefa9b1 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/MemoryPeim.c @@ -0,0 +1,385 @@ +/** @file + Implements MemoryPeim.C + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file + + Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> + + + This program and the accompanying materials are licensed and made available under + + the terms and conditions of the BSD License that accompanies this distribution. + + The full text of the license may be found at + + http://opensource.org/licenses/bsd-license.php. + + + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + + + +Module Name: + + + MemoryPeim.c + +Abstract: + + Tiano PEIM to provide the platform support functionality. + This file implements the Platform Memory Range PPI + +--*/ + +#include "CommonHeader.h" + +#define MTRR_LIB_CACHE_MTRR_ENABLED 0x800 +#define SYS_CFG 0xC0010010ul + +VOID +MtrrLibInitializeMtrrMask ( + OUT UINT64 *MtrrValidBitsMask, + OUT UINT64 *MtrrValidAddressMask + ); + +/** + + This function set different memory range cache attribute. + + @param PeiServices Pointer to the PEI Service Table. + +**/ +EFI_STATUS +EFIAPI +SetPeiCacheMode ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + EFI_BOOT_MODE BootMode; + UINT64 MemoryLength; + UINT64 MemOverflow; + UINT64 MemoryLengthUc; + UINT64 MaxMemoryLength; + UINT64 LowMemoryLength; + UINT64 HighMemoryLength; + UINT8 Index; + MTRR_SETTINGS MtrrSetting; + UINT64 MsrData; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + + MtrrLibInitializeMtrrMask ( + &MtrrValidBitsMask, + &MtrrValidAddressMask + ); + + // + // Variable initialization + // + LowMemoryLength = 0; + HighMemoryLength = 0; + MemoryLengthUc = 0; + + Status = (*PeiServices)->GetBootMode ( + PeiServices, + &BootMode + ); + + // + // Determine memory usage + // + GetMemorySize ( + PeiServices, + &LowMemoryLength, + &HighMemoryLength, + NULL, + NULL + ); + + MaxMemoryLength = LowMemoryLength; + + // + // Round up to nearest 256MB with high memory and 64MB w/o high memory + // + if (HighMemoryLength != 0 ) { + MemOverflow = (LowMemoryLength & 0x0fffffff); + if (MemOverflow != 0) { + MaxMemoryLength = LowMemoryLength + (0x10000000 - MemOverflow); + } + } else { + MemOverflow = (LowMemoryLength & 0x03ffffff); + if (MemOverflow != 0) { + MaxMemoryLength = LowMemoryLength + (0x4000000 - MemOverflow); + } + } + + ZeroMem (&MtrrSetting, sizeof (MTRR_SETTINGS)); + for (Index = 0; Index < 2; Index++) { + MtrrSetting.Fixed.Mtrr[Index] = 0x1E1E1E1E1E1E1E1Eul; + } + + // 0xA0000-0xBFFFF used for ASEG which cache type is controlled by bit 10:8 of SMMMask(MSR 0xC0010113) + for (Index = 3; Index < 11; Index++) { + MtrrSetting.Fixed.Mtrr[Index] = 0x1C1C1C1C1C1C1C1Cul; + } + + // + // Cache the flash area to improve the boot performance in PEI phase + // + Index = 0; + MtrrSetting.Variables.Mtrr[Index].Base = FixedPcdGet32 (PcdFlashAreaBaseAddress) | CacheWriteProtected; + MtrrSetting.Variables.Mtrr[Index].Mask = ((~((UINT64)(FixedPcdGet32 (PcdFlashAreaSize) - 1))) & MtrrValidBitsMask) | MTRR_LIB_CACHE_MTRR_ENABLED; + + Index++; + + MemOverflow = 0; + while (MaxMemoryLength > MemOverflow) { + MtrrSetting.Variables.Mtrr[Index].Base = (MemOverflow & MtrrValidAddressMask) | CacheWriteBack; + MemoryLength = MaxMemoryLength - MemOverflow; + MemoryLength = GetPowerOfTwo64 (MemoryLength); + MtrrSetting.Variables.Mtrr[Index].Mask = ((~(MemoryLength - 1)) & MtrrValidBitsMask) | MTRR_LIB_CACHE_MTRR_ENABLED; + + MemOverflow += MemoryLength; + Index++; + } + + MemoryLength = LowMemoryLength; + + while (MaxMemoryLength != MemoryLength) { + MemoryLengthUc = GetPowerOfTwo64 (MaxMemoryLength - MemoryLength); + + MtrrSetting.Variables.Mtrr[Index].Base = ((MaxMemoryLength - MemoryLengthUc) & MtrrValidAddressMask) | CacheUncacheable; + MtrrSetting.Variables.Mtrr[Index].Mask = ((~(MemoryLengthUc - 1)) & MtrrValidBitsMask) | MTRR_LIB_CACHE_MTRR_ENABLED; + MaxMemoryLength -= MemoryLengthUc; + Index++; + } + + if (HighMemoryLength > 0) { + MsrData = AsmReadMsr64 (SYS_CFG); + MsrData |= BIT22; + AsmWriteMsr64 (SYS_CFG, MsrData); + } + + for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; Index++) { + if (MtrrSetting.Variables.Mtrr[Index].Base == 0) { + break; + } + + DEBUG ((EFI_D_INFO, "Base=%lx, Mask=%lx\n", MtrrSetting.Variables.Mtrr[Index].Base, MtrrSetting.Variables.Mtrr[Index].Mask)); + } + + // + // set FE/E bits for IA32_MTRR_DEF_TYPE + // + MtrrSetting.MtrrDefType |= 3 <<10; + + AsmWriteMsr64 (SYS_CFG, (AsmReadMsr64 (SYS_CFG) | (1 << 19))); + MtrrSetAllMtrrs (&MtrrSetting); + AsmWriteMsr64 (SYS_CFG, (AsmReadMsr64 (SYS_CFG) & (~(1 << 19)))); + // + // Dump MTRR Setting + // + MtrrDebugPrintAllMtrrs (); + (VOID)Status; + return EFI_SUCCESS; +} + +/** + + This function returns the different avaiable memory length. + + @param PeiServices Pointer to the PEI Service Table. + @param LowMemoryLength Avaiable memory length below 4G address. + @param HighMemoryLength Avaiable memory length above 4G address. + @param GraphicMemoryBase Avaiable UMA base address. + @param GraphicMemoryLength Avaiable UMA length. + + @retval LowMemoryLength Avaiable memory length below 4G address. + @retval HighMemoryLength Avaiable memory length above 4G address. + @retval GraphicMemoryBase Avaiable UMA base address. + @retval GraphicMemoryLength Avaiable UMA length. + +**/ +EFI_STATUS +GetMemorySize ( + IN CONST EFI_PEI_SERVICES **PeiServices, + OUT UINT64 *LowMemoryLength, + OUT UINT64 *HighMemoryLength, + OUT UINT64 *GraphicMemoryBase OPTIONAL, + OUT UINT64 *GraphicMemoryLength OPTIONAL + ) +{ + AMD_MEMORY_INFO_HOB *AmdMemoryInfoHob; + AMD_MEMORY_RANGE_DESCRIPTOR *Range; + UINT32 Index; + + if (HighMemoryLength != NULL) { + *HighMemoryLength = 0; + } + + if (LowMemoryLength != NULL) { + *LowMemoryLength = 0x100000; + } + + // Get Pointer to HOB + AmdMemoryInfoHob = GetFirstGuidHob (&gAmdMemoryInfoHobGuid); + ASSERT (AmdMemoryInfoHob != NULL); + // Get HOB Data + AmdMemoryInfoHob = GET_GUID_HOB_DATA (AmdMemoryInfoHob); + if (AmdMemoryInfoHob != NULL) { + for (Index = 0; Index < AmdMemoryInfoHob->NumberOfDescriptor; Index++) { + Range = (AMD_MEMORY_RANGE_DESCRIPTOR *)&AmdMemoryInfoHob->Ranges[Index]; + if (Range->Attribute == AMD_MEMORY_ATTRIBUTE_AVAILABLE) { + if (Range->Base < SIZE_4GB) { + if (LowMemoryLength != NULL) { + *LowMemoryLength = Range->Size; + } + } else if (Range->Base >= SIZE_4GB) { + if (HighMemoryLength != NULL) { + *HighMemoryLength = Range->Size; + } + } + } else if (Range->Attribute == AMD_MEMORY_ATTRIBUTE_UMA) { + if (GraphicMemoryBase != NULL) { + *GraphicMemoryBase = Range->Base; + } + + if (GraphicMemoryLength != NULL) { + *GraphicMemoryLength = Range->Size; + } + } + } + } + + return EFI_SUCCESS; +} + +/** + + This function returns the memory ranges to be enabled, along with information + describing how the range should be used. + + @param MemoryMap Buffer to record details of the memory ranges. + @param NumRanges On input, this contains the maximum number of memory ranges that can be described + in the MemoryMap buffer. + + @retval MemoryMap The buffer will be filled in + @retval NumRanges will contain the actual number of memory ranges that are to be anabled. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetAvailableMemoryRanges ( + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ) +{ + AMD_MEMORY_INFO_HOB *AmdMemoryInfoHob; + AMD_MEMORY_RANGE_DESCRIPTOR *Range; + UINT32 Index; + + DEBUG ((EFI_D_INFO, "GetAvailableMemoryRanges++\n")); + if ((*NumRanges) < MAX_RANGES) { + return EFI_BUFFER_TOO_SMALL; + } + + *NumRanges = 0; + + // Get Pointer to HOB + AmdMemoryInfoHob = GetFirstGuidHob (&gAmdMemoryInfoHobGuid); + ASSERT (AmdMemoryInfoHob != NULL); + // Get HOB Data + AmdMemoryInfoHob = GET_GUID_HOB_DATA (AmdMemoryInfoHob); + if (AmdMemoryInfoHob != NULL) { + for (Index = 0; Index < AmdMemoryInfoHob->NumberOfDescriptor; Index++) { + Range = (AMD_MEMORY_RANGE_DESCRIPTOR *)&AmdMemoryInfoHob->Ranges[Index]; + if (Range->Attribute == AMD_MEMORY_ATTRIBUTE_AVAILABLE) { + MemoryMap[*NumRanges].PhysicalAddress = Range->Base; + MemoryMap[*NumRanges].CpuAddress = Range->Base; + MemoryMap[*NumRanges].RangeLength = Range->Size; + MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory; + (*NumRanges)++; + DEBUG ((EFI_D_INFO, " Base:0x%016lX, Size: 0x%016lX\n", Range->Base, Range->Size)); + } + } + } + + return EFI_SUCCESS; +} + +/** + + This function returns the memory ranges to be reserved, along with information + describing how the range should be used. + + @param MemoryMap Buffer to record details of the memory ranges. + @param NumRanges On input, this contains the maximum number of memory ranges that can be described + in the MemoryMap buffer. + + @retval MemoryMap The buffer will be filled in + @retval NumRanges will contain the actual number of memory ranges that are to be reserved. + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetReservedMemoryRanges ( + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ) +{ + AMD_MEMORY_INFO_HOB *AmdMemoryInfoHob; + AMD_MEMORY_RANGE_DESCRIPTOR *Range; + UINT32 Index; + + DEBUG ((EFI_D_INFO, "GetReservedMemoryRanges\n")); + if ((*NumRanges) < MAX_RANGES) { + return EFI_BUFFER_TOO_SMALL; + } + + *NumRanges = 0; + + // Get Pointer to HOB + AmdMemoryInfoHob = GetFirstGuidHob (&gAmdMemoryInfoHobGuid); + ASSERT (AmdMemoryInfoHob != NULL); + // Get HOB Data + AmdMemoryInfoHob = GET_GUID_HOB_DATA (AmdMemoryInfoHob); + if (AmdMemoryInfoHob != NULL) { + for (Index = 0; Index < AmdMemoryInfoHob->NumberOfDescriptor; Index++) { + Range = (AMD_MEMORY_RANGE_DESCRIPTOR *)&AmdMemoryInfoHob->Ranges[Index]; + if (Range->Base > SIZE_4GB) { + if (Range->Attribute == AMD_MEMORY_ATTRIBUTE_RESERVED) { + MemoryMap[*NumRanges].PhysicalAddress = Range->Base; + MemoryMap[*NumRanges].CpuAddress = Range->Base; + MemoryMap[*NumRanges].RangeLength = Range->Size; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + (*NumRanges)++; + DEBUG ((EFI_D_INFO, " GetReservedMemoryRanges Base:0x%016lX, Size: 0x%016lX\n", Range->Base, Range->Size)); + } + + if (Range->Attribute == AMD_MEMORY_ATTRIBUTE_UMA) { + MemoryMap[*NumRanges].PhysicalAddress = Range->Base; + MemoryMap[*NumRanges].CpuAddress = Range->Base; + MemoryMap[*NumRanges].RangeLength = Range->Size; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + (*NumRanges)++; + DEBUG ((EFI_D_INFO, " GetReservedMemoryRanges Base:0x%016lX, Size: 0x%016lX\n", Range->Base, Range->Size)); + } + } + } + } + + return EFI_SUCCESS; +} diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.c b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.c new file mode 100644 index 0000000000..4ff57dfca1 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.c @@ -0,0 +1,176 @@ +/** @file + Implements Platforminit.C + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file +This PEIM initialize platform for MRC, following action is performed, +1. Initizluize GMCH +2. Detect boot mode +3. Detect video adapter to determine whether we need pre allocated memory +4. Calls MRC to initialize memory and install a PPI notify to do post memory initialization. +This file contains the main entrypoint of the PEIM. + +Copyright (c) 2013 - 2016 Intel Corporation. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CommonHeader.h" +#define PEI_STALL_RESOLUTION 1 + +EFI_PEI_STALL_PPI mStallPpi = { + PEI_STALL_RESOLUTION, + Stall +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiStall[1] = { + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiStallPpiGuid, + &mStallPpi + } +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[1] = { + { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiMasterBootModePpiGuid, + NULL + } +}; + +EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gAmdMemoryInfoHobPpiGuid, + MemoryInfoHobPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiMemoryDiscoveredPpiGuid, + MemoryDiscoveredPpiNotifyCallback + } +}; + +/** + Clear all SMI enable bit in SmiControl0-SmiControl9 register + + @param [in] None + + @retval None +*/ +VOID +ClearAllSmiControlRegisters ( + VOID + ) +{ + UINTN SmiControlOffset; + + for (SmiControlOffset = FCH_SMI_REGA0; SmiControlOffset <= FCH_SMI_REGC4; SmiControlOffset += 4) { + MmioWrite32 (ACPI_MMIO_BASE + SMI_BASE + SmiControlOffset, 0x00); + } +} + +/** + Clear any SMI status or wake status left over from boot. + + @param none + + @retval none +**/ +VOID +EFIAPI +ClearSmiAndWake ( + VOID + ) +{ + UINT16 Pm1Status; + UINT16 PmControl; + UINT16 AcpiBaseAddr; + + AcpiBaseAddr = MmioRead16 (ACPI_MMIO_BASE + PMIO_BASE + FCH_PMIOA_REG60); + + // + // Read the ACPI registers + // + Pm1Status = IoRead16 (AcpiBaseAddr); + PmControl = IoRead16 ((UINT16)(AcpiBaseAddr + R_FCH_ACPI_PM_CONTROL)); + + // + // Clear any SMI or wake state from the boot + // + Pm1Status |= 0xFF; // clear all events + PmControl &= 0xFFFE; // clear Bit0(SciEn) in PmControl + + // + // Write them back + // + IoWrite16 (AcpiBaseAddr, Pm1Status); + IoWrite16 ((UINT16)(AcpiBaseAddr + R_FCH_ACPI_PM_CONTROL), PmControl); +} + +/** + This is the entrypoint of PEIM + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS if it completed successfully. +**/ +EFI_STATUS +EFIAPI +PeiInitPlatform ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiStall[0]); + ASSERT_EFI_ERROR (Status); + + // + // Dtermine boot mode and return boot mode. + // + BootMode = 0; + Status = UpdateBootMode (PeiServices, &BootMode); + ASSERT_EFI_ERROR (Status); + + // + // Install Boot mode ppi. + // + if (!EFI_ERROR (Status)) { + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiBootMode[0]); + ASSERT_EFI_ERROR (Status); + } + + if ((BootMode != BOOT_ON_S3_RESUME)) { + // + // Clear all pending SMI. On S3 clear power button enable so it wll not generate an SMI + // + ClearSmiAndWake (); + ClearAllSmiControlRegisters (); + } + + // + // Notify for memory discovery callback + // + Status = (**PeiServices).NotifyPpi (PeiServices, &mMemoryDiscoveredNotifyList[0]); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.inf b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.inf new file mode 100644 index 0000000000..0941b09de3 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/PlatformInit.inf @@ -0,0 +1,114 @@ +## @file +# Platform Init Module +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +# This file includes code originally published under the following license. +## @file +# This is the Platform PEIM to initialize whole platform on PEI phase. +# Copyright (c) 2013 - 2016 Intel Corporation. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformInitPei + FILE_GUID = CD33267E-CF9C-40D6-85F6-4A14AF36F739 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeiInitPlatform + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + BootMode.c + MemoryCallback.c + MemoryPeim.c + PlatformInit.c + MemoryInstall.c + Stall.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + ChachaniBoardPkg/Project.dec + VanGoghCommonPkg/AmdCommonPkg.dec + IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dec + AgesaPublic/AgesaPublic.dec + +[LibraryClasses] + PrintLib + PcdLib + ReportStatusCodeLib + IoLib + HobLib + BaseMemoryLib + BaseLib + PeimEntryPoint + DebugLib + MemoryAllocationLib + MtrrLib + PciExpressLib + +[Guids] + gEfiAcpiVariableGuid # ALWAYS_CONSUMED L"AcpiGlobalVariab" + gEfiMemoryTypeInformationGuid # ALWAYS_CONSUMED L"MemoryTypeInformation" + gEfiSmmPeiSmramMemoryReserveGuid # ALWAYS_PRODUCED Hob: GUID_EXTENSION + gAmdMemoryInfoHobGuid + gPlatformChargerPresentGuid + +[Ppis] + gEfiPeiStallPpiGuid + gEfiPeiMasterBootModePpiGuid + gEfiPeiMemoryDiscoveredPpiGuid + gEfiPeiBootInRecoveryModePpiGuid + gAmdMemoryInfoHobPpiGuid + gEfiPeiReadOnlyVariable2PpiGuid + gPeiSmmControlPpiGuid + gPeiPostScriptTablePpiGuid + gEfiEndOfPeiSignalPpiGuid + gEfiPeiCapsulePpiGuid + gAmdCpmTablePpiGuid + gCapsuleUpdateDetectedPpiGuid + +[FeaturePcd] + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + gPcAtChipsetPkgTokenSpaceGuid.PcdIoApicBaseAddress + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress + gPlatformPkgTokenSpaceGuid.PcdFlashAreaBaseAddress + gPlatformPkgTokenSpaceGuid.PcdFlashAreaSize + gPlatformPkgTokenSpaceGuid.PcdMemoryFvRecoveryBase + gAmdCommonPkgTokenSpaceGuid.PcdMemoryFvMainSize + gPlatformPkgTokenSpaceGuid.PcdFlashFvRecoverySize + gPlatformPkgTokenSpaceGuid.PcdFlashFvMainBase + gPlatformPkgTokenSpaceGuid.PcdFlashFvMainSize + gPlatformPkgTokenSpaceGuid.PcdFlashFvMainUnCompressBase + gPlatformPkgTokenSpaceGuid.PcdFlashFvMainUnCompressSize + gEfiAmdAgesaPkgTokenSpaceGuid.PcdFchOemBeforePciRestoreSwSmi + gEfiAmdAgesaPkgTokenSpaceGuid.PcdFchOemAfterPciRestoreSwSmi + gAmdCpmPkgTokenSpaceGuid.AcpiRestoreSwSmi + gPlatformPkgTokenSpaceGuid.PcdBootState + gIntelFsp2WrapperTokenSpaceGuid.PcdFspModeSelection + +[Depex] + TRUE diff --git a/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/Stall.c b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/Stall.c new file mode 100644 index 0000000000..3c7ef4e965 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Universal/PlatformInitPei/Stall.c @@ -0,0 +1,122 @@ +/** @file + Implements Stall.C + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* This file includes code originally published under the following license. */ + +/** @file + + Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> + + + This program and the accompanying materials are licensed and made available under + + the terms and conditions of the BSD License that accompanies this distribution. + + The full text of the license may be found at + + http://opensource.org/licenses/bsd-license.php. + + + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + + + + + +Module Name: + + Stall.c + +Abstract: + + Produce Stall Ppi. + +--*/ +#include <PiPei.h> +#include <Ppi/Stall.h> +#include <Library/IoLib.h> +#include "CommonHeader.h" + +#define B_FCH_ACPI_PM1_TMR_VAL 0xFFFFFF // The timer value mask +#define V_FCH_ACPI_PM1_TMR_MAX_VAL 0x1000000 // The timer is 24 bit overflow + +/** + + Waits for at least the given number of microseconds. + + @param PeiServices General purpose services available to every PEIM. + @param This PPI instance structure. + @param Microseconds Desired length of time to wait. + + @retval EFI_SUCCESS If the desired amount of time was passed. + +*/ +EFI_STATUS +EFIAPI +Stall ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST EFI_PEI_STALL_PPI *This, + IN UINTN Microseconds + ) +{ + UINTN Ticks; + UINTN Counts; + UINT16 AcpiTimerPort; + UINT32 CurrentTick; + UINT32 OriginalTick; + UINT32 RemainingTick; + + if (Microseconds == 0) { + return EFI_SUCCESS; + } + + AcpiTimerPort = MmioRead16 (ACPI_MMIO_BASE + PMIO_BASE + FCH_PMIOA_REG64); + + OriginalTick = IoRead32 (AcpiTimerPort); + OriginalTick &= (V_FCH_ACPI_PM1_TMR_MAX_VAL - 1); + CurrentTick = OriginalTick; + + // + // The timer frequency is 3.579545MHz, so 1 ms corresponds to 3.58 clocks + // + Ticks = Microseconds * 358 / 100 + OriginalTick + 1; + + // + // The loops needed for timer overflow + // + Counts = (UINTN)RShiftU64 ((UINT64)Ticks, 24); + + // + // Remaining clocks within one loop + // + RemainingTick = Ticks & 0xFFFFFF; + + // + // Do not intend to use TMROF_STS bit of register PM1_STS, because this add extra + // one I/O operation, and may generate SMI + // + while (Counts != 0) { + CurrentTick = IoRead32 (AcpiTimerPort) & B_FCH_ACPI_PM1_TMR_VAL; + if (CurrentTick <= OriginalTick) { + Counts--; + } + + OriginalTick = CurrentTick; + } + + while ((RemainingTick > CurrentTick) && (OriginalTick <= CurrentTick)) { + OriginalTick = CurrentTick; + CurrentTick = IoRead32 (AcpiTimerPort) & B_FCH_ACPI_PM1_TMR_VAL; + } + + return EFI_SUCCESS; +} -- 2.31.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114075): https://edk2.groups.io/g/devel/message/114075 Mute This Topic: https://groups.io/mt/103831198/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-