/** @file | |
This file include all platform action which can be customized | |
by IBV/OEM. | |
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "PlatformBootManager.h" | |
EFI_GUID mBootMenuFile = { | |
0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D } | |
}; | |
/** | |
Perform the platform diagnostic, such like test memory. OEM/IBV also | |
can customize this function to support specific platform diagnostic. | |
@param MemoryTestLevel The memory test intensive level | |
@param QuietBoot Indicate if need to enable the quiet boot | |
**/ | |
VOID | |
PlatformBootManagerDiagnostics ( | |
IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, | |
IN BOOLEAN QuietBoot | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Here we can decide if we need to show | |
// the diagnostics screen | |
// Notes: this quiet boot code should be remove | |
// from the graphic lib | |
// | |
if (QuietBoot) { | |
BootLogoEnableLogo (); | |
// | |
// Perform system diagnostic | |
// | |
Status = PlatformBootManagerMemoryTest (MemoryTestLevel); | |
if (EFI_ERROR (Status)) { | |
BootLogoDisableLogo (); | |
} | |
return; | |
} | |
// | |
// Perform system diagnostic | |
// | |
Status = PlatformBootManagerMemoryTest (MemoryTestLevel); | |
} | |
/** | |
Do the platform specific action before the console is connected. | |
Such as: | |
Update console variable; | |
Register new Driver#### or Boot####; | |
Signal ReadyToLock event. | |
**/ | |
VOID | |
EFIAPI | |
PlatformBootManagerBeforeConsole ( | |
VOID | |
) | |
{ | |
UINTN Index; | |
EFI_STATUS Status; | |
WIN_NT_SYSTEM_CONFIGURATION *Configuration; | |
GetVariable2 (L"Setup", &gEfiWinNtSystemConfigGuid, (VOID **) &Configuration, NULL); | |
if (Configuration != NULL) { | |
// | |
// SetupVariable is corrupt | |
// | |
Configuration->ConOutRow = PcdGet32 (PcdConOutColumn); | |
Configuration->ConOutColumn = PcdGet32 (PcdConOutRow); | |
Status = gRT->SetVariable ( | |
L"Setup", | |
&gEfiWinNtSystemConfigGuid, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
sizeof (WIN_NT_SYSTEM_CONFIGURATION), | |
Configuration | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status)); | |
} | |
FreePool (Configuration); | |
} | |
// | |
// Update the ocnsole variables. | |
// | |
for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) { | |
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); | |
} | |
} | |
// | |
// From PI spec vol2: | |
// Prior to invoking any UEFI drivers, applications, or connecting consoles, | |
// the platform should signal the event EFI_END_OF_DXE_EVENT_GUID | |
// | |
EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); | |
// | |
// Dispatch deferred images after EndOfDxe event. | |
// | |
EfiBootManagerDispatchDeferredImages (); | |
} | |
/** | |
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); | |
} | |
/** | |
Generate device path include the input file guid info. | |
@param FileGuid Input file guid for the BootManagerMenuApp. | |
@retval DevicePath for BootManagerMenuApp. | |
**/ | |
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; | |
} | |
/** | |
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 | |
) | |
{ | |
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; | |
EfiBootManagerConnectAll (); | |
EfiBootManagerRefreshAllBootOption (); | |
// | |
// 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); | |
// | |
// Make Shell as the first boot option | |
// | |
EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, (SORT_COMPARE) CompareBootOption); | |
PlatformBootManagerDiagnostics (QUICK, TRUE); | |
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."); | |
} | |
/** | |
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 | |
); | |
} |