Implements BoardBdsHookLib library class for AMD platforms. Cc: Abner Chang <abner.ch...@amd.com> Cc: Paul Grimes <paul.gri...@amd.com> Signed-off-by: Abdul Lateef Attar <abdullateef.at...@amd.com> --- .../AMD/AmdMinBoardPkg/AmdMinBoardPkg.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/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-