2 Hotkey library functions.
4 Copyright (c) 2011 - 2018, 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
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.
16 #include "InternalBm.h"
19 // Lock for linked list
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;
28 // Set OptionNumber as unassigned value to indicate the option isn't initialized
30 EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption
= { LoadOptionNumberUnassigned
};
32 EFI_BOOT_MANAGER_KEY_OPTION
*mBmContinueKeyOption
= NULL
;
33 VOID
*mBmTxtInExRegistration
= NULL
;
37 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
39 @param KeyOption The input key option info.
41 @retval The buffer size of the key option data.
45 IN CONST EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
48 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION
, Keys
)
49 + KeyOption
->KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
);
54 Check whether the input key option is valid.
56 @param KeyOption Key option.
57 @param KeyOptionSize Size of the key option.
59 @retval TRUE Input key option is valid.
60 @retval FALSE Input key option is not valid.
64 IN CONST EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
65 IN UINTN KeyOptionSize
68 UINT16 OptionName
[BM_OPTION_NAME_LEN
];
73 if (BmSizeOfKeyOption (KeyOption
) != KeyOptionSize
) {
78 // Check whether corresponding Boot Option exist
81 OptionName
, sizeof (OptionName
), L
"%s%04x",
82 mBmLoadOptionName
[LoadOptionTypeBoot
], KeyOption
->BootOption
84 GetEfiGlobalVariable2 (OptionName
, (VOID
**) &BootOption
, &BootOptionSize
);
86 if (BootOption
== NULL
) {
91 // Check CRC for Boot Option
93 gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &Crc
);
94 FreePool (BootOption
);
96 return (BOOLEAN
) (KeyOption
->BootOptionCrc
== Crc
);
101 Check whether the input variable is an key option variable.
103 @param Name Input variable name.
104 @param Guid Input variable guid.
105 @param OptionNumber The option number of this key option variable.
107 @retval TRUE Input variable is a key option variable.
108 @retval FALSE Input variable is not a key option variable.
111 BmIsKeyOptionVariable (
120 if (!CompareGuid (Guid
, &gEfiGlobalVariableGuid
) ||
121 (StrSize (Name
) != sizeof (L
"Key####")) ||
122 (StrnCmp (Name
, L
"Key", 3) != 0)
128 for (Index
= 3; Index
< 7; Index
++) {
129 Uint
= BmCharToUint (Name
[Index
]);
133 *OptionNumber
= (UINT16
) Uint
+ *OptionNumber
* 0x10;
141 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
142 UINTN KeyOptionCount
;
143 } BM_COLLECT_KEY_OPTIONS_PARAM
;
146 Visitor function to collect the key options from NV storage.
148 @param Name Variable name.
149 @param Guid Variable GUID.
150 @param Context The same context passed to BmForEachVariable.
153 BmCollectKeyOptions (
160 BM_COLLECT_KEY_OPTIONS_PARAM
*Param
;
165 Param
= (BM_COLLECT_KEY_OPTIONS_PARAM
*) Context
;
167 if (BmIsKeyOptionVariable (Name
, Guid
, &OptionNumber
)) {
168 GetEfiGlobalVariable2 (Name
, &KeyOption
, &KeyOptionSize
);
169 ASSERT (KeyOption
!= NULL
);
170 if (BmIsKeyOptionValid (KeyOption
, KeyOptionSize
)) {
171 Param
->KeyOptions
= ReallocatePool (
172 Param
->KeyOptionCount
* sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
173 (Param
->KeyOptionCount
+ 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
176 ASSERT (Param
->KeyOptions
!= NULL
);
178 // Insert the key option in order
180 for (Index
= 0; Index
< Param
->KeyOptionCount
; Index
++) {
181 if (OptionNumber
< Param
->KeyOptions
[Index
].OptionNumber
) {
185 CopyMem (&Param
->KeyOptions
[Index
+ 1], &Param
->KeyOptions
[Index
], (Param
->KeyOptionCount
- Index
) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
186 CopyMem (&Param
->KeyOptions
[Index
], KeyOption
, KeyOptionSize
);
187 Param
->KeyOptions
[Index
].OptionNumber
= OptionNumber
;
188 Param
->KeyOptionCount
++;
190 FreePool (KeyOption
);
195 Return the array of key options.
197 @param Count Return the number of key options.
199 @retval NULL No key option.
200 @retval Other Pointer to the key options.
202 EFI_BOOT_MANAGER_KEY_OPTION
*
207 BM_COLLECT_KEY_OPTIONS_PARAM Param
;
213 Param
.KeyOptions
= NULL
;
214 Param
.KeyOptionCount
= 0;
216 BmForEachVariable (BmCollectKeyOptions
, (VOID
*) &Param
);
218 *Count
= Param
.KeyOptionCount
;
220 return Param
.KeyOptions
;
224 Check whether the bit is set in the value.
226 @param Value The value need to be check.
227 @param Bit The bit filed need to be check.
229 @retval TRUE The bit is set.
230 @retval FALSE The bit is not set.
238 return (BOOLEAN
) ((Value
& Bit
) != 0);
242 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
244 @param Modifier Input key info.
245 @param Args Va_list info.
246 @param KeyOption Key info which need to update.
248 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
249 @return EFI_INVALID_PARAMETER Input parameter error.
252 BmInitializeKeyFields (
255 OUT EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
260 if (KeyOption
== NULL
) {
261 return EFI_INVALID_PARAMETER
;
265 while (KeyOption
->KeyData
.Options
.InputKeyCount
< sizeof (KeyOption
->Keys
) / sizeof (KeyOption
->Keys
[0])) {
266 Key
= VA_ARG (Args
, EFI_INPUT_KEY
*);
271 &KeyOption
->Keys
[KeyOption
->KeyData
.Options
.InputKeyCount
],
273 sizeof (EFI_INPUT_KEY
)
275 KeyOption
->KeyData
.Options
.InputKeyCount
++;
282 return EFI_INVALID_PARAMETER
;
285 if ((Modifier
& ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
286 | EFI_BOOT_MANAGER_CONTROL_PRESSED
287 | EFI_BOOT_MANAGER_ALT_PRESSED
288 | EFI_BOOT_MANAGER_LOGO_PRESSED
289 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
290 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
292 return EFI_INVALID_PARAMETER
;
295 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SHIFT_PRESSED
)) {
296 KeyOption
->KeyData
.Options
.ShiftPressed
= 1;
298 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_CONTROL_PRESSED
)) {
299 KeyOption
->KeyData
.Options
.ControlPressed
= 1;
301 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_ALT_PRESSED
)) {
302 KeyOption
->KeyData
.Options
.AltPressed
= 1;
304 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_LOGO_PRESSED
)) {
305 KeyOption
->KeyData
.Options
.LogoPressed
= 1;
307 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_MENU_KEY_PRESSED
)) {
308 KeyOption
->KeyData
.Options
.MenuPressed
= 1;
310 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SYS_REQ_PRESSED
)) {
311 KeyOption
->KeyData
.Options
.SysReqPressed
= 1;
318 Try to boot the boot option triggered by hot key.
322 EfiBootManagerHotkeyBoot (
326 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
327 EfiBootManagerBoot (&mBmHotkeyBootOption
);
328 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption
);
329 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
334 This is the common notification function for HotKeys, it will be registered
335 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
337 @param KeyData A pointer to a buffer that is filled in with the keystroke
338 information for the key that was pressed.
340 @retval EFI_SUCCESS KeyData is successfully processed.
341 @return EFI_NOT_FOUND Fail to find boot option variable.
346 IN EFI_KEY_DATA
*KeyData
351 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
353 EFI_KEY_DATA
*HotkeyData
;
355 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
357 // Do not process sequential hotkey stroke until the current boot option returns
362 DEBUG ((EFI_D_INFO
, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData
->Key
.ScanCode
, KeyData
->Key
.UnicodeChar
));
364 EfiAcquireLock (&mBmHotkeyLock
);
365 for ( Link
= GetFirstNode (&mBmHotkeyList
)
366 ; !IsNull (&mBmHotkeyList
, Link
)
367 ; Link
= GetNextNode (&mBmHotkeyList
, Link
)
369 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
372 // Is this Key Stroke we are waiting for?
374 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
375 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
376 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
377 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
378 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
379 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
384 // Receive an expecting key stroke, transit to next waiting state
386 Hotkey
->WaitingKey
++;
388 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
390 // Reset to initial waiting state
392 Hotkey
->WaitingKey
= 0;
394 // Received the whole key stroke sequence
396 Status
= gBS
->SignalEvent (mBmHotkeyTriggered
);
397 ASSERT_EFI_ERROR (Status
);
399 if (!Hotkey
->IsContinue
) {
401 // Launch its BootOption
404 OptionName
, sizeof (OptionName
), L
"%s%04x",
405 mBmLoadOptionName
[LoadOptionTypeBoot
], Hotkey
->BootOption
407 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &mBmHotkeyBootOption
);
408 DEBUG ((EFI_D_INFO
, "[Bds]Hotkey for %s pressed - %r\n", OptionName
, Status
));
409 if (EFI_ERROR (Status
)) {
410 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
413 DEBUG ((EFI_D_INFO
, "[Bds]Continue key pressed!\n"));
418 // Receive an unexpected key stroke, reset to initial waiting state
420 Hotkey
->WaitingKey
= 0;
424 EfiReleaseLock (&mBmHotkeyLock
);
430 Return the active Simple Text Input Ex handle array.
431 If the SystemTable.ConsoleInHandle is NULL, the function returns all
432 founded Simple Text Input Ex handles.
433 Otherwise, it just returns the ConsoleInHandle.
435 @param Count Return the handle count.
437 @retval The active console handles.
440 BmGetActiveConsoleIn (
450 if (gST
->ConsoleInHandle
!= NULL
) {
451 Status
= gBS
->OpenProtocol (
452 gST
->ConsoleInHandle
,
453 &gEfiSimpleTextInputExProtocolGuid
,
457 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
459 if (!EFI_ERROR (Status
)) {
460 Handles
= AllocateCopyPool (sizeof (EFI_HANDLE
), &gST
->ConsoleInHandle
);
461 if (Handles
!= NULL
) {
466 Status
= gBS
->LocateHandleBuffer (
468 &gEfiSimpleTextInputExProtocolGuid
,
479 Unregister hotkey notify list.
481 @param Hotkey Hotkey list.
483 @retval EFI_SUCCESS Unregister hotkey notify success.
484 @retval Others Unregister hotkey notify failed.
487 BmUnregisterHotkeyNotify (
496 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
499 Handles
= BmGetActiveConsoleIn (&HandleCount
);
500 for (Index
= 0; Index
< HandleCount
; Index
++) {
501 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
502 ASSERT_EFI_ERROR (Status
);
503 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
504 Status
= TxtInEx
->RegisterKeyNotify (
506 &Hotkey
->KeyData
[KeyIndex
],
510 if (!EFI_ERROR (Status
)) {
511 Status
= TxtInEx
->UnregisterKeyNotify (TxtInEx
, NotifyHandle
);
512 DEBUG ((EFI_D_INFO
, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey
->KeyData
[KeyIndex
].Key
.ScanCode
, Hotkey
->KeyData
[KeyIndex
].Key
.UnicodeChar
, Status
));
517 if (Handles
!= NULL
) {
525 Register hotkey notify list.
527 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
528 @param Hotkey Hotkey list.
530 @retval EFI_SUCCESS Register hotkey notify success.
531 @retval Others Register hotkey notify failed.
534 BmRegisterHotkeyNotify (
535 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
,
543 for (Index
= 0; Index
< Hotkey
->CodeCount
; Index
++) {
544 Status
= TxtInEx
->RegisterKeyNotify (
546 &Hotkey
->KeyData
[Index
],
552 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
553 Hotkey
->KeyData
[Index
].Key
.ScanCode
,
554 Hotkey
->KeyData
[Index
].Key
.UnicodeChar
,
555 Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
,
556 Hotkey
->KeyData
[Index
].KeyState
.KeyToggleState
,
559 if (EFI_ERROR (Status
)) {
561 // some of the hotkey registry failed
562 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
572 Generate key shift state base on the input key option info.
574 @param Depth Which key is checked.
575 @param KeyOption Input key option info.
576 @param KeyShiftState Input key shift state.
577 @param KeyShiftStates Return possible key shift state array.
578 @param KeyShiftStateCount Possible key shift state count.
581 BmGenerateKeyShiftState (
583 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
584 IN UINT32 KeyShiftState
,
585 IN UINT32
*KeyShiftStates
,
586 IN UINTN
*KeyShiftStateCount
591 if (KeyOption
->KeyData
.Options
.ShiftPressed
) {
592 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
593 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
595 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
600 if (KeyOption
->KeyData
.Options
.ControlPressed
) {
601 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
602 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
604 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
609 if (KeyOption
->KeyData
.Options
.AltPressed
) {
610 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
611 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
613 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
617 if (KeyOption
->KeyData
.Options
.LogoPressed
) {
618 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
619 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
621 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
625 if (KeyOption
->KeyData
.Options
.MenuPressed
) {
626 KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
628 if (KeyOption
->KeyData
.Options
.SysReqPressed
) {
629 KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
631 KeyShiftStates
[*KeyShiftStateCount
] = KeyShiftState
;
632 (*KeyShiftStateCount
)++;
638 Add it to hot key database, register it to existing TxtInEx.
639 New TxtInEx will be automatically registered with all the hot key in dababase
641 @param KeyOption Input key option info.
645 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
649 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
657 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
659 UINT32 KeyShiftStates
[16];
660 UINTN KeyShiftStateCount
;
662 if (KeyOption
->KeyData
.Options
.InputKeyCount
> mBmHotkeySupportCount
) {
663 return EFI_UNSUPPORTED
;
666 KeyShiftStateCount
= 0;
667 BmGenerateKeyShiftState (0, KeyOption
, EFI_SHIFT_STATE_VALID
, KeyShiftStates
, &KeyShiftStateCount
);
668 ASSERT (KeyShiftStateCount
<= ARRAY_SIZE (KeyShiftStates
));
670 EfiAcquireLock (&mBmHotkeyLock
);
672 Handles
= BmGetActiveConsoleIn (&HandleCount
);
674 for (Index
= 0; Index
< KeyShiftStateCount
; Index
++) {
675 Hotkey
= AllocateZeroPool (sizeof (BM_HOTKEY
));
676 ASSERT (Hotkey
!= NULL
);
678 Hotkey
->Signature
= BM_HOTKEY_SIGNATURE
;
679 Hotkey
->BootOption
= KeyOption
->BootOption
;
680 Hotkey
->IsContinue
= (BOOLEAN
) (KeyOption
== mBmContinueKeyOption
);
681 Hotkey
->CodeCount
= (UINT8
) KeyOption
->KeyData
.Options
.InputKeyCount
;
683 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
684 CopyMem (&Hotkey
->KeyData
[KeyIndex
].Key
, &KeyOption
->Keys
[KeyIndex
], sizeof (EFI_INPUT_KEY
));
685 Hotkey
->KeyData
[KeyIndex
].KeyState
.KeyShiftState
= KeyShiftStates
[Index
];
687 InsertTailList (&mBmHotkeyList
, &Hotkey
->Link
);
689 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
690 Status
= gBS
->HandleProtocol (Handles
[HandleIndex
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
691 ASSERT_EFI_ERROR (Status
);
692 BmRegisterHotkeyNotify (TxtInEx
, Hotkey
);
696 if (Handles
!= NULL
) {
699 EfiReleaseLock (&mBmHotkeyLock
);
705 Callback function for SimpleTextInEx protocol install events
707 @param Event the event that is signaled.
708 @param Context not used here.
721 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
725 BufferSize
= sizeof (EFI_HANDLE
);
726 Status
= gBS
->LocateHandle (
729 mBmTxtInExRegistration
,
733 if (EFI_ERROR (Status
)) {
735 // If no more notification events exist
740 Status
= gBS
->HandleProtocol (
742 &gEfiSimpleTextInputExProtocolGuid
,
745 ASSERT_EFI_ERROR (Status
);
748 // Register the hot key notification for the existing items in the list
750 EfiAcquireLock (&mBmHotkeyLock
);
751 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); Link
= GetNextNode (&mBmHotkeyList
, Link
)) {
752 BmRegisterHotkeyNotify (TxtInEx
, BM_HOTKEY_FROM_LINK (Link
));
754 EfiReleaseLock (&mBmHotkeyLock
);
759 Free the key options returned from BmGetKeyOptions.
761 @param KeyOptions Pointer to the key options.
762 @param KeyOptionCount Number of the key options.
764 @retval EFI_SUCCESS The key options are freed.
765 @retval EFI_NOT_FOUND KeyOptions is NULL.
769 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
,
770 IN UINTN KeyOptionCount
773 if (KeyOptions
!= NULL
) {
774 FreePool (KeyOptions
);
777 return EFI_NOT_FOUND
;
782 Register the key option to exit the waiting of the Boot Manager timeout.
783 Platform should ensure that the continue key option isn't conflict with
784 other boot key options.
786 @param Modifier Key shift state.
787 @param ... Parameter list of pointer of EFI_INPUT_KEY.
789 @retval EFI_SUCCESS Successfully register the continue key option.
790 @retval EFI_ALREADY_STARTED The continue key option is already registered.
794 EfiBootManagerRegisterContinueKeyOption (
800 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
803 if (mBmContinueKeyOption
!= NULL
) {
804 return EFI_ALREADY_STARTED
;
807 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
808 VA_START (Args
, Modifier
);
809 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
812 if (!EFI_ERROR (Status
)) {
813 mBmContinueKeyOption
= AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION
), &KeyOption
);
814 ASSERT (mBmContinueKeyOption
!= NULL
);
815 if (mBmHotkeyServiceStarted
) {
816 BmProcessKeyOption (mBmContinueKeyOption
);
824 Stop the hotkey processing.
826 @param Event Event pointer related to hotkey service.
827 @param Context Context pass to this function.
831 BmStopHotkeyService (
839 DEBUG ((EFI_D_INFO
, "[Bds]Stop Hotkey Service!\n"));
840 gBS
->CloseEvent (Event
);
842 EfiAcquireLock (&mBmHotkeyLock
);
843 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
844 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
845 BmUnregisterHotkeyNotify (Hotkey
);
846 Link
= RemoveEntryList (Link
);
849 EfiReleaseLock (&mBmHotkeyLock
);
853 Start the hot key service so that the key press can trigger the boot option.
855 @param HotkeyTriggered Return the waitable event and it will be signaled
856 when a valid hot key is pressed.
858 @retval EFI_SUCCESS The hot key service is started.
862 EfiBootManagerStartHotkeyService (
863 IN EFI_EVENT
*HotkeyTriggered
867 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
868 UINTN KeyOptionCount
;
871 UINT32
*BootOptionSupport
;
873 GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, (VOID
**) &BootOptionSupport
, NULL
);
874 if (BootOptionSupport
!= NULL
) {
875 if ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_KEY
) != 0) {
876 mBmHotkeySupportCount
= ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_COUNT
) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT
));
878 FreePool (BootOptionSupport
);
881 if (mBmHotkeySupportCount
== 0) {
882 DEBUG ((EFI_D_INFO
, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
883 return EFI_UNSUPPORTED
;
886 Status
= gBS
->CreateEvent (
889 EfiEventEmptyFunction
,
893 ASSERT_EFI_ERROR (Status
);
895 if (HotkeyTriggered
!= NULL
) {
896 *HotkeyTriggered
= mBmHotkeyTriggered
;
899 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
900 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
901 BmProcessKeyOption (&KeyOptions
[Index
]);
903 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
905 if (mBmContinueKeyOption
!= NULL
) {
906 BmProcessKeyOption (mBmContinueKeyOption
);
910 // Hook hotkey on every future SimpleTextInputEx instance when
911 // SystemTable.ConsoleInHandle == NULL, which means the console
912 // manager (ConSplitter) is absent.
914 if (gST
->ConsoleInHandle
== NULL
) {
915 EfiCreateProtocolNotifyEvent (
916 &gEfiSimpleTextInputExProtocolGuid
,
920 &mBmTxtInExRegistration
924 Status
= EfiCreateEventReadyToBootEx (
930 ASSERT_EFI_ERROR (Status
);
932 mBmHotkeyServiceStarted
= TRUE
;
938 It adds the key option variable and the key option takes affect immediately.
940 @param AddedOption Return the added key option.
941 @param BootOptionNumber The boot option number for the key option.
942 @param Modifier Key shift state.
943 @param ... Parameter list of pointer of EFI_INPUT_KEY.
945 @retval EFI_SUCCESS The key option is added.
946 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
950 EfiBootManagerAddKeyOptionVariable (
951 OUT EFI_BOOT_MANAGER_KEY_OPTION
*AddedOption
, OPTIONAL
952 IN UINT16 BootOptionNumber
,
960 UINTN BootOptionSize
;
961 CHAR16 BootOptionName
[BM_OPTION_NAME_LEN
];
962 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
963 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
964 UINTN KeyOptionCount
;
966 UINTN KeyOptionNumber
;
967 CHAR16 KeyOptionName
[sizeof ("Key####")];
970 BootOptionName
, sizeof (BootOptionName
), L
"%s%04x",
971 mBmLoadOptionName
[LoadOptionTypeBoot
], BootOptionNumber
973 GetEfiGlobalVariable2 (BootOptionName
, &BootOption
, &BootOptionSize
);
975 if (BootOption
== NULL
) {
976 return EFI_NOT_FOUND
;
979 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
980 KeyOption
.BootOption
= BootOptionNumber
;
981 Status
= gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &KeyOption
.BootOptionCrc
);
982 ASSERT_EFI_ERROR (Status
);
983 FreePool (BootOption
);
985 VA_START (Args
, Modifier
);
986 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
988 if (EFI_ERROR (Status
)) {
992 KeyOptionNumber
= LoadOptionNumberUnassigned
;
994 // Check if the hot key sequence was defined already
996 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
997 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
998 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
999 (CompareMem (KeyOptions
[Index
].Keys
, KeyOption
.Keys
, KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)) {
1003 if ((KeyOptionNumber
== LoadOptionNumberUnassigned
) &&
1004 (KeyOptions
[Index
].OptionNumber
> Index
)
1006 KeyOptionNumber
= Index
;
1009 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1011 if (Index
< KeyOptionCount
) {
1012 return EFI_ALREADY_STARTED
;
1015 if (KeyOptionNumber
== LoadOptionNumberUnassigned
) {
1016 KeyOptionNumber
= KeyOptionCount
;
1019 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumber
);
1021 Status
= gRT
->SetVariable (
1023 &gEfiGlobalVariableGuid
,
1024 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1025 BmSizeOfKeyOption (&KeyOption
),
1028 if (!EFI_ERROR (Status
)) {
1030 // Return the Key Option in case needed by caller
1032 if (AddedOption
!= NULL
) {
1033 CopyMem (AddedOption
, &KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1037 // Register the newly added hot key
1038 // Calling this function before EfiBootManagerStartHotkeyService doesn't
1039 // need to call BmProcessKeyOption
1041 if (mBmHotkeyServiceStarted
) {
1042 BmProcessKeyOption (&KeyOption
);
1050 Delete the Key Option variable and unregister the hot key
1052 @param DeletedOption Return the deleted key options.
1053 @param Modifier Key shift state.
1054 @param ... Parameter list of pointer of EFI_INPUT_KEY.
1056 @retval EFI_SUCCESS The key option is deleted.
1057 @retval EFI_NOT_FOUND The key option cannot be found.
1061 EfiBootManagerDeleteKeyOptionVariable (
1062 IN EFI_BOOT_MANAGER_KEY_OPTION
*DeletedOption
, OPTIONAL
1070 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
1071 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
1072 UINTN KeyOptionCount
;
1077 CHAR16 KeyOptionName
[sizeof ("Key####")];
1079 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1080 VA_START (Args
, Modifier
);
1081 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1084 if (EFI_ERROR (Status
)) {
1088 EfiAcquireLock (&mBmHotkeyLock
);
1090 // Delete the key option from active hot key list
1091 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
1093 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
1094 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
1095 Match
= (BOOLEAN
) (Hotkey
->CodeCount
== KeyOption
.KeyData
.Options
.InputKeyCount
);
1097 for (Index
= 0; Match
&& (Index
< Hotkey
->CodeCount
); Index
++) {
1098 ShiftState
= Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
;
1100 (BmBitSet (ShiftState
, EFI_RIGHT_SHIFT_PRESSED
| EFI_LEFT_SHIFT_PRESSED
) != KeyOption
.KeyData
.Options
.ShiftPressed
) ||
1101 (BmBitSet (ShiftState
, EFI_RIGHT_CONTROL_PRESSED
| EFI_LEFT_CONTROL_PRESSED
) != KeyOption
.KeyData
.Options
.ControlPressed
) ||
1102 (BmBitSet (ShiftState
, EFI_RIGHT_ALT_PRESSED
| EFI_LEFT_ALT_PRESSED
) != KeyOption
.KeyData
.Options
.AltPressed
) ||
1103 (BmBitSet (ShiftState
, EFI_RIGHT_LOGO_PRESSED
| EFI_LEFT_LOGO_PRESSED
) != KeyOption
.KeyData
.Options
.LogoPressed
) ||
1104 (BmBitSet (ShiftState
, EFI_MENU_KEY_PRESSED
) != KeyOption
.KeyData
.Options
.MenuPressed
) ||
1105 (BmBitSet (ShiftState
, EFI_SYS_REQ_PRESSED
) != KeyOption
.KeyData
.Options
.SysReqPressed
) ||
1106 (CompareMem (&Hotkey
->KeyData
[Index
].Key
, &KeyOption
.Keys
[Index
], sizeof (EFI_INPUT_KEY
)) != 0)
1109 // Break when any field doesn't match
1117 Link
= RemoveEntryList (Link
);
1120 Link
= GetNextNode (&mBmHotkeyList
, Link
);
1125 // Delete the key option from the variable
1127 Status
= EFI_NOT_FOUND
;
1128 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1129 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1130 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1132 KeyOptions
[Index
].Keys
, KeyOption
.Keys
,
1133 KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)
1135 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptions
[Index
].OptionNumber
);
1136 Status
= gRT
->SetVariable (
1138 &gEfiGlobalVariableGuid
,
1139 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1144 // Return the deleted key option in case needed by caller
1146 if (DeletedOption
!= NULL
) {
1147 CopyMem (DeletedOption
, &KeyOptions
[Index
], sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1152 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1154 EfiReleaseLock (&mBmHotkeyLock
);