/** Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options. @retval EFI_SUCCESS Hotkey services successfully initialized. @retval EFI_NOT_FOUND Can not find the "KeyOrder" variable **/ EFI_STATUS InitializeHotkeyService ( VOID ) { EFI_STATUS Status; UINT32 BootOptionSupport; UINT16 *KeyOrder; UINTN KeyOrderSize; UINTN Index; UINT16 KeyOptionName[8]; UINTN KeyOptionSize; EFI_KEY_OPTION *KeyOption; // // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP // with maximum number of key presses of 3 // BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_KEY | EFI_BOOT_OPTION_SUPPORT_APP; SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3); Status = gRT->SetVariable ( L"BootOptionSupport", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (UINT32), &BootOptionSupport ); // // Get valid Key Option List from private EFI variable "KeyOrder" // KeyOrder = BdsLibGetVariableAndSize ( VAR_KEY_ORDER, &gEfiGlobalVariableGuid, &KeyOrderSize ); if (KeyOrder == NULL) { return EFI_NOT_FOUND; } for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index ++) { UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]); KeyOption = BdsLibGetVariableAndSize ( KeyOptionName, &gEfiGlobalVariableGuid, &KeyOptionSize ); if (KeyOption == NULL || !IsKeyOptionValid (KeyOption)) { UnregisterHotkey (KeyOrder[Index]); } else { HotkeyInsertList (KeyOption); } } // // Register Protocol notify for Hotkey service // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, HotkeyEvent, NULL, &mHotkeyEvent ); ASSERT_EFI_ERROR (Status); // // Register for protocol notifications on this event // Status = gBS->RegisterProtocolNotify ( &gEfiSimpleTextInputExProtocolGuid, mHotkeyEvent, &mHotkeyRegistration ); ASSERT_EFI_ERROR (Status); return Status; }
/** Create Key#### for the given hotkey. @param KeyOption The Hot Key Option to be added. @param KeyOptionNumber The key option number for Key#### (optional). @retval EFI_SUCCESS Register hotkey successfully. @retval EFI_INVALID_PARAMETER The hotkey option is invalid. @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource. **/ EFI_STATUS RegisterHotkey ( IN EFI_KEY_OPTION *KeyOption, OUT UINT16 *KeyOptionNumber ) { UINT16 KeyOptionName[10]; UINT16 *KeyOrder; UINTN KeyOrderSize; UINT16 *NewKeyOrder; UINTN Index; UINT16 MaxOptionNumber; UINT16 RegisterOptionNumber; EFI_KEY_OPTION *TempOption; UINTN TempOptionSize; EFI_STATUS Status; UINTN KeyOptionSize; BOOLEAN UpdateBootOption; // // Validate the given key option // if (!IsKeyOptionValid (KeyOption)) { return EFI_INVALID_PARAMETER; } KeyOptionSize = sizeof (EFI_KEY_OPTION) + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY); UpdateBootOption = FALSE; // // Check whether HotKey conflict with keys used by Setup Browser // KeyOrder = BdsLibGetVariableAndSize ( VAR_KEY_ORDER, &gEfiGlobalVariableGuid, &KeyOrderSize ); if (KeyOrder == NULL) { KeyOrderSize = 0; } // // Find free key option number // MaxOptionNumber = 0; TempOption = NULL; for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) { if (MaxOptionNumber < KeyOrder[Index]) { MaxOptionNumber = KeyOrder[Index]; } UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]); TempOption = BdsLibGetVariableAndSize ( KeyOptionName, &gEfiGlobalVariableGuid, &TempOptionSize ); if (CompareMem (TempOption, KeyOption, TempOptionSize) == 0) { // // Got the option, so just return // FreePool (TempOption); FreePool (KeyOrder); return EFI_SUCCESS; } if (KeyOption->KeyData.PackedValue == TempOption->KeyData.PackedValue) { if (KeyOption->KeyData.Options.InputKeyCount == 0 || CompareMem ( ((UINT8 *) TempOption) + sizeof (EFI_KEY_OPTION), ((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION), KeyOptionSize - sizeof (EFI_KEY_OPTION) ) == 0) { // // Hotkey is the same but BootOption changed, need update // UpdateBootOption = TRUE; break; } } FreePool (TempOption); } if (UpdateBootOption) { RegisterOptionNumber = KeyOrder[Index]; FreePool (TempOption); } else { RegisterOptionNumber = (UINT16) (MaxOptionNumber + 1); } if (KeyOptionNumber != NULL) { *KeyOptionNumber = RegisterOptionNumber; } // // Create variable Key#### // UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", RegisterOptionNumber); Status = gRT->SetVariable ( KeyOptionName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, KeyOptionSize, KeyOption ); if (EFI_ERROR (Status)) { FreePool (KeyOrder); return Status; } // // Update the key order variable - "KeyOrder" // if (!UpdateBootOption) { Index = KeyOrderSize / sizeof (UINT16); KeyOrderSize += sizeof (UINT16); } NewKeyOrder = AllocatePool (KeyOrderSize); if (NewKeyOrder == NULL) { FreePool (KeyOrder); return EFI_OUT_OF_RESOURCES; } if (KeyOrder != NULL) { CopyMem (NewKeyOrder, KeyOrder, KeyOrderSize); } NewKeyOrder[Index] = RegisterOptionNumber; Status = gRT->SetVariable ( VAR_KEY_ORDER, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, KeyOrderSize, NewKeyOrder ); FreePool (KeyOrder); FreePool (NewKeyOrder); return Status; }
EFIAPI EfiBootManagerGetKeyOptions ( OUT UINTN *Count ) { EFI_STATUS Status; UINTN Index; CHAR16 *Name; EFI_GUID Guid; UINTN NameSize; UINTN NewNameSize; EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions; EFI_BOOT_MANAGER_KEY_OPTION *KeyOption; UINT16 OptionNumber; if (Count == NULL) { return NULL; } *Count = 0; KeyOptions = NULL; NameSize = sizeof (CHAR16); Name = AllocateZeroPool (NameSize); ASSERT (Name != NULL); while (TRUE) { NewNameSize = NameSize; Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid); if (Status == EFI_BUFFER_TOO_SMALL) { Name = ReallocatePool (NameSize, NewNameSize, Name); ASSERT (Name != NULL); Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid); NameSize = NewNameSize; } if (Status == EFI_NOT_FOUND) { break; } ASSERT_EFI_ERROR (Status); if (IsKeyOptionVariable (Name ,&Guid, &OptionNumber)) { GetEfiGlobalVariable2 (Name, (VOID**) &KeyOption, NULL); ASSERT (KeyOption != NULL); if (IsKeyOptionValid (KeyOption)) { KeyOptions = ReallocatePool ( *Count * sizeof (EFI_BOOT_MANAGER_KEY_OPTION), (*Count + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION), KeyOptions ); ASSERT (KeyOptions != NULL); // // Insert the key option in order // for (Index = 0; Index < *Count; Index++) { if (OptionNumber < KeyOptions[Index].OptionNumber) { break; } } CopyMem (&KeyOptions[Index + 1], &KeyOptions[Index], (*Count - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION)); CopyMem (&KeyOptions[Index], KeyOption, SizeOfKeyOption (KeyOption)); KeyOptions[Index].OptionNumber = OptionNumber; (*Count)++; } FreePool (KeyOption); } } FreePool (Name); return KeyOptions; }