2 Hotkey library functions.
4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBm.h"
18 // Lock for linked list
20 EFI_LOCK mBmHotkeyLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY
);
21 LIST_ENTRY mBmHotkeyList
= INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList
);
22 EFI_EVENT mBmHotkeyTriggered
= NULL
;
23 BOOLEAN mBmHotkeyServiceStarted
= FALSE
;
24 UINTN mBmHotkeySupportCount
= 0;
27 // Set OptionNumber as unassigned value to indicate the option isn't initialized
29 EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption
= { LoadOptionNumberUnassigned
};
31 EFI_BOOT_MANAGER_KEY_OPTION
*mBmContinueKeyOption
= NULL
;
32 VOID
*mBmTxtInExRegistration
= NULL
;
36 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
38 @param KeyOption The input key option info.
40 @retval The buffer size of the key option data.
44 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
47 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION
, Keys
)
48 + KeyOption
->KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
);
53 Check whether the input key option is valid.
55 @param KeyOption Key option.
56 @param KeyOptionSize Size of the key option.
58 @retval TRUE Input key option is valid.
59 @retval FALSE Input key option is not valid.
63 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
64 IN UINTN KeyOptionSize
67 UINT16 OptionName
[BM_OPTION_NAME_LEN
];
72 if (BmSizeOfKeyOption (KeyOption
) != KeyOptionSize
) {
77 // Check whether corresponding Boot Option exist
80 OptionName
, sizeof (OptionName
), L
"%s%04x",
81 mBmLoadOptionName
[LoadOptionTypeBoot
], KeyOption
->BootOption
83 GetEfiGlobalVariable2 (OptionName
, (VOID
**) &BootOption
, &BootOptionSize
);
85 if (BootOption
== NULL
) {
90 // Check CRC for Boot Option
92 gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &Crc
);
93 FreePool (BootOption
);
95 return (BOOLEAN
) (KeyOption
->BootOptionCrc
== Crc
);
100 Check whether the input variable is an key option variable.
102 @param Name Input variable name.
103 @param Guid Input variable guid.
104 @param OptionNumber The option number of this key option variable.
106 @retval TRUE Input variable is a key option variable.
107 @retval FALSE Input variable is not a key option variable.
110 BmIsKeyOptionVariable (
119 if (!CompareGuid (Guid
, &gEfiGlobalVariableGuid
) ||
120 (StrSize (Name
) != sizeof (L
"Key####")) ||
121 (StrnCmp (Name
, L
"Key", 3) != 0)
127 for (Index
= 3; Index
< 7; Index
++) {
128 Uint
= BmCharToUint (Name
[Index
]);
132 *OptionNumber
= (UINT16
) Uint
+ *OptionNumber
* 0x10;
140 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
141 UINTN KeyOptionCount
;
142 } BM_COLLECT_KEY_OPTIONS_PARAM
;
145 Visitor function to collect the key options from NV storage.
147 @param Name Variable name.
148 @param Guid Variable GUID.
149 @param Context The same context passed to BmForEachVariable.
152 BmCollectKeyOptions (
159 BM_COLLECT_KEY_OPTIONS_PARAM
*Param
;
160 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
;
164 Param
= (BM_COLLECT_KEY_OPTIONS_PARAM
*) Context
;
166 if (BmIsKeyOptionVariable (Name
, Guid
, &OptionNumber
)) {
167 GetEfiGlobalVariable2 (Name
, (VOID
**) &KeyOption
, &KeyOptionSize
);
168 ASSERT (KeyOption
!= NULL
);
169 KeyOption
->OptionNumber
= OptionNumber
;
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 (KeyOption
->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
, BmSizeOfKeyOption (KeyOption
));
187 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 Callback function for event.
225 @param Event Event for this callback function.
226 @param Context Context pass to this function.
238 Check whether the bit is set in the value.
240 @param Value The value need to be check.
241 @param Bit The bit filed need to be check.
243 @retval TRUE The bit is set.
244 @retval FALSE The bit is not set.
252 return (BOOLEAN
) ((Value
& Bit
) != 0);
256 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
258 @param Modifier Input key info.
259 @param Args Va_list info.
260 @param KeyOption Key info which need to update.
262 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
263 @return EFI_INVALID_PARAMETER Input parameter error.
266 BmInitializeKeyFields (
269 OUT EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
274 if (KeyOption
== NULL
) {
275 return EFI_INVALID_PARAMETER
;
279 while (KeyOption
->KeyData
.Options
.InputKeyCount
< sizeof (KeyOption
->Keys
) / sizeof (KeyOption
->Keys
[0])) {
280 Key
= VA_ARG (Args
, EFI_INPUT_KEY
*);
285 &KeyOption
->Keys
[KeyOption
->KeyData
.Options
.InputKeyCount
],
287 sizeof (EFI_INPUT_KEY
)
289 KeyOption
->KeyData
.Options
.InputKeyCount
++;
296 return EFI_INVALID_PARAMETER
;
299 if ((Modifier
& ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
300 | EFI_BOOT_MANAGER_CONTROL_PRESSED
301 | EFI_BOOT_MANAGER_ALT_PRESSED
302 | EFI_BOOT_MANAGER_LOGO_PRESSED
303 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
304 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
306 return EFI_INVALID_PARAMETER
;
309 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SHIFT_PRESSED
)) {
310 KeyOption
->KeyData
.Options
.ShiftPressed
= 1;
312 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_CONTROL_PRESSED
)) {
313 KeyOption
->KeyData
.Options
.ControlPressed
= 1;
315 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_ALT_PRESSED
)) {
316 KeyOption
->KeyData
.Options
.AltPressed
= 1;
318 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_LOGO_PRESSED
)) {
319 KeyOption
->KeyData
.Options
.LogoPressed
= 1;
321 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_MENU_KEY_PRESSED
)) {
322 KeyOption
->KeyData
.Options
.MenuPressed
= 1;
324 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SYS_REQ_PRESSED
)) {
325 KeyOption
->KeyData
.Options
.SysReqPressed
= 1;
332 Try to boot the boot option triggered by hot key.
336 EfiBootManagerHotkeyBoot (
340 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
341 EfiBootManagerBoot (&mBmHotkeyBootOption
);
342 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption
);
343 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
348 This is the common notification function for HotKeys, it will be registered
349 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
351 @param KeyData A pointer to a buffer that is filled in with the keystroke
352 information for the key that was pressed.
354 @retval EFI_SUCCESS KeyData is successfully processed.
355 @return EFI_NOT_FOUND Fail to find boot option variable.
360 IN EFI_KEY_DATA
*KeyData
365 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
367 EFI_KEY_DATA
*HotkeyData
;
369 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
371 // Do not process sequential hotkey stroke until the current boot option returns
376 DEBUG ((EFI_D_INFO
, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData
->Key
.ScanCode
, KeyData
->Key
.UnicodeChar
));
378 EfiAcquireLock (&mBmHotkeyLock
);
379 for ( Link
= GetFirstNode (&mBmHotkeyList
)
380 ; !IsNull (&mBmHotkeyList
, Link
)
381 ; Link
= GetNextNode (&mBmHotkeyList
, Link
)
383 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
386 // Is this Key Stroke we are waiting for?
388 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
389 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
390 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
391 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
392 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
393 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
398 // Receive an expecting key stroke, transit to next waiting state
400 Hotkey
->WaitingKey
++;
402 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
404 // Reset to initial waiting state
406 Hotkey
->WaitingKey
= 0;
408 // Received the whole key stroke sequence
410 Status
= gBS
->SignalEvent (mBmHotkeyTriggered
);
411 ASSERT_EFI_ERROR (Status
);
413 if (!Hotkey
->IsContinue
) {
415 // Launch its BootOption
418 OptionName
, sizeof (OptionName
), L
"%s%04x",
419 mBmLoadOptionName
[LoadOptionTypeBoot
], Hotkey
->BootOption
421 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &mBmHotkeyBootOption
);
422 DEBUG ((EFI_D_INFO
, "[Bds]Hotkey for %s pressed - %r\n", OptionName
, Status
));
423 if (EFI_ERROR (Status
)) {
424 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
427 DEBUG ((EFI_D_INFO
, "[Bds]Continue key pressed!\n"));
432 // Receive an unexpected key stroke, reset to initial waiting state
434 Hotkey
->WaitingKey
= 0;
438 EfiReleaseLock (&mBmHotkeyLock
);
444 Return the active Simple Text Input Ex handle array.
445 If the SystemTable.ConsoleInHandle is NULL, the function returns all
446 founded Simple Text Input Ex handles.
447 Otherwise, it just returns the ConsoleInHandle.
449 @param Count Return the handle count.
451 @retval The active console handles.
454 BmGetActiveConsoleIn (
461 if (gST
->ConsoleInHandle
!= NULL
) {
462 Status
= gBS
->OpenProtocol (
463 gST
->ConsoleInHandle
,
464 &gEfiSimpleTextInputExProtocolGuid
,
468 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
470 if (!EFI_ERROR (Status
)) {
471 Handles
= AllocateCopyPool (sizeof (EFI_HANDLE
*), &gST
->ConsoleInHandle
);
475 Status
= gBS
->LocateHandleBuffer (
477 &gEfiSimpleTextInputExProtocolGuid
,
483 if (EFI_ERROR (Status
)) {
492 Unregister hotkey notify list.
494 @param Hotkey Hotkey list.
496 @retval EFI_SUCCESS Unregister hotkey notify success.
497 @retval Others Unregister hotkey notify failed.
500 BmUnregisterHotkeyNotify (
509 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
512 Handles
= BmGetActiveConsoleIn (&HandleCount
);
513 for (Index
= 0; Index
< HandleCount
; Index
++) {
514 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
515 ASSERT_EFI_ERROR (Status
);
516 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
517 Status
= TxtInEx
->RegisterKeyNotify (
519 &Hotkey
->KeyData
[KeyIndex
],
523 if (!EFI_ERROR (Status
)) {
524 Status
= TxtInEx
->UnregisterKeyNotify (TxtInEx
, NotifyHandle
);
525 DEBUG ((EFI_D_INFO
, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey
->KeyData
[KeyIndex
].Key
.ScanCode
, Hotkey
->KeyData
[KeyIndex
].Key
.UnicodeChar
, Status
));
530 if (Handles
!= NULL
) {
538 Register hotkey notify list.
540 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
541 @param Hotkey Hotkey list.
543 @retval EFI_SUCCESS Register hotkey notify success.
544 @retval Others Register hotkey notify failed.
547 BmRegisterHotkeyNotify (
548 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
,
556 for (Index
= 0; Index
< Hotkey
->CodeCount
; Index
++) {
557 Status
= TxtInEx
->RegisterKeyNotify (
559 &Hotkey
->KeyData
[Index
],
565 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
566 Hotkey
->KeyData
[Index
].Key
.ScanCode
,
567 Hotkey
->KeyData
[Index
].Key
.UnicodeChar
,
568 Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
,
569 Hotkey
->KeyData
[Index
].KeyState
.KeyToggleState
,
572 if (EFI_ERROR (Status
)) {
574 // some of the hotkey registry failed
575 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
585 Generate key shift state base on the input key option info.
587 @param Depth Which key is checked.
588 @param KeyOption Input key option info.
589 @param KeyShiftState Input key shift state.
590 @param KeyShiftStates Return possible key shift state array.
591 @param KeyShiftStateCount Possible key shift state count.
594 BmGenerateKeyShiftState (
596 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
597 IN UINT32 KeyShiftState
,
598 IN UINT32
*KeyShiftStates
,
599 IN UINTN
*KeyShiftStateCount
604 if (KeyOption
->KeyData
.Options
.ShiftPressed
) {
605 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
606 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
608 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
613 if (KeyOption
->KeyData
.Options
.ControlPressed
) {
614 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
615 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
617 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
622 if (KeyOption
->KeyData
.Options
.AltPressed
) {
623 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
624 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
626 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
);
638 if (KeyOption
->KeyData
.Options
.MenuPressed
) {
639 KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
641 if (KeyOption
->KeyData
.Options
.SysReqPressed
) {
642 KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
644 KeyShiftStates
[*KeyShiftStateCount
] = KeyShiftState
;
645 (*KeyShiftStateCount
)++;
651 Add it to hot key database, register it to existing TxtInEx.
652 New TxtInEx will be automatically registered with all the hot key in dababase
654 @param KeyOption Input key option info.
658 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
662 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
670 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
672 UINT32 KeyShiftStates
[16];
673 UINTN KeyShiftStateCount
;
675 if (KeyOption
->KeyData
.Options
.InputKeyCount
> mBmHotkeySupportCount
) {
676 return EFI_UNSUPPORTED
;
679 KeyShiftStateCount
= 0;
680 BmGenerateKeyShiftState (0, KeyOption
, EFI_SHIFT_STATE_VALID
, KeyShiftStates
, &KeyShiftStateCount
);
681 ASSERT (KeyShiftStateCount
<= sizeof (KeyShiftStates
) / sizeof (KeyShiftStates
[0]));
683 EfiAcquireLock (&mBmHotkeyLock
);
685 Handles
= BmGetActiveConsoleIn (&HandleCount
);
687 for (Index
= 0; Index
< KeyShiftStateCount
; Index
++) {
688 Hotkey
= AllocateZeroPool (sizeof (BM_HOTKEY
));
689 ASSERT (Hotkey
!= NULL
);
691 Hotkey
->Signature
= BM_HOTKEY_SIGNATURE
;
692 Hotkey
->BootOption
= KeyOption
->BootOption
;
693 Hotkey
->IsContinue
= (BOOLEAN
) (KeyOption
== mBmContinueKeyOption
);
694 Hotkey
->CodeCount
= (UINT8
) KeyOption
->KeyData
.Options
.InputKeyCount
;
696 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
697 CopyMem (&Hotkey
->KeyData
[KeyIndex
].Key
, &KeyOption
->Keys
[KeyIndex
], sizeof (EFI_INPUT_KEY
));
698 Hotkey
->KeyData
[KeyIndex
].KeyState
.KeyShiftState
= KeyShiftStates
[Index
];
700 InsertTailList (&mBmHotkeyList
, &Hotkey
->Link
);
702 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
703 Status
= gBS
->HandleProtocol (Handles
[HandleIndex
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
704 ASSERT_EFI_ERROR (Status
);
705 BmRegisterHotkeyNotify (TxtInEx
, Hotkey
);
709 if (Handles
!= NULL
) {
712 EfiReleaseLock (&mBmHotkeyLock
);
718 Callback function for SimpleTextInEx protocol install events
720 @param Event the event that is signaled.
721 @param Context not used here.
734 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
738 BufferSize
= sizeof (EFI_HANDLE
);
739 Status
= gBS
->LocateHandle (
742 mBmTxtInExRegistration
,
746 if (EFI_ERROR (Status
)) {
748 // If no more notification events exist
753 Status
= gBS
->HandleProtocol (
755 &gEfiSimpleTextInputExProtocolGuid
,
758 ASSERT_EFI_ERROR (Status
);
761 // Register the hot key notification for the existing items in the list
763 EfiAcquireLock (&mBmHotkeyLock
);
764 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); Link
= GetNextNode (&mBmHotkeyList
, Link
)) {
765 BmRegisterHotkeyNotify (TxtInEx
, BM_HOTKEY_FROM_LINK (Link
));
767 EfiReleaseLock (&mBmHotkeyLock
);
772 Free the key options returned from BmGetKeyOptions.
774 @param KeyOptions Pointer to the key options.
775 @param KeyOptionCount Number of the key options.
777 @retval EFI_SUCCESS The key options are freed.
778 @retval EFI_NOT_FOUND KeyOptions is NULL.
782 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
,
783 IN UINTN KeyOptionCount
786 if (KeyOptions
!= NULL
) {
787 FreePool (KeyOptions
);
790 return EFI_NOT_FOUND
;
795 Register the key option to exit the waiting of the Boot Manager timeout.
796 Platform should ensure that the continue key option isn't conflict with
797 other boot key options.
799 @param Modifier Key shift state.
800 @param ... Parameter list of pointer of EFI_INPUT_KEY.
802 @retval EFI_SUCCESS Successfully register the continue key option.
803 @retval EFI_ALREADY_STARTED The continue key option is already registered.
807 EfiBootManagerRegisterContinueKeyOption (
813 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
816 if (mBmContinueKeyOption
!= NULL
) {
817 return EFI_ALREADY_STARTED
;
820 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
821 VA_START (Args
, Modifier
);
822 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
825 if (!EFI_ERROR (Status
)) {
826 mBmContinueKeyOption
= AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION
), &KeyOption
);
827 ASSERT (mBmContinueKeyOption
!= NULL
);
828 if (mBmHotkeyServiceStarted
) {
829 BmProcessKeyOption (mBmContinueKeyOption
);
837 Stop the hotkey processing.
839 @param Event Event pointer related to hotkey service.
840 @param Context Context pass to this function.
844 BmStopHotkeyService (
852 DEBUG ((EFI_D_INFO
, "[Bds]Stop Hotkey Service!\n"));
853 gBS
->CloseEvent (Event
);
855 EfiAcquireLock (&mBmHotkeyLock
);
856 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
857 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
858 BmUnregisterHotkeyNotify (Hotkey
);
859 Link
= RemoveEntryList (Link
);
862 EfiReleaseLock (&mBmHotkeyLock
);
866 Start the hot key service so that the key press can trigger the boot option.
868 @param HotkeyTriggered Return the waitable event and it will be signaled
869 when a valid hot key is pressed.
871 @retval EFI_SUCCESS The hot key service is started.
875 EfiBootManagerStartHotkeyService (
876 IN EFI_EVENT
*HotkeyTriggered
880 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
881 UINTN KeyOptionCount
;
884 UINT32
*BootOptionSupport
;
886 Status
= GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, (VOID
**) &BootOptionSupport
, NULL
);
887 ASSERT (BootOptionSupport
!= NULL
);
889 if ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_KEY
) != 0) {
890 mBmHotkeySupportCount
= ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_COUNT
) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT
));
892 FreePool (BootOptionSupport
);
894 if (mBmHotkeySupportCount
== 0) {
895 DEBUG ((EFI_D_INFO
, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
896 return EFI_UNSUPPORTED
;
899 Status
= gBS
->CreateEvent (
906 ASSERT_EFI_ERROR (Status
);
908 if (HotkeyTriggered
!= NULL
) {
909 *HotkeyTriggered
= mBmHotkeyTriggered
;
912 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
913 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
914 BmProcessKeyOption (&KeyOptions
[Index
]);
916 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
918 if (mBmContinueKeyOption
!= NULL
) {
919 BmProcessKeyOption (mBmContinueKeyOption
);
923 // Hook hotkey on every future SimpleTextInputEx instance when
924 // SystemTable.ConsoleInHandle == NULL, which means the console
925 // manager (ConSplitter) is absent.
927 if (gST
->ConsoleInHandle
== NULL
) {
928 EfiCreateProtocolNotifyEvent (
929 &gEfiSimpleTextInputExProtocolGuid
,
933 &mBmTxtInExRegistration
937 Status
= EfiCreateEventReadyToBootEx (
943 ASSERT_EFI_ERROR (Status
);
945 mBmHotkeyServiceStarted
= TRUE
;
951 It adds the key option variable and the key option takes affect immediately.
953 @param AddedOption Return the added key option.
954 @param BootOptionNumber The boot option number for the key option.
955 @param Modifier Key shift state.
956 @param ... Parameter list of pointer of EFI_INPUT_KEY.
958 @retval EFI_SUCCESS The key option is added.
959 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
963 EfiBootManagerAddKeyOptionVariable (
964 OUT EFI_BOOT_MANAGER_KEY_OPTION
*AddedOption
, OPTIONAL
965 IN UINT16 BootOptionNumber
,
973 UINTN BootOptionSize
;
974 CHAR16 BootOptionName
[BM_OPTION_NAME_LEN
];
975 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
976 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
977 UINTN KeyOptionCount
;
979 UINTN KeyOptionNumber
;
980 CHAR16 KeyOptionName
[sizeof ("Key####")];
983 BootOptionName
, sizeof (BootOptionName
), L
"%s%04x",
984 mBmLoadOptionName
[LoadOptionTypeBoot
], BootOptionNumber
986 GetEfiGlobalVariable2 (BootOptionName
, &BootOption
, &BootOptionSize
);
988 if (BootOption
== NULL
) {
989 return EFI_NOT_FOUND
;
992 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
993 KeyOption
.BootOption
= BootOptionNumber
;
994 Status
= gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &KeyOption
.BootOptionCrc
);
995 ASSERT_EFI_ERROR (Status
);
996 FreePool (BootOption
);
998 VA_START (Args
, Modifier
);
999 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1001 if (EFI_ERROR (Status
)) {
1005 KeyOptionNumber
= LoadOptionNumberUnassigned
;
1007 // Check if the hot key sequence was defined already
1009 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1010 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1011 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1012 (CompareMem (KeyOptions
[Index
].Keys
, KeyOption
.Keys
, KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)) {
1016 if ((KeyOptionNumber
== LoadOptionNumberUnassigned
) &&
1017 (KeyOptions
[Index
].OptionNumber
> Index
)
1019 KeyOptionNumber
= Index
;
1022 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1024 if (Index
< KeyOptionCount
) {
1025 return EFI_ALREADY_STARTED
;
1028 if (KeyOptionNumber
== LoadOptionNumberUnassigned
) {
1029 KeyOptionNumber
= KeyOptionCount
;
1032 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumber
);
1034 Status
= gRT
->SetVariable (
1036 &gEfiGlobalVariableGuid
,
1037 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1038 BmSizeOfKeyOption (&KeyOption
),
1041 if (!EFI_ERROR (Status
)) {
1043 // Return the Key Option in case needed by caller
1045 if (AddedOption
!= NULL
) {
1046 CopyMem (AddedOption
, &KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1050 // Register the newly added hot key
1051 // Calling this function before EfiBootManagerStartHotkeyService doesn't
1052 // need to call BmProcessKeyOption
1054 if (mBmHotkeyServiceStarted
) {
1055 BmProcessKeyOption (&KeyOption
);
1063 Delete the Key Option variable and unregister the hot key
1065 @param DeletedOption Return the deleted key options.
1066 @param Modifier Key shift state.
1067 @param ... Parameter list of pointer of EFI_INPUT_KEY.
1069 @retval EFI_SUCCESS The key option is deleted.
1070 @retval EFI_NOT_FOUND The key option cannot be found.
1074 EfiBootManagerDeleteKeyOptionVariable (
1075 IN EFI_BOOT_MANAGER_KEY_OPTION
*DeletedOption
, OPTIONAL
1083 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
1084 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
1085 UINTN KeyOptionCount
;
1090 CHAR16 KeyOptionName
[sizeof ("Key####")];
1092 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1093 VA_START (Args
, Modifier
);
1094 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1097 if (EFI_ERROR (Status
)) {
1101 EfiAcquireLock (&mBmHotkeyLock
);
1103 // Delete the key option from active hot key list
1104 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
1106 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
1107 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
1108 Match
= (BOOLEAN
) (Hotkey
->CodeCount
== KeyOption
.KeyData
.Options
.InputKeyCount
);
1110 for (Index
= 0; Match
&& (Index
< Hotkey
->CodeCount
); Index
++) {
1111 ShiftState
= Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
;
1113 (BmBitSet (ShiftState
, EFI_RIGHT_SHIFT_PRESSED
| EFI_LEFT_SHIFT_PRESSED
) != KeyOption
.KeyData
.Options
.ShiftPressed
) ||
1114 (BmBitSet (ShiftState
, EFI_RIGHT_CONTROL_PRESSED
| EFI_LEFT_CONTROL_PRESSED
) != KeyOption
.KeyData
.Options
.ControlPressed
) ||
1115 (BmBitSet (ShiftState
, EFI_RIGHT_ALT_PRESSED
| EFI_LEFT_ALT_PRESSED
) != KeyOption
.KeyData
.Options
.AltPressed
) ||
1116 (BmBitSet (ShiftState
, EFI_RIGHT_LOGO_PRESSED
| EFI_LEFT_LOGO_PRESSED
) != KeyOption
.KeyData
.Options
.LogoPressed
) ||
1117 (BmBitSet (ShiftState
, EFI_MENU_KEY_PRESSED
) != KeyOption
.KeyData
.Options
.MenuPressed
) ||
1118 (BmBitSet (ShiftState
, EFI_SYS_REQ_PRESSED
) != KeyOption
.KeyData
.Options
.SysReqPressed
) ||
1119 (CompareMem (&Hotkey
->KeyData
[Index
].Key
, &KeyOption
.Keys
[Index
], sizeof (EFI_INPUT_KEY
)) != 0)
1122 // Break when any field doesn't match
1130 Link
= RemoveEntryList (Link
);
1133 Link
= GetNextNode (&mBmHotkeyList
, Link
);
1138 // Delete the key option from the variable
1140 Status
= EFI_NOT_FOUND
;
1141 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1142 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1143 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1145 KeyOptions
[Index
].Keys
, KeyOption
.Keys
,
1146 KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)
1148 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptions
[Index
].OptionNumber
);
1149 Status
= gRT
->SetVariable (
1151 &gEfiGlobalVariableGuid
,
1152 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1157 // Return the deleted key option in case needed by caller
1159 if (DeletedOption
!= NULL
) {
1160 CopyMem (DeletedOption
, &KeyOptions
[Index
], sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1165 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1167 EfiReleaseLock (&mBmHotkeyLock
);