mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-11 14:28:08 +01:00
1152 lines
36 KiB
C
1152 lines
36 KiB
C
|
/** @file
|
||
|
Hotkey library functions.
|
||
|
|
||
|
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "InternalBm.h"
|
||
|
|
||
|
//
|
||
|
// Lock for linked list
|
||
|
//
|
||
|
EFI_LOCK mBmHotkeyLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
|
||
|
LIST_ENTRY mBmHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);
|
||
|
EFI_EVENT mBmHotkeyTriggered = NULL;
|
||
|
BOOLEAN mBmHotkeyServiceStarted = FALSE;
|
||
|
UINTN mBmHotkeySupportCount = 0;
|
||
|
|
||
|
//
|
||
|
// Set OptionNumber as unassigned value to indicate the option isn't initialized
|
||
|
//
|
||
|
EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption = { LoadOptionNumberUnassigned };
|
||
|
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION *mBmContinueKeyOption = NULL;
|
||
|
VOID *mBmTxtInExRegistration = NULL;
|
||
|
|
||
|
|
||
|
/**
|
||
|
Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
|
||
|
|
||
|
@param KeyOption The input key option info.
|
||
|
|
||
|
@retval The buffer size of the key option data.
|
||
|
**/
|
||
|
UINTN
|
||
|
BmSizeOfKeyOption (
|
||
|
IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
|
||
|
)
|
||
|
{
|
||
|
return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)
|
||
|
+ KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Check whether the input key option is valid.
|
||
|
|
||
|
@param KeyOption Key option.
|
||
|
@param KeyOptionSize Size of the key option.
|
||
|
|
||
|
@retval TRUE Input key option is valid.
|
||
|
@retval FALSE Input key option is not valid.
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
BmIsKeyOptionValid (
|
||
|
IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,
|
||
|
IN UINTN KeyOptionSize
|
||
|
)
|
||
|
{
|
||
|
UINT16 OptionName[BM_OPTION_NAME_LEN];
|
||
|
UINT8 *BootOption;
|
||
|
UINTN BootOptionSize;
|
||
|
UINT32 Crc;
|
||
|
|
||
|
if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check whether corresponding Boot Option exist
|
||
|
//
|
||
|
UnicodeSPrint (
|
||
|
OptionName, sizeof (OptionName), L"%s%04x",
|
||
|
mBmLoadOptionName[LoadOptionTypeBoot], KeyOption->BootOption
|
||
|
);
|
||
|
GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);
|
||
|
|
||
|
if (BootOption == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check CRC for Boot Option
|
||
|
//
|
||
|
gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);
|
||
|
FreePool (BootOption);
|
||
|
|
||
|
return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Check whether the input variable is an key option variable.
|
||
|
|
||
|
@param Name Input variable name.
|
||
|
@param Guid Input variable guid.
|
||
|
@param OptionNumber The option number of this key option variable.
|
||
|
|
||
|
@retval TRUE Input variable is a key option variable.
|
||
|
@retval FALSE Input variable is not a key option variable.
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
BmIsKeyOptionVariable (
|
||
|
CHAR16 *Name,
|
||
|
EFI_GUID *Guid,
|
||
|
UINT16 *OptionNumber
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
UINTN Uint;
|
||
|
|
||
|
if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
|
||
|
(StrSize (Name) != sizeof (L"Key####")) ||
|
||
|
(StrnCmp (Name, L"Key", 3) != 0)
|
||
|
) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*OptionNumber = 0;
|
||
|
for (Index = 3; Index < 7; Index++) {
|
||
|
Uint = BmCharToUint (Name[Index]);
|
||
|
if (Uint == -1) {
|
||
|
return FALSE;
|
||
|
} else {
|
||
|
*OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
typedef struct {
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
|
||
|
UINTN KeyOptionCount;
|
||
|
} BM_COLLECT_KEY_OPTIONS_PARAM;
|
||
|
|
||
|
/**
|
||
|
Visitor function to collect the key options from NV storage.
|
||
|
|
||
|
@param Name Variable name.
|
||
|
@param Guid Variable GUID.
|
||
|
@param Context The same context passed to BmForEachVariable.
|
||
|
**/
|
||
|
VOID
|
||
|
BmCollectKeyOptions (
|
||
|
CHAR16 *Name,
|
||
|
EFI_GUID *Guid,
|
||
|
VOID *Context
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
BM_COLLECT_KEY_OPTIONS_PARAM *Param;
|
||
|
VOID *KeyOption;
|
||
|
UINT16 OptionNumber;
|
||
|
UINTN KeyOptionSize;
|
||
|
|
||
|
Param = (BM_COLLECT_KEY_OPTIONS_PARAM *) Context;
|
||
|
|
||
|
if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {
|
||
|
GetEfiGlobalVariable2 (Name, &KeyOption, &KeyOptionSize);
|
||
|
ASSERT (KeyOption != NULL);
|
||
|
if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {
|
||
|
Param->KeyOptions = ReallocatePool (
|
||
|
Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
|
||
|
(Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
|
||
|
Param->KeyOptions
|
||
|
);
|
||
|
ASSERT (Param->KeyOptions != NULL);
|
||
|
//
|
||
|
// Insert the key option in order
|
||
|
//
|
||
|
for (Index = 0; Index < Param->KeyOptionCount; Index++) {
|
||
|
if (OptionNumber < Param->KeyOptions[Index].OptionNumber) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
|
||
|
CopyMem (&Param->KeyOptions[Index], KeyOption, KeyOptionSize);
|
||
|
Param->KeyOptions[Index].OptionNumber = OptionNumber;
|
||
|
Param->KeyOptionCount++;
|
||
|
}
|
||
|
FreePool (KeyOption);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Return the array of key options.
|
||
|
|
||
|
@param Count Return the number of key options.
|
||
|
|
||
|
@retval NULL No key option.
|
||
|
@retval Other Pointer to the key options.
|
||
|
**/
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION *
|
||
|
BmGetKeyOptions (
|
||
|
OUT UINTN *Count
|
||
|
)
|
||
|
{
|
||
|
BM_COLLECT_KEY_OPTIONS_PARAM Param;
|
||
|
|
||
|
if (Count == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Param.KeyOptions = NULL;
|
||
|
Param.KeyOptionCount = 0;
|
||
|
|
||
|
BmForEachVariable (BmCollectKeyOptions, (VOID *) &Param);
|
||
|
|
||
|
*Count = Param.KeyOptionCount;
|
||
|
|
||
|
return Param.KeyOptions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Check whether the bit is set in the value.
|
||
|
|
||
|
@param Value The value need to be check.
|
||
|
@param Bit The bit filed need to be check.
|
||
|
|
||
|
@retval TRUE The bit is set.
|
||
|
@retval FALSE The bit is not set.
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
BmBitSet (
|
||
|
IN UINT32 Value,
|
||
|
IN UINT32 Bit
|
||
|
)
|
||
|
{
|
||
|
return (BOOLEAN) ((Value & Bit) != 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
|
||
|
|
||
|
@param Modifier Input key info.
|
||
|
@param Args Va_list info.
|
||
|
@param KeyOption Key info which need to update.
|
||
|
|
||
|
@retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
|
||
|
@return EFI_INVALID_PARAMETER Input parameter error.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
BmInitializeKeyFields (
|
||
|
IN UINT32 Modifier,
|
||
|
IN VA_LIST Args,
|
||
|
OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
|
||
|
)
|
||
|
{
|
||
|
EFI_INPUT_KEY *Key;
|
||
|
|
||
|
if (KeyOption == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
Key = NULL;
|
||
|
while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {
|
||
|
Key = VA_ARG (Args, EFI_INPUT_KEY *);
|
||
|
if (Key == NULL) {
|
||
|
break;
|
||
|
}
|
||
|
CopyMem (
|
||
|
&KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],
|
||
|
Key,
|
||
|
sizeof (EFI_INPUT_KEY)
|
||
|
);
|
||
|
KeyOption->KeyData.Options.InputKeyCount++;
|
||
|
}
|
||
|
|
||
|
if (Key != NULL) {
|
||
|
//
|
||
|
// Too many keys
|
||
|
//
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
|
||
|
| EFI_BOOT_MANAGER_CONTROL_PRESSED
|
||
|
| EFI_BOOT_MANAGER_ALT_PRESSED
|
||
|
| EFI_BOOT_MANAGER_LOGO_PRESSED
|
||
|
| EFI_BOOT_MANAGER_MENU_KEY_PRESSED
|
||
|
| EFI_BOOT_MANAGER_SYS_REQ_PRESSED
|
||
|
)) != 0) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {
|
||
|
KeyOption->KeyData.Options.ShiftPressed = 1;
|
||
|
}
|
||
|
if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {
|
||
|
KeyOption->KeyData.Options.ControlPressed = 1;
|
||
|
}
|
||
|
if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {
|
||
|
KeyOption->KeyData.Options.AltPressed = 1;
|
||
|
}
|
||
|
if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {
|
||
|
KeyOption->KeyData.Options.LogoPressed = 1;
|
||
|
}
|
||
|
if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {
|
||
|
KeyOption->KeyData.Options.MenuPressed = 1;
|
||
|
}
|
||
|
if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {
|
||
|
KeyOption->KeyData.Options.SysReqPressed = 1;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Try to boot the boot option triggered by hot key.
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
EfiBootManagerHotkeyBoot (
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
|
||
|
EfiBootManagerBoot (&mBmHotkeyBootOption);
|
||
|
EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);
|
||
|
mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
This is the common notification function for HotKeys, it will be registered
|
||
|
with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
|
||
|
|
||
|
@param KeyData A pointer to a buffer that is filled in with the keystroke
|
||
|
information for the key that was pressed.
|
||
|
|
||
|
@retval EFI_SUCCESS KeyData is successfully processed.
|
||
|
@return EFI_NOT_FOUND Fail to find boot option variable.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
BmHotkeyCallback (
|
||
|
IN EFI_KEY_DATA *KeyData
|
||
|
)
|
||
|
{
|
||
|
LIST_ENTRY *Link;
|
||
|
BM_HOTKEY *Hotkey;
|
||
|
CHAR16 OptionName[BM_OPTION_NAME_LEN];
|
||
|
EFI_STATUS Status;
|
||
|
EFI_KEY_DATA *HotkeyData;
|
||
|
|
||
|
if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
|
||
|
//
|
||
|
// Do not process sequential hotkey stroke until the current boot option returns
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));
|
||
|
|
||
|
EfiAcquireLock (&mBmHotkeyLock);
|
||
|
for ( Link = GetFirstNode (&mBmHotkeyList)
|
||
|
; !IsNull (&mBmHotkeyList, Link)
|
||
|
; Link = GetNextNode (&mBmHotkeyList, Link)
|
||
|
) {
|
||
|
Hotkey = BM_HOTKEY_FROM_LINK (Link);
|
||
|
|
||
|
//
|
||
|
// Is this Key Stroke we are waiting for?
|
||
|
//
|
||
|
ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
|
||
|
HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
|
||
|
if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
|
||
|
(KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
|
||
|
(((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?
|
||
|
(KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
|
||
|
)
|
||
|
) {
|
||
|
|
||
|
//
|
||
|
// Receive an expecting key stroke, transit to next waiting state
|
||
|
//
|
||
|
Hotkey->WaitingKey++;
|
||
|
|
||
|
if (Hotkey->WaitingKey == Hotkey->CodeCount) {
|
||
|
//
|
||
|
// Reset to initial waiting state
|
||
|
//
|
||
|
Hotkey->WaitingKey = 0;
|
||
|
//
|
||
|
// Received the whole key stroke sequence
|
||
|
//
|
||
|
Status = gBS->SignalEvent (mBmHotkeyTriggered);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
if (!Hotkey->IsContinue) {
|
||
|
//
|
||
|
// Launch its BootOption
|
||
|
//
|
||
|
UnicodeSPrint (
|
||
|
OptionName, sizeof (OptionName), L"%s%04x",
|
||
|
mBmLoadOptionName[LoadOptionTypeBoot], Hotkey->BootOption
|
||
|
);
|
||
|
Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
|
||
|
}
|
||
|
} else {
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// Receive an unexpected key stroke, reset to initial waiting state
|
||
|
//
|
||
|
Hotkey->WaitingKey = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
EfiReleaseLock (&mBmHotkeyLock);
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Return the active Simple Text Input Ex handle array.
|
||
|
If the SystemTable.ConsoleInHandle is NULL, the function returns all
|
||
|
founded Simple Text Input Ex handles.
|
||
|
Otherwise, it just returns the ConsoleInHandle.
|
||
|
|
||
|
@param Count Return the handle count.
|
||
|
|
||
|
@retval The active console handles.
|
||
|
**/
|
||
|
EFI_HANDLE *
|
||
|
BmGetActiveConsoleIn (
|
||
|
OUT UINTN *Count
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_HANDLE *Handles;
|
||
|
|
||
|
Handles = NULL;
|
||
|
*Count = 0;
|
||
|
|
||
|
if (gST->ConsoleInHandle != NULL) {
|
||
|
Status = gBS->OpenProtocol (
|
||
|
gST->ConsoleInHandle,
|
||
|
&gEfiSimpleTextInputExProtocolGuid,
|
||
|
NULL,
|
||
|
gImageHandle,
|
||
|
NULL,
|
||
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);
|
||
|
if (Handles != NULL) {
|
||
|
*Count = 1;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
Status = gBS->LocateHandleBuffer (
|
||
|
ByProtocol,
|
||
|
&gEfiSimpleTextInputExProtocolGuid,
|
||
|
NULL,
|
||
|
Count,
|
||
|
&Handles
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return Handles;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Unregister hotkey notify list.
|
||
|
|
||
|
@param Hotkey Hotkey list.
|
||
|
|
||
|
@retval EFI_SUCCESS Unregister hotkey notify success.
|
||
|
@retval Others Unregister hotkey notify failed.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
BmUnregisterHotkeyNotify (
|
||
|
IN BM_HOTKEY *Hotkey
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
UINTN KeyIndex;
|
||
|
EFI_HANDLE *Handles;
|
||
|
UINTN HandleCount;
|
||
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
|
||
|
VOID *NotifyHandle;
|
||
|
|
||
|
Handles = BmGetActiveConsoleIn (&HandleCount);
|
||
|
for (Index = 0; Index < HandleCount; Index++) {
|
||
|
Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
|
||
|
Status = TxtInEx->RegisterKeyNotify (
|
||
|
TxtInEx,
|
||
|
&Hotkey->KeyData[KeyIndex],
|
||
|
BmHotkeyCallback,
|
||
|
&NotifyHandle
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Handles != NULL) {
|
||
|
FreePool (Handles);
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Register hotkey notify list.
|
||
|
|
||
|
@param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
|
||
|
@param Hotkey Hotkey list.
|
||
|
|
||
|
@retval EFI_SUCCESS Register hotkey notify success.
|
||
|
@retval Others Register hotkey notify failed.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
BmRegisterHotkeyNotify (
|
||
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx,
|
||
|
IN BM_HOTKEY *Hotkey
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
VOID *NotifyHandle;
|
||
|
|
||
|
for (Index = 0; Index < Hotkey->CodeCount; Index++) {
|
||
|
Status = TxtInEx->RegisterKeyNotify (
|
||
|
TxtInEx,
|
||
|
&Hotkey->KeyData[Index],
|
||
|
BmHotkeyCallback,
|
||
|
&NotifyHandle
|
||
|
);
|
||
|
DEBUG ((
|
||
|
EFI_D_INFO,
|
||
|
"[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
|
||
|
Hotkey->KeyData[Index].Key.ScanCode,
|
||
|
Hotkey->KeyData[Index].Key.UnicodeChar,
|
||
|
Hotkey->KeyData[Index].KeyState.KeyShiftState,
|
||
|
Hotkey->KeyData[Index].KeyState.KeyToggleState,
|
||
|
Status
|
||
|
));
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// some of the hotkey registry failed
|
||
|
// do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Generate key shift state base on the input key option info.
|
||
|
|
||
|
@param Depth Which key is checked.
|
||
|
@param KeyOption Input key option info.
|
||
|
@param KeyShiftState Input key shift state.
|
||
|
@param KeyShiftStates Return possible key shift state array.
|
||
|
@param KeyShiftStateCount Possible key shift state count.
|
||
|
**/
|
||
|
VOID
|
||
|
BmGenerateKeyShiftState (
|
||
|
IN UINTN Depth,
|
||
|
IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,
|
||
|
IN UINT32 KeyShiftState,
|
||
|
IN UINT32 *KeyShiftStates,
|
||
|
IN UINTN *KeyShiftStateCount
|
||
|
)
|
||
|
{
|
||
|
switch (Depth) {
|
||
|
case 0:
|
||
|
if (KeyOption->KeyData.Options.ShiftPressed) {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
} else {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
if (KeyOption->KeyData.Options.ControlPressed) {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
} else {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
if (KeyOption->KeyData.Options.AltPressed) {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
} else {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
|
||
|
}
|
||
|
break;
|
||
|
case 3:
|
||
|
if (KeyOption->KeyData.Options.LogoPressed) {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
|
||
|
} else {
|
||
|
BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
|
||
|
}
|
||
|
break;
|
||
|
case 4:
|
||
|
if (KeyOption->KeyData.Options.MenuPressed) {
|
||
|
KeyShiftState |= EFI_MENU_KEY_PRESSED;
|
||
|
}
|
||
|
if (KeyOption->KeyData.Options.SysReqPressed) {
|
||
|
KeyShiftState |= EFI_SYS_REQ_PRESSED;
|
||
|
}
|
||
|
KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;
|
||
|
(*KeyShiftStateCount)++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Add it to hot key database, register it to existing TxtInEx.
|
||
|
New TxtInEx will be automatically registered with all the hot key in dababase
|
||
|
|
||
|
@param KeyOption Input key option info.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
BmProcessKeyOption (
|
||
|
IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
|
||
|
EFI_HANDLE *Handles;
|
||
|
UINTN HandleCount;
|
||
|
UINTN HandleIndex;
|
||
|
UINTN Index;
|
||
|
BM_HOTKEY *Hotkey;
|
||
|
UINTN KeyIndex;
|
||
|
//
|
||
|
// 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
|
||
|
//
|
||
|
UINT32 KeyShiftStates[16];
|
||
|
UINTN KeyShiftStateCount;
|
||
|
|
||
|
if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {
|
||
|
return EFI_UNSUPPORTED;
|
||
|
}
|
||
|
|
||
|
KeyShiftStateCount = 0;
|
||
|
BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);
|
||
|
ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));
|
||
|
|
||
|
EfiAcquireLock (&mBmHotkeyLock);
|
||
|
|
||
|
Handles = BmGetActiveConsoleIn (&HandleCount);
|
||
|
|
||
|
for (Index = 0; Index < KeyShiftStateCount; Index++) {
|
||
|
Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));
|
||
|
ASSERT (Hotkey != NULL);
|
||
|
|
||
|
Hotkey->Signature = BM_HOTKEY_SIGNATURE;
|
||
|
Hotkey->BootOption = KeyOption->BootOption;
|
||
|
Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);
|
||
|
Hotkey->CodeCount = (UINT8) KeyOption->KeyData.Options.InputKeyCount;
|
||
|
|
||
|
for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
|
||
|
CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));
|
||
|
Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];
|
||
|
}
|
||
|
InsertTailList (&mBmHotkeyList, &Hotkey->Link);
|
||
|
|
||
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
||
|
Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
BmRegisterHotkeyNotify (TxtInEx, Hotkey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Handles != NULL) {
|
||
|
FreePool (Handles);
|
||
|
}
|
||
|
EfiReleaseLock (&mBmHotkeyLock);
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Callback function for SimpleTextInEx protocol install events
|
||
|
|
||
|
@param Event the event that is signaled.
|
||
|
@param Context not used here.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
BmTxtInExCallback (
|
||
|
IN EFI_EVENT Event,
|
||
|
IN VOID *Context
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN BufferSize;
|
||
|
EFI_HANDLE Handle;
|
||
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
|
||
|
LIST_ENTRY *Link;
|
||
|
|
||
|
while (TRUE) {
|
||
|
BufferSize = sizeof (EFI_HANDLE);
|
||
|
Status = gBS->LocateHandle (
|
||
|
ByRegisterNotify,
|
||
|
NULL,
|
||
|
mBmTxtInExRegistration,
|
||
|
&BufferSize,
|
||
|
&Handle
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// If no more notification events exist
|
||
|
//
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
Status = gBS->HandleProtocol (
|
||
|
Handle,
|
||
|
&gEfiSimpleTextInputExProtocolGuid,
|
||
|
(VOID **) &TxtInEx
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
//
|
||
|
// Register the hot key notification for the existing items in the list
|
||
|
//
|
||
|
EfiAcquireLock (&mBmHotkeyLock);
|
||
|
for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {
|
||
|
BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));
|
||
|
}
|
||
|
EfiReleaseLock (&mBmHotkeyLock);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Free the key options returned from BmGetKeyOptions.
|
||
|
|
||
|
@param KeyOptions Pointer to the key options.
|
||
|
@param KeyOptionCount Number of the key options.
|
||
|
|
||
|
@retval EFI_SUCCESS The key options are freed.
|
||
|
@retval EFI_NOT_FOUND KeyOptions is NULL.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
BmFreeKeyOptions (
|
||
|
IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions,
|
||
|
IN UINTN KeyOptionCount
|
||
|
)
|
||
|
{
|
||
|
if (KeyOptions != NULL) {
|
||
|
FreePool (KeyOptions);
|
||
|
return EFI_SUCCESS;
|
||
|
} else {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Register the key option to exit the waiting of the Boot Manager timeout.
|
||
|
Platform should ensure that the continue key option isn't conflict with
|
||
|
other boot key options.
|
||
|
|
||
|
@param Modifier Key shift state.
|
||
|
@param ... Parameter list of pointer of EFI_INPUT_KEY.
|
||
|
|
||
|
@retval EFI_SUCCESS Successfully register the continue key option.
|
||
|
@retval EFI_ALREADY_STARTED The continue key option is already registered.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
EfiBootManagerRegisterContinueKeyOption (
|
||
|
IN UINT32 Modifier,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
|
||
|
VA_LIST Args;
|
||
|
|
||
|
if (mBmContinueKeyOption != NULL) {
|
||
|
return EFI_ALREADY_STARTED;
|
||
|
}
|
||
|
|
||
|
ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
|
||
|
VA_START (Args, Modifier);
|
||
|
Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
|
||
|
VA_END (Args);
|
||
|
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);
|
||
|
ASSERT (mBmContinueKeyOption != NULL);
|
||
|
if (mBmHotkeyServiceStarted) {
|
||
|
BmProcessKeyOption (mBmContinueKeyOption);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Stop the hotkey processing.
|
||
|
|
||
|
@param Event Event pointer related to hotkey service.
|
||
|
@param Context Context pass to this function.
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
BmStopHotkeyService (
|
||
|
IN EFI_EVENT Event,
|
||
|
IN VOID *Context
|
||
|
)
|
||
|
{
|
||
|
LIST_ENTRY *Link;
|
||
|
BM_HOTKEY *Hotkey;
|
||
|
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));
|
||
|
gBS->CloseEvent (Event);
|
||
|
|
||
|
EfiAcquireLock (&mBmHotkeyLock);
|
||
|
for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
|
||
|
Hotkey = BM_HOTKEY_FROM_LINK (Link);
|
||
|
BmUnregisterHotkeyNotify (Hotkey);
|
||
|
Link = RemoveEntryList (Link);
|
||
|
FreePool (Hotkey);
|
||
|
}
|
||
|
EfiReleaseLock (&mBmHotkeyLock);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Start the hot key service so that the key press can trigger the boot option.
|
||
|
|
||
|
@param HotkeyTriggered Return the waitable event and it will be signaled
|
||
|
when a valid hot key is pressed.
|
||
|
|
||
|
@retval EFI_SUCCESS The hot key service is started.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
EfiBootManagerStartHotkeyService (
|
||
|
IN EFI_EVENT *HotkeyTriggered
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
|
||
|
UINTN KeyOptionCount;
|
||
|
UINTN Index;
|
||
|
EFI_EVENT Event;
|
||
|
UINT32 *BootOptionSupport;
|
||
|
|
||
|
GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);
|
||
|
if (BootOptionSupport != NULL) {
|
||
|
if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY) != 0) {
|
||
|
mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));
|
||
|
}
|
||
|
FreePool (BootOptionSupport);
|
||
|
}
|
||
|
|
||
|
if (mBmHotkeySupportCount == 0) {
|
||
|
DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
|
||
|
return EFI_UNSUPPORTED;
|
||
|
}
|
||
|
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_WAIT,
|
||
|
TPL_CALLBACK,
|
||
|
EfiEventEmptyFunction,
|
||
|
NULL,
|
||
|
&mBmHotkeyTriggered
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
if (HotkeyTriggered != NULL) {
|
||
|
*HotkeyTriggered = mBmHotkeyTriggered;
|
||
|
}
|
||
|
|
||
|
KeyOptions = BmGetKeyOptions (&KeyOptionCount);
|
||
|
for (Index = 0; Index < KeyOptionCount; Index ++) {
|
||
|
BmProcessKeyOption (&KeyOptions[Index]);
|
||
|
}
|
||
|
BmFreeKeyOptions (KeyOptions, KeyOptionCount);
|
||
|
|
||
|
if (mBmContinueKeyOption != NULL) {
|
||
|
BmProcessKeyOption (mBmContinueKeyOption);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Hook hotkey on every future SimpleTextInputEx instance when
|
||
|
// SystemTable.ConsoleInHandle == NULL, which means the console
|
||
|
// manager (ConSplitter) is absent.
|
||
|
//
|
||
|
if (gST->ConsoleInHandle == NULL) {
|
||
|
EfiCreateProtocolNotifyEvent (
|
||
|
&gEfiSimpleTextInputExProtocolGuid,
|
||
|
TPL_CALLBACK,
|
||
|
BmTxtInExCallback,
|
||
|
NULL,
|
||
|
&mBmTxtInExRegistration
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Status = EfiCreateEventReadyToBootEx (
|
||
|
TPL_CALLBACK,
|
||
|
BmStopHotkeyService,
|
||
|
NULL,
|
||
|
&Event
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
mBmHotkeyServiceStarted = TRUE;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Add the key option.
|
||
|
It adds the key option variable and the key option takes affect immediately.
|
||
|
|
||
|
@param AddedOption Return the added key option.
|
||
|
@param BootOptionNumber The boot option number for the key option.
|
||
|
@param Modifier Key shift state.
|
||
|
@param ... Parameter list of pointer of EFI_INPUT_KEY.
|
||
|
|
||
|
@retval EFI_SUCCESS The key option is added.
|
||
|
@retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
EfiBootManagerAddKeyOptionVariable (
|
||
|
OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption, OPTIONAL
|
||
|
IN UINT16 BootOptionNumber,
|
||
|
IN UINT32 Modifier,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
VA_LIST Args;
|
||
|
VOID *BootOption;
|
||
|
UINTN BootOptionSize;
|
||
|
CHAR16 BootOptionName[BM_OPTION_NAME_LEN];
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
|
||
|
UINTN KeyOptionCount;
|
||
|
UINTN Index;
|
||
|
UINTN KeyOptionNumber;
|
||
|
CHAR16 KeyOptionName[sizeof ("Key####")];
|
||
|
|
||
|
UnicodeSPrint (
|
||
|
BootOptionName, sizeof (BootOptionName), L"%s%04x",
|
||
|
mBmLoadOptionName[LoadOptionTypeBoot], BootOptionNumber
|
||
|
);
|
||
|
GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);
|
||
|
|
||
|
if (BootOption == NULL) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
|
||
|
KeyOption.BootOption = BootOptionNumber;
|
||
|
Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
FreePool (BootOption);
|
||
|
|
||
|
VA_START (Args, Modifier);
|
||
|
Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
|
||
|
VA_END (Args);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
KeyOptionNumber = LoadOptionNumberUnassigned;
|
||
|
//
|
||
|
// Check if the hot key sequence was defined already
|
||
|
//
|
||
|
KeyOptions = BmGetKeyOptions (&KeyOptionCount);
|
||
|
for (Index = 0; Index < KeyOptionCount; Index++) {
|
||
|
if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
|
||
|
(CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&
|
||
|
(KeyOptions[Index].OptionNumber > Index)
|
||
|
){
|
||
|
KeyOptionNumber = Index;
|
||
|
}
|
||
|
}
|
||
|
BmFreeKeyOptions (KeyOptions, KeyOptionCount);
|
||
|
|
||
|
if (Index < KeyOptionCount) {
|
||
|
return EFI_ALREADY_STARTED;
|
||
|
}
|
||
|
|
||
|
if (KeyOptionNumber == LoadOptionNumberUnassigned) {
|
||
|
KeyOptionNumber = KeyOptionCount;
|
||
|
}
|
||
|
|
||
|
UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);
|
||
|
|
||
|
Status = gRT->SetVariable (
|
||
|
KeyOptionName,
|
||
|
&gEfiGlobalVariableGuid,
|
||
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
||
|
BmSizeOfKeyOption (&KeyOption),
|
||
|
&KeyOption
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// Return the Key Option in case needed by caller
|
||
|
//
|
||
|
if (AddedOption != NULL) {
|
||
|
CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Register the newly added hot key
|
||
|
// Calling this function before EfiBootManagerStartHotkeyService doesn't
|
||
|
// need to call BmProcessKeyOption
|
||
|
//
|
||
|
if (mBmHotkeyServiceStarted) {
|
||
|
BmProcessKeyOption (&KeyOption);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Delete the Key Option variable and unregister the hot key
|
||
|
|
||
|
@param DeletedOption Return the deleted key options.
|
||
|
@param Modifier Key shift state.
|
||
|
@param ... Parameter list of pointer of EFI_INPUT_KEY.
|
||
|
|
||
|
@retval EFI_SUCCESS The key option is deleted.
|
||
|
@retval EFI_NOT_FOUND The key option cannot be found.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
EfiBootManagerDeleteKeyOptionVariable (
|
||
|
IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
|
||
|
IN UINT32 Modifier,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
VA_LIST Args;
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
|
||
|
EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
|
||
|
UINTN KeyOptionCount;
|
||
|
LIST_ENTRY *Link;
|
||
|
BM_HOTKEY *Hotkey;
|
||
|
UINT32 ShiftState;
|
||
|
BOOLEAN Match;
|
||
|
CHAR16 KeyOptionName[sizeof ("Key####")];
|
||
|
|
||
|
ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
|
||
|
VA_START (Args, Modifier);
|
||
|
Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
|
||
|
VA_END (Args);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
EfiAcquireLock (&mBmHotkeyLock);
|
||
|
//
|
||
|
// Delete the key option from active hot key list
|
||
|
// Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
|
||
|
//
|
||
|
for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
|
||
|
Hotkey = BM_HOTKEY_FROM_LINK (Link);
|
||
|
Match = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);
|
||
|
|
||
|
for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {
|
||
|
ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;
|
||
|
if (
|
||
|
(BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||
|
||
|
(BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||
|
||
|
(BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||
|
||
|
(BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||
|
||
|
(BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||
|
||
|
(BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||
|
||
|
(CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)
|
||
|
) {
|
||
|
//
|
||
|
// Break when any field doesn't match
|
||
|
//
|
||
|
Match = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Match) {
|
||
|
Link = RemoveEntryList (Link);
|
||
|
FreePool (Hotkey);
|
||
|
} else {
|
||
|
Link = GetNextNode (&mBmHotkeyList, Link);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Delete the key option from the variable
|
||
|
//
|
||
|
Status = EFI_NOT_FOUND;
|
||
|
KeyOptions = BmGetKeyOptions (&KeyOptionCount);
|
||
|
for (Index = 0; Index < KeyOptionCount; Index++) {
|
||
|
if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
|
||
|
(CompareMem (
|
||
|
KeyOptions[Index].Keys, KeyOption.Keys,
|
||
|
KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)
|
||
|
) {
|
||
|
UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);
|
||
|
Status = gRT->SetVariable (
|
||
|
KeyOptionName,
|
||
|
&gEfiGlobalVariableGuid,
|
||
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
//
|
||
|
// Return the deleted key option in case needed by caller
|
||
|
//
|
||
|
if (DeletedOption != NULL) {
|
||
|
CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
BmFreeKeyOptions (KeyOptions, KeyOptionCount);
|
||
|
|
||
|
EfiReleaseLock (&mBmHotkeyLock);
|
||
|
|
||
|
return Status;
|
||
|
}
|