* [edk2-devel] [PATCH 4/5] AmdMinBoardPkg: Implement BoardInitLib for DXE phase
2024-05-17 3:49 [edk2-devel] [PATCH 0/5] AmdMinBoardPkg: AMD board specific modules Abdul Lateef Attar via groups.io
` (2 preceding siblings ...)
2024-05-17 3:49 ` [edk2-devel] [PATCH 3/5] AmdMinBoardPkg: Implement BoardInitLib for PEI phase Abdul Lateef Attar via groups.io
@ 2024-05-17 3:49 ` Abdul Lateef Attar via groups.io
2024-05-17 3:49 ` [edk2-devel] [PATCH 5/5] AmdMinBoardPkg: Implements BoardBdsHookLib library Abdul Lateef Attar via groups.io
2024-05-17 5:53 ` [edk2-devel] [PATCH 0/5] AmdMinBoardPkg: AMD board specific modules Chang, Abner via groups.io
5 siblings, 0 replies; 7+ messages in thread
From: Abdul Lateef Attar via groups.io @ 2024-05-17 3:49 UTC (permalink / raw)
To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes
DxeBoardInitLib library provides board-specific
initialization functions for the DXE phase.
Cc: Abner Chang <abner.chang@amd.com>
Cc: Paul Grimes <paul.grimes@amd.com>
Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@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/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [edk2-devel] [PATCH 5/5] AmdMinBoardPkg: Implements BoardBdsHookLib library
2024-05-17 3:49 [edk2-devel] [PATCH 0/5] AmdMinBoardPkg: AMD board specific modules Abdul Lateef Attar via groups.io
` (3 preceding siblings ...)
2024-05-17 3:49 ` [edk2-devel] [PATCH 4/5] AmdMinBoardPkg: Implement BoardInitLib for DXE phase Abdul Lateef Attar via groups.io
@ 2024-05-17 3:49 ` Abdul Lateef Attar via groups.io
2024-05-17 5:53 ` [edk2-devel] [PATCH 0/5] AmdMinBoardPkg: AMD board specific modules Chang, Abner via groups.io
5 siblings, 0 replies; 7+ messages in thread
From: Abdul Lateef Attar via groups.io @ 2024-05-17 3:49 UTC (permalink / raw)
To: devel; +Cc: Abdul Lateef Attar, Abner Chang, Paul Grimes
Implements BoardBdsHookLib library class for AMD platforms.
Cc: Abner Chang <abner.chang@amd.com>
Cc: Paul Grimes <paul.grimes@amd.com>
Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com>
---
.../AMD/AmdMinBoardPkg/AmdMinBoardPkg.dec | 10 +
.../AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc | 2 +
.../Include/Library/AmdBoardBdsHookLib.h | 130 ++
.../Library/BoardBdsHookLib/BoardBdsHook.h | 242 +++
.../Library/BoardBdsHookLib/BoardBdsHookLib.c | 1712 +++++++++++++++++
.../BoardBdsHookLib/BoardBdsHookLib.inf | 105 +
.../Library/BoardBdsHookLib/BoardBootOption.c | 754 ++++++++
.../Library/BoardBdsHookLib/BoardMemoryTest.c | 83 +
8 files changed, 3038 insertions(+)
create mode 100644 Platform/AMD/AmdMinBoardPkg/Include/Library/AmdBoardBdsHookLib.h
create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHook.h
create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.c
create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.inf
create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBootOption.c
create mode 100644 Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardMemoryTest.c
diff --git a/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dec b/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dec
index 03d1d77c34..47ec5b4b56 100644
--- a/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dec
+++ b/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dec
@@ -17,9 +17,19 @@
PACKAGE_GUID = 44F9D761-9ECB-43DD-A5AC-177E5048701B
PACKAGE_VERSION = 0.1
+[Includes]
+ Include
+
[Guids]
gAmdMinBoardPkgTokenSpaceGuid = {0xd4d23d79, 0x73bf, 0x460a, {0xa1, 0xc7, 0x85, 0xa3, 0xca, 0x71, 0xb9, 0x4c}}
+[LibraryClasses]
+ ## @libraryclass Provide services to platform BDS hook.
+ BoardBdsHookLib|Include/Library/AmdBoardBdsHookLib.h
+
+[Protocols]
+ gAmdBoardBdsBootOptionPriorityProtocolGuid = { 0x5806db97, 0x5303, 0x409f, { 0x8f, 0x09, 0xab, 0x29, 0xd8, 0x07, 0xa3, 0xf1}}
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
#
# PCI HotPlug Resource Padding
diff --git a/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc b/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc
index e0afe1e755..e002e78f21 100644
--- a/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc
+++ b/Platform/AMD/AmdMinBoardPkg/AmdMinBoardPkg.dsc
@@ -41,6 +41,7 @@
BoardInitLib|AmdMinBoardPkg/Library/PeiBoardInitPreMemLib/PeiBoardInitPreMemLib.inf
[LibraryClasses.common.DXE_DRIVER]
+ BoardBdsHookLib|AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.inf
BoardInitLib|AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf
[Components]
@@ -53,4 +54,5 @@
[Components.X64]
AmdMinBoardPkg/Library/DxeBoardInitLib/DxeBoardInitLib.inf
+ AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.inf
AmdMinBoardPkg/PciHotPlug/PciHotPlugInit.inf
\ No newline at end of file
diff --git a/Platform/AMD/AmdMinBoardPkg/Include/Library/AmdBoardBdsHookLib.h b/Platform/AMD/AmdMinBoardPkg/Include/Library/AmdBoardBdsHookLib.h
new file mode 100644
index 0000000000..6bfa4747e0
--- /dev/null
+++ b/Platform/AMD/AmdMinBoardPkg/Include/Library/AmdBoardBdsHookLib.h
@@ -0,0 +1,130 @@
+/** @file
+ Header file for BDS Hook Library
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef AMD_BOARD_BDS_HOOK_LIB_H_
+#define AMD_BOARD_BDS_HOOK_LIB_H_
+
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PlatformBootManagerLib.h>
+#include <Library/SortLib.h>
+
+#define AMD_BOARD_BDS_BOOT_OPTION_PRIORITY_PROTOCOL_GUID \
+ { 0x5806db97, 0x5303, 0x409f, \
+ { 0x8f, 0x09, 0xab, 0x29, 0xd8, 0x07, 0xa3, 0xf1 }}
+
+/*
+ This protocol is introduced so the platform can give certain boot options
+ a custom priority value. Useful in boot overrides, or when IPMI doesn't inherently
+ support a specific boot override needed by the platform.
+*/
+struct _AMD_BOARD_BDS_BOOT_OPTION_PRIORITY_PROTOCOL {
+ UINT8 IpmiBootDeviceSelectorType;
+ SORT_COMPARE Compare;
+};
+
+typedef struct _AMD_BOARD_BDS_BOOT_OPTION_PRIORITY_PROTOCOL AMD_BOARD_BDS_BOOT_OPTION_PRIORITY_PROTOCOL;
+
+extern EFI_GUID gAmdBoardBdsBootOptionPriorityProtocolGuid;
+
+/**
+ Returns the boot option type of a device
+
+ @param[in] DevicePath The path of device whose boot option type
+ should be returned
+ @retval -1 Device type not found
+ @retval > -1 Device type found
+**/
+UINT8
+BootOptionType (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ This is the callback function for Bds Ready To Boot event.
+
+ @param[in] Event Pointer to this event
+ @param[in] Context Event handler private data
+
+ @retval None.
+**/
+VOID
+EFIAPI
+BdsReadyToBootCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ This is the callback function for Smm Ready To Lock event.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsSmmReadyToLockCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ This is the callback function for PCI ENUMERATION COMPLETE.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsPciEnumCompleteCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Before console after trusted console event callback
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsBeforeConsoleAfterTrustedConsoleCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Before console before end of DXE event callback
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsBeforeConsoleBeforeEndOfDxeGuidCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ After console ready before boot option event callback
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsAfterConsoleReadyBeforeBootOptionCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHook.h b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHook.h
new file mode 100644
index 0000000000..5c950c4866
--- /dev/null
+++ b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHook.h
@@ -0,0 +1,242 @@
+/** @file
+ Header file for BDS Hook Library
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BOARD_BDS_HOOK_H_
+#define BOARD_BDS_HOOK_H_
+
+#include <PiDxe.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/CpuIo2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Guid/CapsuleVendor.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <Guid/FileInfo.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PlatformBootManagerLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HobLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/PerformanceLib.h>
+
+#include <IndustryStandard/Pci30.h>
+#include <IndustryStandard/PciCodeId.h>
+#include <Protocol/PciEnumerationComplete.h>
+
+///
+/// For boot order override.
+///
+#define IPMI_BOOT_OVERRIDE_VAR_NAME L"IpmiBootOverride"
+#define IS_FIRST_BOOT_VAR_NAME L"IsFirstBoot"
+#define UEFI_HARD_DRIVE_NAME L"UEFI Hard Drive"
+
+///
+/// ConnectType
+///
+#define CONSOLE_OUT 0x00000001
+#define STD_ERROR 0x00000002
+#define CONSOLE_IN 0x00000004
+#define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR)
+#define END_ENTIRE_DEVICE_PATH \
+ { \
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
+ }
+
+extern EFI_GUID gUefiShellFileGuid;
+extern EFI_BOOT_MODE gBootMode;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN ConnectType;
+} BDS_CONSOLE_CONNECT_ENTRY;
+
+//
+// Platform Root Bridge
+//
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_ROOT_BRIDGE_DEVICE_PATH;
+
+//
+// Below is the platform console device path
+//
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ PCI_DEVICE_PATH IsaBridge;
+ ACPI_HID_DEVICE_PATH Keyboard;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_KEYBOARD_DEVICE_PATH;
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ PCI_DEVICE_PATH PciDevice;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_ONBOARD_CONTROLLER_DEVICE_PATH;
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ PCI_DEVICE_PATH Pci0Device;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_PEG_ROOT_CONTROLLER_DEVICE_PATH;
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ PCI_DEVICE_PATH PciBridge;
+ PCI_DEVICE_PATH PciDevice;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_PCI_CONTROLLER_DEVICE_PATH;
+
+//
+// Below is the boot option device path
+//
+
+#define CLASS_HID 3
+#define SUBCLASS_BOOT 1
+#define PROTOCOL_KEYBOARD 1
+
+typedef struct {
+ USB_CLASS_DEVICE_PATH UsbClass;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} USB_CLASS_FORMAT_DEVICE_PATH;
+
+extern USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath;
+
+//
+// Platform BDS Functions
+//
+
+/**
+ Perform the memory test base on the memory test intensive level,
+ and update the memory resource.
+
+ @param[in] Level The memory test intensive level.
+
+ @retval EFI_STATUS Success test all the system memory and update
+ the memory resource
+
+**/
+EFI_STATUS
+MemoryTest (
+ IN EXTENDMEM_COVERAGE_LEVEL Level
+ );
+
+/**
+ Connect with predeined platform connect sequence,
+ the OEM/IBV can customize with their own connect sequence.
+
+ @param[in] BootMode Boot mode of this boot.
+**/
+VOID
+ConnectSequence (
+ IN EFI_BOOT_MODE BootMode
+ );
+
+/**
+ Compares boot priorities of two boot options
+
+ @param[in] Left The left boot option
+ @param[in] Right The right boot option
+
+ @return The difference between the Left and Right
+ boot options
+ **/
+INTN
+EFIAPI
+CompareBootOption (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ );
+
+/**
+ Compares boot priorities of two boot options, while giving PXE the highest priority
+
+ @param[in] Left The left boot option
+ @param[in] Right The right boot option
+
+ @return The difference between the Left and Right
+ boot options
+**/
+INTN
+EFIAPI
+CompareBootOptionPxePriority (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ );
+
+/**
+ Compares boot priorities of two boot options, while giving HDD the highest priority
+
+ @param[in] Left The left boot option
+ @param[in] Right The right boot option
+
+ @return The difference between the Left and Right
+ boot options
+**/
+INTN
+EFIAPI
+CompareBootOptionHddPriority (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ );
+
+/**
+ This function is called after all the boot options are enumerated and ordered properly.
+**/
+VOID
+RegisterStaticHotkey (
+ VOID
+ );
+
+/**
+ Registers/Unregisters boot option hotkey
+**/
+VOID
+RegisterDefaultBootOption (
+ VOID
+ );
+
+/**
+ Add console variable device paths
+
+ @param[in] ConsoleType ConIn or ConOut
+ @param[in] ConsoleDevicePath Device path to be added
+**/
+VOID
+AddConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType,
+ IN EFI_DEVICE_PATH *ConsoleDevicePath
+ );
+
+#endif //BOARD_BDS_HOOK_H_
diff --git a/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.c b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.c
new file mode 100644
index 0000000000..3d7c0c2bf7
--- /dev/null
+++ b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.c
@@ -0,0 +1,1712 @@
+/** @file
+ This library registers Bds callbacks. It is a default library
+ implementation instance of the BDS hook library
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/EventGroup.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/IpmiBaseLib.h>
+#include <Library/IpmiCommandLib.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/PciEnumerationComplete.h>
+#include <IndustryStandard/Ipmi.h>
+#include <Library/AmdBoardBdsHookLib.h>
+#include "BoardBdsHook.h"
+
+#ifdef INTERNAL_IDS
+ #include <Register/Amd/Msr.h>
+#endif
+
+CHAR16 *mConsoleVar[] = { L"ConIn", L"ConOut" };
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_BOOT_MODE gBootMode;
+BOOLEAN gPPRequireUIConfirm;
+extern UINTN mBootMenuOptionNumber;
+
+GLOBAL_REMOVE_IF_UNREFERENCED USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath = {
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_USB_CLASS_DP,
+ {
+ (UINT8)(sizeof (USB_CLASS_DEVICE_PATH)),
+ (UINT8)((sizeof (USB_CLASS_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0xffff, // VendorId
+ 0xffff, // ProductId
+ CLASS_HID, // DeviceClass
+ SUBCLASS_BOOT, // DeviceSubClass
+ PROTOCOL_KEYBOARD // DeviceProtocol
+ },
+ END_ENTIRE_DEVICE_PATH
+};
+
+#ifdef INTERNAL_IDS
+EFI_STATUS
+PrintSocOpnInfo (
+ IN VOID
+ );
+
+#endif
+
+//
+// BDS Platform Functions
+//
+
+/**
+ Checks if Mor bit is set.
+ @retval TRUE The MOR bit is set
+ @retval FALSE The MOR bit is not set
+**/
+BOOLEAN
+IsMorBitSet (
+ VOID
+ )
+{
+ UINTN MorControl;
+ EFI_STATUS Status;
+ UINTN DataSize;
+
+ //
+ // Check if the MOR bit is set.
+ //
+ DataSize = sizeof (MorControl);
+ Status = gRT->GetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &MorControl
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, " gEfiMemoryOverwriteControlDataGuid doesn't exist!!***\n"));
+ MorControl = 0;
+ } else {
+ DEBUG ((DEBUG_INFO, " Get the gEfiMemoryOverwriteControlDataGuid = %x!!***\n", MorControl));
+ }
+
+ return (BOOLEAN)(MorControl & 0x01);
+}
+
+/**
+ Prints device paths.
+ @param[in] Name The device name.
+ @param[in] DevicePath The device path to be printed
+**/
+VOID
+EFIAPI
+DumpDevicePath (
+ IN CHAR16 *Name,
+ IN EFI_DEVICE_PATH *DevicePath
+ )
+{
+ CHAR16 *Str;
+
+ Str = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
+ DEBUG ((DEBUG_INFO, "%s: %s\n", Name, Str));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+}
+
+/**
+ Return whether the device is trusted console.
+
+ @param[in] ConsoleType The console type.
+ @param[in] Device The device path to be tested.
+
+ @retval TRUE The device can be trusted.
+ @retval FALSE The device cannot be trusted.
+**/
+BOOLEAN
+IsTrustedConsole (
+ IN CONSOLE_TYPE ConsoleType,
+ IN EFI_DEVICE_PATH_PROTOCOL *Device
+ )
+{
+ VOID *TrustedConsoleDevicepath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+ EFI_DEVICE_PATH_PROTOCOL *ConsoleDevice;
+
+ if (Device == NULL) {
+ return FALSE;
+ }
+
+ ConsoleDevice = DuplicateDevicePath (Device);
+
+ TrustedConsoleDevicepath = NULL;
+
+ switch (ConsoleType) {
+ case ConIn:
+ TrustedConsoleDevicepath = DuplicateDevicePath (PcdGetPtr (PcdTrustedConsoleInputDevicePath));
+ break;
+ case ConOut:
+ //
+ // Check GOP and remove last node
+ //
+ TempDevicePath = ConsoleDevice;
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == ACPI_DEVICE_PATH) &&
+ (DevicePathSubType (TempDevicePath) == ACPI_ADR_DP))
+ {
+ SetDevicePathEndNode (TempDevicePath);
+ break;
+ }
+
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ TrustedConsoleDevicepath = DuplicateDevicePath (PcdGetPtr (PcdTrustedConsoleOutputDevicePath));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ TempDevicePath = TrustedConsoleDevicepath;
+ do {
+ Instance = GetNextDevicePathInstance (&TempDevicePath, &Size);
+ if (Instance == NULL) {
+ break;
+ }
+
+ if (CompareMem (ConsoleDevice, Instance, Size - END_DEVICE_PATH_LENGTH) == 0) {
+ FreePool (Instance);
+ FreePool (ConsoleDevice);
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+
+ return TRUE;
+ }
+
+ FreePool (Instance);
+ } while (TempDevicePath != NULL);
+
+ FreePool (ConsoleDevice);
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+
+ return FALSE;
+}
+
+/**
+ Return whether the USB device path is in a short form.
+
+ @param[in] DevicePath The device path to be tested.
+
+ @retval TRUE The device path is in short form.
+ @retval FALSE The device path is not in short form.
+**/
+BOOLEAN
+IsUsbShortForm (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Connect the USB short form device path.
+
+ @param[in] DevicePath USB short form device path
+
+ @retval EFI_SUCCESS Successfully connected the USB device
+ @retval EFI_NOT_FOUND Cannot connect the USB device
+ @retval EFI_INVALID_PARAMETER The device path is invalid.
+**/
+EFI_STATUS
+ConnectUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Class[3];
+ BOOLEAN AtLeastOneConnected;
+
+ //
+ // Check the passed in parameters
+ //
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsUsbShortForm (DevicePath)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the usb host controller firstly, then connect with the remaining device path
+ //
+ AtLeastOneConnected = FALSE;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check whether the Pci device is the wanted usb host controller
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
+ if (!EFI_ERROR (Status) &&
+ ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1])))
+ {
+ Status = gBS->ConnectController (
+ Handles[Index],
+ NULL,
+ DevicePath,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ AtLeastOneConnected = TRUE;
+ }
+ }
+ }
+ }
+
+ return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
+}
+
+/**
+ Return whether the Handle is a vga handle.
+
+ @param[in] Handle The handle to be tested.
+
+ @retval TRUE The handle is a vga handle.
+ @retval FALSE The handle is not a vga handle..
+**/
+BOOLEAN
+IsVgaHandle (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ EFI_STATUS Status;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (!EFI_ERROR (Status)) {
+ if (IS_PCI_VGA (&Pci) || IS_PCI_OLD_VGA (&Pci)) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Return whether the device path points to a video controller.
+
+ @param[in] DevicePath The device path to be tested.
+
+ @retval TRUE The device path points to a video controller.
+ @retval FALSE The device path does not point to a video controller.
+**/
+EFI_HANDLE
+IsVideoController (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+
+ DupDevicePath = DuplicateDevicePath (DevicePath);
+ ASSERT (DupDevicePath != NULL);
+ if (DupDevicePath == NULL) {
+ return NULL;
+ }
+
+ TempDevicePath = DupDevicePath;
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ FreePool (DupDevicePath);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ if (IsVgaHandle (DeviceHandle)) {
+ return DeviceHandle;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ Return whether the device path is a GOP device path.
+
+ @param[in] DevicePath The device path to be tested.
+
+ @retval TRUE The device path is a GOP device path.
+ @retval FALSE The device on the device path is not a GOP device path.
+**/
+BOOLEAN
+IsGopDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ while (!IsDevicePathEndType (DevicePath)) {
+ if ((DevicePathType (DevicePath) == ACPI_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == ACPI_ADR_DP))
+ {
+ return TRUE;
+ }
+
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ return FALSE;
+}
+
+/**
+ Remove all GOP device path instance from DevicePath and add the Gop to the DevicePath.
+
+ @param[in] DevicePath The device path to be removed
+ @param[in] Gop The device path to be added.
+
+ @retval Return The updated device path.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+UpdateGopDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *Gop
+ )
+{
+ UINTN Size;
+ UINTN GopSize;
+ EFI_DEVICE_PATH_PROTOCOL *Temp;
+ EFI_DEVICE_PATH_PROTOCOL *Return;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ BOOLEAN Exist;
+
+ Exist = FALSE;
+ Return = NULL;
+ GopSize = GetDevicePathSize (Gop);
+ do {
+ Instance = GetNextDevicePathInstance (&DevicePath, &Size);
+ if (Instance == NULL) {
+ break;
+ }
+
+ if (!IsGopDevicePath (Instance) ||
+ ((Size == GopSize) && (CompareMem (Instance, Gop, GopSize) == 0))
+ )
+ {
+ if ((Size == GopSize) && (CompareMem (Instance, Gop, GopSize) == 0)) {
+ Exist = TRUE;
+ }
+
+ Temp = Return;
+ Return = AppendDevicePathInstance (Return, Instance);
+ if (Temp != NULL) {
+ FreePool (Temp);
+ }
+ }
+
+ FreePool (Instance);
+ } while (DevicePath != NULL);
+
+ if (!Exist) {
+ Temp = Return;
+ Return = AppendDevicePathInstance (Return, Gop);
+ if (Temp != NULL) {
+ FreePool (Temp);
+ }
+ }
+
+ return Return;
+}
+
+/**
+ Get Graphics Controller Handle. VgaDevices needs to be freed by caller.
+
+ @param[in] NeedTrustedConsole The flag to determine if trusted console
+ or non trusted console should be returned
+ @param[out] VgaDevices Array of handles corresponding to
+ valid VGA devices
+ @param[out] VgaDevicesCount Number of VGA devices found and placed in
+ VgaDevices
+
+ @retval EFI ERROR No VGA capable devices found
+ @retval EFI_SUCCESS At least one VGA device found
+**/
+EFI_STATUS
+EFIAPI
+GetGraphicsController (
+ IN BOOLEAN NeedTrustedConsole,
+ OUT EFI_HANDLE **VgaDevices,
+ OUT UINTN *VgaDevicesCount
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE *PciHandles;
+ UINTN PciHandlesSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT32 NumDevices;
+
+ if ((VgaDevicesCount == NULL) || (VgaDevices == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumDevices = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &PciHandlesSize,
+ &PciHandles
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *VgaDevices = AllocateZeroPool (sizeof (EFI_HANDLE) * PciHandlesSize);
+ if (VgaDevices == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < PciHandlesSize; Index++) {
+ Status = gBS->HandleProtocol (
+ PciHandles[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (!IsVgaHandle (PciHandles[Index])) {
+ continue;
+ }
+
+ if ((NeedTrustedConsole && IsTrustedConsole (ConOut, DevicePath)) ||
+ ((!NeedTrustedConsole) && (!IsTrustedConsole (ConOut, DevicePath))))
+ {
+ VgaDevices[0][NumDevices] = PciHandles[Index];
+ NumDevices++;
+ }
+ }
+
+ *VgaDevicesCount = NumDevices;
+ if (NumDevices > 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Updates Graphic ConOut variable. This function searches for all VGA capable output devices and
+ adds them to the ConOut variable.
+
+ @param[in] NeedTrustedConsole The flag that determines if trusted console
+ or non trusted console should be returned
+**/
+VOID
+UpdateGraphicConOut (
+ IN BOOLEAN NeedTrustedConsole
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ConOutDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *UpdatedConOutDevicePath;
+ EFI_HANDLE *VgaDevices;
+ UINTN VgaDevicesCount;
+ UINTN Count;
+ EFI_STATUS Status;
+
+ Count = 0;
+ VgaDevicesCount = 0;
+
+ //
+ // Update ConOut variable
+ //
+ Status = GetGraphicsController (NeedTrustedConsole, &VgaDevices, &VgaDevicesCount);
+ if (Status == EFI_SUCCESS) {
+ GetEfiGlobalVariable2 (L"ConOut", (VOID **)&ConOutDevicePath, NULL);
+ if (ConOutDevicePath != NULL) {
+ DumpDevicePath (L"Original ConOut variable", ConOutDevicePath);
+ FreePool (ConOutDevicePath);
+ }
+
+ // Add VGA devices to ConOut
+ for (Count = 0; Count < VgaDevicesCount; Count++) {
+ //
+ // Connect the GOP driver
+ //
+ gBS->ConnectController (VgaDevices[Count], NULL, NULL, TRUE);
+ //
+ // Get the GOP device path
+ // NOTE: We may get a device path that contains Controller node in it.
+ //
+ GopDevicePath = EfiBootManagerGetGopDevicePath (VgaDevices[Count]);
+ if (GopDevicePath != NULL) {
+ GetEfiGlobalVariable2 (L"ConOut", (VOID **)&ConOutDevicePath, NULL);
+ if (ConOutDevicePath != NULL) {
+ UpdatedConOutDevicePath = UpdateGopDevicePath (ConOutDevicePath, GopDevicePath);
+ if (UpdatedConOutDevicePath != NULL) {
+ gRT->SetVariable (
+ L"ConOut",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ GetDevicePathSize (UpdatedConOutDevicePath),
+ UpdatedConOutDevicePath
+ );
+ FreePool (UpdatedConOutDevicePath);
+ }
+
+ FreePool (ConOutDevicePath);
+ }
+
+ FreePool (GopDevicePath);
+ }
+ }
+
+ FreePool (VgaDevices);
+ }
+
+ GetEfiGlobalVariable2 (L"ConOut", (VOID **)&ConOutDevicePath, NULL);
+ if (ConOutDevicePath != NULL) {
+ DumpDevicePath (L"Final ConOut variable", ConOutDevicePath);
+ FreePool (ConOutDevicePath);
+ }
+}
+
+/**
+ The function connects the trusted consoles.
+**/
+VOID
+ConnectTrustedConsole (
+ VOID
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Consoles;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ UINTN Size;
+ UINTN Index;
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ VOID *TrustedConsoleDevicepath;
+
+ TrustedConsoleDevicepath = PcdGetPtr (PcdTrustedConsoleInputDevicePath);
+ DumpDevicePath (L"TrustedConsoleIn", TrustedConsoleDevicepath);
+ TrustedConsoleDevicepath = PcdGetPtr (PcdTrustedConsoleOutputDevicePath);
+ DumpDevicePath (L"TrustedConsoleOut", TrustedConsoleDevicepath);
+
+ for (Index = 0; Index < sizeof (mConsoleVar) / sizeof (mConsoleVar[0]); Index++) {
+ GetEfiGlobalVariable2 (mConsoleVar[Index], (VOID **)&Consoles, NULL);
+
+ TempDevicePath = Consoles;
+ do {
+ Instance = GetNextDevicePathInstance (&TempDevicePath, &Size);
+ if (Instance == NULL) {
+ break;
+ }
+
+ if (IsTrustedConsole (Index, Instance)) {
+ if (IsUsbShortForm (Instance)) {
+ ConnectUsbShortFormDevicePath (Instance);
+ } else {
+ for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
+ if ((DevicePathType (Next) == ACPI_DEVICE_PATH) && (DevicePathSubType (Next) == ACPI_ADR_DP)) {
+ break;
+ } else if ((DevicePathType (Next) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (Next) == HW_CONTROLLER_DP) &&
+ (DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH) &&
+ (DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP)
+ )
+ {
+ break;
+ }
+ }
+
+ if (!IsDevicePathEnd (Next)) {
+ SetDevicePathEndNode (Next);
+ Status = EfiBootManagerConnectDevicePath (Instance, &Handle);
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ }
+ } else {
+ EfiBootManagerConnectDevicePath (Instance, NULL);
+ }
+ }
+ }
+
+ FreePool (Instance);
+ } while (TempDevicePath != NULL);
+
+ if (Consoles != NULL) {
+ FreePool (Consoles);
+ }
+ }
+}
+
+/**
+ The function connects the trusted Storages.
+**/
+VOID
+ConnectTrustedStorage (
+ VOID
+ )
+{
+ VOID *TrustedStorageDevicepath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+ EFI_DEVICE_PATH_PROTOCOL *TempStorageDevicePath;
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+
+ TrustedStorageDevicepath = DuplicateDevicePath (PcdGetPtr (PcdTrustedStorageDevicePath));
+ DumpDevicePath (L"TrustedStorage", TrustedStorageDevicepath);
+
+ TempDevicePath = TrustedStorageDevicepath;
+ do {
+ Instance = GetNextDevicePathInstance (&TempDevicePath, &Size);
+ if (Instance == NULL) {
+ break;
+ }
+
+ EfiBootManagerConnectDevicePath (Instance, NULL);
+
+ TempStorageDevicePath = Instance;
+
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TempStorageDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (DeviceHandle, NULL, NULL, FALSE);
+ }
+
+ FreePool (Instance);
+ } while (TempDevicePath != NULL);
+
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+}
+
+/**
+ Check if current BootCurrent variable is internal shell boot option.
+
+ @retval TRUE BootCurrent is internal shell.
+ @retval FALSE BootCurrent is not internal shell.
+**/
+BOOLEAN
+BootCurrentIsInternalShell (
+ VOID
+ )
+{
+ UINTN VarSize;
+ UINT16 BootCurrent;
+ CHAR16 BootOptionName[16];
+ UINT8 *BootOption;
+ UINT8 *Ptr;
+ BOOLEAN Result;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_GUID *GuidPoint;
+
+ BootOption = NULL;
+ Result = FALSE;
+
+ //
+ // Get BootCurrent variable
+ //
+ VarSize = sizeof (UINT16);
+ Status = gRT->GetVariable (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &VarSize,
+ &BootCurrent
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Create boot option Bootxxxx from BootCurrent
+ //
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04X", BootCurrent);
+
+ GetEfiGlobalVariable2 (BootOptionName, (VOID **)&BootOption, &VarSize);
+ if ((BootOption == NULL) || (VarSize == 0)) {
+ return FALSE;
+ }
+
+ Ptr = BootOption;
+ Ptr += sizeof (UINT32);
+ Ptr += sizeof (UINT16);
+ Ptr += StrSize ((CHAR16 *)Ptr);
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Ptr;
+ LastDeviceNode = TempDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
+ (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LastDeviceNode
+ );
+ if ((GuidPoint != NULL) &&
+ ((CompareGuid (GuidPoint, &gUefiShellFileGuid))))
+ {
+ //
+ // if this option is internal shell, return TRUE
+ //
+ Result = TRUE;
+ }
+
+ if (BootOption != NULL) {
+ FreePool (BootOption);
+ BootOption = NULL;
+ }
+
+ return Result;
+}
+
+/**
+ This function will change video resolution and text mode
+ for internal shell when internal shell is launched.
+
+ @param None.
+
+ @retval EFI_SUCCESS Mode is changed successfully.
+ @retval Others Mode failed to changed.
+**/
+EFI_STATUS
+EFIAPI
+ChangeModeForInternalShell (
+ VOID
+ )
+{
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ UINT32 MaxGopMode;
+ UINT32 MaxTextMode;
+ UINT32 ModeNumber;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN CurrentColumn;
+ UINTN CurrentRow;
+
+ //
+ // Internal shell mode
+ //
+ UINT32 mShellModeColumn;
+ UINT32 mShellModeRow;
+ UINT32 mShellHorizontalResolution;
+ UINT32 mShellVerticalResolution;
+
+ //
+ // Get user defined text mode for internal shell only once.
+ //
+ mShellHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
+ mShellVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
+ mShellModeColumn = PcdGet32 (PcdSetupConOutColumn);
+ mShellModeRow = PcdGet32 (PcdSetupConOutRow);
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **)&GraphicsOutput
+ );
+ if (EFI_ERROR (Status)) {
+ GraphicsOutput = NULL;
+ }
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **)&SimpleTextOut
+ );
+ if (EFI_ERROR (Status)) {
+ SimpleTextOut = NULL;
+ }
+
+ if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MaxGopMode = GraphicsOutput->Mode->MaxMode;
+ MaxTextMode = SimpleTextOut->Mode->MaxMode;
+
+ //
+ // 1. If current video resolution is same with new video resolution,
+ // video resolution need not be changed.
+ // 1.1. If current text mode is same with new text mode, text mode need not be change.
+ // 1.2. If current text mode is different with new text mode, text mode need be change to new text mode.
+ // 2. If current video resolution is different with new video resolution, we need restart whole console drivers.
+ //
+ for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
+ Status = GraphicsOutput->QueryMode (
+ GraphicsOutput,
+ ModeNumber,
+ &SizeOfInfo,
+ &Info
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Info->HorizontalResolution == mShellHorizontalResolution) &&
+ (Info->VerticalResolution == mShellVerticalResolution))
+ {
+ if ((GraphicsOutput->Mode->Info->HorizontalResolution == mShellHorizontalResolution) &&
+ (GraphicsOutput->Mode->Info->VerticalResolution == mShellVerticalResolution))
+ {
+ //
+ // If current video resolution is same with new resolution,
+ // then check if current text mode is same with new text mode.
+ //
+ Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
+ ASSERT_EFI_ERROR (Status);
+ if ((CurrentColumn == mShellModeColumn) && (CurrentRow == mShellModeRow)) {
+ //
+ // Current text mode is same with new text mode, text mode need not be change.
+ //
+ FreePool (Info);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Current text mode is different with new text mode, text mode need be change to new text mode.
+ //
+ for (Index = 0; Index < MaxTextMode; Index++) {
+ Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
+ if (!EFI_ERROR (Status)) {
+ if ((CurrentColumn == mShellModeColumn) && (CurrentRow == mShellModeRow)) {
+ //
+ // New text mode is supported, set it.
+ //
+ Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Update text mode PCD.
+ //
+ Status = PcdSet32S (PcdConOutColumn, mShellModeColumn);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PcdSet32S (PcdConOutRow, mShellModeRow);
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Info);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (Index == MaxTextMode) {
+ //
+ // If new text mode is not supported, return error.
+ //
+ FreePool (Info);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ } else {
+ FreePool (Info);
+ //
+ // If current video resolution is not same with the new one, set new video resolution.
+ // In this case, the driver which produces simple text out need be restarted.
+ //
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set PCD to restart GraphicsConsole and Consplitter to change video resolution
+ // and produce new text mode based on new resolution.
+ //
+ Status = PcdSet32S (PcdVideoHorizontalResolution, mShellHorizontalResolution);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PcdSet32S (PcdVideoVerticalResolution, mShellVerticalResolution);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PcdSet32S (PcdConOutColumn, mShellModeColumn);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PcdSet32S (PcdConOutRow, mShellModeRow);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextOutProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ FreePool (Info);
+ }
+ }
+
+ if (ModeNumber == MaxGopMode) {
+ //
+ // If the new resolution is not supported, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The function connects the trusted consoles and then call the PP processing library interface.
+**/
+VOID
+ProcessTcgPp (
+ VOID
+ )
+{
+ gPPRequireUIConfirm |= Tcg2PhysicalPresenceLibNeedUserConfirm ();
+
+ if (gPPRequireUIConfirm) {
+ ConnectTrustedConsole ();
+ }
+
+ Tcg2PhysicalPresenceLibProcessRequest (NULL);
+}
+
+/**
+ The function connects the trusted storage to perform TPerReset.
+**/
+VOID
+ProcessTcgMor (
+ VOID
+ )
+{
+ if (IsMorBitSet ()) {
+ ConnectTrustedConsole ();
+ ConnectTrustedStorage ();
+ }
+}
+
+/**
+ Update the ConIn variable with USB Keyboard device path,if its not already exists in ConIn.
+**/
+VOID
+EnumUsbKeyboard (
+ VOID
+ )
+{
+ DEBUG ((DEBUG_INFO, "[EnumUsbKeyboard]\n"));
+ EfiBootManagerUpdateConsoleVariable (ConIn, (EFI_DEVICE_PATH_PROTOCOL *)&gUsbClassKeyboardDevicePath, NULL);
+ //
+ // Append Usb Keyboard short form DevicePath into "ConInDev"
+ //
+ EfiBootManagerUpdateConsoleVariable (ConInDev, (EFI_DEVICE_PATH_PROTOCOL *)&gUsbClassKeyboardDevicePath, NULL);
+}
+
+/**
+ Connect with predeined platform connect sequence,
+ the OEM/IBV can customize with their own connect sequence.
+
+ @param[in] BootMode Boot mode of this boot.
+**/
+VOID
+ConnectSequence (
+ IN EFI_BOOT_MODE BootMode
+ )
+{
+ EfiBootManagerConnectAll ();
+}
+
+/**
+ Connects Root Bridge.
+
+ @param[in] Recursive Recursively connect controllers if TRUE
+ **/
+VOID
+ConnectRootBridge (
+ IN BOOLEAN Recursive
+ )
+{
+ UINTN RootBridgeHandleCount;
+ EFI_HANDLE *RootBridgeHandleBuffer;
+ UINTN RootBridgeIndex;
+
+ RootBridgeHandleCount = 0;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &RootBridgeHandleCount,
+ &RootBridgeHandleBuffer
+ );
+ for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
+ gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, Recursive);
+ }
+}
+
+/**
+ Add console variable device paths.
+
+ @param[in] ConsoleType ConIn or ConOut
+ @param[in] ConsoleDevicePath Device path to be added
+**/
+VOID
+AddConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType,
+ IN EFI_DEVICE_PATH *ConsoleDevicePath
+ )
+{
+ EFI_DEVICE_PATH *TempDevicePath;
+ EFI_DEVICE_PATH *Instance;
+ UINTN Size;
+ EFI_HANDLE GraphicsControllerHandle;
+ EFI_DEVICE_PATH *GopDevicePath;
+
+ TempDevicePath = DuplicateDevicePath (ConsoleDevicePath);
+ do {
+ Instance = GetNextDevicePathInstance (&TempDevicePath, &Size);
+ if (Instance == NULL) {
+ break;
+ }
+
+ switch (ConsoleType) {
+ case ConIn:
+ if (IsUsbShortForm (Instance)) {
+ //
+ // Append Usb Keyboard short form DevicePath into "ConInDev"
+ //
+ EfiBootManagerUpdateConsoleVariable (ConInDev, Instance, NULL);
+ }
+
+ EfiBootManagerUpdateConsoleVariable (ConsoleType, Instance, NULL);
+ break;
+ case ConOut:
+ GraphicsControllerHandle = IsVideoController (Instance);
+ if (GraphicsControllerHandle == NULL) {
+ EfiBootManagerUpdateConsoleVariable (ConsoleType, Instance, NULL);
+ } else {
+ //
+ // Connect the GOP driver
+ //
+ gBS->ConnectController (GraphicsControllerHandle, NULL, NULL, TRUE);
+ //
+ // Get the GOP device path
+ // NOTE: We may get a device path that contains Controller node in it.
+ //
+ GopDevicePath = EfiBootManagerGetGopDevicePath (GraphicsControllerHandle);
+ if (GopDevicePath != NULL) {
+ EfiBootManagerUpdateConsoleVariable (ConsoleType, GopDevicePath, NULL);
+ }
+ }
+
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ FreePool (Instance);
+ } while (TempDevicePath != NULL);
+
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+}
+
+/**
+ This is the callback function for PCI ENUMERATION COMPLETE.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsPciEnumCompleteCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *ProtocolPointer;
+ EFI_DEVICE_PATH_PROTOCOL *VarConOut;
+ EFI_DEVICE_PATH_PROTOCOL *VarConIn;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
+ // if it is, we will skip it until real event is triggered
+ //
+ Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **)&ProtocolPointer);
+ if (EFI_SUCCESS != Status) {
+ return;
+ }
+
+ // gBS->CloseEvent (Event);
+
+ DEBUG ((DEBUG_INFO, "Event BdsPciEnumCompleteCallback callback starts\n"));
+
+ gBootMode = GetBootModeHob ();
+
+ //
+ // Fill ConIn/ConOut in Full Configuration boot mode
+ //
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerInit - %x\n", gBootMode));
+
+ if ((gBootMode == BOOT_WITH_FULL_CONFIGURATION) ||
+ (gBootMode == BOOT_WITH_DEFAULT_SETTINGS) ||
+ (gBootMode == BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS) ||
+ (gBootMode == BOOT_IN_RECOVERY_MODE))
+ {
+ GetEfiGlobalVariable2 (L"ConOut", (VOID **)&VarConOut, NULL);
+ if (VarConOut != NULL) {
+ FreePool (VarConOut);
+ }
+
+ GetEfiGlobalVariable2 (L"ConIn", (VOID **)&VarConIn, NULL);
+ if (VarConIn != NULL) {
+ FreePool (VarConIn);
+ }
+
+ //
+ // Only fill ConIn/ConOut when ConIn/ConOut is empty because we may drop to Full Configuration boot mode in non-first boot
+ //
+ if ((VarConOut == NULL) || (VarConIn == NULL)) {
+ if (PcdGetSize (PcdTrustedConsoleOutputDevicePath) >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ AddConsoleVariable (ConOut, PcdGetPtr (PcdTrustedConsoleOutputDevicePath));
+ }
+
+ if (PcdGetSize (PcdTrustedConsoleInputDevicePath) >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ AddConsoleVariable (ConIn, PcdGetPtr (PcdTrustedConsoleInputDevicePath));
+ }
+ }
+ }
+
+ //
+ // Enumerate USB keyboard
+ //
+ EnumUsbKeyboard ();
+
+ //
+ // For trusted console it must be handled here.
+ //
+ UpdateGraphicConOut (TRUE);
+
+ //
+ // Register Boot Options
+ //
+ RegisterDefaultBootOption ();
+
+ //
+ // Register Static Hot keys
+ //
+ RegisterStaticHotkey ();
+
+ //
+ // Process Physical Preo
+ //
+ PERF_START_EX (NULL, "EventRec", NULL, AsmReadTsc (), 0x7010);
+ if (PcdGetBool (PcdTpm2Enable)) {
+ ProcessTcgPp ();
+ ProcessTcgMor ();
+ }
+
+ PERF_END_EX (NULL, "EventRec", NULL, AsmReadTsc (), 0x7011);
+
+ //
+ // Perform memory test
+ // We should make all UEFI memory and GCD information populated before ExitPmAuth.
+ // SMM may consume these information.
+ //
+ MemoryTest ((EXTENDMEM_COVERAGE_LEVEL)PcdGet32 (PcdPlatformMemoryCheckLevel));
+}
+
+/**
+ This is the callback function for Smm Ready To Lock.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsSmmReadyToLockCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VOID *ProtocolPointer;
+ EFI_STATUS Status;
+
+ //
+ // Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
+ // if it is, we will skip it until real event is triggered
+ //
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, (VOID **)&ProtocolPointer);
+ if (EFI_SUCCESS != Status) {
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO, "Event gEfiDxeSmmReadyToLockProtocolGuid callback starts\n"));
+
+ //
+ // Dispatch the deferred 3rd party images.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+
+ //
+ // For non-trusted console it must be handled here.
+ //
+ UpdateGraphicConOut (FALSE);
+}
+
+/**
+ ReadyToBoot callback to set video and text mode for internal shell boot.
+ That will not connect USB controller while CSM and FastBoot are disabled, we need to connect them
+ before booting to Shell for showing USB devices in Shell.
+
+ When FastBoot is enabled and Windows Console is the chosen Console behavior, input devices will not be connected
+ by default. Hence, when booting to EFI shell, connecting input consoles are required.
+
+ @param[in] Event Pointer to this event
+ @param[in] Context Event handler private data
+**/
+VOID
+EFIAPI
+BdsReadyToBootCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DEBUG ((DEBUG_INFO, "BdsReadyToBootCallback\n"));
+
+ if (BootCurrentIsInternalShell ()) {
+ ChangeModeForInternalShell ();
+ EfiBootManagerConnectAllDefaultConsoles ();
+ gDS->Dispatch ();
+ }
+}
+
+/**
+ Before console after trusted console event callback
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsBeforeConsoleAfterTrustedConsoleCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DEBUG ((DEBUG_INFO, "Event gBdsEventBeforeConsoleBeforeEndOfDxeGuid callback starts\n"));
+
+ //
+ // Connect Root Bridge to make PCI BAR resource allocated and all PciIo created
+ //
+ ConnectRootBridge (FALSE);
+}
+
+/**
+ Before console before end of DXE event callback
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsBeforeConsoleBeforeEndOfDxeGuidCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DEBUG ((DEBUG_INFO, "Event gBdsBeforeConsoleBeforeEndOfDxeGuid callback starts\n"));
+}
+
+/**
+ Handles possible IPMI boot overrides by modifying the LoadOptions variable.
+ Uses sorting function installed in BootOptionPriorityProtocol if the protocol
+ is installed and a valid IPMI override is detected.
+
+ @retval EFI_SUCCESS Boot override successful, or not necessary.
+ @retval EFI_NOT_FOUND Attempted to override boot to an unsupported boot option.
+**/
+EFI_STATUS
+HandleIpmiBootOverride (
+ VOID
+ )
+{
+ UINT8 NvIpmiBootOverride;
+ UINT8 Index;
+ UINT8 CurrentIpmiBootOverride;
+ UINT8 *GetBootOptionsBuffer;
+ UINT8 *SetBootOptionsBuffer;
+ UINTN BootOptionCount;
+ UINTN DataSize;
+ IPMI_GET_BOOT_OPTIONS_REQUEST BootOptionsRequest;
+ IPMI_GET_BOOT_OPTIONS_RESPONSE *BootOptionsResponse;
+ IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5 *BootOptionsParameterData;
+ IPMI_SET_BOOT_OPTIONS_REQUEST *SetBootOptionsRequest;
+ IPMI_SET_BOOT_OPTIONS_RESPONSE SetBootOptionsResponse;
+ IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5 *SetBootOptionsParameterData;
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptionToManipulate;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ EFI_STATUS Status;
+ AMD_BOARD_BDS_BOOT_OPTION_PRIORITY_PROTOCOL *BootOptionPriorityProtocol;
+ EFI_HANDLE *BootPriorityHandles;
+ UINTN BootPriorityCount;
+ UINTN BootPriorityIndex;
+ BOOLEAN ValidBootPriorityOverride;
+
+ ZeroMem (&BootOptionsRequest, sizeof (IPMI_GET_BOOT_OPTIONS_REQUEST));
+ ZeroMem (&SetBootOptionsResponse, sizeof (IPMI_SET_BOOT_OPTIONS_RESPONSE));
+
+ LoadOptionToManipulate = NULL;
+ Status = EFI_SUCCESS;
+ ValidBootPriorityOverride = FALSE;
+ // setup buffers
+ GetBootOptionsBuffer = (UINT8 *)AllocateZeroPool (sizeof (BootOptionsResponse) + sizeof (IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5));
+ SetBootOptionsBuffer = (UINT8 *)AllocateZeroPool (sizeof (SetBootOptionsRequest) + sizeof (IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5));
+
+ // setup parameter data
+ BootOptionsRequest.ParameterSelector.Bits.ParameterSelector = IPMI_BOOT_OPTIONS_PARAMETER_BOOT_FLAGS;
+ BootOptionsResponse = (IPMI_GET_BOOT_OPTIONS_RESPONSE *)&GetBootOptionsBuffer[0];
+ Status = IpmiGetSystemBootOptions (&BootOptionsRequest, BootOptionsResponse);
+ BootOptionsParameterData = (IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5 *)BootOptionsResponse->ParameterData;
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto end;
+ }
+
+ // setup SetBootOptions parameter data
+ SetBootOptionsRequest = (IPMI_SET_BOOT_OPTIONS_REQUEST *)&SetBootOptionsBuffer[0];
+ SetBootOptionsParameterData = (IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5 *)SetBootOptionsRequest->ParameterData;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ // if received valid IPMI data, then override boot option
+ if (!BootOptionsResponse->ParameterValid.Bits.ParameterValid && BootOptionsParameterData->Data1.Bits.BootFlagValid) {
+ // get non volatile IpmiBootOverride variable
+ DataSize = sizeof (UINT8);
+ Status = gRT->GetVariable (
+ IPMI_BOOT_OVERRIDE_VAR_NAME,
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &NvIpmiBootOverride
+ );
+ if (EFI_ERROR (Status)) {
+ NvIpmiBootOverride = IPMI_BOOT_DEVICE_SELECTOR_NO_OVERRIDE;
+ }
+
+ CurrentIpmiBootOverride = BootOptionsParameterData->Data2.Bits.BootDeviceSelector;
+
+ // Handle platform specific boot priority override
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gAmdBoardBdsBootOptionPriorityProtocolGuid,
+ NULL,
+ &BootPriorityCount,
+ &BootPriorityHandles
+ );
+
+ if (!EFI_ERROR (Status)) {
+ for (BootPriorityIndex = 0; BootPriorityIndex < BootPriorityCount; BootPriorityIndex++) {
+ Status = gBS->HandleProtocol (
+ BootPriorityHandles[BootPriorityIndex],
+ &gAmdBoardBdsBootOptionPriorityProtocolGuid,
+ (VOID **)&BootOptionPriorityProtocol
+ );
+ if (!EFI_ERROR (Status) &&
+ (BootOptionPriorityProtocol->IpmiBootDeviceSelectorType == CurrentIpmiBootOverride))
+ {
+ DEBUG ((DEBUG_INFO, "Valid BootOptionPriority Override detected\n"));
+ ValidBootPriorityOverride = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (CurrentIpmiBootOverride == IPMI_BOOT_DEVICE_SELECTOR_BIOS_SETUP) {
+ DEBUG ((DEBUG_INFO, "[Bds]BiosSetup option override detected via IPMI\n"));
+ // need to find boot option corresponding to BiosSetup
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if ((StrCmp (BootOptions[Index].Description, L"Enter Setup") == 0) && (BootOptions[Index].Attributes == (LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN))) {
+ LoadOptionToManipulate = &BootOptions[Index];
+ } else if (StrCmp (BootOptions[Index].Description, L"Enter Setup") == 0) {
+ // delete duplicate BiosSetup Menu option
+ EfiBootManagerDeleteLoadOptionVariable (BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ }
+ }
+
+ if (LoadOptionToManipulate == NULL) {
+ Status = EFI_UNSUPPORTED;
+ goto end;
+ }
+
+ // have Load option for bios setup, now update loadoptions
+ Status = EfiBootManagerDeleteLoadOptionVariable (LoadOptionToManipulate->OptionNumber, LoadOptionTypeBoot);
+ LoadOptionToManipulate->Attributes &= LOAD_OPTION_CATEGORY_BOOT;
+ LoadOptionToManipulate->Attributes |= (LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN);
+ Status = EfiBootManagerAddLoadOptionVariable (LoadOptionToManipulate, 0); // add back in loadoptions in 0th index (first option)
+ } else if (CurrentIpmiBootOverride == IPMI_BOOT_DEVICE_SELECTOR_PXE) {
+ DEBUG ((DEBUG_INFO, "[Bds]PXE option override detected via IPMI\n"));
+
+ if (ValidBootPriorityOverride) {
+ EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, BootOptionPriorityProtocol->Compare);
+ } else {
+ EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, CompareBootOptionPxePriority);
+ }
+ } else if (CurrentIpmiBootOverride == IPMI_BOOT_DEVICE_SELECTOR_HARDDRIVE) {
+ DEBUG ((DEBUG_INFO, "[Bds]HDD option override detected via IPMI\n"));
+ if (ValidBootPriorityOverride) {
+ EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, BootOptionPriorityProtocol->Compare);
+ } else {
+ EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, CompareBootOptionHddPriority);
+ }
+ } else if ((CurrentIpmiBootOverride == IPMI_BOOT_DEVICE_SELECTOR_NO_OVERRIDE) && (CurrentIpmiBootOverride != NvIpmiBootOverride)) {
+ // delete BiosSetup option corresponding to the override
+ Status = EfiBootManagerDeleteLoadOptionVariable (BootOptions[0].OptionNumber, LoadOptionTypeBoot);
+ // re sort boot options
+ EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, CompareBootOption);
+ }
+
+ // if Ipmi override not persistent, reset boot option to None and persistent to true
+ if (!BootOptionsParameterData->Data1.Bits.PersistentOptions) {
+ SetBootOptionsRequest->ParameterValid.Bits.ParameterSelector = IPMI_BOOT_OPTIONS_PARAMETER_BOOT_FLAGS;
+ CopyMem (SetBootOptionsParameterData, BootOptionsParameterData, sizeof (IPMI_BOOT_OPTIONS_RESPONSE_PARAMETER_5));
+ SetBootOptionsParameterData->Data1.Bits.PersistentOptions = 1; // persistent
+ SetBootOptionsParameterData->Data2.Bits.BootDeviceSelector = IPMI_BOOT_DEVICE_SELECTOR_NO_OVERRIDE; // revert to no override
+ Status = IpmiSetSystemBootOptions (SetBootOptionsRequest, &SetBootOptionsResponse);
+ }
+
+ Status = gRT->SetVariable (
+ IPMI_BOOT_OVERRIDE_VAR_NAME,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT8),
+ &CurrentIpmiBootOverride
+ );
+ }
+
+end:
+ // Free buffers
+ FreePool (GetBootOptionsBuffer);
+ FreePool (SetBootOptionsBuffer);
+ return Status;
+}
+
+/**
+ After console ready before boot option event callback.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+BdsAfterConsoleReadyBeforeBootOptionCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_BOOT_MODE LocalBootMode;
+ EFI_STATUS Status;
+ BOOLEAN IsFirstBoot;
+ UINTN DataSize;
+
+ DEBUG ((DEBUG_INFO, "Event gBdsAfterConsoleReadyBeforeBootOptionEvent callback starts\n"));
+ //
+ // Get current Boot Mode
+ //
+ LocalBootMode = gBootMode;
+ DEBUG ((DEBUG_INFO, "Current local bootmode - %x\n", LocalBootMode));
+
+ //
+ // Go the different platform policy with different boot mode
+ // Notes: this part code can be change with the table policy
+ //
+ switch (LocalBootMode) {
+ case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
+ case BOOT_WITH_MINIMAL_CONFIGURATION:
+ case BOOT_ON_S4_RESUME:
+ //
+ // Perform some platform specific connect sequence
+ //
+ PERF_START_EX (NULL, "EventRec", NULL, AsmReadTsc (), 0x7050);
+ ConnectSequence (LocalBootMode);
+ PERF_END_EX (NULL, "EventRec", NULL, AsmReadTsc (), 0x7051);
+
+ break;
+
+ case BOOT_WITH_FULL_CONFIGURATION:
+ case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
+ case BOOT_WITH_DEFAULT_SETTINGS:
+ default:
+ //
+ // Perform some platform specific connect sequence
+ //
+ ConnectSequence (LocalBootMode);
+
+ //
+ // Only in Full Configuration boot mode we do the enumeration of boot device
+ //
+ //
+ // Dispatch all but Storage Oprom explicitly, because we assume Int13Thunk driver is there.
+ //
+
+ //
+ // PXE boot option may appear after boot option enumeration
+ //
+
+ EfiBootManagerRefreshAllBootOption ();
+ DataSize = sizeof (BOOLEAN);
+ Status = gRT->GetVariable (
+ IS_FIRST_BOOT_VAR_NAME,
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &IsFirstBoot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If can't find the variable, see it as the first boot
+ //
+ IsFirstBoot = TRUE;
+ }
+
+ if (IsFirstBoot) {
+ //
+ // In the first boot, sort the boot option
+ //
+ EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, CompareBootOption);
+ IsFirstBoot = FALSE;
+ Status = gRT->SetVariable (
+ IS_FIRST_BOOT_VAR_NAME,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (BOOLEAN),
+ &IsFirstBoot
+ );
+ }
+
+ break;
+ }
+
+ HandleIpmiBootOverride ();
+
+ Print (L"Press F2 for Setup, or F7 for BootMenu!\n");
+
+ #ifdef INTERNAL_IDS
+ PrintSocOpnInfo ();
+ #endif
+}
+
+#ifdef INTERNAL_IDS
+
+/**
+ Display CPU OPN on Splash screen After console ready.
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+PrintSocOpnInfo (
+ IN VOID
+ )
+{
+ CHAR16 OpnChar[(sizeof (UINT64) / sizeof (UINT8)) * (MSR_CPUID_NAME_STRING5 - MSR_CPUID_NAME_STRING0 + 1) + 1];
+ UINT32 Msr;
+ UINT64 Value;
+ UINTN CharIndex;
+ UINTN ByteIndex;
+
+ CharIndex = 0;
+ for (Msr = MSR_CPUID_NAME_STRING0; Msr <= MSR_CPUID_NAME_STRING5; Msr++) {
+ Value = AsmReadMsr64 (Msr);
+ for (ByteIndex = 0; ByteIndex < (sizeof (UINT64) / sizeof (UINT8)); ByteIndex++) {
+ OpnChar[CharIndex] = (Value & 0xFF);
+ CharIndex++;
+ Value = RShiftU64 (Value, 8);
+ }
+ }
+
+ OpnChar[CharIndex] = L'\0';
+
+ DEBUG ((DEBUG_INFO, "\nProcessor OPN: "));
+ DEBUG ((DEBUG_INFO, "%s\n", OpnChar));
+
+ Print (L"Processor OPN: ");
+ Print (OpnChar);
+ Print (L"\n\r");
+
+ return EFI_SUCCESS;
+}
+
+#endif
diff --git a/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.inf b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.inf
new file mode 100644
index 0000000000..23e834e332
--- /dev/null
+++ b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBdsHookLib.inf
@@ -0,0 +1,105 @@
+### @file
+# Module Information file for the Bds Hook Library.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2023- 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = BoardBdsHookLib
+ FILE_GUID = A500CFFB-26DA-4CB1-B214-EC16524C9733
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = BoardBdsHookLib|DXE_DRIVER
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DxeServicesLib
+ DxeServicesTableLib
+ HiiLib
+ HobLib
+ IpmiCommandLib
+ IpmiLib
+ MemoryAllocationLib
+ PcdLib
+ PerformanceLib
+ PrintLib
+ SortLib
+ Tcg2PhysicalPresenceLib
+ TimerLib
+ UefiBootManagerLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Packages]
+ AmdMinBoardPkg/AmdMinBoardPkg.dec
+ BoardModulePkg/BoardModulePkg.dec
+ IpmiFeaturePkg/IpmiFeaturePkg.dec
+ ManageabilityPkg/ManageabilityPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ MinPlatformPkg/MinPlatformPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut ## PRODUCES
+ gMinPlatformPkgTokenSpaceGuid.PcdBootToShellOnly ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdPlatformMemoryCheckLevel ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdShellFile ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdShellFileDesc ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdTpm2Enable ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdTrustedConsoleInputDevicePath ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdTrustedConsoleOutputDevicePath ## CONSUMES
+ gMinPlatformPkgTokenSpaceGuid.PcdTrustedStorageDevicePath ## CONSUMES
+
+[Sources]
+ BoardBdsHook.h
+ BoardBdsHookLib.c
+ BoardBootOption.c
+ BoardMemoryTest.c
+
+[Protocols]
+ gAmdBoardBdsBootOptionPriorityProtocolGuid ## CONSUMES
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## CONSUMES
+ gEfiDiskInfoProtocolGuid ## CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+ gEfiDxeSmmReadyToLockProtocolGuid ## PRODUCES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiGenericMemTestProtocolGuid ## CONSUMES
+ gEfiGenericMemTestProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## CONSUMES
+ gEfiPciRootBridgeIoProtocolGuid ## CONSUMES
+ gEfiSimpleTextInputExProtocolGuid ## CONSUMES
+
+[Guids]
+ gBdsEventAfterConsoleReadyBeforeBootOptionGuid
+ gBdsEventBeforeConsoleAfterTrustedConsoleGuid
+ gBdsEventBeforeConsoleBeforeEndOfDxeGuid
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES
+ gEfiGlobalVariableGuid ## PRODUCES
+ gEfiMemoryOverwriteControlDataGuid ## PRODUCES
+
+[Depex.common.DXE_DRIVER]
+ gEfiVariableArchProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBootOption.c b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBootOption.c
new file mode 100644
index 0000000000..16a47c2f82
--- /dev/null
+++ b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardBootOption.c
@@ -0,0 +1,754 @@
+/** @file
+ Driver for Platform Boot Options support.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BoardBdsHook.h"
+
+EFI_GUID gUefiShellFileGuid = { 0 };
+EFI_GUID mUiFile = {
+ 0x462CAA21, 0x7614, 0x4503, { 0x83, 0x6E, 0x8A, 0xB6, 0xF4, 0x66, 0x23, 0x31 }
+};
+EFI_GUID mBootMenuFile = {
+ 0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D }
+};
+
+BOOLEAN mContinueBoot = FALSE;
+BOOLEAN mBootMenuBoot = FALSE;
+BOOLEAN mPxeBoot = FALSE;
+BOOLEAN mHotKeypressed = FALSE;
+EFI_EVENT HotKeyEvent = NULL;
+
+UINTN mBootMenuOptionNumber;
+UINTN mSetupOptionNumber;
+
+/**
+ This function will create a SHELL BootOption to boot.
+
+ @return Shell Device path for booting.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BdsCreateShellDevicePath (
+ VOID
+ )
+{
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINTN Size;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ VOID *Buffer;
+
+ DevicePath = NULL;
+ Status = EFI_SUCCESS;
+
+ DEBUG ((DEBUG_INFO, "BdsCreateShellDevicePath\n"));
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&Fv
+ );
+
+ Buffer = NULL;
+ Size = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &gUefiShellFileGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Buffer,
+ &Size,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if no shell file in the FV
+ //
+ continue;
+ } else {
+ //
+ // Found the shell
+ //
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No shell present
+ //
+ if (FvHandleCount) {
+ FreePool (FvHandleBuffer);
+ }
+
+ return NULL;
+ }
+
+ //
+ // Build the shell boot option
+ //
+ DevicePath = DevicePathFromHandle (FvHandleBuffer[Index]);
+
+ if (FvHandleCount) {
+ FreePool (FvHandleBuffer);
+ }
+
+ return DevicePath;
+}
+
+/**
+ Create Boot option for passed Firmware Volume.
+
+ @param[in] FileGuid FV file name to use in FvDevicePathNode
+ @param[in] Description Description of the load option.
+ @param[in, out] BootOption Pointer to the load option to be initialized.
+ @param[in] Attributes Attributes of the load option.
+ @param[in] OptionalData Optional data of the load option.
+ @param[in] OptionalDataSize Size of the optional data of the load option.
+
+ @retval EFI_SUCCESS The load option was initialized successfully.
+ @retval EFI_INVALID_PARAMETER BootOption, Description or FileGuid is NULL.
+**/
+EFI_STATUS
+CreateFvBootOption (
+ IN EFI_GUID *FileGuid,
+ IN CHAR16 *Description,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
+ IN UINT32 Attributes,
+ IN UINT8 *OptionalData, OPTIONAL IN UINT32 OptionalDataSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINT32 AuthenticationStatus;
+ VOID *Buffer;
+ UINTN Size;
+
+ if ((BootOption == NULL) || (FileGuid == NULL) || (Description == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+
+ if (!CompareGuid (&gUefiShellFileGuid, FileGuid)) {
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ LoadedImage->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Buffer = NULL;
+ Size = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ FileGuid,
+ EFI_SECTION_PE32,
+ 0,
+ &Buffer,
+ &Size,
+ &AuthenticationStatus
+ );
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ DevicePath = AppendDevicePathNode (
+ DevicePathFromHandle (LoadedImage->DeviceHandle),
+ (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
+ );
+ } else {
+ DevicePath = AppendDevicePathNode (
+ BdsCreateShellDevicePath (),
+ (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
+ );
+ }
+
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ OptionalData,
+ OptionalDataSize
+ );
+ FreePool (DevicePath);
+ return Status;
+}
+
+/**
+ Return the index of the load option in the load option array.
+
+ The function consider two load options are equal when the
+ OptionType, Attributes, Description, FilePath and OptionalData are equal.
+
+ @param[in] Key Pointer to the load option to be found.
+ @param[in] Array Pointer to the array of load options to be found.
+ @param[in] Count Number of entries in the Array.
+
+ @retval -1 Key wasn't found in the Array.
+ @retval 0 ~ Count-1 The index of the Key in the Array.
+**/
+INTN
+PlatformFindLoadOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if ((Key->OptionType == Array[Index].OptionType) &&
+ (Key->Attributes == Array[Index].Attributes) &&
+ (StrCmp (Key->Description, Array[Index].Description) == 0) &&
+ (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
+ (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
+ (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0))
+ {
+ return (INTN)Index;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ Registers a boot option.
+
+ @param[in] FileGuid Boot file GUID
+ @param[in] Description Boot option description
+ @param[in] Position Position of the new load option to put in the ****Order variable.
+ @param[in] Attributes Boot option attributes
+ @param[in] OptionalData Optional data of the boot option.
+ @param[in] OptionalDataSize Size of the optional data of the boot option
+
+ @return boot option number
+**/
+UINTN
+RegisterFvBootOption (
+ IN EFI_GUID *FileGuid,
+ IN CHAR16 *Description,
+ IN UINTN Position,
+ IN UINT32 Attributes,
+ IN UINT8 *OptionalData, OPTIONAL IN UINT32 OptionalDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+
+ NewOption.OptionNumber = LoadOptionNumberUnassigned;
+ Status = CreateFvBootOption (FileGuid, Description, &NewOption, Attributes, OptionalData, OptionalDataSize);
+ if (!EFI_ERROR (Status)) {
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, Position);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ NewOption.OptionNumber = BootOptions[OptionIndex].OptionNumber;
+ }
+
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ }
+
+ return NewOption.OptionNumber;
+}
+
+/**
+ Boot manager wait callback.
+
+ @param[in] TimeoutRemain The remaining timeout period
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ IN UINT16 TimeoutRemain
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ EFI_KEY_DATA KeyData;
+ BOOLEAN PausePressed;
+
+ //
+ // Pause on PAUSE key
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);
+ ASSERT_EFI_ERROR (Status);
+
+ PausePressed = FALSE;
+
+ while (TRUE) {
+ Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (KeyData.Key.ScanCode == SCAN_PAUSE) {
+ PausePressed = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Loop until non-PAUSE key pressed
+ //
+ while (PausePressed) {
+ Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "[PauseCallback] %x/%x %x/%x\n",
+ KeyData.Key.ScanCode,
+ KeyData.Key.UnicodeChar,
+ KeyData.KeyState.KeyShiftState,
+ KeyData.KeyState.KeyToggleState
+ ));
+ PausePressed = (BOOLEAN)(KeyData.Key.ScanCode == SCAN_PAUSE);
+ }
+ }
+}
+
+/**
+ Registers default boot option.
+**/
+VOID
+RegisterDefaultBootOption (
+ VOID
+ )
+{
+ UINT16 *ShellData;
+ UINT32 ShellDataSize;
+
+ ShellData = NULL;
+ ShellDataSize = 0;
+ CopyMem (&gUefiShellFileGuid, PcdGetPtr (PcdShellFile), sizeof (GUID));
+ RegisterFvBootOption (&gUefiShellFileGuid, (CHAR16 *)PcdGetPtr (PcdShellFileDesc), (UINTN)-1, LOAD_OPTION_ACTIVE, (UINT8 *)ShellData, ShellDataSize);
+
+ //
+ // Boot Menu
+ //
+ mBootMenuOptionNumber = RegisterFvBootOption (&mBootMenuFile, L"Boot Device List", (UINTN)-1, LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN, NULL, 0);
+
+ if (mBootMenuOptionNumber == LoadOptionNumberUnassigned) {
+ DEBUG ((DEBUG_INFO, "BootMenuOptionNumber (%d) should not be same to LoadOptionNumberUnassigned(%d).\n", mBootMenuOptionNumber, LoadOptionNumberUnassigned));
+ }
+
+ //
+ // Boot Manager Menu
+ //
+ mSetupOptionNumber = RegisterFvBootOption (&mUiFile, L"Enter Setup", (UINTN)-1, LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN, NULL, 0);
+}
+
+/**
+ Registers/Unregisters boot option hotkey.
+
+ @param[in] OptionNumber The boot option number for the key option.
+ @param[in] Key The key input
+ @param[in] Add Flag to indicate to add or remove a key
+**/
+VOID
+RegisterBootOptionHotkey (
+ IN UINT16 OptionNumber,
+ IN EFI_INPUT_KEY *Key,
+ IN BOOLEAN Add
+ )
+{
+ EFI_STATUS Status;
+
+ if (!Add) {
+ //
+ // No enter hotkey when force to setup or there is no boot option
+ //
+ Status = EfiBootManagerDeleteKeyOptionVariable (NULL, 0, Key, NULL);
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+ } else {
+ //
+ // Register enter hotkey for the first boot option
+ //
+ Status = EfiBootManagerAddKeyOptionVariable (NULL, OptionNumber, 0, Key, NULL);
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+ }
+}
+
+/**
+ Detect key press callback.
+
+ @param[in] KeyData The key data
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+DetectKeypressCallback (
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ mHotKeypressed = TRUE;
+
+ if (HotKeyEvent != NULL) {
+ gBS->SignalEvent (HotKeyEvent);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called after all the boot options are enumerated and ordered properly.
+**/
+VOID
+RegisterStaticHotkey (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Enter;
+ EFI_KEY_DATA F2;
+ EFI_KEY_DATA F7;
+ BOOLEAN EnterSetup;
+
+ EnterSetup = FALSE;
+
+ //
+ // [Enter]
+ //
+ mContinueBoot = !EnterSetup;
+ if (mContinueBoot) {
+ Enter.ScanCode = SCAN_NULL;
+ Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+ EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+ }
+
+ //
+ // [F2]
+ //
+ if (mSetupOptionNumber != LoadOptionNumberUnassigned) {
+ F2.Key.ScanCode = SCAN_F2;
+ F2.Key.UnicodeChar = CHAR_NULL;
+ F2.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ F2.KeyState.KeyToggleState = 0;
+ RegisterBootOptionHotkey ((UINT16)mSetupOptionNumber, &F2.Key, TRUE);
+ }
+
+ //
+ // Register [F7] only when the mBootMenuOptionNumber is valid
+ //
+ if (mBootMenuOptionNumber != LoadOptionNumberUnassigned) {
+ F7.Key.ScanCode = SCAN_F7;
+ F7.Key.UnicodeChar = CHAR_NULL;
+ F7.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ F7.KeyState.KeyToggleState = 0;
+ mBootMenuBoot = !EnterSetup;
+ RegisterBootOptionHotkey ((UINT16)mBootMenuOptionNumber, &F7.Key, mBootMenuBoot);
+ }
+}
+
+/**
+ Returns the boot option type of a device.
+
+ @param[in] DevicePath The DevicePath whose boot option type is
+ to be returned
+ @retval -1 Device type not found
+ @retval > -1 Device type found
+**/
+UINT8
+BootOptionType (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *NextNode;
+
+ for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
+ if (DevicePathType (Node) == MESSAGING_DEVICE_PATH) {
+ //
+ // Make sure the device path points to the driver device.
+ //
+ NextNode = NextDevicePathNode (Node);
+ if (DevicePathSubType (NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
+ //
+ // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
+ // skip it
+ //
+ NextNode = NextDevicePathNode (NextNode);
+ }
+
+ if (IsDevicePathEndType (NextNode)) {
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH)) {
+ return DevicePathSubType (Node);
+ } else {
+ return MSG_SATA_DP;
+ }
+ }
+ }
+ }
+
+ return (UINT8)-1;
+}
+
+/**
+ Returns the priority number.
+
+ @param[in] BootOption Load option to get the priority value for
+ @retval
+ OptionType EFI
+ ------------------------------------
+ PXE 2
+ DVD 4
+ USB 6
+ NVME 7
+ HDD 8
+ EFI Shell 9
+ Others 100
+
+**/
+UINTN
+BootOptionPriority (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ //
+ // EFI boot options
+ //
+ switch (BootOptionType (BootOption->FilePath)) {
+ case MSG_MAC_ADDR_DP:
+ case MSG_VLAN_DP:
+ case MSG_IPv4_DP:
+ case MSG_IPv6_DP:
+ return 2;
+
+ case MSG_SATA_DP:
+ case MSG_ATAPI_DP:
+ case MSG_UFS_DP:
+ case MSG_NVME_NAMESPACE_DP:
+ return 4;
+
+ case MSG_USB_DP:
+ return 6;
+ }
+
+ if (StrCmp (BootOption->Description, (CHAR16 *)PcdGetPtr (PcdShellFileDesc)) == 0) {
+ if (PcdGetBool (PcdBootToShellOnly)) {
+ return 0;
+ }
+
+ return 9;
+ }
+
+ if (StrCmp (BootOption->Description, UEFI_HARD_DRIVE_NAME) == 0) {
+ return 8;
+ }
+
+ return 100;
+}
+
+/**
+ Returns the priority number while giving PXE highest
+ priority.
+
+ @param[in] BootOption Load option to get the priority value for
+ @retval
+ OptionType EFI
+ ------------------------------------
+ PXE 2
+ DVD 4
+ USB 6
+ NVME 7
+ HDD 8
+ EFI Shell 9
+ Others 100
+**/
+UINTN
+PxeBootOptionPriority (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ //
+ // EFI boot options
+ //
+ switch (BootOptionType (BootOption->FilePath)) {
+ case MSG_MAC_ADDR_DP:
+ case MSG_VLAN_DP:
+ case MSG_IPv4_DP:
+ case MSG_IPv6_DP:
+ return 2;
+
+ case MSG_SATA_DP:
+ case MSG_ATAPI_DP:
+ case MSG_UFS_DP:
+ case MSG_NVME_NAMESPACE_DP:
+ return 4;
+
+ case MSG_USB_DP:
+ return 6;
+ }
+
+ if (StrCmp (BootOption->Description, (CHAR16 *)PcdGetPtr (PcdShellFileDesc)) == 0) {
+ if (PcdGetBool (PcdBootToShellOnly)) {
+ return 0;
+ }
+
+ return 9;
+ }
+
+ if (StrCmp (BootOption->Description, UEFI_HARD_DRIVE_NAME) == 0) {
+ return 8;
+ }
+
+ return 100;
+}
+
+/**
+ Returns the priority number while giving HDD, DVD, and NVME highest priority.
+
+ @param[in] BootOption Load option to get the priority value for
+ @retval
+ OptionType EFI
+ ------------------------------------
+ NVME, DVD, HDD 2
+ PXE 4
+ USB 6
+ HDD 8
+ EFI Shell 9
+ Others 100
+**/
+UINTN
+HddBootOptionPriority (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ //
+ // EFI boot options
+ //
+ switch (BootOptionType (BootOption->FilePath)) {
+ case MSG_SATA_DP:
+ case MSG_UFS_DP:
+ case MSG_NVME_NAMESPACE_DP:
+ return 2;
+
+ case MSG_ATAPI_DP:
+ return 3;
+
+ case MSG_MAC_ADDR_DP:
+ case MSG_VLAN_DP:
+ case MSG_IPv4_DP:
+ case MSG_IPv6_DP:
+ return 4;
+
+ case MSG_USB_DP:
+ return 6;
+ }
+
+ if (StrCmp (BootOption->Description, (CHAR16 *)PcdGetPtr (PcdShellFileDesc)) == 0) {
+ if (PcdGetBool (PcdBootToShellOnly)) {
+ return 0;
+ }
+
+ return 9;
+ }
+
+ if (StrCmp (BootOption->Description, UEFI_HARD_DRIVE_NAME) == 0) {
+ return 2;
+ }
+
+ return 100;
+}
+
+/**
+ Compares boot priorities of two boot options.
+
+ @param[in] Left The left boot option
+ @param[in] Right The right boot option
+
+ @retval The difference between the Left and Right
+ boot options
+ **/
+INTN
+EFIAPI
+CompareBootOption (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ )
+{
+ return BootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *)Left) -
+ BootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *)Right);
+}
+
+/**
+ Compares boot priorities of two boot options, while giving PXE the highest priority.
+
+ @param[in] Left The left boot option
+ @param[in] Right The right boot option
+
+ @retval The difference between the Left and Right
+ boot options
+ **/
+INTN
+EFIAPI
+CompareBootOptionPxePriority (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ )
+{
+ return PxeBootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *)Left) -
+ PxeBootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *)Right);
+}
+
+/**
+ Compares boot priorities of two boot options, while giving HDD the highest priority.
+
+ @param[in] Left The left boot option
+ @param[in] Right The right boot option
+
+ @retval The difference between the Left and Right
+ boot options
+ **/
+INTN
+EFIAPI
+CompareBootOptionHddPriority (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ )
+{
+ return HddBootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *)Left) -
+ HddBootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *)Right);
+}
diff --git a/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardMemoryTest.c b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardMemoryTest.c
new file mode 100644
index 0000000000..fff0ef2993
--- /dev/null
+++ b/Platform/AMD/AmdMinBoardPkg/Library/BoardBdsHookLib/BoardMemoryTest.c
@@ -0,0 +1,83 @@
+/** @file
+ Perform the platform memory test
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "BoardBdsHook.h"
+#include <Protocol/GenericMemoryTest.h>
+
+/**
+ Perform the memory test base on the memory test intensive level,
+ and update the memory resource.
+
+ @param[in] Level The memory test intensive level.
+
+ @retval EFI_STATUS Success test all the system memory and update
+ the memory resource
+
+**/
+EFI_STATUS
+MemoryTest (
+ IN EXTENDMEM_COVERAGE_LEVEL Level
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN RequireSoftECCInit;
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
+ UINT64 TestedMemorySize;
+ UINT64 TotalMemorySize;
+ BOOLEAN ErrorOut;
+ BOOLEAN TestAbort;
+
+ TestedMemorySize = 0;
+ TotalMemorySize = 0;
+ ErrorOut = FALSE;
+ TestAbort = FALSE;
+
+ RequireSoftECCInit = FALSE;
+
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **)&GenMemoryTest
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ Status = GenMemoryTest->MemoryTestInit (
+ GenMemoryTest,
+ Level,
+ &RequireSoftECCInit
+ );
+ if (Status == EFI_NO_MEDIA) {
+ //
+ // The PEI codes also have the relevant memory test code to check the memory,
+ // it can select to test some range of the memory or all of them. If PEI code
+ // checks all the memory, this BDS memory test will has no not-test memory to
+ // do the test, and then the status of EFI_NO_MEDIA will be returned by
+ // "MemoryTestInit". So it does not need to test memory again, just return.
+ //
+ return EFI_SUCCESS;
+ }
+
+ do {
+ Status = GenMemoryTest->PerformMemoryTest (
+ GenMemoryTest,
+ &TestedMemorySize,
+ &TotalMemorySize,
+ &ErrorOut,
+ TestAbort
+ );
+ if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
+ ASSERT (0);
+ }
+ } while (Status != EFI_NOT_FOUND);
+
+ Status = GenMemoryTest->Finished (GenMemoryTest);
+
+ return EFI_SUCCESS;
+}
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118979): https://edk2.groups.io/g/devel/message/118979
Mute This Topic: https://groups.io/mt/106148095/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 7+ messages in thread