2 Hotkey library functions.
4 Copyright (c) 2011 - 2015, 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 Check whether the input key option is valid.
38 @param KeyOption Input key option info.
40 @retval TRUE Input key option is valid.
41 @retval FALSE Input key option is not valid.
45 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
48 UINT16 OptionName
[sizeof (L
"Boot####")];
54 // Check whether corresponding Boot Option exist
56 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", KeyOption
->BootOption
);
57 GetEfiGlobalVariable2 (OptionName
, (VOID
**) &BootOption
, &BootOptionSize
);
59 if (BootOption
== NULL
) {
64 // Check CRC for Boot Option
66 gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &Crc
);
67 FreePool (BootOption
);
69 return (BOOLEAN
) (KeyOption
->BootOptionCrc
== Crc
);
74 Check whether the input variable is an key option variable.
76 @param Name Input variable name.
77 @param Guid Input variable guid.
78 @param OptionNumber The option number of this key option variable.
80 @retval TRUE Input variable is a key option variable.
81 @retval FALSE Input variable is not a key option variable.
84 BmIsKeyOptionVariable (
92 if (!CompareGuid (Guid
, &gEfiGlobalVariableGuid
) ||
93 (StrSize (Name
) != sizeof (L
"Key####")) ||
94 (StrnCmp (Name
, L
"Key", 3) != 0)
100 for (Index
= 3; Index
< 7; Index
++) {
101 if ((Name
[Index
] >= L
'0') && (Name
[Index
] <= L
'9')) {
102 *OptionNumber
= *OptionNumber
* 16 + Name
[Index
] - L
'0';
103 } else if ((Name
[Index
] >= L
'A') && (Name
[Index
] <= L
'F')) {
104 *OptionNumber
= *OptionNumber
* 16 + Name
[Index
] - L
'A' + 10;
114 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
116 @param KeyOption The input key option info.
118 @retval The buffer size of the key option data.
122 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
125 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION
, Keys
)
126 + KeyOption
->KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
);
130 Return the array of key options.
132 @param Count Return the number of key options.
134 @retval NULL No key option.
135 @retval Other Pointer to the key options.
137 EFI_BOOT_MANAGER_KEY_OPTION
*
148 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
149 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
;
159 NameSize
= sizeof (CHAR16
);
160 Name
= AllocateZeroPool (NameSize
);
161 ASSERT (Name
!= NULL
);
163 NewNameSize
= NameSize
;
164 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
165 if (Status
== EFI_BUFFER_TOO_SMALL
) {
166 Name
= ReallocatePool (NameSize
, NewNameSize
, Name
);
167 ASSERT (Name
!= NULL
);
168 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
169 NameSize
= NewNameSize
;
172 if (Status
== EFI_NOT_FOUND
) {
175 ASSERT_EFI_ERROR (Status
);
177 if (BmIsKeyOptionVariable (Name
,&Guid
, &OptionNumber
)) {
178 GetEfiGlobalVariable2 (Name
, (VOID
**) &KeyOption
, NULL
);
179 ASSERT (KeyOption
!= NULL
);
180 if (BmIsKeyOptionValid (KeyOption
)) {
181 KeyOptions
= ReallocatePool (
182 *Count
* sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
183 (*Count
+ 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
),
186 ASSERT (KeyOptions
!= NULL
);
188 // Insert the key option in order
190 for (Index
= 0; Index
< *Count
; Index
++) {
191 if (OptionNumber
< KeyOptions
[Index
].OptionNumber
) {
195 CopyMem (&KeyOptions
[Index
+ 1], &KeyOptions
[Index
], (*Count
- Index
) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
196 CopyMem (&KeyOptions
[Index
], KeyOption
, BmSizeOfKeyOption (KeyOption
));
197 KeyOptions
[Index
].OptionNumber
= OptionNumber
;
200 FreePool (KeyOption
);
210 Callback function for event.
212 @param Event Event for this callback function.
213 @param Context Context pass to this function.
225 Check whether the bit is set in the value.
227 @param Value The value need to be check.
228 @param Bit The bit filed need to be check.
230 @retval TRUE The bit is set.
231 @retval FALSE The bit is not set.
239 return (BOOLEAN
) ((Value
& Bit
) != 0);
243 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
245 @param Modifier Input key info.
246 @param Args Va_list info.
247 @param KeyOption Key info which need to update.
249 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
250 @return EFI_INVALID_PARAMETER Input parameter error.
253 BmInitializeKeyFields (
256 OUT EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
261 if (KeyOption
== NULL
) {
262 return EFI_INVALID_PARAMETER
;
266 while (KeyOption
->KeyData
.Options
.InputKeyCount
< sizeof (KeyOption
->Keys
) / sizeof (KeyOption
->Keys
[0])) {
267 Key
= VA_ARG (Args
, EFI_INPUT_KEY
*);
272 &KeyOption
->Keys
[KeyOption
->KeyData
.Options
.InputKeyCount
],
274 sizeof (EFI_INPUT_KEY
)
276 KeyOption
->KeyData
.Options
.InputKeyCount
++;
283 return EFI_INVALID_PARAMETER
;
286 if ((Modifier
& ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
287 | EFI_BOOT_MANAGER_CONTROL_PRESSED
288 | EFI_BOOT_MANAGER_ALT_PRESSED
289 | EFI_BOOT_MANAGER_LOGO_PRESSED
290 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
291 | 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;
299 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_CONTROL_PRESSED
)) {
300 KeyOption
->KeyData
.Options
.ControlPressed
= 1;
302 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_ALT_PRESSED
)) {
303 KeyOption
->KeyData
.Options
.AltPressed
= 1;
305 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_LOGO_PRESSED
)) {
306 KeyOption
->KeyData
.Options
.LogoPressed
= 1;
308 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_MENU_KEY_PRESSED
)) {
309 KeyOption
->KeyData
.Options
.MenuPressed
= 1;
311 if (BmBitSet (Modifier
, EFI_BOOT_MANAGER_SYS_REQ_PRESSED
)) {
312 KeyOption
->KeyData
.Options
.SysReqPressed
= 1;
319 Try to boot the boot option triggered by hot key.
323 EfiBootManagerHotkeyBoot (
327 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
328 EfiBootManagerBoot (&mBmHotkeyBootOption
);
329 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption
);
330 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
335 This is the common notification function for HotKeys, it will be registered
336 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
338 @param KeyData A pointer to a buffer that is filled in with the keystroke
339 information for the key that was pressed.
341 @retval EFI_SUCCESS KeyData is successfully processed.
342 @return EFI_NOT_FOUND Fail to find boot option variable.
347 IN EFI_KEY_DATA
*KeyData
352 CHAR16 OptionName
[sizeof ("Boot####")];
354 EFI_KEY_DATA
*HotkeyData
;
356 if (mBmHotkeyBootOption
.OptionNumber
!= LoadOptionNumberUnassigned
) {
358 // Do not process sequential hotkey stroke until the current boot option returns
363 DEBUG ((EFI_D_INFO
, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData
->Key
.ScanCode
, KeyData
->Key
.UnicodeChar
));
365 EfiAcquireLock (&mBmHotkeyLock
);
366 for ( Link
= GetFirstNode (&mBmHotkeyList
)
367 ; !IsNull (&mBmHotkeyList
, Link
)
368 ; Link
= GetNextNode (&mBmHotkeyList
, Link
)
370 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
373 // Is this Key Stroke we are waiting for?
375 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
376 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
377 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
378 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
379 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
380 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
385 // Receive an expecting key stroke, transit to next waiting state
387 Hotkey
->WaitingKey
++;
389 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
391 // Reset to initial waiting state
393 Hotkey
->WaitingKey
= 0;
395 // Received the whole key stroke sequence
397 Status
= gBS
->SignalEvent (mBmHotkeyTriggered
);
398 ASSERT_EFI_ERROR (Status
);
400 if (!Hotkey
->IsContinue
) {
402 // Launch its BootOption
404 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", Hotkey
->BootOption
);
405 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &mBmHotkeyBootOption
);
406 DEBUG ((EFI_D_INFO
, "[Bds]Hotkey for %s pressed - %r\n", OptionName
, Status
));
407 if (EFI_ERROR (Status
)) {
408 mBmHotkeyBootOption
.OptionNumber
= LoadOptionNumberUnassigned
;
411 DEBUG ((EFI_D_INFO
, "[Bds]Continue key pressed!\n"));
416 // Receive an unexpected key stroke, reset to initial waiting state
418 Hotkey
->WaitingKey
= 0;
422 EfiReleaseLock (&mBmHotkeyLock
);
428 Unregister hotkey notify list.
430 @param Hotkey Hotkey list.
432 @retval EFI_SUCCESS Unregister hotkey notify success.
433 @retval Others Unregister hotkey notify failed.
436 BmUnregisterHotkeyNotify (
445 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
448 gBS
->LocateHandleBuffer (
450 &gEfiSimpleTextInputExProtocolGuid
,
455 for (Index
= 0; Index
< HandleCount
; Index
++) {
456 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
457 ASSERT_EFI_ERROR (Status
);
458 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
459 Status
= TxtInEx
->RegisterKeyNotify (
461 &Hotkey
->KeyData
[KeyIndex
],
465 if (!EFI_ERROR (Status
)) {
466 Status
= TxtInEx
->UnregisterKeyNotify (TxtInEx
, NotifyHandle
);
467 DEBUG ((EFI_D_INFO
, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey
->KeyData
[KeyIndex
].Key
.ScanCode
, Hotkey
->KeyData
[KeyIndex
].Key
.UnicodeChar
, Status
));
476 Register hotkey notify list.
478 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
479 @param Hotkey Hotkey list.
481 @retval EFI_SUCCESS Register hotkey notify success.
482 @retval Others Register hotkey notify failed.
485 BmRegisterHotkeyNotify (
486 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
,
494 for (Index
= 0; Index
< Hotkey
->CodeCount
; Index
++) {
495 Status
= TxtInEx
->RegisterKeyNotify (
497 &Hotkey
->KeyData
[Index
],
503 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
504 Hotkey
->KeyData
[Index
].Key
.ScanCode
,
505 Hotkey
->KeyData
[Index
].Key
.UnicodeChar
,
506 Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
,
507 Hotkey
->KeyData
[Index
].KeyState
.KeyToggleState
,
510 if (EFI_ERROR (Status
)) {
512 // some of the hotkey registry failed
513 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
523 Generate key shift state base on the input key option info.
525 @param Depth Which key is checked.
526 @param KeyOption Input key option info.
527 @param KeyShiftState Input key shift state.
528 @param KeyShiftStates Return possible key shift state array.
529 @param KeyShiftStateCount Possible key shift state count.
532 BmGenerateKeyShiftState (
534 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
,
535 IN UINT32 KeyShiftState
,
536 IN UINT32
*KeyShiftStates
,
537 IN UINTN
*KeyShiftStateCount
542 if (KeyOption
->KeyData
.Options
.ShiftPressed
) {
543 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
544 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_SHIFT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
546 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
551 if (KeyOption
->KeyData
.Options
.ControlPressed
) {
552 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
553 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_CONTROL_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
555 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
560 if (KeyOption
->KeyData
.Options
.AltPressed
) {
561 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
562 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_ALT_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
564 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
568 if (KeyOption
->KeyData
.Options
.LogoPressed
) {
569 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_RIGHT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
570 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
| EFI_LEFT_LOGO_PRESSED
, KeyShiftStates
, KeyShiftStateCount
);
572 BmGenerateKeyShiftState (Depth
+ 1, KeyOption
, KeyShiftState
, KeyShiftStates
, KeyShiftStateCount
);
576 if (KeyOption
->KeyData
.Options
.MenuPressed
) {
577 KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
579 if (KeyOption
->KeyData
.Options
.SysReqPressed
) {
580 KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
582 KeyShiftStates
[*KeyShiftStateCount
] = KeyShiftState
;
583 (*KeyShiftStateCount
)++;
589 Add it to hot key database, register it to existing TxtInEx.
590 New TxtInEx will be automatically registered with all the hot key in dababase
592 @param KeyOption Input key option info.
596 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOption
600 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
608 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
610 UINT32 KeyShiftStates
[16];
611 UINTN KeyShiftStateCount
;
613 if (KeyOption
->KeyData
.Options
.InputKeyCount
> mBmHotkeySupportCount
) {
614 return EFI_UNSUPPORTED
;
617 KeyShiftStateCount
= 0;
618 BmGenerateKeyShiftState (0, KeyOption
, EFI_SHIFT_STATE_VALID
, KeyShiftStates
, &KeyShiftStateCount
);
619 ASSERT (KeyShiftStateCount
<= sizeof (KeyShiftStates
) / sizeof (KeyShiftStates
[0]));
621 EfiAcquireLock (&mBmHotkeyLock
);
623 for (Index
= 0; Index
< KeyShiftStateCount
; Index
++) {
624 Hotkey
= AllocateZeroPool (sizeof (BM_HOTKEY
));
625 ASSERT (Hotkey
!= NULL
);
627 Hotkey
->Signature
= BM_HOTKEY_SIGNATURE
;
628 Hotkey
->BootOption
= KeyOption
->BootOption
;
629 Hotkey
->IsContinue
= (BOOLEAN
) (KeyOption
== mBmContinueKeyOption
);
630 Hotkey
->CodeCount
= (UINT8
) KeyOption
->KeyData
.Options
.InputKeyCount
;
632 for (KeyIndex
= 0; KeyIndex
< Hotkey
->CodeCount
; KeyIndex
++) {
633 CopyMem (&Hotkey
->KeyData
[KeyIndex
].Key
, &KeyOption
->Keys
[KeyIndex
], sizeof (EFI_INPUT_KEY
));
634 Hotkey
->KeyData
[KeyIndex
].KeyState
.KeyShiftState
= KeyShiftStates
[Index
];
636 InsertTailList (&mBmHotkeyList
, &Hotkey
->Link
);
638 gBS
->LocateHandleBuffer (
640 &gEfiSimpleTextInputExProtocolGuid
,
645 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
646 Status
= gBS
->HandleProtocol (Handles
[HandleIndex
], &gEfiSimpleTextInputExProtocolGuid
, (VOID
**) &TxtInEx
);
647 ASSERT_EFI_ERROR (Status
);
648 BmRegisterHotkeyNotify (TxtInEx
, Hotkey
);
652 EfiReleaseLock (&mBmHotkeyLock
);
658 Callback function for SimpleTextInEx protocol install events
660 @param Event the event that is signaled.
661 @param Context not used here.
674 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*TxtInEx
;
678 BufferSize
= sizeof (EFI_HANDLE
);
679 Status
= gBS
->LocateHandle (
682 mBmTxtInExRegistration
,
686 if (EFI_ERROR (Status
)) {
688 // If no more notification events exist
693 Status
= gBS
->HandleProtocol (
695 &gEfiSimpleTextInputExProtocolGuid
,
698 ASSERT_EFI_ERROR (Status
);
701 // Register the hot key notification for the existing items in the list
703 EfiAcquireLock (&mBmHotkeyLock
);
704 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); Link
= GetNextNode (&mBmHotkeyList
, Link
)) {
705 BmRegisterHotkeyNotify (TxtInEx
, BM_HOTKEY_FROM_LINK (Link
));
707 EfiReleaseLock (&mBmHotkeyLock
);
712 Free the key options returned from BmGetKeyOptions.
714 @param KeyOptions Pointer to the key options.
715 @param KeyOptionCount Number of the key options.
717 @retval EFI_SUCCESS The key options are freed.
718 @retval EFI_NOT_FOUND KeyOptions is NULL.
722 IN EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
,
723 IN UINTN KeyOptionCount
726 if (KeyOptions
!= NULL
) {
727 FreePool (KeyOptions
);
730 return EFI_NOT_FOUND
;
735 Register the key option to exit the waiting of the Boot Manager timeout.
736 Platform should ensure that the continue key option isn't conflict with
737 other boot key options.
739 @param Modifier Key shift state.
740 @param ... Parameter list of pointer of EFI_INPUT_KEY.
742 @retval EFI_SUCCESS Successfully register the continue key option.
743 @retval EFI_ALREADY_STARTED The continue key option is already registered.
747 EfiBootManagerRegisterContinueKeyOption (
753 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
756 if (mBmContinueKeyOption
!= NULL
) {
757 return EFI_ALREADY_STARTED
;
760 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
761 VA_START (Args
, Modifier
);
762 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
765 if (!EFI_ERROR (Status
)) {
766 mBmContinueKeyOption
= AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION
), &KeyOption
);
767 ASSERT (mBmContinueKeyOption
!= NULL
);
768 if (mBmHotkeyServiceStarted
) {
769 BmProcessKeyOption (mBmContinueKeyOption
);
777 Stop the hotkey processing.
779 @param Event Event pointer related to hotkey service.
780 @param Context Context pass to this function.
784 BmStopHotkeyService (
792 DEBUG ((EFI_D_INFO
, "[Bds]Stop Hotkey Service!\n"));
793 gBS
->CloseEvent (Event
);
795 EfiAcquireLock (&mBmHotkeyLock
);
796 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
797 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
798 BmUnregisterHotkeyNotify (Hotkey
);
799 Link
= RemoveEntryList (Link
);
802 EfiReleaseLock (&mBmHotkeyLock
);
806 Start the hot key service so that the key press can trigger the boot option.
808 @param HotkeyTriggered Return the waitable event and it will be signaled
809 when a valid hot key is pressed.
811 @retval EFI_SUCCESS The hot key service is started.
815 EfiBootManagerStartHotkeyService (
816 IN EFI_EVENT
*HotkeyTriggered
820 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
821 UINTN KeyOptionCount
;
824 UINT32
*BootOptionSupport
;
826 Status
= GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, (VOID
**) &BootOptionSupport
, NULL
);
827 ASSERT (BootOptionSupport
!= NULL
);
829 if ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_KEY
) != 0) {
830 mBmHotkeySupportCount
= ((*BootOptionSupport
& EFI_BOOT_OPTION_SUPPORT_COUNT
) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT
));
832 FreePool (BootOptionSupport
);
834 if (mBmHotkeySupportCount
== 0) {
835 DEBUG ((EFI_D_INFO
, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
836 return EFI_UNSUPPORTED
;
839 Status
= gBS
->CreateEvent (
846 ASSERT_EFI_ERROR (Status
);
848 if (HotkeyTriggered
!= NULL
) {
849 *HotkeyTriggered
= mBmHotkeyTriggered
;
852 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
853 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
854 BmProcessKeyOption (&KeyOptions
[Index
]);
856 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
858 if (mBmContinueKeyOption
!= NULL
) {
859 BmProcessKeyOption (mBmContinueKeyOption
);
862 EfiCreateProtocolNotifyEvent (
863 &gEfiSimpleTextInputExProtocolGuid
,
867 &mBmTxtInExRegistration
870 Status
= EfiCreateEventReadyToBootEx (
876 ASSERT_EFI_ERROR (Status
);
879 mBmHotkeyServiceStarted
= TRUE
;
885 It adds the key option variable and the key option takes affect immediately.
887 @param AddedOption Return the added key option.
888 @param BootOptionNumber The boot option number for the key option.
889 @param Modifier Key shift state.
890 @param ... Parameter list of pointer of EFI_INPUT_KEY.
892 @retval EFI_SUCCESS The key option is added.
893 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
897 EfiBootManagerAddKeyOptionVariable (
898 OUT EFI_BOOT_MANAGER_KEY_OPTION
*AddedOption
, OPTIONAL
899 IN UINT16 BootOptionNumber
,
907 UINTN BootOptionSize
;
908 CHAR16 BootOptionName
[sizeof (L
"Boot####")];
909 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
910 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
911 UINTN KeyOptionCount
;
913 UINTN KeyOptionNumber
;
914 CHAR16 KeyOptionName
[sizeof (L
"Key####")];
916 UnicodeSPrint (BootOptionName
, sizeof (BootOptionName
), L
"Boot%04x", BootOptionNumber
);
917 GetEfiGlobalVariable2 (BootOptionName
, &BootOption
, &BootOptionSize
);
919 if (BootOption
== NULL
) {
920 return EFI_NOT_FOUND
;
923 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
924 KeyOption
.BootOption
= BootOptionNumber
;
925 Status
= gBS
->CalculateCrc32 (BootOption
, BootOptionSize
, &KeyOption
.BootOptionCrc
);
926 ASSERT_EFI_ERROR (Status
);
927 FreePool (BootOption
);
929 VA_START (Args
, Modifier
);
930 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
932 if (EFI_ERROR (Status
)) {
936 KeyOptionNumber
= LoadOptionNumberUnassigned
;
938 // Check if the hot key sequence was defined already
940 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
941 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
942 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
943 (CompareMem (KeyOptions
[Index
].Keys
, KeyOption
.Keys
, KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)) {
947 if ((KeyOptionNumber
== LoadOptionNumberUnassigned
) &&
948 (KeyOptions
[Index
].OptionNumber
> Index
)
950 KeyOptionNumber
= Index
;
953 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
955 if (Index
< KeyOptionCount
) {
956 return EFI_ALREADY_STARTED
;
959 if (KeyOptionNumber
== LoadOptionNumberUnassigned
) {
960 KeyOptionNumber
= KeyOptionCount
;
963 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumber
);
965 Status
= gRT
->SetVariable (
967 &gEfiGlobalVariableGuid
,
968 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
969 BmSizeOfKeyOption (&KeyOption
),
972 if (!EFI_ERROR (Status
)) {
974 // Return the Key Option in case needed by caller
976 if (AddedOption
!= NULL
) {
977 CopyMem (AddedOption
, &KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
981 // Register the newly added hot key
982 // Calling this function before EfiBootManagerStartHotkeyService doesn't
983 // need to call BmProcessKeyOption
985 if (mBmHotkeyServiceStarted
) {
986 BmProcessKeyOption (&KeyOption
);
994 Delete the Key Option variable and unregister the hot key
996 @param DeletedOption Return the deleted key options.
997 @param Modifier Key shift state.
998 @param ... Parameter list of pointer of EFI_INPUT_KEY.
1000 @retval EFI_SUCCESS The key option is deleted.
1001 @retval EFI_NOT_FOUND The key option cannot be found.
1005 EfiBootManagerDeleteKeyOptionVariable (
1006 IN EFI_BOOT_MANAGER_KEY_OPTION
*DeletedOption
, OPTIONAL
1014 EFI_BOOT_MANAGER_KEY_OPTION KeyOption
;
1015 EFI_BOOT_MANAGER_KEY_OPTION
*KeyOptions
;
1016 UINTN KeyOptionCount
;
1021 CHAR16 KeyOptionName
[sizeof (L
"Key####")];
1023 ZeroMem (&KeyOption
, sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1024 VA_START (Args
, Modifier
);
1025 Status
= BmInitializeKeyFields (Modifier
, Args
, &KeyOption
);
1028 if (EFI_ERROR (Status
)) {
1032 EfiAcquireLock (&mBmHotkeyLock
);
1034 // Delete the key option from active hot key list
1035 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
1037 for (Link
= GetFirstNode (&mBmHotkeyList
); !IsNull (&mBmHotkeyList
, Link
); ) {
1038 Hotkey
= BM_HOTKEY_FROM_LINK (Link
);
1039 Match
= (BOOLEAN
) (Hotkey
->CodeCount
== KeyOption
.KeyData
.Options
.InputKeyCount
);
1041 for (Index
= 0; Match
&& (Index
< Hotkey
->CodeCount
); Index
++) {
1042 ShiftState
= Hotkey
->KeyData
[Index
].KeyState
.KeyShiftState
;
1044 (BmBitSet (ShiftState
, EFI_RIGHT_SHIFT_PRESSED
| EFI_LEFT_SHIFT_PRESSED
) != KeyOption
.KeyData
.Options
.ShiftPressed
) ||
1045 (BmBitSet (ShiftState
, EFI_RIGHT_CONTROL_PRESSED
| EFI_LEFT_CONTROL_PRESSED
) != KeyOption
.KeyData
.Options
.ControlPressed
) ||
1046 (BmBitSet (ShiftState
, EFI_RIGHT_ALT_PRESSED
| EFI_LEFT_ALT_PRESSED
) != KeyOption
.KeyData
.Options
.AltPressed
) ||
1047 (BmBitSet (ShiftState
, EFI_RIGHT_LOGO_PRESSED
| EFI_LEFT_LOGO_PRESSED
) != KeyOption
.KeyData
.Options
.LogoPressed
) ||
1048 (BmBitSet (ShiftState
, EFI_MENU_KEY_PRESSED
) != KeyOption
.KeyData
.Options
.MenuPressed
) ||
1049 (BmBitSet (ShiftState
, EFI_SYS_REQ_PRESSED
) != KeyOption
.KeyData
.Options
.SysReqPressed
) ||
1050 (CompareMem (&Hotkey
->KeyData
[Index
].Key
, &KeyOption
.Keys
[Index
], sizeof (EFI_INPUT_KEY
)) != 0)
1053 // Break when any field doesn't match
1061 Link
= RemoveEntryList (Link
);
1064 Link
= GetNextNode (&mBmHotkeyList
, Link
);
1069 // Delete the key option from the variable
1071 Status
= EFI_NOT_FOUND
;
1072 KeyOptions
= BmGetKeyOptions (&KeyOptionCount
);
1073 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
1074 if ((KeyOptions
[Index
].KeyData
.PackedValue
== KeyOption
.KeyData
.PackedValue
) &&
1076 KeyOptions
[Index
].Keys
, KeyOption
.Keys
,
1077 KeyOption
.KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
)) == 0)
1079 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptions
[Index
].OptionNumber
);
1080 Status
= gRT
->SetVariable (
1082 &gEfiGlobalVariableGuid
,
1083 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1088 // Return the deleted key option in case needed by caller
1090 if (DeletedOption
!= NULL
) {
1091 CopyMem (DeletedOption
, &KeyOptions
[Index
], sizeof (EFI_BOOT_MANAGER_KEY_OPTION
));
1096 BmFreeKeyOptions (KeyOptions
, KeyOptionCount
);
1098 EfiReleaseLock (&mBmHotkeyLock
);