| /*++ @file | |
| Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> | |
| Portions copyright (c) 2011, Apple Inc. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "PlatformBm.h" | |
| EFI_GUID mBootMenuFile = { | |
| 0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D } | |
| }; | |
| /** | |
| Initialize the "Setup" variable. | |
| **/ | |
| VOID | |
| SetupVariableInit ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Size; | |
| EMU_SYSTEM_CONFIGURATION SystemConfigData; | |
| Size = sizeof (SystemConfigData); | |
| Status = gRT->GetVariable ( | |
| L"Setup", | |
| &gEmuSystemConfigGuid, | |
| NULL, | |
| &Size, | |
| (VOID *)&SystemConfigData | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // SetupVariable is corrupt | |
| // | |
| SystemConfigData.ConOutRow = PcdGet32 (PcdConOutColumn); | |
| SystemConfigData.ConOutColumn = PcdGet32 (PcdConOutRow); | |
| Status = gRT->SetVariable ( | |
| L"Setup", | |
| &gEmuSystemConfigGuid, | |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
| sizeof (SystemConfigData), | |
| (VOID *)&SystemConfigData | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status)); | |
| } | |
| } | |
| } | |
| EFI_DEVICE_PATH * | |
| FvFilePath ( | |
| EFI_GUID *FileGuid | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; | |
| MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode; | |
| EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid); | |
| Status = gBS->HandleProtocol ( | |
| gImageHandle, | |
| &gEfiLoadedImageProtocolGuid, | |
| (VOID **)&LoadedImage | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return AppendDevicePathNode ( | |
| DevicePathFromHandle (LoadedImage->DeviceHandle), | |
| (EFI_DEVICE_PATH_PROTOCOL *)&FileNode | |
| ); | |
| } | |
| /** | |
| Create one boot option for BootManagerMenuApp. | |
| @param FileGuid Input file guid for the BootManagerMenuApp. | |
| @param Description Description of the BootManagerMenuApp boot option. | |
| @param Position Position of the new load option to put in the ****Order variable. | |
| @param IsBootCategory Whether this is a boot category. | |
| @retval OptionNumber Return the option number info. | |
| **/ | |
| UINTN | |
| RegisterBootManagerMenuAppBootOption ( | |
| EFI_GUID *FileGuid, | |
| CHAR16 *Description, | |
| UINTN Position, | |
| BOOLEAN IsBootCategory | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_BOOT_MANAGER_LOAD_OPTION NewOption; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| UINTN OptionNumber; | |
| DevicePath = FvFilePath (FileGuid); | |
| Status = EfiBootManagerInitializeLoadOption ( | |
| &NewOption, | |
| LoadOptionNumberUnassigned, | |
| LoadOptionTypeBoot, | |
| IsBootCategory ? LOAD_OPTION_ACTIVE : LOAD_OPTION_CATEGORY_APP, | |
| Description, | |
| DevicePath, | |
| NULL, | |
| 0 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (DevicePath); | |
| Status = EfiBootManagerAddLoadOptionVariable (&NewOption, Position); | |
| ASSERT_EFI_ERROR (Status); | |
| OptionNumber = NewOption.OptionNumber; | |
| EfiBootManagerFreeLoadOption (&NewOption); | |
| return OptionNumber; | |
| } | |
| /** | |
| Check if it's a Device Path pointing to BootManagerMenuApp. | |
| @param DevicePath Input device path. | |
| @retval TRUE The device path is BootManagerMenuApp File Device Path. | |
| @retval FALSE The device path is NOT BootManagerMenuApp File Device Path. | |
| **/ | |
| BOOLEAN | |
| IsBootManagerMenuAppFilePath ( | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ) | |
| { | |
| EFI_HANDLE FvHandle; | |
| VOID *NameGuid; | |
| EFI_STATUS Status; | |
| Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle); | |
| if (!EFI_ERROR (Status)) { | |
| NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)DevicePath); | |
| if (NameGuid != NULL) { | |
| return CompareGuid (NameGuid, &mBootMenuFile); | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Return the boot option number to the BootManagerMenuApp. | |
| If not found it in the current boot option, create a new one. | |
| @retval OptionNumber Return the boot option number to the BootManagerMenuApp. | |
| **/ | |
| UINTN | |
| GetBootManagerMenuAppOption ( | |
| VOID | |
| ) | |
| { | |
| UINTN BootOptionCount; | |
| EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; | |
| UINTN Index; | |
| UINTN OptionNumber; | |
| OptionNumber = 0; | |
| BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); | |
| for (Index = 0; Index < BootOptionCount; Index++) { | |
| if (IsBootManagerMenuAppFilePath (BootOptions[Index].FilePath)) { | |
| OptionNumber = BootOptions[Index].OptionNumber; | |
| break; | |
| } | |
| } | |
| EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); | |
| if (Index >= BootOptionCount) { | |
| // | |
| // If not found the BootManagerMenuApp, create it. | |
| // | |
| OptionNumber = (UINT16)RegisterBootManagerMenuAppBootOption (&mBootMenuFile, L"UEFI BootManagerMenuApp", (UINTN)-1, FALSE); | |
| } | |
| return OptionNumber; | |
| } | |
| /** | |
| Platform Bds init. Include the platform firmware vendor, revision | |
| and so crc check. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PlatformBootManagerBeforeConsole ( | |
| VOID | |
| ) | |
| { | |
| UINTN Index; | |
| SetupVariableInit (); | |
| EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); | |
| Index = 0; | |
| while (gPlatformConsole[Index].DevicePath != NULL) { | |
| // | |
| // Update the console variable with the connect type | |
| // | |
| if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { | |
| EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL); | |
| } | |
| if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { | |
| EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL); | |
| } | |
| if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { | |
| EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL); | |
| } | |
| Index++; | |
| } | |
| } | |
| /** | |
| Connect with predefined platform connect sequence, | |
| the OEM/IBV can customize with their own connect sequence. | |
| **/ | |
| VOID | |
| PlatformBdsConnectSequence ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Just use the simple policy to connect all devices | |
| // | |
| EfiBootManagerConnectAll (); | |
| } | |
| /** | |
| Perform the platform diagnostic, such like test memory. OEM/IBV also | |
| can customize this fuction to support specific platform diagnostic. | |
| @param MemoryTestLevel The memory test intensive level | |
| @param QuietBoot Indicate if need to enable the quiet boot | |
| **/ | |
| VOID | |
| PlatformBdsDiagnostics ( | |
| IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, | |
| IN BOOLEAN QuietBoot | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Here we can decide if we need to show | |
| // the diagnostics screen | |
| // | |
| if (QuietBoot) { | |
| BootLogoEnableLogo (); | |
| // | |
| // Perform system diagnostic | |
| // | |
| Status = PlatformBootManagerMemoryTest (MemoryTestLevel); | |
| if (EFI_ERROR (Status)) { | |
| BootLogoDisableLogo (); | |
| } | |
| return; | |
| } | |
| // | |
| // Perform system diagnostic | |
| // | |
| PlatformBootManagerMemoryTest (MemoryTestLevel); | |
| } | |
| /** | |
| Register the static boot options. | |
| **/ | |
| VOID | |
| PlatformBdsRegisterStaticBootOptions ( | |
| VOID | |
| ) | |
| { | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black; | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL White; | |
| EFI_INPUT_KEY Enter; | |
| EFI_INPUT_KEY F2; | |
| EFI_INPUT_KEY F7; | |
| EFI_BOOT_MANAGER_LOAD_OPTION BootOption; | |
| UINTN OptionNumber; | |
| Black.Blue = Black.Green = Black.Red = Black.Reserved = 0; | |
| White.Blue = White.Green = White.Red = White.Reserved = 0xFF; | |
| // | |
| // Register ENTER as CONTINUE key | |
| // | |
| Enter.ScanCode = SCAN_NULL; | |
| Enter.UnicodeChar = CHAR_CARRIAGE_RETURN; | |
| EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL); | |
| // | |
| // Map F2 to Boot Manager Menu | |
| // | |
| F2.ScanCode = SCAN_F2; | |
| F2.UnicodeChar = CHAR_NULL; | |
| EfiBootManagerGetBootManagerMenu (&BootOption); | |
| EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)BootOption.OptionNumber, 0, &F2, NULL); | |
| // | |
| // 3. Boot Device List menu | |
| // | |
| F7.ScanCode = SCAN_F7; | |
| F7.UnicodeChar = CHAR_NULL; | |
| OptionNumber = GetBootManagerMenuAppOption (); | |
| EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)OptionNumber, 0, &F7, NULL); | |
| PrintXY (10, 10, &White, &Black, L"F2 to enter Setup. "); | |
| PrintXY (10, 30, &White, &Black, L"F7 to enter Boot Manager Menu."); | |
| PrintXY (10, 50, &White, &Black, L"Enter to boot directly."); | |
| } | |
| /** | |
| Returns the priority number. | |
| @param BootOption | |
| **/ | |
| UINTN | |
| BootOptionPriority ( | |
| CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption | |
| ) | |
| { | |
| // | |
| // Make sure Shell is first | |
| // | |
| if (StrCmp (BootOption->Description, L"UEFI Shell") == 0) { | |
| return 0; | |
| } | |
| return 100; | |
| } | |
| INTN | |
| EFIAPI | |
| CompareBootOption ( | |
| CONST EFI_BOOT_MANAGER_LOAD_OPTION *Left, | |
| CONST EFI_BOOT_MANAGER_LOAD_OPTION *Right | |
| ) | |
| { | |
| return BootOptionPriority (Left) - BootOptionPriority (Right); | |
| } | |
| /** | |
| Do the platform specific action after the console is connected. | |
| Such as: | |
| Dynamically switch output mode; | |
| Signal console ready platform customized event; | |
| Run diagnostics like memory testing; | |
| Connect certain devices; | |
| Dispatch aditional option roms. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PlatformBootManagerAfterConsole ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Go the different platform policy with different boot mode | |
| // Notes: this part code can be change with the table policy | |
| // | |
| switch (GetBootModeHob ()) { | |
| case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: | |
| case BOOT_WITH_MINIMAL_CONFIGURATION: | |
| PlatformBdsDiagnostics (IGNORE, TRUE); | |
| // | |
| // Perform some platform specific connect sequence | |
| // | |
| PlatformBdsConnectSequence (); | |
| break; | |
| case BOOT_IN_RECOVERY_MODE: | |
| PlatformBdsDiagnostics (EXTENSIVE, FALSE); | |
| break; | |
| case BOOT_WITH_FULL_CONFIGURATION: | |
| case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: | |
| case BOOT_WITH_DEFAULT_SETTINGS: | |
| default: | |
| PlatformBdsDiagnostics (IGNORE, TRUE); | |
| PlatformBdsConnectSequence (); | |
| EfiBootManagerRefreshAllBootOption (); | |
| PlatformBdsRegisterStaticBootOptions (); | |
| EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, (SORT_COMPARE)CompareBootOption); | |
| break; | |
| } | |
| } | |
| /** | |
| This function is called each second during the boot manager waits the timeout. | |
| @param TimeoutRemain The remaining timeout. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PlatformBootManagerWaitCallback ( | |
| UINT16 TimeoutRemain | |
| ) | |
| { | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black; | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White; | |
| UINT16 Timeout; | |
| Timeout = PcdGet16 (PcdPlatformBootTimeOut); | |
| Black.Raw = 0x00000000; | |
| White.Raw = 0x00FFFFFF; | |
| BootLogoUpdateProgress ( | |
| White.Pixel, | |
| Black.Pixel, | |
| L"Start boot option", | |
| White.Pixel, | |
| (Timeout - TimeoutRemain) * 100 / Timeout, | |
| 0 | |
| ); | |
| } | |
| /** | |
| The function is called when no boot option could be launched, | |
| including platform recovery options and options pointing to applications | |
| built into firmware volumes. | |
| If this function returns, BDS attempts to enter an infinite loop. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PlatformBootManagerUnableToBoot ( | |
| VOID | |
| ) | |
| { | |
| return; | |
| } |