+++ /dev/null
-/** @file\r
- Provides a way for 3rd party applications to register themselves for launch by the\r
- Boot Manager based on hot key\r
-\r
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "Hotkey.h"\r
-\r
-\r
-LIST_ENTRY mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);\r
-BDS_COMMON_OPTION *mHotkeyBootOption = NULL;\r
-EFI_EVENT mHotkeyEvent;\r
-VOID *mHotkeyRegistration;\r
-\r
-\r
-/**\r
- Check if the Key Option is valid or not.\r
-\r
- @param KeyOption The Hot Key Option to be checked.\r
-\r
- @retval TRUE The Hot Key Option is valid.\r
- @retval FALSE The Hot Key Option is invalid.\r
-\r
-**/\r
-BOOLEAN\r
-IsKeyOptionValid (\r
- IN EFI_KEY_OPTION *KeyOption\r
-)\r
-{\r
- UINT16 BootOptionName[10];\r
- UINT8 *BootOptionVar;\r
- UINTN BootOptionSize;\r
- UINT32 Crc;\r
-\r
- //\r
- // Check whether corresponding Boot Option exist\r
- //\r
- UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", KeyOption->BootOption);\r
- BootOptionVar = BdsLibGetVariableAndSize (\r
- BootOptionName,\r
- &gEfiGlobalVariableGuid,\r
- &BootOptionSize\r
- );\r
-\r
- if (BootOptionVar == NULL || BootOptionSize == 0) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // Check CRC for Boot Option\r
- //\r
- gBS->CalculateCrc32 (BootOptionVar, BootOptionSize, &Crc);\r
- FreePool (BootOptionVar);\r
-\r
- return (BOOLEAN) ((KeyOption->BootOptionCrc == Crc) ? TRUE : FALSE);\r
-}\r
-\r
-/**\r
- Try to boot the boot option triggered by hotkey.\r
- @retval EFI_SUCCESS There is HotkeyBootOption & it is processed\r
- @retval EFI_NOT_FOUND There is no HotkeyBootOption\r
-**/\r
-EFI_STATUS\r
-HotkeyBoot (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN ExitDataSize;\r
- CHAR16 *ExitData;\r
-\r
- if (mHotkeyBootOption == NULL) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- BdsLibConnectDevicePath (mHotkeyBootOption->DevicePath);\r
-\r
- //\r
- // Clear the screen before launch this BootOption\r
- //\r
- gST->ConOut->Reset (gST->ConOut, FALSE);\r
-\r
- Status = BdsLibBootViaBootOption (mHotkeyBootOption, mHotkeyBootOption->DevicePath, &ExitDataSize, &ExitData);\r
-\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Call platform action to indicate the boot fail\r
- //\r
- mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));\r
- PlatformBdsBootFail (mHotkeyBootOption, Status, ExitData, ExitDataSize);\r
- } else {\r
- //\r
- // Call platform action to indicate the boot success\r
- //\r
- mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));\r
- PlatformBdsBootSuccess (mHotkeyBootOption);\r
- }\r
- FreePool (mHotkeyBootOption->Description);\r
- FreePool (mHotkeyBootOption->DevicePath);\r
- FreePool (mHotkeyBootOption->LoadOptions);\r
- FreePool (mHotkeyBootOption);\r
-\r
- mHotkeyBootOption = NULL;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-\r
- This is the common notification function for HotKeys, it will be registered\r
- with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.\r
-\r
- @param KeyData A pointer to a buffer that is filled in with the keystroke\r
- information for the key that was pressed.\r
-\r
- @retval EFI_SUCCESS KeyData is successfully processed.\r
- @return EFI_NOT_FOUND Fail to find boot option variable.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-HotkeyCallback (\r
- IN EFI_KEY_DATA *KeyData\r
-)\r
-{\r
- BOOLEAN HotkeyCatched;\r
- LIST_ENTRY BootLists;\r
- LIST_ENTRY *Link;\r
- BDS_HOTKEY_OPTION *Hotkey;\r
- UINT16 Buffer[10];\r
- EFI_STATUS Status;\r
- EFI_KEY_DATA *HotkeyData;\r
-\r
- if (mHotkeyBootOption != NULL) {\r
- //\r
- // Do not process sequential hotkey stroke until the current boot option returns\r
- //\r
- return EFI_SUCCESS;\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- for ( Link = GetFirstNode (&mHotkeyList)\r
- ; !IsNull (&mHotkeyList, Link)\r
- ; Link = GetNextNode (&mHotkeyList, Link)\r
- ) {\r
- HotkeyCatched = FALSE;\r
- Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);\r
-\r
- //\r
- // Is this Key Stroke we are waiting for?\r
- //\r
- ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));\r
- HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];\r
- if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&\r
- (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&\r
- (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?\r
- (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE\r
- )\r
- ) {\r
- //\r
- // For hotkey of key combination, transit to next waiting state\r
- //\r
- Hotkey->WaitingKey++;\r
-\r
- if (Hotkey->WaitingKey == Hotkey->CodeCount) {\r
- //\r
- // Received the whole key stroke sequence\r
- //\r
- HotkeyCatched = TRUE;\r
- }\r
- } else {\r
- //\r
- // Receive an unexpected key stroke, reset to initial waiting state\r
- //\r
- Hotkey->WaitingKey = 0;\r
- }\r
-\r
- if (HotkeyCatched) {\r
- //\r
- // Reset to initial waiting state\r
- //\r
- Hotkey->WaitingKey = 0;\r
-\r
- //\r
- // Launch its BootOption\r
- //\r
- InitializeListHead (&BootLists);\r
-\r
- UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);\r
- mHotkeyBootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Register the common HotKey notify function to given SimpleTextInEx protocol instance.\r
-\r
- @param SimpleTextInEx Simple Text Input Ex protocol instance\r
-\r
- @retval EFI_SUCCESS Register hotkey notification function successfully.\r
- @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.\r
-\r
-**/\r
-EFI_STATUS\r
-HotkeyRegisterNotify (\r
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx\r
-)\r
-{\r
- UINTN Index;\r
- EFI_STATUS Status;\r
- LIST_ENTRY *Link;\r
- BDS_HOTKEY_OPTION *Hotkey;\r
-\r
- //\r
- // Register notification function for each hotkey\r
- //\r
- Link = GetFirstNode (&mHotkeyList);\r
-\r
- while (!IsNull (&mHotkeyList, Link)) {\r
- Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);\r
-\r
- Index = 0;\r
- do {\r
- Status = SimpleTextInEx->RegisterKeyNotify (\r
- SimpleTextInEx,\r
- &Hotkey->KeyData[Index],\r
- HotkeyCallback,\r
- &Hotkey->NotifyHandle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // some of the hotkey registry failed\r
- //\r
- return Status;\r
- }\r
- Index ++;\r
- } while ((Index < Hotkey->CodeCount) && (Index < (sizeof (Hotkey->KeyData) / sizeof (EFI_KEY_DATA))));\r
-\r
- Link = GetNextNode (&mHotkeyList, Link);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Callback function for SimpleTextInEx protocol install events\r
-\r
- @param Event the event that is signaled.\r
- @param Context not used here.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-HotkeyEvent (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN BufferSize;\r
- EFI_HANDLE Handle;\r
- EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;\r
-\r
- while (TRUE) {\r
- BufferSize = sizeof (EFI_HANDLE);\r
- Status = gBS->LocateHandle (\r
- ByRegisterNotify,\r
- NULL,\r
- mHotkeyRegistration,\r
- &BufferSize,\r
- &Handle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // If no more notification events exist\r
- //\r
- return ;\r
- }\r
-\r
- Status = gBS->HandleProtocol (\r
- Handle,\r
- &gEfiSimpleTextInputExProtocolGuid,\r
- (VOID **) &SimpleTextInEx\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- HotkeyRegisterNotify (SimpleTextInEx);\r
- }\r
-}\r
-\r
-/**\r
- Insert Key Option to hotkey list.\r
-\r
- @param KeyOption The Hot Key Option to be added to hotkey list.\r
-\r
- @retval EFI_SUCCESS Add to hotkey list success.\r
- @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource.\r
-**/\r
-EFI_STATUS\r
-HotkeyInsertList (\r
- IN EFI_KEY_OPTION *KeyOption\r
-)\r
-{\r
- BDS_HOTKEY_OPTION *HotkeyLeft;\r
- BDS_HOTKEY_OPTION *HotkeyRight;\r
- UINTN Index;\r
- EFI_BOOT_KEY_DATA KeyOptions;\r
- UINT32 KeyShiftStateLeft;\r
- UINT32 KeyShiftStateRight;\r
- EFI_INPUT_KEY *InputKey;\r
- EFI_KEY_DATA *KeyData;\r
-\r
- HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));\r
- if (HotkeyLeft == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;\r
- HotkeyLeft->BootOptionNumber = KeyOption->BootOption;\r
-\r
- KeyOptions = KeyOption->KeyData;\r
-\r
- HotkeyLeft->CodeCount = (UINT8) KeyOptions.Options.InputKeyCount;\r
-\r
- //\r
- // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState\r
- //\r
- KeyShiftStateRight = EFI_SHIFT_STATE_VALID;\r
- if (KeyOptions.Options.ShiftPressed) {\r
- KeyShiftStateRight |= EFI_RIGHT_SHIFT_PRESSED;\r
- }\r
- if (KeyOptions.Options.ControlPressed) {\r
- KeyShiftStateRight |= EFI_RIGHT_CONTROL_PRESSED;\r
- }\r
- if (KeyOptions.Options.AltPressed) {\r
- KeyShiftStateRight |= EFI_RIGHT_ALT_PRESSED;\r
- }\r
- if (KeyOptions.Options.LogoPressed) {\r
- KeyShiftStateRight |= EFI_RIGHT_LOGO_PRESSED;\r
- }\r
- if (KeyOptions.Options.MenuPressed) {\r
- KeyShiftStateRight |= EFI_MENU_KEY_PRESSED;\r
- }\r
- if (KeyOptions.Options.SysReqPressed) {\r
- KeyShiftStateRight |= EFI_SYS_REQ_PRESSED;\r
- }\r
-\r
- KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);\r
-\r
- InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));\r
-\r
- Index = 0;\r
- KeyData = &HotkeyLeft->KeyData[0];\r
- do {\r
- //\r
- // If Key CodeCount is 0, then only KeyData[0] is used;\r
- // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used\r
- //\r
- KeyData->Key.ScanCode = InputKey[Index].ScanCode;\r
- KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;\r
- KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;\r
-\r
- Index++;\r
- KeyData++;\r
- } while (Index < HotkeyLeft->CodeCount);\r
- InsertTailList (&mHotkeyList, &HotkeyLeft->Link);\r
-\r
- if (KeyShiftStateLeft != KeyShiftStateRight) {\r
- //\r
- // Need an extra hotkey for shift key on right\r
- //\r
- HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);\r
- if (HotkeyRight == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Index = 0;\r
- KeyData = &HotkeyRight->KeyData[0];\r
- do {\r
- //\r
- // Key.ScanCode and Key.UnicodeChar have already been initialized,\r
- // only need to update KeyState.KeyShiftState\r
- //\r
- KeyData->KeyState.KeyShiftState = KeyShiftStateRight;\r
-\r
- Index++;\r
- KeyData++;\r
- } while (Index < HotkeyRight->CodeCount);\r
- InsertTailList (&mHotkeyList, &HotkeyRight->Link);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Return TRUE when the variable pointed by Name and Guid is a Key#### variable.\r
-\r
- @param Name The name of the variable.\r
- @param Guid The GUID of the variable.\r
- @param OptionNumber Return the option number parsed from the Name.\r
-\r
- @retval TRUE The variable pointed by Name and Guid is a Key#### variable.\r
- @retval FALSE The variable pointed by Name and Guid isn't a Key#### variable.\r
-**/\r
-BOOLEAN\r
-IsKeyOptionVariable (\r
- CHAR16 *Name,\r
- EFI_GUID *Guid,\r
- UINT16 *OptionNumber\r
- )\r
-{\r
- UINTN Index;\r
-\r
- if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||\r
- (StrSize (Name) != sizeof (L"Key####")) ||\r
- (StrnCmp (Name, L"Key", 3) != 0)\r
- ) {\r
- return FALSE;\r
- }\r
-\r
- *OptionNumber = 0;\r
- for (Index = 3; Index < 7; Index++) {\r
- if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {\r
- *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';\r
- } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {\r
- *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;\r
- } else {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Return an array of key option numbers.\r
-\r
- @param Count Return the count of key option numbers.\r
-\r
- @return UINT16* Pointer to an array of key option numbers;\r
-**/\r
-UINT16 *\r
-EFIAPI\r
-HotkeyGetOptionNumbers (\r
- OUT UINTN *Count\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Index;\r
- CHAR16 *Name;\r
- EFI_GUID Guid;\r
- UINTN NameSize;\r
- UINTN NewNameSize;\r
- UINT16 *OptionNumbers;\r
- UINT16 OptionNumber;\r
-\r
- if (Count == NULL) {\r
- return NULL;\r
- }\r
-\r
- *Count = 0;\r
- OptionNumbers = NULL;\r
-\r
- NameSize = sizeof (CHAR16);\r
- Name = AllocateZeroPool (NameSize);\r
- ASSERT (Name != NULL);\r
- while (TRUE) {\r
- NewNameSize = NameSize;\r
- Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- Name = ReallocatePool (NameSize, NewNameSize, Name);\r
- ASSERT (Name != NULL);\r
- Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
- NameSize = NewNameSize;\r
- }\r
-\r
- if (Status == EFI_NOT_FOUND) {\r
- break;\r
- }\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- if (IsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {\r
- OptionNumbers = ReallocatePool (\r
- *Count * sizeof (UINT16),\r
- (*Count + 1) * sizeof (UINT16),\r
- OptionNumbers\r
- );\r
- ASSERT (OptionNumbers != NULL);\r
- for (Index = 0; Index < *Count; Index++) {\r
- if (OptionNumber < OptionNumbers[Index]) {\r
- break;\r
- }\r
- }\r
- CopyMem (&OptionNumbers[Index + 1], &OptionNumbers[Index], (*Count - Index) * sizeof (UINT16));\r
- OptionNumbers[Index] = OptionNumber;\r
- (*Count)++;\r
- }\r
- }\r
-\r
- FreePool (Name);\r
-\r
- return OptionNumbers;\r
-}\r
-\r
-/**\r
-\r
- Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.\r
-\r
- @retval EFI_SUCCESS Hotkey services successfully initialized.\r
-**/\r
-EFI_STATUS\r
-InitializeHotkeyService (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 BootOptionSupport;\r
- UINT16 *KeyOptionNumbers;\r
- UINTN KeyOptionCount;\r
- UINTN Index;\r
- CHAR16 KeyOptionName[8];\r
- EFI_KEY_OPTION *KeyOption;\r
-\r
- //\r
- // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP.\r
- // with maximum number of key presses of 3\r
- // Do not report the hotkey capability if PcdConInConnectOnDemand is enabled.\r
- //\r
- BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;\r
- if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
- BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
- SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
- }\r
-\r
- Status = gRT->SetVariable (\r
- L"BootOptionSupport",\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- sizeof (UINT32),\r
- &BootOptionSupport\r
- );\r
- //\r
- // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
- //\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- KeyOptionNumbers = HotkeyGetOptionNumbers (&KeyOptionCount);\r
- for (Index = 0; Index < KeyOptionCount; Index ++) {\r
- UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumbers[Index]);\r
- GetEfiGlobalVariable2 (KeyOptionName, (VOID **) &KeyOption, NULL);\r
- ASSERT (KeyOption != NULL);\r
- if (IsKeyOptionValid (KeyOption)) {\r
- HotkeyInsertList (KeyOption);\r
- }\r
- FreePool (KeyOption);\r
- }\r
-\r
- if (KeyOptionNumbers != NULL) {\r
- FreePool (KeyOptionNumbers);\r
- }\r
-\r
- //\r
- // Register Protocol notify for Hotkey service\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- HotkeyEvent,\r
- NULL,\r
- &mHotkeyEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Register for protocol notifications on this event\r
- //\r
- Status = gBS->RegisterProtocolNotify (\r
- &gEfiSimpleTextInputExProtocolGuid,\r
- mHotkeyEvent,\r
- &mHotkeyRegistration\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r
-\r