123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 |
- /** @file
- Driver for Platform Boot Options support.
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "BdsPlatform.h"
- #include <Library/PcdLib.h>
- BOOLEAN mContinueBoot = FALSE;
- BOOLEAN mBootMenuBoot = FALSE;
- BOOLEAN mPxeBoot = FALSE;
- BOOLEAN mHotKeypressed = FALSE;
- EFI_EVENT HotKeyEvent = NULL;
- UINTN mBootMenuOptionNumber;
- EFI_DEVICE_PATH_PROTOCOL *
- BdsCreateShellDevicePath (
- VOID
- )
- /*++
- Routine Description:
- This function will create a SHELL BootOption to boot.
- Arguments:
- None.
- Returns:
- Shell Device path for booting.
- --*/
- {
- 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;
- }
- EFI_STATUS
- CreateFvBootOption (
- EFI_GUID *FileGuid,
- CHAR16 *Description,
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
- UINT32 Attributes,
- UINT8 *OptionalData, OPTIONAL
- 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;
- }
- 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 }
- };
- /**
- 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 Key Pointer to the load option to be found.
- @param Array Pointer to the array of load options to be found.
- @param 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;
- }
- UINTN
- RegisterFvBootOption (
- EFI_GUID *FileGuid,
- CHAR16 *Description,
- UINTN Position,
- UINT32 Attributes,
- UINT8 *OptionalData, OPTIONAL
- 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;
- }
- VOID
- EFIAPI
- PlatformBootManagerWaitCallback (
- 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);
- }
- }
- }
- EFI_GUID gUefiShellFileGuid = { 0x7C04A583, 0x9E3E, 0x4f1c, { 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 } };
- #define INTERNAL_UEFI_SHELL_NAME L"Internal UEFI Shell 2.0"
- #define UEFI_HARD_DRIVE_NAME L"UEFI Hard Drive"
- VOID
- RegisterDefaultBootOption (
- VOID
- )
- {
- #if 0
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
- #endif
- UINT16 *ShellData;
- UINT32 ShellDataSize;
- ShellData = NULL;
- ShellDataSize = 0;
- RegisterFvBootOption (&gUefiShellFileGuid, INTERNAL_UEFI_SHELL_NAME, (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));
- }
- #if 0
- //
- // Boot Manager Menu
- //
- EfiInitializeFwVolDevicepathNode (&FileNode, &mUiFile);
- gBS->HandleProtocol (
- gImageHandle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **) &LoadedImage
- );
- DevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), (EFI_DEVICE_PATH_PROTOCOL *) &FileNode);
- #endif
- }
- VOID
- RegisterBootOptionHotkey (
- UINT16 OptionNumber,
- EFI_INPUT_KEY *Key,
- 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);
- }
- }
- 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;
- EFI_STATUS Status;
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
- EnterSetup = FALSE;
- //
- // [Enter]
- //
- mContinueBoot = !EnterSetup;
- if (mContinueBoot) {
- Enter.ScanCode = SCAN_NULL;
- Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
- EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
- }
- //
- // [F2]/[F7]
- //
- F2.Key.ScanCode = SCAN_F2;
- F2.Key.UnicodeChar = CHAR_NULL;
- F2.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
- F2.KeyState.KeyToggleState = 0;
- Status = EfiBootManagerGetBootManagerMenu (&BootOption);
- ASSERT_EFI_ERROR (Status);
- RegisterBootOptionHotkey ((UINT16) BootOption.OptionNumber, &F2.Key, TRUE);
- EfiBootManagerFreeLoadOption (&BootOption);
- 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);
- }
- 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.
- OptionType EFI
- ------------------------------------
- PXE 2
- DVD 4
- USB 6
- NVME 7
- HDD 8
- EFI Shell 9
- Others 100
- @param BootOption
- **/
- UINTN
- BootOptionPriority (
- 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, INTERNAL_UEFI_SHELL_NAME) == 0) {
- if (PcdGetBool (PcdBootToShellOnly)) {
- return 0;
- }
- return 9;
- }
- if (StrCmp (BootOption->Description, UEFI_HARD_DRIVE_NAME) == 0) {
- return 8;
- }
- return 100;
- }
- INTN
- EFIAPI
- CompareBootOption (
- CONST VOID *Left,
- CONST VOID *Right
- )
- {
- return BootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *) Left) -
- BootOptionPriority ((EFI_BOOT_MANAGER_LOAD_OPTION *) Right);
- }
|