2 Provides a way for 3rd party applications to register themselves for launch by the
3 Boot Manager based on hot key
5 Copyright (c) 2007 - 2008, Intel Corporation. <BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 LIST_ENTRY mHotkeyList
= INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList
);
20 BOOLEAN mHotkeyCallbackPending
= FALSE
;
21 EFI_EVENT mHotkeyEvent
;
22 VOID
*mHotkeyRegistration
;
27 Check if the Key Option is valid or not.
30 @param KeyOption The Hot Key Option to be checked.
32 @retval TRUE The Hot Key Option is valid.
33 @retval FALSE The Hot Key Option is invalid.
38 IN EFI_KEY_OPTION
*KeyOption
41 UINT16 BootOptionName
[10];
47 // Check whether corresponding Boot Option exist
49 UnicodeSPrint (BootOptionName
, sizeof (BootOptionName
), L
"Boot%04x", KeyOption
->BootOption
);
50 BootOptionVar
= BdsLibGetVariableAndSize (
52 &gEfiGlobalVariableGuid
,
56 if (BootOptionVar
== NULL
|| BootOptionSize
== 0) {
61 // Check CRC for Boot Option
63 gBS
->CalculateCrc32 (BootOptionVar
, BootOptionSize
, &Crc
);
64 FreePool (BootOptionVar
);
66 return (BOOLEAN
) ((KeyOption
->BootOptionCrc
== Crc
) ? TRUE
: FALSE
);
71 Create Key#### for the given hotkey.
74 @param KeyOption The Hot Key Option to be added.
75 @param KeyOptionNumber The key option number for Key#### (optional).
77 @retval EFI_SUCCESS Register hotkey successfully.
78 @retval EFI_INVALID_PARAMETER The hotkey option is invalid.
83 IN EFI_KEY_OPTION
*KeyOption
,
84 OUT UINT16
*KeyOptionNumber
87 UINT16 KeyOptionName
[10];
92 UINT16 MaxOptionNumber
;
93 UINT16 RegisterOptionNumber
;
94 EFI_KEY_OPTION
*TempOption
;
98 BOOLEAN UpdateBootOption
;
101 // Validate the given key option
103 if (!IsKeyOptionValid (KeyOption
)) {
104 return EFI_INVALID_PARAMETER
;
107 KeyOptionSize
= sizeof (EFI_KEY_OPTION
) + GET_KEY_CODE_COUNT (KeyOption
->KeyOptions
.PackedValue
) * sizeof (EFI_INPUT_KEY
);
108 UpdateBootOption
= FALSE
;
111 // check whether HotKey conflict with keys used by Setup Browser
114 KeyOrder
= BdsLibGetVariableAndSize (
116 &gEfiGlobalVariableGuid
,
119 if (KeyOrder
== NULL
) {
124 // Find free key option number
128 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
129 if (MaxOptionNumber
< KeyOrder
[Index
]) {
130 MaxOptionNumber
= KeyOrder
[Index
];
133 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
134 TempOption
= BdsLibGetVariableAndSize (
136 &gEfiGlobalVariableGuid
,
140 if (CompareMem (TempOption
, KeyOption
, TempOptionSize
) == 0) {
142 // Got the option, so just return
144 FreePool (TempOption
);
149 if (KeyOption
->KeyOptions
.PackedValue
== TempOption
->KeyOptions
.PackedValue
) {
150 if (GET_KEY_CODE_COUNT (KeyOption
->KeyOptions
.PackedValue
) == 0 ||
152 ((UINT8
*) TempOption
) + sizeof (EFI_KEY_OPTION
),
153 ((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
),
154 KeyOptionSize
- sizeof (EFI_KEY_OPTION
)
157 // Hotkey is the same but BootOption changed, need update
159 UpdateBootOption
= TRUE
;
164 FreePool (TempOption
);
167 if (UpdateBootOption
) {
168 RegisterOptionNumber
= KeyOrder
[Index
];
169 FreePool (TempOption
);
171 RegisterOptionNumber
= (UINT16
) (MaxOptionNumber
+ 1);
174 if (KeyOptionNumber
!= NULL
) {
175 *KeyOptionNumber
= RegisterOptionNumber
;
179 // Create variable Key####
181 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", RegisterOptionNumber
);
182 Status
= gRT
->SetVariable (
184 &gEfiGlobalVariableGuid
,
185 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
189 if (EFI_ERROR (Status
)) {
190 gBS
->FreePool (KeyOrder
);
195 // Update the key order variable - "KeyOrder"
197 if (!UpdateBootOption
) {
198 Index
= KeyOrderSize
/ sizeof (UINT16
);
199 KeyOrderSize
+= sizeof (UINT16
);
202 NewKeyOrder
= AllocatePool (KeyOrderSize
);
203 if (NewKeyOrder
== NULL
) {
204 return EFI_OUT_OF_RESOURCES
;
207 if (KeyOrder
!= NULL
) {
208 CopyMem (NewKeyOrder
, KeyOrder
, KeyOrderSize
);
211 NewKeyOrder
[Index
] = RegisterOptionNumber
;
213 Status
= gRT
->SetVariable (
215 &gEfiGlobalVariableGuid
,
216 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
222 FreePool (NewKeyOrder
);
229 Delete Key#### for the given Key Option number.
231 @param KeyOptionNumber Key option number for Key####
233 @retval EFI_SUCCESS Unregister hotkey successfully.
234 @retval EFI_NOT_FOUND No Key#### is found for the given Key Option number.
239 IN UINT16 KeyOptionNumber
242 UINT16 KeyOption
[10];
250 // Delete variable Key####
252 UnicodeSPrint (KeyOption
, sizeof (KeyOption
), L
"Key%04x", KeyOptionNumber
);
255 &gEfiGlobalVariableGuid
,
256 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
262 // Adjust key order array
264 KeyOrder
= BdsLibGetVariableAndSize (
266 &gEfiGlobalVariableGuid
,
269 if (KeyOrder
== NULL
) {
274 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
275 if (KeyOrder
[Index
] == KeyOptionNumber
) {
281 if (Index
!= KeyOrderSize
/ sizeof (UINT16
)) {
283 // KeyOptionNumber found in "KeyOrder", delete it
285 for (Index
= Index2Del
; Index
< KeyOrderSize
/ sizeof (UINT16
) - 1; Index
++) {
286 KeyOrder
[Index
] = KeyOrder
[Index
+ 1];
289 KeyOrderSize
-= sizeof (UINT16
);
292 Status
= gRT
->SetVariable (
294 &gEfiGlobalVariableGuid
,
295 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
307 This is the common notification function for HotKeys, it will be registered
308 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
311 @param KeyData A pointer to a buffer that is filled in with the keystroke
312 information for the key that was pressed.
314 @retval EFI_SUCCESS KeyData is successfully processed.
319 IN EFI_KEY_DATA
*KeyData
322 BOOLEAN HotkeyCatched
;
323 LIST_ENTRY BootLists
;
325 BDS_HOTKEY_OPTION
*Hotkey
;
327 BDS_COMMON_OPTION
*BootOption
;
332 EFI_KEY_DATA
*HotkeyData
;
334 if (mHotkeyCallbackPending
) {
336 // When responsing to a Hotkey, ignore sequential hotkey stroke until
337 // the current Boot#### load option returned
342 Status
= EFI_SUCCESS
;
343 Link
= GetFirstNode (&mHotkeyList
);
345 while (!IsNull (&mHotkeyList
, Link
)) {
346 HotkeyCatched
= FALSE
;
347 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
350 // Is this Key Stroke we are waiting for?
352 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
353 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
354 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
355 ((HotkeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) ? (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : 1)) {
357 // Receive an expecting key stroke
359 if (Hotkey
->CodeCount
> 1) {
361 // For hotkey of key combination, transit to next waiting state
363 Hotkey
->WaitingKey
++;
365 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
367 // Received the whole key stroke sequence
369 HotkeyCatched
= TRUE
;
373 // For hotkey of single key stroke
375 HotkeyCatched
= TRUE
;
379 // Receive an unexpected key stroke, reset to initial waiting state
381 Hotkey
->WaitingKey
= 0;
386 // Reset to initial waiting state
388 Hotkey
->WaitingKey
= 0;
391 // Launch its BootOption
393 InitializeListHead (&BootLists
);
395 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", Hotkey
->BootOptionNumber
);
396 BootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
397 BootOption
->BootCurrent
= Hotkey
->BootOptionNumber
;
398 BdsLibConnectDevicePath (BootOption
->DevicePath
);
401 // Clear the screen before launch this BootOption
403 gST
->ConOut
->Reset (gST
->ConOut
, FALSE
);
406 // BdsLibBootViaBootOption() is expected to be invoked at TPL level TPL_APPLICATION,
407 // so raise the TPL to TPL_APPLICATION first, then restore it
409 OldTpl
= gBS
->RaiseTPL (TPL_APPLICATION
);
411 mHotkeyCallbackPending
= TRUE
;
412 Status
= BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
413 mHotkeyCallbackPending
= FALSE
;
415 gBS
->RestoreTPL (OldTpl
);
417 if (EFI_ERROR (Status
)) {
419 // Call platform action to indicate the boot fail
421 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
422 PlatformBdsBootFail (BootOption
, Status
, ExitData
, ExitDataSize
);
425 // Call platform action to indicate the boot success
427 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
428 PlatformBdsBootSuccess (BootOption
);
432 Link
= GetNextNode (&mHotkeyList
, Link
);
440 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
443 @param SimpleTextInEx Simple Text Input Ex protocol instance
445 @retval EFI_SUCCESS Register hotkey notification function successfully.
446 @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
450 HotkeyRegisterNotify (
451 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
457 BDS_HOTKEY_OPTION
*Hotkey
;
460 // Register notification function for each hotkey
462 Link
= GetFirstNode (&mHotkeyList
);
464 while (!IsNull (&mHotkeyList
, Link
)) {
465 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
469 Status
= SimpleTextInEx
->RegisterKeyNotify (
471 &Hotkey
->KeyData
[Index
],
473 &Hotkey
->NotifyHandle
475 if (EFI_ERROR (Status
)) {
477 // some of the hotkey registry failed
482 } while (Index
< Hotkey
->CodeCount
);
484 Link
= GetNextNode (&mHotkeyList
, Link
);
491 Callback function for SimpleTextInEx protocol install events
494 @param Event the event that is signaled.
495 @param Context not used here.
510 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
;
513 BufferSize
= sizeof (EFI_HANDLE
);
514 Status
= gBS
->LocateHandle (
521 if (EFI_ERROR (Status
)) {
523 // If no more notification events exist
528 Status
= gBS
->HandleProtocol (
530 &gEfiSimpleTextInputExProtocolGuid
,
531 (VOID
**) &SimpleTextInEx
533 ASSERT_EFI_ERROR (Status
);
535 HotkeyRegisterNotify (SimpleTextInEx
);
541 Insert Key Option to hotkey list.
544 @param KeyOption The Hot Key Option to be added to hotkey list.
546 @retval EFI_SUCCESS Add to hotkey list success.
551 IN EFI_KEY_OPTION
*KeyOption
554 BDS_HOTKEY_OPTION
*HotkeyLeft
;
555 BDS_HOTKEY_OPTION
*HotkeyRight
;
558 UINT32 KeyShiftStateLeft
;
559 UINT32 KeyShiftStateRight
;
560 EFI_INPUT_KEY
*InputKey
;
561 EFI_KEY_DATA
*KeyData
;
563 HotkeyLeft
= AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION
));
564 if (HotkeyLeft
== NULL
) {
565 return EFI_OUT_OF_RESOURCES
;
568 HotkeyLeft
->Signature
= BDS_HOTKEY_OPTION_SIGNATURE
;
569 HotkeyLeft
->BootOptionNumber
= KeyOption
->BootOption
;
571 KeyOptions
= KeyOption
->KeyOptions
.PackedValue
;
573 HotkeyLeft
->CodeCount
= (UINT8
) GET_KEY_CODE_COUNT (KeyOptions
);
576 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
578 KeyShiftStateRight
= (KeyOptions
& EFI_KEY_OPTION_SHIFT
) |
579 ((KeyOptions
& EFI_KEY_OPTION_CONTROL
) << 1) |
580 ((KeyOptions
& EFI_KEY_OPTION_ALT
) << 2) |
581 ((KeyOptions
& EFI_KEY_OPTION_LOGO
) << 3) |
582 ((KeyOptions
& (EFI_KEY_OPTION_MENU
| EFI_KEY_OPTION_SYSREQ
)) << 4) |
583 EFI_SHIFT_STATE_VALID
;
585 KeyShiftStateLeft
= (KeyShiftStateRight
& 0xffffff00) | ((KeyShiftStateRight
& 0xff) << 1);
587 InputKey
= (EFI_INPUT_KEY
*) (((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
));
590 KeyData
= &HotkeyLeft
->KeyData
[0];
593 // If Key CodeCount is 0, then only KeyData[0] is used;
594 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
596 KeyData
->Key
.ScanCode
= InputKey
[Index
].ScanCode
;
597 KeyData
->Key
.UnicodeChar
= InputKey
[Index
].UnicodeChar
;
598 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateLeft
;
602 } while (Index
< HotkeyLeft
->CodeCount
);
603 InsertTailList (&mHotkeyList
, &HotkeyLeft
->Link
);
605 if (KeyShiftStateLeft
!= KeyShiftStateRight
) {
607 // Need an extra hotkey for shift key on right
609 HotkeyRight
= AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION
), HotkeyLeft
);
610 if (HotkeyRight
== NULL
) {
611 return EFI_OUT_OF_RESOURCES
;
615 KeyData
= &HotkeyRight
->KeyData
[0];
618 // Key.ScanCode and Key.UnicodeChar have already been initialized,
619 // only need to update KeyState.KeyShiftState
621 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateRight
;
625 } while (Index
< HotkeyRight
->CodeCount
);
626 InsertTailList (&mHotkeyList
, &HotkeyRight
->Link
);
634 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
636 @retval EFI_SUCCESS Hotkey services successfully initialized.
637 @retval EFI_NOT_FOUND Can not find the "KeyOrder" variable
640 InitializeHotkeyService (
645 UINT32 BootOptionSupport
;
649 UINT16 KeyOptionName
[8];
651 EFI_KEY_OPTION
*KeyOption
;
654 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
656 BootOptionSupport
= EFI_BOOT_OPTION_SUPPORT_KEY
| EFI_BOOT_OPTION_SUPPORT_APP
;
657 Status
= gRT
->SetVariable (
658 L
"BootOptionSupport",
659 &gEfiGlobalVariableGuid
,
660 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
666 // Get valid Key Option List from private EFI variable "KeyOrder"
668 KeyOrder
= BdsLibGetVariableAndSize (
670 &gEfiGlobalVariableGuid
,
674 if (KeyOrder
== NULL
) {
675 return EFI_NOT_FOUND
;
678 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
679 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
680 KeyOption
= BdsLibGetVariableAndSize (
682 &gEfiGlobalVariableGuid
,
686 if (KeyOption
== NULL
|| !IsKeyOptionValid (KeyOption
)) {
687 UnregisterHotkey (KeyOrder
[Index
]);
689 HotkeyInsertList (KeyOption
);
694 // Register Protocol notify for Hotkey service
696 Status
= gBS
->CreateEvent (
703 ASSERT_EFI_ERROR (Status
);
706 // Register for protocol notifications on this event
708 Status
= gBS
->RegisterProtocolNotify (
709 &gEfiSimpleTextInputExProtocolGuid
,
713 ASSERT_EFI_ERROR (Status
);