2 Hotkey library functions.
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
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 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 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
;
161 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
;
165 Param
= (BM_COLLECT_KEY_OPTIONS_PARAM
*) Context
;
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
),
177 ASSERT (Param
->KeyOptions
!= NULL
);
179 // Insert the key option in order
181 for (Index
= 0; Index
< Param
->KeyOptionCount
; Index
++) {
182 if (KeyOption
->OptionNumber
< Param
->KeyOptions
[Index
].OptionNumber
) {
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
++;
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 Callback function for event.
226 @param Event Event for this callback function.
227 @param Context Context pass to this function.
239 Check whether the bit is set in the value.
241 @param Value The value need to be check.
242 @param Bit The bit filed need to be check.
244 @retval TRUE The bit is set.
245 @retval FALSE The bit is not set.
253 return (BOOLEAN
) ((Value
& Bit
) != 0);
257 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
259 @param Modifier Input key info.
260 @param Args Va_list info.
261 @param KeyOption Key info which need to update.
263 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
264 @return EFI_INVALID_PARAMETER Input parameter error.
267 BmInitializeKeyFields (
270 OUT EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
275 if (KeyOption
== NULL
) {
276 return EFI_INVALID_PARAMETER
;
280 while (KeyOption
->KeyData
.Options
.InputKeyCount
< sizeof (KeyOption
->Keys
) / sizeof (KeyOption
->Keys
[0])) {
281 Key
= VA_ARG (Args
, EFI_INPUT_KEY
*);
286 &KeyOption
->Keys
[KeyOption
->KeyData
.Options
.InputKeyCount
],
288 sizeof (EFI_INPUT_KEY
)
290 KeyOption
->KeyData
.Options
.InputKeyCount
++;
297 return EFI_INVALID_PARAMETER
;
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
307 return EFI_INVALID_PARAMETER
;
310 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SHIFT_PRESSED
)) {
311 KeyOption
->KeyData
.Options
.ShiftPressed
= 1;
313 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_CONTROL_PRESSED
)) {
314 KeyOption
->KeyData
.Options
.ControlPressed
= 1;
316 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_ALT_PRESSED
)) {
317 KeyOption
->KeyData
.Options
.AltPressed
= 1;
319 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_LOGO_PRESSED
)) {
320 KeyOption
->KeyData
.Options
.LogoPressed
= 1;
322 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_MENU_KEY_PRESSED
)) {
323 KeyOption
->KeyData
.Options
.MenuPressed
= 1;
325 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SYS_REQ_PRESSED
)) {
326 KeyOption
->KeyData
.Options
.SysReqPressed
= 1;
333 Try to boot the boot option triggered by hot key.
337 EfiBootManagerHotkeyBoot (
341 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
342 EfiBootManagerBoot (&mBmHotkeyBootOption
);
343 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption
);
344 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
349 This is the common notification function for HotKeys, it will be registered
350 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
352 @param KeyData A pointer to a buffer that is filled in with the keystroke
353 information for the key that was pressed.
355 @retval EFI_SUCCESS KeyData is successfully processed.
356 @return EFI_NOT_FOUND Fail to find boot option variable.
361 IN EFI_KEY_DATA
*KeyData
366 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
368 EFI_KEY_DATA
*HotkeyData
;
370 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
372 // Do not process sequential hotkey stroke until the current boot option returns
377 DEBUG ((EFI_D_INFO
, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData
->Key
.ScanCode
, KeyData
->Key
.UnicodeChar
));
379 EfiAcquireLock (&mBmHotkeyLock
);
380 for ( Link
= GetFirstNode (&mBmHotkeyList
)
381 ; !IsNull (&mBmHotkeyList
, Link
)
382 ; Link
= GetNextNode (&mBmHotkeyList
, Link
)
384 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
387 // Is this Key Stroke we are waiting for?
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
399 // Receive an expecting key stroke, transit to next waiting state
401 Hotkey
->WaitingKey
++;
403 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
405 // Reset to initial waiting state
407 Hotkey
->WaitingKey
= 0;
409 // Received the whole key stroke sequence
411 Status
= gBS
->SignalEvent (mBmHotkeyTriggered
);
412 ASSERT_EFI_ERROR (Status
);
414 if (!Hotkey
->IsContinue
) {
416 // Launch its BootOption
419 OptionName
, sizeof (OptionName
), L
"%s%04x",
420 mBmLoadOptionName
[LoadOptionTypeBoot
], Hotkey
->BootOption
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
;
428 DEBUG ((EFI_D_INFO
, "[Bds]Continue key pressed!\n"));
433 // Receive an unexpected key stroke, reset to initial waiting state
435 Hotkey
->WaitingKey
= 0;
439 EfiReleaseLock (&mBmHotkeyLock
);
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.
450 @param Count Return the handle count.
452 @retval The active console handles.
455 BmGetActiveConsoleIn (
465 if (gST
->ConsoleInHandle
!= NULL
) {
466 Status
= gBS
->OpenProtocol (
467 gST
->ConsoleInHandle
,
468 &gEfiSimpleTextInputExProtocolGuid
,
472 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
474 if (!EFI_ERROR (Status
)) {
475 Handles
= AllocateCopyPool (sizeof (EFI_HANDLE
), &gST
->ConsoleInHandle
);
476 if (Handles
!= NULL
) {
481 Status
= gBS
->LocateHandleBuffer (
483 &gEfiSimpleTextInputExProtocolGuid
,
494 Unregister hotkey notify list.
496 @param Hotkey Hotkey list.
498 @retval EFI_SUCCESS Unregister hotkey notify success.
499 @retval Others Unregister hotkey notify failed.
502 BmUnregisterHotkeyNotify (
511 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
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 (
521 &Hotkey
->KeyData
[KeyIndex
],
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
));
532 if (Handles
!= NULL
) {
540 Register hotkey notify list.
542 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
543 @param Hotkey Hotkey list.
545 @retval EFI_SUCCESS Register hotkey notify success.
546 @retval Others Register hotkey notify failed.
549 BmRegisterHotkeyNotify (
550 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
,
558 for (Index
= 0; Index
< Hotkey
->CodeCount
; Index
++) {
559 Status
= TxtInEx
->RegisterKeyNotify (
561 &Hotkey
->KeyData
[Index
],
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
,
574 if (EFI_ERROR (Status
)) {
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
587 Generate key shift state base on the input key option info.
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.
596 BmGenerateKeyShiftState (
598 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
599 IN UINT32 KeyShiftState
,
600 IN UINT32
*KeyShiftStates
,
601 IN UINTN
*KeyShiftStateCount
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
);
610 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
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
);
619 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
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
);
628 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
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
);
636 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
640 if (KeyOption
->KeyData
.Options
.MenuPressed
) {
641 KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
643 if (KeyOption
->KeyData
.Options
.SysReqPressed
) {
644 KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
646 KeyShiftStates
[*KeyShiftStateCount
] = KeyShiftState
;
647 (*KeyShiftStateCount
)++;
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
656 @param KeyOption Input key option info.
660 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
664 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
672 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
674 UINT32 KeyShiftStates
[16];
675 UINTN KeyShiftStateCount
;
677 if (KeyOption
->KeyData
.Options
.InputKeyCount
> mBmHotkeySupportCount
) {
678 return EFI_UNSUPPORTED
;
681 KeyShiftStateCount
= 0;
682 BmGenerateKeyShiftState (0, KeyOption
, EFI_SHIFT_STATE_VALID
, KeyShiftStates
, &KeyShiftStateCount
);
683 ASSERT (KeyShiftStateCount
<= sizeof (KeyShiftStates
) / sizeof (KeyShiftStates
[0]));
685 EfiAcquireLock (&mBmHotkeyLock
);
687 Handles
= BmGetActiveConsoleIn (&HandleCount
);
689 for (Index
= 0; Index
< KeyShiftStateCount
; Index
++) {
690 Hotkey
= AllocateZeroPool (sizeof (BM_HOTKEY
));
691 ASSERT (Hotkey
!= NULL
);
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
;
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
];
702 InsertTailList (&mBmHotkeyList
, &Hotkey
->Link
);
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
);
711 if (Handles
!= NULL
) {
714 EfiReleaseLock (&mBmHotkeyLock
);
720 Callback function for SimpleTextInEx protocol install events
722 @param Event the event that is signaled.
723 @param Context not used here.
736 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
740 BufferSize
= sizeof (EFI_HANDLE
);
741 Status
= gBS
->LocateHandle (
744 mBmTxtInExRegistration
,
748 if (EFI_ERROR (Status
)) {
750 // If no more notification events exist
755 Status
= gBS
->HandleProtocol (
757 &gEfiSimpleTextInputExProtocolGuid
,
760 ASSERT_EFI_ERROR (Status
);
763 // Register the hot key notification for the existing items in the list
765 EfiAcquireLock (&mBmHotkeyLock
);
766 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); Link
= GetNextNode (&mBmHotkeyList
, Link
)) {
767 BmRegisterHotkeyNotify (TxtInEx
, BM_HOTKEY_FROM_LINK (Link
));
769 EfiReleaseLock (&mBmHotkeyLock
);
774 Free the key options returned from BmGetKeyOptions.
776 @param KeyOptions Pointer to the key options.
777 @param KeyOptionCount Number of the key options.
779 @retval EFI_SUCCESS The key options are freed.
780 @retval EFI_NOT_FOUND KeyOptions is NULL.
784 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
,
785 IN UINTN KeyOptionCount
788 if (KeyOptions
!= NULL
) {
789 FreePool (KeyOptions
);
792 return EFI_NOT_FOUND
;
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.
801 @param Modifier Key shift state.
802 @param ... Parameter list of pointer of EFI_INPUT_KEY.
804 @retval EFI_SUCCESS Successfully register the continue key option.
805 @retval EFI_ALREADY_STARTED The continue key option is already registered.
809 EfiBootManagerRegisterContinueKeyOption (
815 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
818 if (mBmContinueKeyOption
!= NULL
) {
819 return EFI_ALREADY_STARTED
;
822 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
823 VA_START (Args
, Modifier
);
824 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
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
);
839 Stop the hotkey processing.
841 @param Event Event pointer related to hotkey service.
842 @param Context Context pass to this function.
846 BmStopHotkeyService (
854 DEBUG ((EFI_D_INFO
, "[Bds]Stop Hotkey Service!\n"));
855 gBS
->CloseEvent (Event
);
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
);
864 EfiReleaseLock (&mBmHotkeyLock
);
868 Start the hot key service so that the key press can trigger the boot option.
870 @param HotkeyTriggered Return the waitable event and it will be signaled
871 when a valid hot key is pressed.
873 @retval EFI_SUCCESS The hot key service is started.
877 EfiBootManagerStartHotkeyService (
878 IN EFI_EVENT
*HotkeyTriggered
882 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
883 UINTN KeyOptionCount
;
886 UINT32
*BootOptionSupport
;
888 Status
= GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, (VOID
**) &BootOptionSupport
, NULL
);
889 ASSERT (BootOptionSupport
!= NULL
);
891 if ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_KEY
) != 0) {
892 mBmHotkeySupportCount
= ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_COUNT
) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT
));
894 FreePool (BootOptionSupport
);
896 if (mBmHotkeySupportCount
== 0) {
897 DEBUG ((EFI_D_INFO
, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
898 return EFI_UNSUPPORTED
;
901 Status
= gBS
->CreateEvent (
908 ASSERT_EFI_ERROR (Status
);
910 if (HotkeyTriggered
!= NULL
) {
911 *HotkeyTriggered
= mBmHotkeyTriggered
;
914 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
915 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
916 BmProcessKeyOption (&KeyOptions
[Index
]);
918 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
920 if (mBmContinueKeyOption
!= NULL
) {
921 BmProcessKeyOption (mBmContinueKeyOption
);
925 // Hook hotkey on every future SimpleTextInputEx instance when
926 // SystemTable.ConsoleInHandle == NULL, which means the console
927 // manager (ConSplitter) is absent.
929 if (gST
->ConsoleInHandle
== NULL
) {
930 EfiCreateProtocolNotifyEvent (
931 &gEfiSimpleTextInputExProtocolGuid
,
935 &mBmTxtInExRegistration
939 Status
= EfiCreateEventReadyToBootEx (
945 ASSERT_EFI_ERROR (Status
);
947 mBmHotkeyServiceStarted
= TRUE
;
953 It adds the key option variable and the key option takes affect immediately.
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.
960 @retval EFI_SUCCESS The key option is added.
961 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
965 EfiBootManagerAddKeyOptionVariable (
966 OUT EFI_BOOT_MANAGER_KEY_OPTION
*AddedOption
, OPTIONAL
967 IN UINT16 BootOptionNumber
,
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
;
981 UINTN KeyOptionNumber
;
982 CHAR16 KeyOptionName
[sizeof ("Key####")];
985 BootOptionName
, sizeof (BootOptionName
), L
"%s%04x",
986 mBmLoadOptionName
[LoadOptionTypeBoot
], BootOptionNumber
988 GetEfiGlobalVariable2 (BootOptionName
, &BootOption
, &BootOptionSize
);
990 if (BootOption
== NULL
) {
991 return EFI_NOT_FOUND
;
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
);
1000 VA_START (Args
, Modifier
);
1001 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1003 if (EFI_ERROR (Status
)) {
1007 KeyOptionNumber
= LoadOptionNumberUnassigned
;
1009 // Check if the hot key sequence was defined already
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)) {
1018 if ((KeyOptionNumber
== LoadOptionNumberUnassigned
) &&
1019 (KeyOptions
[Index
].OptionNumber
> Index
)
1021 KeyOptionNumber
= Index
;
1024 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1026 if (Index
< KeyOptionCount
) {
1027 return EFI_ALREADY_STARTED
;
1030 if (KeyOptionNumber
== LoadOptionNumberUnassigned
) {
1031 KeyOptionNumber
= KeyOptionCount
;
1034 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumber
);
1036 Status
= gRT
->SetVariable (
1038 &gEfiGlobalVariableGuid
,
1039 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1040 BmSizeOfKeyOption (&KeyOption
),
1043 if (!EFI_ERROR (Status
)) {
1045 // Return the Key Option in case needed by caller
1047 if (AddedOption
!= NULL
) {
1048 CopyMem (AddedOption
, &KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1052 // Register the newly added hot key
1053 // Calling this function before EfiBootManagerStartHotkeyService doesn't
1054 // need to call BmProcessKeyOption
1056 if (mBmHotkeyServiceStarted
) {
1057 BmProcessKeyOption (&KeyOption
);
1065 Delete the Key Option variable and unregister the hot key
1067 @param DeletedOption Return the deleted key options.
1068 @param Modifier Key shift state.
1069 @param ... Parameter list of pointer of EFI_INPUT_KEY.
1071 @retval EFI_SUCCESS The key option is deleted.
1072 @retval EFI_NOT_FOUND The key option cannot be found.
1076 EfiBootManagerDeleteKeyOptionVariable (
1077 IN EFI_BOOT_MANAGER_KEY_OPTION
*DeletedOption
, OPTIONAL
1085 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
1086 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
1087 UINTN KeyOptionCount
;
1092 CHAR16 KeyOptionName
[sizeof ("Key####")];
1094 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1095 VA_START (Args
, Modifier
);
1096 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1099 if (EFI_ERROR (Status
)) {
1103 EfiAcquireLock (&mBmHotkeyLock
);
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
1108 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
1109 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
1110 Match
= (BOOLEAN
) (Hotkey
->CodeCount
== KeyOption
.KeyData
.Options
.InputKeyCount
);
1112 for (Index
= 0; Match
&& (Index
< Hotkey
->CodeCount
); Index
++) {
1113 ShiftState
= Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
;
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)
1124 // Break when any field doesn't match
1132 Link
= RemoveEntryList (Link
);
1135 Link
= GetNextNode (&mBmHotkeyList
, Link
);
1140 // Delete the key option from the variable
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
) &&
1147 KeyOptions
[Index
].Keys
, KeyOption
.Keys
,
1148 KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)
1150 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptions
[Index
].OptionNumber
);
1151 Status
= gRT
->SetVariable (
1153 &gEfiGlobalVariableGuid
,
1154 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1159 // Return the deleted key option in case needed by caller
1161 if (DeletedOption
!= NULL
) {
1162 CopyMem (DeletedOption
, &KeyOptions
[Index
], sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1167 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1169 EfiReleaseLock (&mBmHotkeyLock
);