Home | History | Annotate | Download | only in UefiBootManagerLib
      1 /** @file
      2   Hotkey library functions.
      3 
      4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "InternalBm.h"
     17 
     18 //
     19 // Lock for linked list
     20 //
     21 EFI_LOCK                     mBmHotkeyLock            = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
     22 LIST_ENTRY                   mBmHotkeyList            = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);
     23 EFI_EVENT                    mBmHotkeyTriggered       = NULL;
     24 BOOLEAN                      mBmHotkeyServiceStarted  = FALSE;
     25 UINTN                        mBmHotkeySupportCount    = 0;
     26 
     27 //
     28 // Set OptionNumber as unassigned value to indicate the option isn't initialized
     29 //
     30 EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption      = { LoadOptionNumberUnassigned };
     31 
     32 EFI_BOOT_MANAGER_KEY_OPTION  *mBmContinueKeyOption    = NULL;
     33 VOID                         *mBmTxtInExRegistration  = NULL;
     34 
     35 
     36 /**
     37   Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
     38 
     39   @param   KeyOption            The input key option info.
     40 
     41   @retval  The buffer size of the key option data.
     42 **/
     43 UINTN
     44 BmSizeOfKeyOption (
     45   EFI_BOOT_MANAGER_KEY_OPTION  *KeyOption
     46   )
     47 {
     48   return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)
     49     + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
     50 }
     51 
     52 /**
     53 
     54   Check whether the input key option is valid.
     55 
     56   @param   KeyOption          Key option.
     57   @param   KeyOptionSize      Size of the key option.
     58 
     59   @retval  TRUE               Input key option is valid.
     60   @retval  FALSE              Input key option is not valid.
     61 **/
     62 BOOLEAN
     63 BmIsKeyOptionValid (
     64   IN EFI_BOOT_MANAGER_KEY_OPTION     *KeyOption,
     65   IN UINTN                           KeyOptionSize
     66 )
     67 {
     68   UINT16   OptionName[BM_OPTION_NAME_LEN];
     69   UINT8    *BootOption;
     70   UINTN    BootOptionSize;
     71   UINT32   Crc;
     72 
     73   if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {
     74     return FALSE;
     75   }
     76 
     77   //
     78   // Check whether corresponding Boot Option exist
     79   //
     80   UnicodeSPrint (
     81     OptionName, sizeof (OptionName), L"%s%04x",
     82     mBmLoadOptionName[LoadOptionTypeBoot], KeyOption->BootOption
     83     );
     84   GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);
     85 
     86   if (BootOption == NULL) {
     87     return FALSE;
     88   }
     89 
     90   //
     91   // Check CRC for Boot Option
     92   //
     93   gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);
     94   FreePool (BootOption);
     95 
     96   return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);
     97 }
     98 
     99 /**
    100 
    101   Check whether the input variable is an key option variable.
    102 
    103   @param   Name               Input variable name.
    104   @param   Guid               Input variable guid.
    105   @param   OptionNumber       The option number of this key option variable.
    106 
    107   @retval  TRUE               Input variable is a key option variable.
    108   @retval  FALSE              Input variable is not a key option variable.
    109 **/
    110 BOOLEAN
    111 BmIsKeyOptionVariable (
    112   CHAR16        *Name,
    113   EFI_GUID      *Guid,
    114   UINT16        *OptionNumber
    115   )
    116 {
    117   UINTN         Index;
    118   UINTN         Uint;
    119 
    120   if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
    121       (StrSize (Name) != sizeof (L"Key####")) ||
    122       (StrnCmp (Name, L"Key", 3) != 0)
    123      ) {
    124     return FALSE;
    125   }
    126 
    127   *OptionNumber = 0;
    128   for (Index = 3; Index < 7; Index++) {
    129     Uint = BmCharToUint (Name[Index]);
    130     if (Uint == -1) {
    131       return FALSE;
    132     } else {
    133       *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
    134     }
    135   }
    136 
    137   return TRUE;
    138 }
    139 
    140 typedef struct {
    141   EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
    142   UINTN                       KeyOptionCount;
    143 } BM_COLLECT_KEY_OPTIONS_PARAM;
    144 
    145 /**
    146   Visitor function to collect the key options from NV storage.
    147 
    148   @param Name    Variable name.
    149   @param Guid    Variable GUID.
    150   @param Context The same context passed to BmForEachVariable.
    151 **/
    152 VOID
    153 BmCollectKeyOptions (
    154   CHAR16               *Name,
    155   EFI_GUID             *Guid,
    156   VOID                 *Context
    157   )
    158 {
    159   UINTN                        Index;
    160   BM_COLLECT_KEY_OPTIONS_PARAM *Param;
    161   EFI_BOOT_MANAGER_KEY_OPTION  *KeyOption;
    162   UINT16                       OptionNumber;
    163   UINTN                        KeyOptionSize;
    164 
    165   Param = (BM_COLLECT_KEY_OPTIONS_PARAM *) Context;
    166 
    167   if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {
    168     GetEfiGlobalVariable2 (Name, (VOID**) &KeyOption, &KeyOptionSize);
    169     ASSERT (KeyOption != NULL);
    170     KeyOption->OptionNumber = OptionNumber;
    171     if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {
    172       Param->KeyOptions = ReallocatePool (
    173                             Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
    174                             (Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
    175                             Param->KeyOptions
    176                             );
    177       ASSERT (Param->KeyOptions != NULL);
    178       //
    179       // Insert the key option in order
    180       //
    181       for (Index = 0; Index < Param->KeyOptionCount; Index++) {
    182         if (KeyOption->OptionNumber < Param->KeyOptions[Index].OptionNumber) {
    183           break;
    184         }
    185       }
    186       CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
    187       CopyMem (&Param->KeyOptions[Index], KeyOption, BmSizeOfKeyOption (KeyOption));
    188       Param->KeyOptionCount++;
    189     }
    190     FreePool (KeyOption);
    191   }
    192 }
    193 
    194 /**
    195   Return the array of key options.
    196 
    197   @param Count  Return the number of key options.
    198 
    199   @retval NULL  No key option.
    200   @retval Other Pointer to the key options.
    201 **/
    202 EFI_BOOT_MANAGER_KEY_OPTION *
    203 BmGetKeyOptions (
    204   OUT UINTN     *Count
    205   )
    206 {
    207   BM_COLLECT_KEY_OPTIONS_PARAM Param;
    208 
    209   if (Count == NULL) {
    210     return NULL;
    211   }
    212 
    213   Param.KeyOptions = NULL;
    214   Param.KeyOptionCount = 0;
    215 
    216   BmForEachVariable (BmCollectKeyOptions, (VOID *) &Param);
    217 
    218   *Count = Param.KeyOptionCount;
    219 
    220   return Param.KeyOptions;
    221 }
    222 
    223 /**
    224   Callback function for event.
    225 
    226   @param    Event          Event for this callback function.
    227   @param    Context        Context pass to this function.
    228 **/
    229 VOID
    230 EFIAPI
    231 BmEmptyFunction (
    232   IN EFI_EVENT                Event,
    233   IN VOID                     *Context
    234   )
    235 {
    236 }
    237 
    238 /**
    239   Check whether the bit is set in the value.
    240 
    241   @param   Value            The value need to be check.
    242   @param   Bit              The bit filed need to be check.
    243 
    244   @retval  TRUE             The bit is set.
    245   @retval  FALSE            The bit is not set.
    246 **/
    247 BOOLEAN
    248 BmBitSet (
    249   IN UINT32   Value,
    250   IN UINT32   Bit
    251   )
    252 {
    253   return (BOOLEAN) ((Value & Bit) != 0);
    254 }
    255 
    256 /**
    257   Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
    258 
    259   @param  Modifier   Input key info.
    260   @param  Args       Va_list info.
    261   @param  KeyOption  Key info which need to update.
    262 
    263   @retval  EFI_SUCCESS             Succeed to initialize the KeyData and Key[].
    264   @return  EFI_INVALID_PARAMETER   Input parameter error.
    265 **/
    266 EFI_STATUS
    267 BmInitializeKeyFields (
    268   IN UINT32                       Modifier,
    269   IN VA_LIST                      Args,
    270   OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
    271   )
    272 {
    273   EFI_INPUT_KEY                   *Key;
    274 
    275   if (KeyOption == NULL) {
    276     return EFI_INVALID_PARAMETER;
    277   }
    278 
    279   Key = NULL;
    280   while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {
    281     Key = VA_ARG (Args, EFI_INPUT_KEY *);
    282     if (Key == NULL) {
    283       break;
    284     }
    285     CopyMem (
    286       &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],
    287       Key,
    288       sizeof (EFI_INPUT_KEY)
    289       );
    290     KeyOption->KeyData.Options.InputKeyCount++;
    291   }
    292 
    293   if (Key != NULL) {
    294     //
    295     // Too many keys
    296     //
    297     return EFI_INVALID_PARAMETER;
    298   }
    299 
    300   if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
    301                  | EFI_BOOT_MANAGER_CONTROL_PRESSED
    302                  | EFI_BOOT_MANAGER_ALT_PRESSED
    303                  | EFI_BOOT_MANAGER_LOGO_PRESSED
    304                  | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
    305                  | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
    306                  )) != 0) {
    307     return EFI_INVALID_PARAMETER;
    308   }
    309 
    310   if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {
    311     KeyOption->KeyData.Options.ShiftPressed = 1;
    312   }
    313   if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {
    314     KeyOption->KeyData.Options.ControlPressed = 1;
    315   }
    316   if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {
    317     KeyOption->KeyData.Options.AltPressed = 1;
    318   }
    319   if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {
    320     KeyOption->KeyData.Options.LogoPressed = 1;
    321   }
    322   if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {
    323     KeyOption->KeyData.Options.MenuPressed = 1;
    324   }
    325   if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {
    326     KeyOption->KeyData.Options.SysReqPressed = 1;
    327   }
    328 
    329   return EFI_SUCCESS;
    330 }
    331 
    332 /**
    333   Try to boot the boot option triggered by hot key.
    334 **/
    335 VOID
    336 EFIAPI
    337 EfiBootManagerHotkeyBoot (
    338   VOID
    339   )
    340 {
    341   if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
    342     EfiBootManagerBoot (&mBmHotkeyBootOption);
    343     EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);
    344     mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
    345   }
    346 }
    347 
    348 /**
    349   This is the common notification function for HotKeys, it will be registered
    350   with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
    351 
    352   @param KeyData         A pointer to a buffer that is filled in with the keystroke
    353                          information for the key that was pressed.
    354 
    355   @retval  EFI_SUCCESS   KeyData is successfully processed.
    356   @return  EFI_NOT_FOUND Fail to find boot option variable.
    357 **/
    358 EFI_STATUS
    359 EFIAPI
    360 BmHotkeyCallback (
    361   IN EFI_KEY_DATA     *KeyData
    362 )
    363 {
    364   LIST_ENTRY                    *Link;
    365   BM_HOTKEY                     *Hotkey;
    366   CHAR16                        OptionName[BM_OPTION_NAME_LEN];
    367   EFI_STATUS                    Status;
    368   EFI_KEY_DATA                  *HotkeyData;
    369 
    370   if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
    371     //
    372     // Do not process sequential hotkey stroke until the current boot option returns
    373     //
    374     return EFI_SUCCESS;
    375   }
    376 
    377   DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));
    378 
    379   EfiAcquireLock (&mBmHotkeyLock);
    380   for ( Link = GetFirstNode (&mBmHotkeyList)
    381       ; !IsNull (&mBmHotkeyList, Link)
    382       ; Link = GetNextNode (&mBmHotkeyList, Link)
    383       ) {
    384     Hotkey = BM_HOTKEY_FROM_LINK (Link);
    385 
    386     //
    387     // Is this Key Stroke we are waiting for?
    388     //
    389     ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
    390     HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
    391     if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
    392         (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
    393         (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?
    394           (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
    395         )
    396        ) {
    397 
    398       //
    399       // Receive an expecting key stroke, transit to next waiting state
    400       //
    401       Hotkey->WaitingKey++;
    402 
    403       if (Hotkey->WaitingKey == Hotkey->CodeCount) {
    404         //
    405         // Reset to initial waiting state
    406         //
    407         Hotkey->WaitingKey = 0;
    408         //
    409         // Received the whole key stroke sequence
    410         //
    411         Status = gBS->SignalEvent (mBmHotkeyTriggered);
    412         ASSERT_EFI_ERROR (Status);
    413 
    414         if (!Hotkey->IsContinue) {
    415           //
    416           // Launch its BootOption
    417           //
    418           UnicodeSPrint (
    419             OptionName, sizeof (OptionName), L"%s%04x",
    420             mBmLoadOptionName[LoadOptionTypeBoot], Hotkey->BootOption
    421             );
    422           Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);
    423           DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));
    424           if (EFI_ERROR (Status)) {
    425             mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
    426           }
    427         } else {
    428           DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));
    429         }
    430       }
    431     } else {
    432       //
    433       // Receive an unexpected key stroke, reset to initial waiting state
    434       //
    435       Hotkey->WaitingKey = 0;
    436     }
    437 
    438   }
    439   EfiReleaseLock (&mBmHotkeyLock);
    440 
    441   return EFI_SUCCESS;
    442 }
    443 
    444 /**
    445   Return the active Simple Text Input Ex handle array.
    446   If the SystemTable.ConsoleInHandle is NULL, the function returns all
    447   founded Simple Text Input Ex handles.
    448   Otherwise, it just returns the ConsoleInHandle.
    449 
    450   @param Count  Return the handle count.
    451 
    452   @retval The active console handles.
    453 **/
    454 EFI_HANDLE *
    455 BmGetActiveConsoleIn (
    456   OUT UINTN                             *Count
    457   )
    458 {
    459   EFI_STATUS                            Status;
    460   EFI_HANDLE                            *Handles;
    461 
    462   Handles = NULL;
    463   *Count  = 0;
    464 
    465   if (gST->ConsoleInHandle != NULL) {
    466     Status = gBS->OpenProtocol (
    467                     gST->ConsoleInHandle,
    468                     &gEfiSimpleTextInputExProtocolGuid,
    469                     NULL,
    470                     gImageHandle,
    471                     NULL,
    472                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    473                     );
    474     if (!EFI_ERROR (Status)) {
    475       Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);
    476       if (Handles != NULL) {
    477         *Count = 1;
    478       }
    479     }
    480   } else {
    481     Status = gBS->LocateHandleBuffer (
    482                     ByProtocol,
    483                     &gEfiSimpleTextInputExProtocolGuid,
    484                     NULL,
    485                     Count,
    486                     &Handles
    487                     );
    488   }
    489 
    490   return Handles;
    491 }
    492 
    493 /**
    494   Unregister hotkey notify list.
    495 
    496   @param    Hotkey                Hotkey list.
    497 
    498   @retval   EFI_SUCCESS           Unregister hotkey notify success.
    499   @retval   Others                Unregister hotkey notify failed.
    500 **/
    501 EFI_STATUS
    502 BmUnregisterHotkeyNotify (
    503   IN BM_HOTKEY                          *Hotkey
    504   )
    505 {
    506   EFI_STATUS                            Status;
    507   UINTN                                 Index;
    508   UINTN                                 KeyIndex;
    509   EFI_HANDLE                            *Handles;
    510   UINTN                                 HandleCount;
    511   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TxtInEx;
    512   VOID                                  *NotifyHandle;
    513 
    514   Handles = BmGetActiveConsoleIn (&HandleCount);
    515   for (Index = 0; Index < HandleCount; Index++) {
    516     Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
    517     ASSERT_EFI_ERROR (Status);
    518     for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
    519       Status = TxtInEx->RegisterKeyNotify (
    520                           TxtInEx,
    521                           &Hotkey->KeyData[KeyIndex],
    522                           BmHotkeyCallback,
    523                           &NotifyHandle
    524                           );
    525       if (!EFI_ERROR (Status)) {
    526         Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);
    527         DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));
    528       }
    529     }
    530   }
    531 
    532   if (Handles != NULL) {
    533     FreePool (Handles);
    534   }
    535 
    536   return EFI_SUCCESS;
    537 }
    538 
    539 /**
    540   Register hotkey notify list.
    541 
    542   @param    TxtInEx               Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
    543   @param    Hotkey                Hotkey list.
    544 
    545   @retval   EFI_SUCCESS           Register hotkey notify success.
    546   @retval   Others                Register hotkey notify failed.
    547 **/
    548 EFI_STATUS
    549 BmRegisterHotkeyNotify (
    550   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TxtInEx,
    551   IN BM_HOTKEY                          *Hotkey
    552   )
    553 {
    554   EFI_STATUS                            Status;
    555   UINTN                                 Index;
    556   VOID                                  *NotifyHandle;
    557 
    558   for (Index = 0; Index < Hotkey->CodeCount; Index++) {
    559     Status = TxtInEx->RegisterKeyNotify (
    560                         TxtInEx,
    561                         &Hotkey->KeyData[Index],
    562                         BmHotkeyCallback,
    563                         &NotifyHandle
    564                         );
    565     DEBUG ((
    566       EFI_D_INFO,
    567       "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
    568       Hotkey->KeyData[Index].Key.ScanCode,
    569       Hotkey->KeyData[Index].Key.UnicodeChar,
    570       Hotkey->KeyData[Index].KeyState.KeyShiftState,
    571       Hotkey->KeyData[Index].KeyState.KeyToggleState,
    572       Status
    573       ));
    574     if (EFI_ERROR (Status)) {
    575       //
    576       // some of the hotkey registry failed
    577       // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
    578       //
    579       break;
    580     }
    581   }
    582 
    583   return EFI_SUCCESS;
    584 }
    585 
    586 /**
    587   Generate key shift state base on the input key option info.
    588 
    589   @param    Depth                 Which key is checked.
    590   @param    KeyOption             Input key option info.
    591   @param    KeyShiftState         Input key shift state.
    592   @param    KeyShiftStates        Return possible key shift state array.
    593   @param    KeyShiftStateCount    Possible key shift state count.
    594 **/
    595 VOID
    596 BmGenerateKeyShiftState (
    597   IN UINTN                             Depth,
    598   IN EFI_BOOT_MANAGER_KEY_OPTION       *KeyOption,
    599   IN UINT32                            KeyShiftState,
    600   IN UINT32                            *KeyShiftStates,
    601   IN UINTN                             *KeyShiftStateCount
    602   )
    603 {
    604   switch (Depth) {
    605   case 0:
    606     if (KeyOption->KeyData.Options.ShiftPressed) {
    607       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
    608       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED,  KeyShiftStates, KeyShiftStateCount);
    609     } else {
    610       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
    611     }
    612     break;
    613 
    614   case 1:
    615     if (KeyOption->KeyData.Options.ControlPressed) {
    616       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
    617       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED,  KeyShiftStates, KeyShiftStateCount);
    618     } else {
    619       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
    620     }
    621     break;
    622 
    623   case 2:
    624     if (KeyOption->KeyData.Options.AltPressed) {
    625       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
    626       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED,  KeyShiftStates, KeyShiftStateCount);
    627     } else {
    628       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
    629     }
    630     break;
    631   case  3:
    632     if (KeyOption->KeyData.Options.LogoPressed) {
    633       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
    634       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED,  KeyShiftStates, KeyShiftStateCount);
    635     } else {
    636       BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
    637     }
    638     break;
    639   case 4:
    640     if (KeyOption->KeyData.Options.MenuPressed) {
    641       KeyShiftState |= EFI_MENU_KEY_PRESSED;
    642     }
    643     if (KeyOption->KeyData.Options.SysReqPressed) {
    644       KeyShiftState |= EFI_SYS_REQ_PRESSED;
    645     }
    646     KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;
    647     (*KeyShiftStateCount)++;
    648     break;
    649   }
    650 }
    651 
    652 /**
    653   Add it to hot key database, register it to existing TxtInEx.
    654   New TxtInEx will be automatically registered with all the hot key in dababase
    655 
    656   @param    KeyOption  Input key option info.
    657 **/
    658 EFI_STATUS
    659 BmProcessKeyOption (
    660   IN EFI_BOOT_MANAGER_KEY_OPTION       *KeyOption
    661   )
    662 {
    663   EFI_STATUS                           Status;
    664   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL    *TxtInEx;
    665   EFI_HANDLE                           *Handles;
    666   UINTN                                HandleCount;
    667   UINTN                                HandleIndex;
    668   UINTN                                Index;
    669   BM_HOTKEY                            *Hotkey;
    670   UINTN                                KeyIndex;
    671   //
    672   // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
    673   //
    674   UINT32                               KeyShiftStates[16];
    675   UINTN                                KeyShiftStateCount;
    676 
    677   if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {
    678     return EFI_UNSUPPORTED;
    679   }
    680 
    681   KeyShiftStateCount = 0;
    682   BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);
    683   ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));
    684 
    685   EfiAcquireLock (&mBmHotkeyLock);
    686 
    687   Handles = BmGetActiveConsoleIn (&HandleCount);
    688 
    689   for (Index = 0; Index < KeyShiftStateCount; Index++) {
    690     Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));
    691     ASSERT (Hotkey != NULL);
    692 
    693     Hotkey->Signature  = BM_HOTKEY_SIGNATURE;
    694     Hotkey->BootOption = KeyOption->BootOption;
    695     Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);
    696     Hotkey->CodeCount  = (UINT8) KeyOption->KeyData.Options.InputKeyCount;
    697 
    698     for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
    699       CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));
    700       Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];
    701     }
    702     InsertTailList (&mBmHotkeyList, &Hotkey->Link);
    703 
    704     for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
    705       Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
    706       ASSERT_EFI_ERROR (Status);
    707       BmRegisterHotkeyNotify (TxtInEx, Hotkey);
    708     }
    709   }
    710 
    711   if (Handles != NULL) {
    712     FreePool (Handles);
    713   }
    714   EfiReleaseLock (&mBmHotkeyLock);
    715 
    716   return EFI_SUCCESS;
    717 }
    718 
    719 /**
    720   Callback function for SimpleTextInEx protocol install events
    721 
    722   @param Event           the event that is signaled.
    723   @param Context         not used here.
    724 
    725 **/
    726 VOID
    727 EFIAPI
    728 BmTxtInExCallback (
    729   IN EFI_EVENT    Event,
    730   IN VOID         *Context
    731   )
    732 {
    733   EFI_STATUS                         Status;
    734   UINTN                              BufferSize;
    735   EFI_HANDLE                         Handle;
    736   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TxtInEx;
    737   LIST_ENTRY                         *Link;
    738 
    739   while (TRUE) {
    740     BufferSize = sizeof (EFI_HANDLE);
    741     Status = gBS->LocateHandle (
    742                     ByRegisterNotify,
    743                     NULL,
    744                     mBmTxtInExRegistration,
    745                     &BufferSize,
    746                     &Handle
    747                     );
    748     if (EFI_ERROR (Status)) {
    749       //
    750       // If no more notification events exist
    751       //
    752       return ;
    753     }
    754 
    755     Status = gBS->HandleProtocol (
    756                     Handle,
    757                     &gEfiSimpleTextInputExProtocolGuid,
    758                     (VOID **) &TxtInEx
    759                     );
    760     ASSERT_EFI_ERROR (Status);
    761 
    762     //
    763     // Register the hot key notification for the existing items in the list
    764     //
    765     EfiAcquireLock (&mBmHotkeyLock);
    766     for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {
    767       BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));
    768     }
    769     EfiReleaseLock (&mBmHotkeyLock);
    770   }
    771 }
    772 
    773 /**
    774   Free the key options returned from BmGetKeyOptions.
    775 
    776   @param KeyOptions     Pointer to the key options.
    777   @param KeyOptionCount Number of the key options.
    778 
    779   @retval EFI_SUCCESS   The key options are freed.
    780   @retval EFI_NOT_FOUND KeyOptions is NULL.
    781 **/
    782 EFI_STATUS
    783 BmFreeKeyOptions (
    784   IN EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions,
    785   IN UINTN                          KeyOptionCount
    786   )
    787 {
    788   if (KeyOptions != NULL) {
    789     FreePool (KeyOptions);
    790     return EFI_SUCCESS;
    791   } else {
    792     return EFI_NOT_FOUND;
    793   }
    794 }
    795 
    796 /**
    797   Register the key option to exit the waiting of the Boot Manager timeout.
    798   Platform should ensure that the continue key option isn't conflict with
    799   other boot key options.
    800 
    801   @param Modifier     Key shift state.
    802   @param  ...         Parameter list of pointer of EFI_INPUT_KEY.
    803 
    804   @retval EFI_SUCCESS         Successfully register the continue key option.
    805   @retval EFI_ALREADY_STARTED The continue key option is already registered.
    806 **/
    807 EFI_STATUS
    808 EFIAPI
    809 EfiBootManagerRegisterContinueKeyOption (
    810   IN UINT32           Modifier,
    811   ...
    812   )
    813 {
    814   EFI_STATUS                   Status;
    815   EFI_BOOT_MANAGER_KEY_OPTION  KeyOption;
    816   VA_LIST                      Args;
    817 
    818   if (mBmContinueKeyOption != NULL) {
    819     return EFI_ALREADY_STARTED;
    820   }
    821 
    822   ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
    823   VA_START (Args, Modifier);
    824   Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
    825   VA_END (Args);
    826 
    827   if (!EFI_ERROR (Status)) {
    828     mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);
    829     ASSERT (mBmContinueKeyOption != NULL);
    830     if (mBmHotkeyServiceStarted) {
    831       BmProcessKeyOption (mBmContinueKeyOption);
    832     }
    833   }
    834 
    835   return Status;
    836 }
    837 
    838 /**
    839   Stop the hotkey processing.
    840 
    841   @param    Event          Event pointer related to hotkey service.
    842   @param    Context        Context pass to this function.
    843 **/
    844 VOID
    845 EFIAPI
    846 BmStopHotkeyService (
    847   IN EFI_EVENT    Event,
    848   IN VOID         *Context
    849   )
    850 {
    851   LIST_ENTRY            *Link;
    852   BM_HOTKEY             *Hotkey;
    853 
    854   DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));
    855   gBS->CloseEvent (Event);
    856 
    857   EfiAcquireLock (&mBmHotkeyLock);
    858   for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
    859     Hotkey = BM_HOTKEY_FROM_LINK (Link);
    860     BmUnregisterHotkeyNotify (Hotkey);
    861     Link   = RemoveEntryList (Link);
    862     FreePool (Hotkey);
    863   }
    864   EfiReleaseLock (&mBmHotkeyLock);
    865 }
    866 
    867 /**
    868   Start the hot key service so that the key press can trigger the boot option.
    869 
    870   @param HotkeyTriggered  Return the waitable event and it will be signaled
    871                           when a valid hot key is pressed.
    872 
    873   @retval EFI_SUCCESS     The hot key service is started.
    874 **/
    875 EFI_STATUS
    876 EFIAPI
    877 EfiBootManagerStartHotkeyService (
    878   IN EFI_EVENT                 *HotkeyTriggered
    879   )
    880 {
    881   EFI_STATUS                   Status;
    882   EFI_BOOT_MANAGER_KEY_OPTION  *KeyOptions;
    883   UINTN                        KeyOptionCount;
    884   UINTN                        Index;
    885   EFI_EVENT                    Event;
    886   UINT32                       *BootOptionSupport;
    887 
    888   Status = GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);
    889   ASSERT (BootOptionSupport != NULL);
    890 
    891   if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY)  != 0) {
    892     mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));
    893   }
    894   FreePool (BootOptionSupport);
    895 
    896   if (mBmHotkeySupportCount == 0) {
    897     DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
    898     return EFI_UNSUPPORTED;
    899   }
    900 
    901   Status = gBS->CreateEvent (
    902                   EVT_NOTIFY_WAIT,
    903                   TPL_CALLBACK,
    904                   BmEmptyFunction,
    905                   NULL,
    906                   &mBmHotkeyTriggered
    907                   );
    908   ASSERT_EFI_ERROR (Status);
    909 
    910   if (HotkeyTriggered != NULL) {
    911     *HotkeyTriggered = mBmHotkeyTriggered;
    912   }
    913 
    914   KeyOptions = BmGetKeyOptions (&KeyOptionCount);
    915   for (Index = 0; Index < KeyOptionCount; Index ++) {
    916     BmProcessKeyOption (&KeyOptions[Index]);
    917   }
    918   BmFreeKeyOptions (KeyOptions, KeyOptionCount);
    919 
    920   if (mBmContinueKeyOption != NULL) {
    921     BmProcessKeyOption (mBmContinueKeyOption);
    922   }
    923 
    924   //
    925   // Hook hotkey on every future SimpleTextInputEx instance when
    926   // SystemTable.ConsoleInHandle == NULL, which means the console
    927   // manager (ConSplitter) is absent.
    928   //
    929   if (gST->ConsoleInHandle == NULL) {
    930     EfiCreateProtocolNotifyEvent (
    931       &gEfiSimpleTextInputExProtocolGuid,
    932       TPL_CALLBACK,
    933       BmTxtInExCallback,
    934       NULL,
    935       &mBmTxtInExRegistration
    936       );
    937   }
    938 
    939   Status = EfiCreateEventReadyToBootEx (
    940              TPL_CALLBACK,
    941              BmStopHotkeyService,
    942              NULL,
    943              &Event
    944              );
    945   ASSERT_EFI_ERROR (Status);
    946 
    947   mBmHotkeyServiceStarted = TRUE;
    948   return Status;
    949 }
    950 
    951 /**
    952   Add the key option.
    953   It adds the key option variable and the key option takes affect immediately.
    954 
    955   @param AddedOption      Return the added key option.
    956   @param BootOptionNumber The boot option number for the key option.
    957   @param Modifier         Key shift state.
    958   @param ...              Parameter list of pointer of EFI_INPUT_KEY.
    959 
    960   @retval EFI_SUCCESS         The key option is added.
    961   @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
    962 **/
    963 EFI_STATUS
    964 EFIAPI
    965 EfiBootManagerAddKeyOptionVariable (
    966   OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption,   OPTIONAL
    967   IN UINT16                       BootOptionNumber,
    968   IN UINT32                       Modifier,
    969   ...
    970   )
    971 {
    972   EFI_STATUS                     Status;
    973   VA_LIST                        Args;
    974   VOID                           *BootOption;
    975   UINTN                          BootOptionSize;
    976   CHAR16                         BootOptionName[BM_OPTION_NAME_LEN];
    977   EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;
    978   EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;
    979   UINTN                          KeyOptionCount;
    980   UINTN                          Index;
    981   UINTN                          KeyOptionNumber;
    982   CHAR16                         KeyOptionName[sizeof ("Key####")];
    983 
    984   UnicodeSPrint (
    985     BootOptionName, sizeof (BootOptionName), L"%s%04x",
    986     mBmLoadOptionName[LoadOptionTypeBoot], BootOptionNumber
    987     );
    988   GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);
    989 
    990   if (BootOption == NULL) {
    991     return EFI_NOT_FOUND;
    992   }
    993 
    994   ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
    995   KeyOption.BootOption = BootOptionNumber;
    996   Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);
    997   ASSERT_EFI_ERROR (Status);
    998   FreePool (BootOption);
    999 
   1000   VA_START (Args, Modifier);
   1001   Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
   1002   VA_END (Args);
   1003   if (EFI_ERROR (Status)) {
   1004     return Status;
   1005   }
   1006 
   1007   KeyOptionNumber = LoadOptionNumberUnassigned;
   1008   //
   1009   // Check if the hot key sequence was defined already
   1010   //
   1011   KeyOptions = BmGetKeyOptions (&KeyOptionCount);
   1012   for (Index = 0; Index < KeyOptionCount; Index++) {
   1013     if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
   1014       (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {
   1015       break;
   1016     }
   1017 
   1018     if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&
   1019         (KeyOptions[Index].OptionNumber > Index)
   1020        ){
   1021       KeyOptionNumber = Index;
   1022     }
   1023   }
   1024   BmFreeKeyOptions (KeyOptions, KeyOptionCount);
   1025 
   1026   if (Index < KeyOptionCount) {
   1027     return EFI_ALREADY_STARTED;
   1028   }
   1029 
   1030   if (KeyOptionNumber == LoadOptionNumberUnassigned) {
   1031     KeyOptionNumber = KeyOptionCount;
   1032   }
   1033 
   1034   UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);
   1035 
   1036   Status = gRT->SetVariable (
   1037                   KeyOptionName,
   1038                   &gEfiGlobalVariableGuid,
   1039                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1040                   BmSizeOfKeyOption (&KeyOption),
   1041                   &KeyOption
   1042                   );
   1043   if (!EFI_ERROR (Status)) {
   1044     //
   1045     // Return the Key Option in case needed by caller
   1046     //
   1047     if (AddedOption != NULL) {
   1048       CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
   1049     }
   1050 
   1051     //
   1052     // Register the newly added hot key
   1053     // Calling this function before EfiBootManagerStartHotkeyService doesn't
   1054     // need to call BmProcessKeyOption
   1055     //
   1056     if (mBmHotkeyServiceStarted) {
   1057       BmProcessKeyOption (&KeyOption);
   1058     }
   1059   }
   1060 
   1061   return Status;
   1062 }
   1063 
   1064 /**
   1065   Delete the Key Option variable and unregister the hot key
   1066 
   1067   @param DeletedOption  Return the deleted key options.
   1068   @param Modifier       Key shift state.
   1069   @param ...            Parameter list of pointer of EFI_INPUT_KEY.
   1070 
   1071   @retval EFI_SUCCESS   The key option is deleted.
   1072   @retval EFI_NOT_FOUND The key option cannot be found.
   1073 **/
   1074 EFI_STATUS
   1075 EFIAPI
   1076 EfiBootManagerDeleteKeyOptionVariable (
   1077   IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
   1078   IN UINT32                      Modifier,
   1079   ...
   1080   )
   1081 {
   1082   EFI_STATUS                     Status;
   1083   UINTN                          Index;
   1084   VA_LIST                        Args;
   1085   EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;
   1086   EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;
   1087   UINTN                          KeyOptionCount;
   1088   LIST_ENTRY                     *Link;
   1089   BM_HOTKEY                      *Hotkey;
   1090   UINT32                         ShiftState;
   1091   BOOLEAN                        Match;
   1092   CHAR16                         KeyOptionName[sizeof ("Key####")];
   1093 
   1094   ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
   1095   VA_START (Args, Modifier);
   1096   Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
   1097   VA_END (Args);
   1098 
   1099   if (EFI_ERROR (Status)) {
   1100     return Status;
   1101   }
   1102 
   1103   EfiAcquireLock (&mBmHotkeyLock);
   1104   //
   1105   // Delete the key option from active hot key list
   1106   // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
   1107   //
   1108   for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
   1109     Hotkey = BM_HOTKEY_FROM_LINK (Link);
   1110     Match  = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);
   1111 
   1112     for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {
   1113       ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;
   1114       if (
   1115         (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||
   1116         (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||
   1117         (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||
   1118         (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||
   1119         (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||
   1120         (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||
   1121         (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)
   1122         ) {
   1123         //
   1124         // Break when any field doesn't match
   1125         //
   1126         Match = FALSE;
   1127         break;
   1128       }
   1129     }
   1130 
   1131     if (Match) {
   1132       Link = RemoveEntryList (Link);
   1133       FreePool (Hotkey);
   1134     } else {
   1135       Link = GetNextNode (&mBmHotkeyList, Link);
   1136     }
   1137   }
   1138 
   1139   //
   1140   // Delete the key option from the variable
   1141   //
   1142   Status     = EFI_NOT_FOUND;
   1143   KeyOptions = BmGetKeyOptions (&KeyOptionCount);
   1144   for (Index = 0; Index < KeyOptionCount; Index++) {
   1145     if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
   1146         (CompareMem (
   1147            KeyOptions[Index].Keys, KeyOption.Keys,
   1148            KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)
   1149        ) {
   1150       UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);
   1151       Status = gRT->SetVariable (
   1152                  KeyOptionName,
   1153                  &gEfiGlobalVariableGuid,
   1154                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1155                  0,
   1156                  NULL
   1157                  );
   1158       //
   1159       // Return the deleted key option in case needed by caller
   1160       //
   1161       if (DeletedOption != NULL) {
   1162         CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
   1163       }
   1164       break;
   1165     }
   1166   }
   1167   BmFreeKeyOptions (KeyOptions, KeyOptionCount);
   1168 
   1169   EfiReleaseLock (&mBmHotkeyLock);
   1170 
   1171   return Status;
   1172 }
   1173