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 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "InternalBm.h"
13 // Lock for linked list
15 EFI_LOCK mBmHotkeyLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY
);
16 LIST_ENTRY mBmHotkeyList
= INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList
);
17 EFI_EVENT mBmHotkeyTriggered
= NULL
;
18 BOOLEAN mBmHotkeyServiceStarted
= FALSE
;
19 UINTN mBmHotkeySupportCount
= 0;
22 // Set OptionNumber as unassigned value to indicate the option isn't initialized
24 EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption
= { LoadOptionNumberUnassigned
};
26 EFI_BOOT_MANAGER_KEY_OPTION
*mBmContinueKeyOption
= NULL
;
27 VOID
*mBmTxtInExRegistration
= NULL
;
30 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
32 @param KeyOption The input key option info.
34 @retval The buffer size of the key option data.
38 IN CONST EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
41 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION
, Keys
)
42 + KeyOption
->KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
);
47 Check whether the input key option is valid.
49 @param KeyOption Key option.
50 @param KeyOptionSize Size of the key option.
52 @retval TRUE Input key option is valid.
53 @retval FALSE Input key option is not valid.
57 IN CONST EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
58 IN UINTN KeyOptionSize
61 UINT16 OptionName
[BM_OPTION_NAME_LEN
];
66 if (BmSizeOfKeyOption (KeyOption
) != KeyOptionSize
) {
71 // Check whether corresponding Boot Option exist
77 mBmLoadOptionName
[LoadOptionTypeBoot
],
80 GetEfiGlobalVariable2 (OptionName
, (VOID
**)&BootOption
, &BootOptionSize
);
82 if (BootOption
== NULL
) {
87 // Check CRC for Boot Option
89 gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &Crc
);
90 FreePool (BootOption
);
92 return (BOOLEAN
)(KeyOption
->BootOptionCrc
== Crc
);
97 Check whether the input variable is an key option variable.
99 @param Name Input variable name.
100 @param Guid Input variable guid.
101 @param OptionNumber The option number of this key option variable.
103 @retval TRUE Input variable is a key option variable.
104 @retval FALSE Input variable is not a key option variable.
107 BmIsKeyOptionVariable (
116 if (!CompareGuid (Guid
, &gEfiGlobalVariableGuid
) ||
117 (StrSize (Name
) != sizeof (L
"Key####")) ||
118 (StrnCmp (Name
, L
"Key", 3) != 0)
125 for (Index
= 3; Index
< 7; Index
++) {
126 Uint
= BmCharToUint (Name
[Index
]);
130 *OptionNumber
= (UINT16
)Uint
+ *OptionNumber
* 0x10;
138 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
139 UINTN KeyOptionCount
;
140 } BM_COLLECT_KEY_OPTIONS_PARAM
;
143 Visitor function to collect the key options from NV storage.
145 @param Name Variable name.
146 @param Guid Variable GUID.
147 @param Context The same context passed to BmForEachVariable.
150 BmCollectKeyOptions (
157 BM_COLLECT_KEY_OPTIONS_PARAM
*Param
;
162 Param
= (BM_COLLECT_KEY_OPTIONS_PARAM
*)Context
;
164 if (BmIsKeyOptionVariable (Name
, Guid
, &OptionNumber
)) {
165 GetEfiGlobalVariable2 (Name
, &KeyOption
, &KeyOptionSize
);
166 ASSERT (KeyOption
!= NULL
);
167 if (BmIsKeyOptionValid (KeyOption
, KeyOptionSize
)) {
168 Param
->KeyOptions
= ReallocatePool (
169 Param
->KeyOptionCount
* sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
170 (Param
->KeyOptionCount
+ 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
173 ASSERT (Param
->KeyOptions
!= NULL
);
175 // Insert the key option in order
177 for (Index
= 0; Index
< Param
->KeyOptionCount
; Index
++) {
178 if (OptionNumber
< Param
->KeyOptions
[Index
].OptionNumber
) {
183 CopyMem (&Param
->KeyOptions
[Index
+ 1], &Param
->KeyOptions
[Index
], (Param
->KeyOptionCount
- Index
) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
184 CopyMem (&Param
->KeyOptions
[Index
], KeyOption
, KeyOptionSize
);
185 Param
->KeyOptions
[Index
].OptionNumber
= OptionNumber
;
186 Param
->KeyOptionCount
++;
189 FreePool (KeyOption
);
194 Return the array of key options.
196 @param Count Return the number of key options.
198 @retval NULL No key option.
199 @retval Other Pointer to the key options.
201 EFI_BOOT_MANAGER_KEY_OPTION
*
206 BM_COLLECT_KEY_OPTIONS_PARAM Param
;
212 Param
.KeyOptions
= NULL
;
213 Param
.KeyOptionCount
= 0;
215 BmForEachVariable (BmCollectKeyOptions
, (VOID
*)&Param
);
217 *Count
= Param
.KeyOptionCount
;
219 return Param
.KeyOptions
;
223 Check whether the bit is set in the value.
225 @param Value The value need to be check.
226 @param Bit The bit filed need to be check.
228 @retval TRUE The bit is set.
229 @retval FALSE The bit is not set.
237 return (BOOLEAN
)((Value
& Bit
) != 0);
241 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
243 @param Modifier Input key info.
244 @param Args Va_list info.
245 @param KeyOption Key info which need to update.
247 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
248 @return EFI_INVALID_PARAMETER Input parameter error.
251 BmInitializeKeyFields (
254 OUT EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
259 if (KeyOption
== NULL
) {
260 return EFI_INVALID_PARAMETER
;
264 while (KeyOption
->KeyData
.Options
.InputKeyCount
< sizeof (KeyOption
->Keys
) / sizeof (KeyOption
->Keys
[0])) {
265 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
293 return EFI_INVALID_PARAMETER
;
296 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SHIFT_PRESSED
)) {
297 KeyOption
->KeyData
.Options
.ShiftPressed
= 1;
300 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_CONTROL_PRESSED
)) {
301 KeyOption
->KeyData
.Options
.ControlPressed
= 1;
304 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_ALT_PRESSED
)) {
305 KeyOption
->KeyData
.Options
.AltPressed
= 1;
308 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_LOGO_PRESSED
)) {
309 KeyOption
->KeyData
.Options
.LogoPressed
= 1;
312 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_MENU_KEY_PRESSED
)) {
313 KeyOption
->KeyData
.Options
.MenuPressed
= 1;
316 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SYS_REQ_PRESSED
)) {
317 KeyOption
->KeyData
.Options
.SysReqPressed
= 1;
324 Try to boot the boot option triggered by hot key.
328 EfiBootManagerHotkeyBoot (
332 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
333 EfiBootManagerBoot (&mBmHotkeyBootOption
);
334 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption
);
335 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
340 This is the common notification function for HotKeys, it will be registered
341 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
343 @param KeyData A pointer to a buffer that is filled in with the keystroke
344 information for the key that was pressed.
346 @retval EFI_SUCCESS KeyData is successfully processed.
347 @return EFI_NOT_FOUND Fail to find boot option variable.
352 IN EFI_KEY_DATA
*KeyData
357 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
359 EFI_KEY_DATA
*HotkeyData
;
361 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
363 // Do not process sequential hotkey stroke until the current boot option returns
368 DEBUG ((DEBUG_INFO
, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData
->Key
.ScanCode
, KeyData
->Key
.UnicodeChar
));
370 EfiAcquireLock (&mBmHotkeyLock
);
371 for ( Link
= GetFirstNode (&mBmHotkeyList
)
372 ; !IsNull (&mBmHotkeyList
, Link
)
373 ; Link
= GetNextNode (&mBmHotkeyList
, Link
)
376 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
379 // Is this Key Stroke we are waiting for?
381 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
382 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
383 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
384 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
385 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
386 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
391 // Receive an expecting key stroke, transit to next waiting state
393 Hotkey
->WaitingKey
++;
395 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
397 // Reset to initial waiting state
399 Hotkey
->WaitingKey
= 0;
401 // Received the whole key stroke sequence
403 Status
= gBS
->SignalEvent (mBmHotkeyTriggered
);
404 ASSERT_EFI_ERROR (Status
);
406 if (!Hotkey
->IsContinue
) {
408 // Launch its BootOption
414 mBmLoadOptionName
[LoadOptionTypeBoot
],
417 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &mBmHotkeyBootOption
);
418 DEBUG ((DEBUG_INFO
, "[Bds]Hotkey for %s pressed - %r\n", OptionName
, Status
));
419 if (EFI_ERROR (Status
)) {
420 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
423 DEBUG ((DEBUG_INFO
, "[Bds]Continue key pressed!\n"));
428 // Receive an unexpected key stroke, reset to initial waiting state
430 Hotkey
->WaitingKey
= 0;
434 EfiReleaseLock (&mBmHotkeyLock
);
440 Return the active Simple Text Input Ex handle array.
441 If the SystemTable.ConsoleInHandle is NULL, the function returns all
442 founded Simple Text Input Ex handles.
443 Otherwise, it just returns the ConsoleInHandle.
445 @param Count Return the handle count.
447 @retval The active console handles.
450 BmGetActiveConsoleIn (
460 if (gST
->ConsoleInHandle
!= NULL
) {
461 Status
= gBS
->OpenProtocol (
462 gST
->ConsoleInHandle
,
463 &gEfiSimpleTextInputExProtocolGuid
,
467 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
469 if (!EFI_ERROR (Status
)) {
470 Handles
= AllocateCopyPool (sizeof (EFI_HANDLE
), &gST
->ConsoleInHandle
);
471 if (Handles
!= NULL
) {
476 Status
= gBS
->LocateHandleBuffer (
478 &gEfiSimpleTextInputExProtocolGuid
,
489 Unregister hotkey notify list.
491 @param Hotkey Hotkey list.
493 @retval EFI_SUCCESS Unregister hotkey notify success.
494 @retval Others Unregister hotkey notify failed.
497 BmUnregisterHotkeyNotify (
506 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
509 Handles
= BmGetActiveConsoleIn (&HandleCount
);
510 for (Index
= 0; Index
< HandleCount
; Index
++) {
511 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**)&TxtInEx
);
512 ASSERT_EFI_ERROR (Status
);
513 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
514 Status
= TxtInEx
->RegisterKeyNotify (
516 &Hotkey
->KeyData
[KeyIndex
],
520 if (!EFI_ERROR (Status
)) {
521 Status
= TxtInEx
->UnregisterKeyNotify (TxtInEx
, NotifyHandle
);
522 DEBUG ((DEBUG_INFO
, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey
->KeyData
[KeyIndex
].Key
.ScanCode
, Hotkey
->KeyData
[KeyIndex
].Key
.UnicodeChar
, Status
));
527 if (Handles
!= NULL
) {
535 Register hotkey notify list.
537 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
538 @param Hotkey Hotkey list.
540 @retval EFI_SUCCESS Register hotkey notify success.
541 @retval Others Register hotkey notify failed.
544 BmRegisterHotkeyNotify (
545 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
,
553 for (Index
= 0; Index
< Hotkey
->CodeCount
; Index
++) {
554 Status
= TxtInEx
->RegisterKeyNotify (
556 &Hotkey
->KeyData
[Index
],
562 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
563 Hotkey
->KeyData
[Index
].Key
.ScanCode
,
564 Hotkey
->KeyData
[Index
].Key
.UnicodeChar
,
565 Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
,
566 Hotkey
->KeyData
[Index
].KeyState
.KeyToggleState
,
569 if (EFI_ERROR (Status
)) {
571 // some of the hotkey registry failed
572 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
582 Generate key shift state base on the input key option info.
584 @param Depth Which key is checked.
585 @param KeyOption Input key option info.
586 @param KeyShiftState Input key shift state.
587 @param KeyShiftStates Return possible key shift state array.
588 @param KeyShiftStateCount Possible key shift state count.
591 BmGenerateKeyShiftState (
593 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
594 IN UINT32 KeyShiftState
,
595 IN UINT32
*KeyShiftStates
,
596 IN UINTN
*KeyShiftStateCount
601 if (KeyOption
->KeyData
.Options
.ShiftPressed
) {
602 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
603 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
605 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
611 if (KeyOption
->KeyData
.Options
.ControlPressed
) {
612 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
613 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
615 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
621 if (KeyOption
->KeyData
.Options
.AltPressed
) {
622 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
623 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
625 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
630 if (KeyOption
->KeyData
.Options
.LogoPressed
) {
631 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
632 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
634 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
639 if (KeyOption
->KeyData
.Options
.MenuPressed
) {
640 KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
643 if (KeyOption
->KeyData
.Options
.SysReqPressed
) {
644 KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
647 KeyShiftStates
[*KeyShiftStateCount
] = KeyShiftState
;
648 (*KeyShiftStateCount
)++;
654 Add it to hot key database, register it to existing TxtInEx.
655 New TxtInEx will be automatically registered with all the hot key in dababase
657 @param KeyOption Input key option info.
661 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
665 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
673 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
675 UINT32 KeyShiftStates
[16];
676 UINTN KeyShiftStateCount
;
678 if (KeyOption
->KeyData
.Options
.InputKeyCount
> mBmHotkeySupportCount
) {
679 return EFI_UNSUPPORTED
;
682 KeyShiftStateCount
= 0;
683 BmGenerateKeyShiftState (0, KeyOption
, EFI_SHIFT_STATE_VALID
, KeyShiftStates
, &KeyShiftStateCount
);
684 ASSERT (KeyShiftStateCount
<= ARRAY_SIZE (KeyShiftStates
));
686 EfiAcquireLock (&mBmHotkeyLock
);
688 Handles
= BmGetActiveConsoleIn (&HandleCount
);
690 for (Index
= 0; Index
< KeyShiftStateCount
; Index
++) {
691 Hotkey
= AllocateZeroPool (sizeof (BM_HOTKEY
));
692 ASSERT (Hotkey
!= NULL
);
694 Hotkey
->Signature
= BM_HOTKEY_SIGNATURE
;
695 Hotkey
->BootOption
= KeyOption
->BootOption
;
696 Hotkey
->IsContinue
= (BOOLEAN
)(KeyOption
== mBmContinueKeyOption
);
697 Hotkey
->CodeCount
= (UINT8
)KeyOption
->KeyData
.Options
.InputKeyCount
;
699 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
700 CopyMem (&Hotkey
->KeyData
[KeyIndex
].Key
, &KeyOption
->Keys
[KeyIndex
], sizeof (EFI_INPUT_KEY
));
701 Hotkey
->KeyData
[KeyIndex
].KeyState
.KeyShiftState
= KeyShiftStates
[Index
];
704 InsertTailList (&mBmHotkeyList
, &Hotkey
->Link
);
706 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
707 Status
= gBS
->HandleProtocol (Handles
[HandleIndex
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**)&TxtInEx
);
708 ASSERT_EFI_ERROR (Status
);
709 BmRegisterHotkeyNotify (TxtInEx
, Hotkey
);
713 if (Handles
!= NULL
) {
717 EfiReleaseLock (&mBmHotkeyLock
);
723 Callback function for SimpleTextInEx protocol install events
725 @param Event the event that is signaled.
726 @param Context not used here.
739 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
743 BufferSize
= sizeof (EFI_HANDLE
);
744 Status
= gBS
->LocateHandle (
747 mBmTxtInExRegistration
,
751 if (EFI_ERROR (Status
)) {
753 // If no more notification events exist
758 Status
= gBS
->HandleProtocol (
760 &gEfiSimpleTextInputExProtocolGuid
,
763 ASSERT_EFI_ERROR (Status
);
766 // Register the hot key notification for the existing items in the list
768 EfiAcquireLock (&mBmHotkeyLock
);
769 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); Link
= GetNextNode (&mBmHotkeyList
, Link
)) {
770 BmRegisterHotkeyNotify (TxtInEx
, BM_HOTKEY_FROM_LINK (Link
));
773 EfiReleaseLock (&mBmHotkeyLock
);
778 Free the key options returned from BmGetKeyOptions.
780 @param KeyOptions Pointer to the key options.
781 @param KeyOptionCount Number of the key options.
783 @retval EFI_SUCCESS The key options are freed.
784 @retval EFI_NOT_FOUND KeyOptions is NULL.
788 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
,
789 IN UINTN KeyOptionCount
792 if (KeyOptions
!= NULL
) {
793 FreePool (KeyOptions
);
796 return EFI_NOT_FOUND
;
801 Register the key option to exit the waiting of the Boot Manager timeout.
802 Platform should ensure that the continue key option isn't conflict with
803 other boot key options.
805 @param Modifier Key shift state.
806 @param ... Parameter list of pointer of EFI_INPUT_KEY.
808 @retval EFI_SUCCESS Successfully register the continue key option.
809 @retval EFI_ALREADY_STARTED The continue key option is already registered.
813 EfiBootManagerRegisterContinueKeyOption (
819 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
822 if (mBmContinueKeyOption
!= NULL
) {
823 return EFI_ALREADY_STARTED
;
826 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
827 VA_START (Args
, Modifier
);
828 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
831 if (!EFI_ERROR (Status
)) {
832 mBmContinueKeyOption
= AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION
), &KeyOption
);
833 ASSERT (mBmContinueKeyOption
!= NULL
);
834 if (mBmHotkeyServiceStarted
) {
835 BmProcessKeyOption (mBmContinueKeyOption
);
843 Stop the hotkey processing.
845 @param Event Event pointer related to hotkey service.
846 @param Context Context pass to this function.
850 BmStopHotkeyService (
858 DEBUG ((DEBUG_INFO
, "[Bds]Stop Hotkey Service!\n"));
859 gBS
->CloseEvent (Event
);
861 EfiAcquireLock (&mBmHotkeyLock
);
862 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
863 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
864 BmUnregisterHotkeyNotify (Hotkey
);
865 Link
= RemoveEntryList (Link
);
869 EfiReleaseLock (&mBmHotkeyLock
);
873 Start the hot key service so that the key press can trigger the boot option.
875 @param HotkeyTriggered Return the waitable event and it will be signaled
876 when a valid hot key is pressed.
878 @retval EFI_SUCCESS The hot key service is started.
882 EfiBootManagerStartHotkeyService (
883 IN EFI_EVENT
*HotkeyTriggered
887 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
888 UINTN KeyOptionCount
;
891 UINT32
*BootOptionSupport
;
893 GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, (VOID
**)&BootOptionSupport
, NULL
);
894 if (BootOptionSupport
!= NULL
) {
895 if ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_KEY
) != 0) {
896 mBmHotkeySupportCount
= ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_COUNT
) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT
));
899 FreePool (BootOptionSupport
);
902 if (mBmHotkeySupportCount
== 0) {
903 DEBUG ((DEBUG_INFO
, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
904 return EFI_UNSUPPORTED
;
907 Status
= gBS
->CreateEvent (
910 EfiEventEmptyFunction
,
914 ASSERT_EFI_ERROR (Status
);
916 if (HotkeyTriggered
!= NULL
) {
917 *HotkeyTriggered
= mBmHotkeyTriggered
;
920 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
921 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
922 BmProcessKeyOption (&KeyOptions
[Index
]);
925 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
927 if (mBmContinueKeyOption
!= NULL
) {
928 BmProcessKeyOption (mBmContinueKeyOption
);
932 // Hook hotkey on every future SimpleTextInputEx instance when
933 // SystemTable.ConsoleInHandle == NULL, which means the console
934 // manager (ConSplitter) is absent.
936 if (gST
->ConsoleInHandle
== NULL
) {
937 EfiCreateProtocolNotifyEvent (
938 &gEfiSimpleTextInputExProtocolGuid
,
942 &mBmTxtInExRegistration
946 Status
= EfiCreateEventReadyToBootEx (
952 ASSERT_EFI_ERROR (Status
);
954 mBmHotkeyServiceStarted
= TRUE
;
960 It adds the key option variable and the key option takes affect immediately.
962 @param AddedOption Return the added key option.
963 @param BootOptionNumber The boot option number for the key option.
964 @param Modifier Key shift state.
965 @param ... Parameter list of pointer of EFI_INPUT_KEY.
967 @retval EFI_SUCCESS The key option is added.
968 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
972 EfiBootManagerAddKeyOptionVariable (
973 OUT EFI_BOOT_MANAGER_KEY_OPTION
*AddedOption OPTIONAL
,
974 IN UINT16 BootOptionNumber
,
982 UINTN BootOptionSize
;
983 CHAR16 BootOptionName
[BM_OPTION_NAME_LEN
];
984 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
985 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
986 UINTN KeyOptionCount
;
988 UINTN KeyOptionNumber
;
989 CHAR16 KeyOptionName
[sizeof ("Key####")];
993 sizeof (BootOptionName
),
995 mBmLoadOptionName
[LoadOptionTypeBoot
],
998 GetEfiGlobalVariable2 (BootOptionName
, &BootOption
, &BootOptionSize
);
1000 if (BootOption
== NULL
) {
1001 return EFI_NOT_FOUND
;
1004 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1005 KeyOption
.BootOption
= BootOptionNumber
;
1006 Status
= gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &KeyOption
.BootOptionCrc
);
1007 ASSERT_EFI_ERROR (Status
);
1008 FreePool (BootOption
);
1010 VA_START (Args
, Modifier
);
1011 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1013 if (EFI_ERROR (Status
)) {
1017 KeyOptionNumber
= LoadOptionNumberUnassigned
;
1019 // Check if the hot key sequence was defined already
1021 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1022 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1023 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1024 (CompareMem (KeyOptions
[Index
].Keys
, KeyOption
.Keys
, KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0))
1029 if ((KeyOptionNumber
== LoadOptionNumberUnassigned
) &&
1030 (KeyOptions
[Index
].OptionNumber
> Index
)
1033 KeyOptionNumber
= Index
;
1037 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1039 if (Index
< KeyOptionCount
) {
1040 return EFI_ALREADY_STARTED
;
1043 if (KeyOptionNumber
== LoadOptionNumberUnassigned
) {
1044 KeyOptionNumber
= KeyOptionCount
;
1047 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumber
);
1049 Status
= gRT
->SetVariable (
1051 &gEfiGlobalVariableGuid
,
1052 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1053 BmSizeOfKeyOption (&KeyOption
),
1056 if (!EFI_ERROR (Status
)) {
1058 // Return the Key Option in case needed by caller
1060 if (AddedOption
!= NULL
) {
1061 CopyMem (AddedOption
, &KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1065 // Register the newly added hot key
1066 // Calling this function before EfiBootManagerStartHotkeyService doesn't
1067 // need to call BmProcessKeyOption
1069 if (mBmHotkeyServiceStarted
) {
1070 BmProcessKeyOption (&KeyOption
);
1078 Delete the Key Option variable and unregister the hot key
1080 @param DeletedOption Return the deleted key options.
1081 @param Modifier Key shift state.
1082 @param ... Parameter list of pointer of EFI_INPUT_KEY.
1084 @retval EFI_SUCCESS The key option is deleted.
1085 @retval EFI_NOT_FOUND The key option cannot be found.
1089 EfiBootManagerDeleteKeyOptionVariable (
1090 IN EFI_BOOT_MANAGER_KEY_OPTION
*DeletedOption OPTIONAL
,
1098 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
1099 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
1100 UINTN KeyOptionCount
;
1105 CHAR16 KeyOptionName
[sizeof ("Key####")];
1107 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1108 VA_START (Args
, Modifier
);
1109 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1112 if (EFI_ERROR (Status
)) {
1116 EfiAcquireLock (&mBmHotkeyLock
);
1118 // Delete the key option from active hot key list
1119 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
1121 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
1122 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
1123 Match
= (BOOLEAN
)(Hotkey
->CodeCount
== KeyOption
.KeyData
.Options
.InputKeyCount
);
1125 for (Index
= 0; Match
&& (Index
< Hotkey
->CodeCount
); Index
++) {
1126 ShiftState
= Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
;
1128 (BmBitSet (ShiftState
, EFI_RIGHT_SHIFT_PRESSED
| EFI_LEFT_SHIFT_PRESSED
) != KeyOption
.KeyData
.Options
.ShiftPressed
) ||
1129 (BmBitSet (ShiftState
, EFI_RIGHT_CONTROL_PRESSED
| EFI_LEFT_CONTROL_PRESSED
) != KeyOption
.KeyData
.Options
.ControlPressed
) ||
1130 (BmBitSet (ShiftState
, EFI_RIGHT_ALT_PRESSED
| EFI_LEFT_ALT_PRESSED
) != KeyOption
.KeyData
.Options
.AltPressed
) ||
1131 (BmBitSet (ShiftState
, EFI_RIGHT_LOGO_PRESSED
| EFI_LEFT_LOGO_PRESSED
) != KeyOption
.KeyData
.Options
.LogoPressed
) ||
1132 (BmBitSet (ShiftState
, EFI_MENU_KEY_PRESSED
) != KeyOption
.KeyData
.Options
.MenuPressed
) ||
1133 (BmBitSet (ShiftState
, EFI_SYS_REQ_PRESSED
) != KeyOption
.KeyData
.Options
.SysReqPressed
) ||
1134 (CompareMem (&Hotkey
->KeyData
[Index
].Key
, &KeyOption
.Keys
[Index
], sizeof (EFI_INPUT_KEY
)) != 0)
1138 // Break when any field doesn't match
1146 Link
= RemoveEntryList (Link
);
1149 Link
= GetNextNode (&mBmHotkeyList
, Link
);
1154 // Delete the key option from the variable
1156 Status
= EFI_NOT_FOUND
;
1157 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1158 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1159 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1161 KeyOptions
[Index
].Keys
,
1163 KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)
1167 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptions
[Index
].OptionNumber
);
1168 Status
= gRT
->SetVariable (
1170 &gEfiGlobalVariableGuid
,
1171 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1176 // Return the deleted key option in case needed by caller
1178 if (DeletedOption
!= NULL
) {
1179 CopyMem (DeletedOption
, &KeyOptions
[Index
], sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1186 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1188 EfiReleaseLock (&mBmHotkeyLock
);