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
;
31 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
33 @param KeyOption The input key option info.
35 @retval The buffer size of the key option data.
39 IN CONST EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
42 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION
, Keys
)
43 + KeyOption
->KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
);
48 Check whether the input key option is valid.
50 @param KeyOption Key option.
51 @param KeyOptionSize Size of the key option.
53 @retval TRUE Input key option is valid.
54 @retval FALSE Input key option is not valid.
58 IN CONST EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
59 IN UINTN KeyOptionSize
62 UINT16 OptionName
[BM_OPTION_NAME_LEN
];
67 if (BmSizeOfKeyOption (KeyOption
) != KeyOptionSize
) {
72 // Check whether corresponding Boot Option exist
75 OptionName
, sizeof (OptionName
), L
"%s%04x",
76 mBmLoadOptionName
[LoadOptionTypeBoot
], KeyOption
->BootOption
78 GetEfiGlobalVariable2 (OptionName
, (VOID
**) &BootOption
, &BootOptionSize
);
80 if (BootOption
== NULL
) {
85 // Check CRC for Boot Option
87 gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &Crc
);
88 FreePool (BootOption
);
90 return (BOOLEAN
) (KeyOption
->BootOptionCrc
== Crc
);
95 Check whether the input variable is an key option variable.
97 @param Name Input variable name.
98 @param Guid Input variable guid.
99 @param OptionNumber The option number of this key option variable.
101 @retval TRUE Input variable is a key option variable.
102 @retval FALSE Input variable is not a key option variable.
105 BmIsKeyOptionVariable (
114 if (!CompareGuid (Guid
, &gEfiGlobalVariableGuid
) ||
115 (StrSize (Name
) != sizeof (L
"Key####")) ||
116 (StrnCmp (Name
, L
"Key", 3) != 0)
122 for (Index
= 3; Index
< 7; Index
++) {
123 Uint
= BmCharToUint (Name
[Index
]);
127 *OptionNumber
= (UINT16
) Uint
+ *OptionNumber
* 0x10;
135 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
136 UINTN KeyOptionCount
;
137 } BM_COLLECT_KEY_OPTIONS_PARAM
;
140 Visitor function to collect the key options from NV storage.
142 @param Name Variable name.
143 @param Guid Variable GUID.
144 @param Context The same context passed to BmForEachVariable.
147 BmCollectKeyOptions (
154 BM_COLLECT_KEY_OPTIONS_PARAM
*Param
;
159 Param
= (BM_COLLECT_KEY_OPTIONS_PARAM
*) Context
;
161 if (BmIsKeyOptionVariable (Name
, Guid
, &OptionNumber
)) {
162 GetEfiGlobalVariable2 (Name
, &KeyOption
, &KeyOptionSize
);
163 ASSERT (KeyOption
!= NULL
);
164 if (BmIsKeyOptionValid (KeyOption
, KeyOptionSize
)) {
165 Param
->KeyOptions
= ReallocatePool (
166 Param
->KeyOptionCount
* sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
167 (Param
->KeyOptionCount
+ 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
170 ASSERT (Param
->KeyOptions
!= NULL
);
172 // Insert the key option in order
174 for (Index
= 0; Index
< Param
->KeyOptionCount
; Index
++) {
175 if (OptionNumber
< Param
->KeyOptions
[Index
].OptionNumber
) {
179 CopyMem (&Param
->KeyOptions
[Index
+ 1], &Param
->KeyOptions
[Index
], (Param
->KeyOptionCount
- Index
) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
180 CopyMem (&Param
->KeyOptions
[Index
], KeyOption
, KeyOptionSize
);
181 Param
->KeyOptions
[Index
].OptionNumber
= OptionNumber
;
182 Param
->KeyOptionCount
++;
184 FreePool (KeyOption
);
189 Return the array of key options.
191 @param Count Return the number of key options.
193 @retval NULL No key option.
194 @retval Other Pointer to the key options.
196 EFI_BOOT_MANAGER_KEY_OPTION
*
201 BM_COLLECT_KEY_OPTIONS_PARAM Param
;
207 Param
.KeyOptions
= NULL
;
208 Param
.KeyOptionCount
= 0;
210 BmForEachVariable (BmCollectKeyOptions
, (VOID
*) &Param
);
212 *Count
= Param
.KeyOptionCount
;
214 return Param
.KeyOptions
;
218 Check whether the bit is set in the value.
220 @param Value The value need to be check.
221 @param Bit The bit filed need to be check.
223 @retval TRUE The bit is set.
224 @retval FALSE The bit is not set.
232 return (BOOLEAN
) ((Value
& Bit
) != 0);
236 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
238 @param Modifier Input key info.
239 @param Args Va_list info.
240 @param KeyOption Key info which need to update.
242 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
243 @return EFI_INVALID_PARAMETER Input parameter error.
246 BmInitializeKeyFields (
249 OUT EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
254 if (KeyOption
== NULL
) {
255 return EFI_INVALID_PARAMETER
;
259 while (KeyOption
->KeyData
.Options
.InputKeyCount
< sizeof (KeyOption
->Keys
) / sizeof (KeyOption
->Keys
[0])) {
260 Key
= VA_ARG (Args
, EFI_INPUT_KEY
*);
265 &KeyOption
->Keys
[KeyOption
->KeyData
.Options
.InputKeyCount
],
267 sizeof (EFI_INPUT_KEY
)
269 KeyOption
->KeyData
.Options
.InputKeyCount
++;
276 return EFI_INVALID_PARAMETER
;
279 if ((Modifier
& ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
280 | EFI_BOOT_MANAGER_CONTROL_PRESSED
281 | EFI_BOOT_MANAGER_ALT_PRESSED
282 | EFI_BOOT_MANAGER_LOGO_PRESSED
283 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
284 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
286 return EFI_INVALID_PARAMETER
;
289 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SHIFT_PRESSED
)) {
290 KeyOption
->KeyData
.Options
.ShiftPressed
= 1;
292 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_CONTROL_PRESSED
)) {
293 KeyOption
->KeyData
.Options
.ControlPressed
= 1;
295 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_ALT_PRESSED
)) {
296 KeyOption
->KeyData
.Options
.AltPressed
= 1;
298 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_LOGO_PRESSED
)) {
299 KeyOption
->KeyData
.Options
.LogoPressed
= 1;
301 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_MENU_KEY_PRESSED
)) {
302 KeyOption
->KeyData
.Options
.MenuPressed
= 1;
304 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SYS_REQ_PRESSED
)) {
305 KeyOption
->KeyData
.Options
.SysReqPressed
= 1;
312 Try to boot the boot option triggered by hot key.
316 EfiBootManagerHotkeyBoot (
320 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
321 EfiBootManagerBoot (&mBmHotkeyBootOption
);
322 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption
);
323 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
328 This is the common notification function for HotKeys, it will be registered
329 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
331 @param KeyData A pointer to a buffer that is filled in with the keystroke
332 information for the key that was pressed.
334 @retval EFI_SUCCESS KeyData is successfully processed.
335 @return EFI_NOT_FOUND Fail to find boot option variable.
340 IN EFI_KEY_DATA
*KeyData
345 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
347 EFI_KEY_DATA
*HotkeyData
;
349 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
351 // Do not process sequential hotkey stroke until the current boot option returns
356 DEBUG ((EFI_D_INFO
, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData
->Key
.ScanCode
, KeyData
->Key
.UnicodeChar
));
358 EfiAcquireLock (&mBmHotkeyLock
);
359 for ( Link
= GetFirstNode (&mBmHotkeyList
)
360 ; !IsNull (&mBmHotkeyList
, Link
)
361 ; Link
= GetNextNode (&mBmHotkeyList
, Link
)
363 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
366 // Is this Key Stroke we are waiting for?
368 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
369 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
370 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
371 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
372 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
373 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
378 // Receive an expecting key stroke, transit to next waiting state
380 Hotkey
->WaitingKey
++;
382 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
384 // Reset to initial waiting state
386 Hotkey
->WaitingKey
= 0;
388 // Received the whole key stroke sequence
390 Status
= gBS
->SignalEvent (mBmHotkeyTriggered
);
391 ASSERT_EFI_ERROR (Status
);
393 if (!Hotkey
->IsContinue
) {
395 // Launch its BootOption
398 OptionName
, sizeof (OptionName
), L
"%s%04x",
399 mBmLoadOptionName
[LoadOptionTypeBoot
], Hotkey
->BootOption
401 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &mBmHotkeyBootOption
);
402 DEBUG ((EFI_D_INFO
, "[Bds]Hotkey for %s pressed - %r\n", OptionName
, Status
));
403 if (EFI_ERROR (Status
)) {
404 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
407 DEBUG ((EFI_D_INFO
, "[Bds]Continue key pressed!\n"));
412 // Receive an unexpected key stroke, reset to initial waiting state
414 Hotkey
->WaitingKey
= 0;
418 EfiReleaseLock (&mBmHotkeyLock
);
424 Return the active Simple Text Input Ex handle array.
425 If the SystemTable.ConsoleInHandle is NULL, the function returns all
426 founded Simple Text Input Ex handles.
427 Otherwise, it just returns the ConsoleInHandle.
429 @param Count Return the handle count.
431 @retval The active console handles.
434 BmGetActiveConsoleIn (
444 if (gST
->ConsoleInHandle
!= NULL
) {
445 Status
= gBS
->OpenProtocol (
446 gST
->ConsoleInHandle
,
447 &gEfiSimpleTextInputExProtocolGuid
,
451 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
453 if (!EFI_ERROR (Status
)) {
454 Handles
= AllocateCopyPool (sizeof (EFI_HANDLE
), &gST
->ConsoleInHandle
);
455 if (Handles
!= NULL
) {
460 Status
= gBS
->LocateHandleBuffer (
462 &gEfiSimpleTextInputExProtocolGuid
,
473 Unregister hotkey notify list.
475 @param Hotkey Hotkey list.
477 @retval EFI_SUCCESS Unregister hotkey notify success.
478 @retval Others Unregister hotkey notify failed.
481 BmUnregisterHotkeyNotify (
490 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
493 Handles
= BmGetActiveConsoleIn (&HandleCount
);
494 for (Index
= 0; Index
< HandleCount
; Index
++) {
495 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
496 ASSERT_EFI_ERROR (Status
);
497 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
498 Status
= TxtInEx
->RegisterKeyNotify (
500 &Hotkey
->KeyData
[KeyIndex
],
504 if (!EFI_ERROR (Status
)) {
505 Status
= TxtInEx
->UnregisterKeyNotify (TxtInEx
, NotifyHandle
);
506 DEBUG ((EFI_D_INFO
, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey
->KeyData
[KeyIndex
].Key
.ScanCode
, Hotkey
->KeyData
[KeyIndex
].Key
.UnicodeChar
, Status
));
511 if (Handles
!= NULL
) {
519 Register hotkey notify list.
521 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
522 @param Hotkey Hotkey list.
524 @retval EFI_SUCCESS Register hotkey notify success.
525 @retval Others Register hotkey notify failed.
528 BmRegisterHotkeyNotify (
529 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
,
537 for (Index
= 0; Index
< Hotkey
->CodeCount
; Index
++) {
538 Status
= TxtInEx
->RegisterKeyNotify (
540 &Hotkey
->KeyData
[Index
],
546 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
547 Hotkey
->KeyData
[Index
].Key
.ScanCode
,
548 Hotkey
->KeyData
[Index
].Key
.UnicodeChar
,
549 Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
,
550 Hotkey
->KeyData
[Index
].KeyState
.KeyToggleState
,
553 if (EFI_ERROR (Status
)) {
555 // some of the hotkey registry failed
556 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
566 Generate key shift state base on the input key option info.
568 @param Depth Which key is checked.
569 @param KeyOption Input key option info.
570 @param KeyShiftState Input key shift state.
571 @param KeyShiftStates Return possible key shift state array.
572 @param KeyShiftStateCount Possible key shift state count.
575 BmGenerateKeyShiftState (
577 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
578 IN UINT32 KeyShiftState
,
579 IN UINT32
*KeyShiftStates
,
580 IN UINTN
*KeyShiftStateCount
585 if (KeyOption
->KeyData
.Options
.ShiftPressed
) {
586 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
587 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
589 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
594 if (KeyOption
->KeyData
.Options
.ControlPressed
) {
595 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
596 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
598 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
603 if (KeyOption
->KeyData
.Options
.AltPressed
) {
604 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
605 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
607 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
611 if (KeyOption
->KeyData
.Options
.LogoPressed
) {
612 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
613 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
615 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
619 if (KeyOption
->KeyData
.Options
.MenuPressed
) {
620 KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
622 if (KeyOption
->KeyData
.Options
.SysReqPressed
) {
623 KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
625 KeyShiftStates
[*KeyShiftStateCount
] = KeyShiftState
;
626 (*KeyShiftStateCount
)++;
632 Add it to hot key database, register it to existing TxtInEx.
633 New TxtInEx will be automatically registered with all the hot key in dababase
635 @param KeyOption Input key option info.
639 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
643 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
651 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
653 UINT32 KeyShiftStates
[16];
654 UINTN KeyShiftStateCount
;
656 if (KeyOption
->KeyData
.Options
.InputKeyCount
> mBmHotkeySupportCount
) {
657 return EFI_UNSUPPORTED
;
660 KeyShiftStateCount
= 0;
661 BmGenerateKeyShiftState (0, KeyOption
, EFI_SHIFT_STATE_VALID
, KeyShiftStates
, &KeyShiftStateCount
);
662 ASSERT (KeyShiftStateCount
<= ARRAY_SIZE (KeyShiftStates
));
664 EfiAcquireLock (&mBmHotkeyLock
);
666 Handles
= BmGetActiveConsoleIn (&HandleCount
);
668 for (Index
= 0; Index
< KeyShiftStateCount
; Index
++) {
669 Hotkey
= AllocateZeroPool (sizeof (BM_HOTKEY
));
670 ASSERT (Hotkey
!= NULL
);
672 Hotkey
->Signature
= BM_HOTKEY_SIGNATURE
;
673 Hotkey
->BootOption
= KeyOption
->BootOption
;
674 Hotkey
->IsContinue
= (BOOLEAN
) (KeyOption
== mBmContinueKeyOption
);
675 Hotkey
->CodeCount
= (UINT8
) KeyOption
->KeyData
.Options
.InputKeyCount
;
677 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
678 CopyMem (&Hotkey
->KeyData
[KeyIndex
].Key
, &KeyOption
->Keys
[KeyIndex
], sizeof (EFI_INPUT_KEY
));
679 Hotkey
->KeyData
[KeyIndex
].KeyState
.KeyShiftState
= KeyShiftStates
[Index
];
681 InsertTailList (&mBmHotkeyList
, &Hotkey
->Link
);
683 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
684 Status
= gBS
->HandleProtocol (Handles
[HandleIndex
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
685 ASSERT_EFI_ERROR (Status
);
686 BmRegisterHotkeyNotify (TxtInEx
, Hotkey
);
690 if (Handles
!= NULL
) {
693 EfiReleaseLock (&mBmHotkeyLock
);
699 Callback function for SimpleTextInEx protocol install events
701 @param Event the event that is signaled.
702 @param Context not used here.
715 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
719 BufferSize
= sizeof (EFI_HANDLE
);
720 Status
= gBS
->LocateHandle (
723 mBmTxtInExRegistration
,
727 if (EFI_ERROR (Status
)) {
729 // If no more notification events exist
734 Status
= gBS
->HandleProtocol (
736 &gEfiSimpleTextInputExProtocolGuid
,
739 ASSERT_EFI_ERROR (Status
);
742 // Register the hot key notification for the existing items in the list
744 EfiAcquireLock (&mBmHotkeyLock
);
745 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); Link
= GetNextNode (&mBmHotkeyList
, Link
)) {
746 BmRegisterHotkeyNotify (TxtInEx
, BM_HOTKEY_FROM_LINK (Link
));
748 EfiReleaseLock (&mBmHotkeyLock
);
753 Free the key options returned from BmGetKeyOptions.
755 @param KeyOptions Pointer to the key options.
756 @param KeyOptionCount Number of the key options.
758 @retval EFI_SUCCESS The key options are freed.
759 @retval EFI_NOT_FOUND KeyOptions is NULL.
763 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
,
764 IN UINTN KeyOptionCount
767 if (KeyOptions
!= NULL
) {
768 FreePool (KeyOptions
);
771 return EFI_NOT_FOUND
;
776 Register the key option to exit the waiting of the Boot Manager timeout.
777 Platform should ensure that the continue key option isn't conflict with
778 other boot key options.
780 @param Modifier Key shift state.
781 @param ... Parameter list of pointer of EFI_INPUT_KEY.
783 @retval EFI_SUCCESS Successfully register the continue key option.
784 @retval EFI_ALREADY_STARTED The continue key option is already registered.
788 EfiBootManagerRegisterContinueKeyOption (
794 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
797 if (mBmContinueKeyOption
!= NULL
) {
798 return EFI_ALREADY_STARTED
;
801 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
802 VA_START (Args
, Modifier
);
803 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
806 if (!EFI_ERROR (Status
)) {
807 mBmContinueKeyOption
= AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION
), &KeyOption
);
808 ASSERT (mBmContinueKeyOption
!= NULL
);
809 if (mBmHotkeyServiceStarted
) {
810 BmProcessKeyOption (mBmContinueKeyOption
);
818 Stop the hotkey processing.
820 @param Event Event pointer related to hotkey service.
821 @param Context Context pass to this function.
825 BmStopHotkeyService (
833 DEBUG ((EFI_D_INFO
, "[Bds]Stop Hotkey Service!\n"));
834 gBS
->CloseEvent (Event
);
836 EfiAcquireLock (&mBmHotkeyLock
);
837 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
838 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
839 BmUnregisterHotkeyNotify (Hotkey
);
840 Link
= RemoveEntryList (Link
);
843 EfiReleaseLock (&mBmHotkeyLock
);
847 Start the hot key service so that the key press can trigger the boot option.
849 @param HotkeyTriggered Return the waitable event and it will be signaled
850 when a valid hot key is pressed.
852 @retval EFI_SUCCESS The hot key service is started.
856 EfiBootManagerStartHotkeyService (
857 IN EFI_EVENT
*HotkeyTriggered
861 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
862 UINTN KeyOptionCount
;
865 UINT32
*BootOptionSupport
;
867 GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, (VOID
**) &BootOptionSupport
, NULL
);
868 if (BootOptionSupport
!= NULL
) {
869 if ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_KEY
) != 0) {
870 mBmHotkeySupportCount
= ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_COUNT
) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT
));
872 FreePool (BootOptionSupport
);
875 if (mBmHotkeySupportCount
== 0) {
876 DEBUG ((EFI_D_INFO
, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
877 return EFI_UNSUPPORTED
;
880 Status
= gBS
->CreateEvent (
883 EfiEventEmptyFunction
,
887 ASSERT_EFI_ERROR (Status
);
889 if (HotkeyTriggered
!= NULL
) {
890 *HotkeyTriggered
= mBmHotkeyTriggered
;
893 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
894 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
895 BmProcessKeyOption (&KeyOptions
[Index
]);
897 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
899 if (mBmContinueKeyOption
!= NULL
) {
900 BmProcessKeyOption (mBmContinueKeyOption
);
904 // Hook hotkey on every future SimpleTextInputEx instance when
905 // SystemTable.ConsoleInHandle == NULL, which means the console
906 // manager (ConSplitter) is absent.
908 if (gST
->ConsoleInHandle
== NULL
) {
909 EfiCreateProtocolNotifyEvent (
910 &gEfiSimpleTextInputExProtocolGuid
,
914 &mBmTxtInExRegistration
918 Status
= EfiCreateEventReadyToBootEx (
924 ASSERT_EFI_ERROR (Status
);
926 mBmHotkeyServiceStarted
= TRUE
;
932 It adds the key option variable and the key option takes affect immediately.
934 @param AddedOption Return the added key option.
935 @param BootOptionNumber The boot option number for the key option.
936 @param Modifier Key shift state.
937 @param ... Parameter list of pointer of EFI_INPUT_KEY.
939 @retval EFI_SUCCESS The key option is added.
940 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
944 EfiBootManagerAddKeyOptionVariable (
945 OUT EFI_BOOT_MANAGER_KEY_OPTION
*AddedOption
, OPTIONAL
946 IN UINT16 BootOptionNumber
,
954 UINTN BootOptionSize
;
955 CHAR16 BootOptionName
[BM_OPTION_NAME_LEN
];
956 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
957 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
958 UINTN KeyOptionCount
;
960 UINTN KeyOptionNumber
;
961 CHAR16 KeyOptionName
[sizeof ("Key####")];
964 BootOptionName
, sizeof (BootOptionName
), L
"%s%04x",
965 mBmLoadOptionName
[LoadOptionTypeBoot
], BootOptionNumber
967 GetEfiGlobalVariable2 (BootOptionName
, &BootOption
, &BootOptionSize
);
969 if (BootOption
== NULL
) {
970 return EFI_NOT_FOUND
;
973 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
974 KeyOption
.BootOption
= BootOptionNumber
;
975 Status
= gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &KeyOption
.BootOptionCrc
);
976 ASSERT_EFI_ERROR (Status
);
977 FreePool (BootOption
);
979 VA_START (Args
, Modifier
);
980 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
982 if (EFI_ERROR (Status
)) {
986 KeyOptionNumber
= LoadOptionNumberUnassigned
;
988 // Check if the hot key sequence was defined already
990 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
991 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
992 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
993 (CompareMem (KeyOptions
[Index
].Keys
, KeyOption
.Keys
, KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)) {
997 if ((KeyOptionNumber
== LoadOptionNumberUnassigned
) &&
998 (KeyOptions
[Index
].OptionNumber
> Index
)
1000 KeyOptionNumber
= Index
;
1003 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1005 if (Index
< KeyOptionCount
) {
1006 return EFI_ALREADY_STARTED
;
1009 if (KeyOptionNumber
== LoadOptionNumberUnassigned
) {
1010 KeyOptionNumber
= KeyOptionCount
;
1013 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumber
);
1015 Status
= gRT
->SetVariable (
1017 &gEfiGlobalVariableGuid
,
1018 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1019 BmSizeOfKeyOption (&KeyOption
),
1022 if (!EFI_ERROR (Status
)) {
1024 // Return the Key Option in case needed by caller
1026 if (AddedOption
!= NULL
) {
1027 CopyMem (AddedOption
, &KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1031 // Register the newly added hot key
1032 // Calling this function before EfiBootManagerStartHotkeyService doesn't
1033 // need to call BmProcessKeyOption
1035 if (mBmHotkeyServiceStarted
) {
1036 BmProcessKeyOption (&KeyOption
);
1044 Delete the Key Option variable and unregister the hot key
1046 @param DeletedOption Return the deleted key options.
1047 @param Modifier Key shift state.
1048 @param ... Parameter list of pointer of EFI_INPUT_KEY.
1050 @retval EFI_SUCCESS The key option is deleted.
1051 @retval EFI_NOT_FOUND The key option cannot be found.
1055 EfiBootManagerDeleteKeyOptionVariable (
1056 IN EFI_BOOT_MANAGER_KEY_OPTION
*DeletedOption
, OPTIONAL
1064 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
1065 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
1066 UINTN KeyOptionCount
;
1071 CHAR16 KeyOptionName
[sizeof ("Key####")];
1073 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1074 VA_START (Args
, Modifier
);
1075 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1078 if (EFI_ERROR (Status
)) {
1082 EfiAcquireLock (&mBmHotkeyLock
);
1084 // Delete the key option from active hot key list
1085 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
1087 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
1088 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
1089 Match
= (BOOLEAN
) (Hotkey
->CodeCount
== KeyOption
.KeyData
.Options
.InputKeyCount
);
1091 for (Index
= 0; Match
&& (Index
< Hotkey
->CodeCount
); Index
++) {
1092 ShiftState
= Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
;
1094 (BmBitSet (ShiftState
, EFI_RIGHT_SHIFT_PRESSED
| EFI_LEFT_SHIFT_PRESSED
) != KeyOption
.KeyData
.Options
.ShiftPressed
) ||
1095 (BmBitSet (ShiftState
, EFI_RIGHT_CONTROL_PRESSED
| EFI_LEFT_CONTROL_PRESSED
) != KeyOption
.KeyData
.Options
.ControlPressed
) ||
1096 (BmBitSet (ShiftState
, EFI_RIGHT_ALT_PRESSED
| EFI_LEFT_ALT_PRESSED
) != KeyOption
.KeyData
.Options
.AltPressed
) ||
1097 (BmBitSet (ShiftState
, EFI_RIGHT_LOGO_PRESSED
| EFI_LEFT_LOGO_PRESSED
) != KeyOption
.KeyData
.Options
.LogoPressed
) ||
1098 (BmBitSet (ShiftState
, EFI_MENU_KEY_PRESSED
) != KeyOption
.KeyData
.Options
.MenuPressed
) ||
1099 (BmBitSet (ShiftState
, EFI_SYS_REQ_PRESSED
) != KeyOption
.KeyData
.Options
.SysReqPressed
) ||
1100 (CompareMem (&Hotkey
->KeyData
[Index
].Key
, &KeyOption
.Keys
[Index
], sizeof (EFI_INPUT_KEY
)) != 0)
1103 // Break when any field doesn't match
1111 Link
= RemoveEntryList (Link
);
1114 Link
= GetNextNode (&mBmHotkeyList
, Link
);
1119 // Delete the key option from the variable
1121 Status
= EFI_NOT_FOUND
;
1122 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1123 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1124 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1126 KeyOptions
[Index
].Keys
, KeyOption
.Keys
,
1127 KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)
1129 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptions
[Index
].OptionNumber
);
1130 Status
= gRT
->SetVariable (
1132 &gEfiGlobalVariableGuid
,
1133 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1138 // Return the deleted key option in case needed by caller
1140 if (DeletedOption
!= NULL
) {
1141 CopyMem (DeletedOption
, &KeyOptions
[Index
], sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1146 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1148 EfiReleaseLock (&mBmHotkeyLock
);