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 - 2014, Intel Corporation. All rights reserved.<BR>
6 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 BDS_COMMON_OPTION
*mHotkeyBootOption
= NULL
;
21 EFI_EVENT mHotkeyEvent
;
22 VOID
*mHotkeyRegistration
;
26 Check if the Key Option is valid or not.
28 @param KeyOption The Hot Key Option to be checked.
30 @retval TRUE The Hot Key Option is valid.
31 @retval FALSE The Hot Key Option is invalid.
36 IN EFI_KEY_OPTION
*KeyOption
39 UINT16 BootOptionName
[10];
45 // Check whether corresponding Boot Option exist
47 UnicodeSPrint (BootOptionName
, sizeof (BootOptionName
), L
"Boot%04x", KeyOption
->BootOption
);
48 BootOptionVar
= BdsLibGetVariableAndSize (
50 &gEfiGlobalVariableGuid
,
54 if (BootOptionVar
== NULL
|| BootOptionSize
== 0) {
59 // Check CRC for Boot Option
61 gBS
->CalculateCrc32 (BootOptionVar
, BootOptionSize
, &Crc
);
62 FreePool (BootOptionVar
);
64 return (BOOLEAN
) ((KeyOption
->BootOptionCrc
== Crc
) ? TRUE
: FALSE
);
68 Try to boot the boot option triggered by hotkey.
69 @retval EFI_SUCCESS There is HotkeyBootOption & it is processed
70 @retval EFI_NOT_FOUND There is no HotkeyBootOption
81 if (mHotkeyBootOption
== NULL
) {
85 BdsLibConnectDevicePath (mHotkeyBootOption
->DevicePath
);
88 // Clear the screen before launch this BootOption
90 gST
->ConOut
->Reset (gST
->ConOut
, FALSE
);
92 Status
= BdsLibBootViaBootOption (mHotkeyBootOption
, mHotkeyBootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
94 if (EFI_ERROR (Status
)) {
96 // Call platform action to indicate the boot fail
98 mHotkeyBootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
99 PlatformBdsBootFail (mHotkeyBootOption
, Status
, ExitData
, ExitDataSize
);
102 // Call platform action to indicate the boot success
104 mHotkeyBootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
105 PlatformBdsBootSuccess (mHotkeyBootOption
);
107 FreePool (mHotkeyBootOption
->Description
);
108 FreePool (mHotkeyBootOption
->DevicePath
);
109 FreePool (mHotkeyBootOption
->LoadOptions
);
110 FreePool (mHotkeyBootOption
);
112 mHotkeyBootOption
= NULL
;
119 This is the common notification function for HotKeys, it will be registered
120 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
122 @param KeyData A pointer to a buffer that is filled in with the keystroke
123 information for the key that was pressed.
125 @retval EFI_SUCCESS KeyData is successfully processed.
126 @return EFI_NOT_FOUND Fail to find boot option variable.
131 IN EFI_KEY_DATA
*KeyData
134 BOOLEAN HotkeyCatched
;
135 LIST_ENTRY BootLists
;
137 BDS_HOTKEY_OPTION
*Hotkey
;
140 EFI_KEY_DATA
*HotkeyData
;
142 if (mHotkeyBootOption
!= NULL
) {
144 // Do not process sequential hotkey stroke until the current boot option returns
149 Status
= EFI_SUCCESS
;
151 for ( Link
= GetFirstNode (&mHotkeyList
)
152 ; !IsNull (&mHotkeyList
, Link
)
153 ; Link
= GetNextNode (&mHotkeyList
, Link
)
155 HotkeyCatched
= FALSE
;
156 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
159 // Is this Key Stroke we are waiting for?
161 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
162 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
163 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
164 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
165 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
166 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
170 // For hotkey of key combination, transit to next waiting state
172 Hotkey
->WaitingKey
++;
174 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
176 // Received the whole key stroke sequence
178 HotkeyCatched
= TRUE
;
182 // Receive an unexpected key stroke, reset to initial waiting state
184 Hotkey
->WaitingKey
= 0;
189 // Reset to initial waiting state
191 Hotkey
->WaitingKey
= 0;
194 // Launch its BootOption
196 InitializeListHead (&BootLists
);
198 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", Hotkey
->BootOptionNumber
);
199 mHotkeyBootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
207 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
209 @param SimpleTextInEx Simple Text Input Ex protocol instance
211 @retval EFI_SUCCESS Register hotkey notification function successfully.
212 @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
216 HotkeyRegisterNotify (
217 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
223 BDS_HOTKEY_OPTION
*Hotkey
;
226 // Register notification function for each hotkey
228 Link
= GetFirstNode (&mHotkeyList
);
230 while (!IsNull (&mHotkeyList
, Link
)) {
231 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
235 Status
= SimpleTextInEx
->RegisterKeyNotify (
237 &Hotkey
->KeyData
[Index
],
239 &Hotkey
->NotifyHandle
241 if (EFI_ERROR (Status
)) {
243 // some of the hotkey registry failed
248 } while ((Index
< Hotkey
->CodeCount
) && (Index
< (sizeof (Hotkey
->KeyData
) / sizeof (EFI_KEY_DATA
))));
250 Link
= GetNextNode (&mHotkeyList
, Link
);
257 Callback function for SimpleTextInEx protocol install events
259 @param Event the event that is signaled.
260 @param Context not used here.
273 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
;
276 BufferSize
= sizeof (EFI_HANDLE
);
277 Status
= gBS
->LocateHandle (
284 if (EFI_ERROR (Status
)) {
286 // If no more notification events exist
291 Status
= gBS
->HandleProtocol (
293 &gEfiSimpleTextInputExProtocolGuid
,
294 (VOID
**) &SimpleTextInEx
296 ASSERT_EFI_ERROR (Status
);
298 HotkeyRegisterNotify (SimpleTextInEx
);
303 Insert Key Option to hotkey list.
305 @param KeyOption The Hot Key Option to be added to hotkey list.
307 @retval EFI_SUCCESS Add to hotkey list success.
308 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource.
312 IN EFI_KEY_OPTION
*KeyOption
315 BDS_HOTKEY_OPTION
*HotkeyLeft
;
316 BDS_HOTKEY_OPTION
*HotkeyRight
;
318 EFI_BOOT_KEY_DATA KeyOptions
;
319 UINT32 KeyShiftStateLeft
;
320 UINT32 KeyShiftStateRight
;
321 EFI_INPUT_KEY
*InputKey
;
322 EFI_KEY_DATA
*KeyData
;
324 HotkeyLeft
= AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION
));
325 if (HotkeyLeft
== NULL
) {
326 return EFI_OUT_OF_RESOURCES
;
329 HotkeyLeft
->Signature
= BDS_HOTKEY_OPTION_SIGNATURE
;
330 HotkeyLeft
->BootOptionNumber
= KeyOption
->BootOption
;
332 KeyOptions
= KeyOption
->KeyData
;
334 HotkeyLeft
->CodeCount
= (UINT8
) KeyOptions
.Options
.InputKeyCount
;
337 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
339 KeyShiftStateRight
= EFI_SHIFT_STATE_VALID
;
340 if (KeyOptions
.Options
.ShiftPressed
) {
341 KeyShiftStateRight
|= EFI_RIGHT_SHIFT_PRESSED
;
343 if (KeyOptions
.Options
.ControlPressed
) {
344 KeyShiftStateRight
|= EFI_RIGHT_CONTROL_PRESSED
;
346 if (KeyOptions
.Options
.AltPressed
) {
347 KeyShiftStateRight
|= EFI_RIGHT_ALT_PRESSED
;
349 if (KeyOptions
.Options
.LogoPressed
) {
350 KeyShiftStateRight
|= EFI_RIGHT_LOGO_PRESSED
;
352 if (KeyOptions
.Options
.MenuPressed
) {
353 KeyShiftStateRight
|= EFI_MENU_KEY_PRESSED
;
355 if (KeyOptions
.Options
.SysReqPressed
) {
356 KeyShiftStateRight
|= EFI_SYS_REQ_PRESSED
;
359 KeyShiftStateLeft
= (KeyShiftStateRight
& 0xffffff00) | ((KeyShiftStateRight
& 0xff) << 1);
361 InputKey
= (EFI_INPUT_KEY
*) (((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
));
364 KeyData
= &HotkeyLeft
->KeyData
[0];
367 // If Key CodeCount is 0, then only KeyData[0] is used;
368 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
370 KeyData
->Key
.ScanCode
= InputKey
[Index
].ScanCode
;
371 KeyData
->Key
.UnicodeChar
= InputKey
[Index
].UnicodeChar
;
372 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateLeft
;
376 } while (Index
< HotkeyLeft
->CodeCount
);
377 InsertTailList (&mHotkeyList
, &HotkeyLeft
->Link
);
379 if (KeyShiftStateLeft
!= KeyShiftStateRight
) {
381 // Need an extra hotkey for shift key on right
383 HotkeyRight
= AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION
), HotkeyLeft
);
384 if (HotkeyRight
== NULL
) {
385 return EFI_OUT_OF_RESOURCES
;
389 KeyData
= &HotkeyRight
->KeyData
[0];
392 // Key.ScanCode and Key.UnicodeChar have already been initialized,
393 // only need to update KeyState.KeyShiftState
395 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateRight
;
399 } while (Index
< HotkeyRight
->CodeCount
);
400 InsertTailList (&mHotkeyList
, &HotkeyRight
->Link
);
407 Return TRUE when the variable pointed by Name and Guid is a Key#### variable.
409 @param Name The name of the variable.
410 @param Guid The GUID of the variable.
411 @param OptionNumber Return the option number parsed from the Name.
413 @retval TRUE The variable pointed by Name and Guid is a Key#### variable.
414 @retval FALSE The variable pointed by Name and Guid isn't a Key#### variable.
417 IsKeyOptionVariable (
425 if (!CompareGuid (Guid
, &gEfiGlobalVariableGuid
) ||
426 (StrSize (Name
) != sizeof (L
"Key####")) ||
427 (StrnCmp (Name
, L
"Key", 3) != 0)
433 for (Index
= 3; Index
< 7; Index
++) {
434 if ((Name
[Index
] >= L
'0') && (Name
[Index
] <= L
'9')) {
435 *OptionNumber
= *OptionNumber
* 10 + Name
[Index
] - L
'0';
436 } else if ((Name
[Index
] >= L
'A') && (Name
[Index
] <= L
'F')) {
437 *OptionNumber
= *OptionNumber
* 10 + Name
[Index
] - L
'A';
447 Return an array of key option numbers.
449 @param Count Return the count of key option numbers.
451 @return UINT16* Pointer to an array of key option numbers;
455 HotkeyGetOptionNumbers (
465 UINT16
*OptionNumbers
;
473 OptionNumbers
= NULL
;
475 NameSize
= sizeof (CHAR16
);
476 Name
= AllocateZeroPool (NameSize
);
477 ASSERT (Name
!= NULL
);
479 NewNameSize
= NameSize
;
480 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
481 if (Status
== EFI_BUFFER_TOO_SMALL
) {
482 Name
= ReallocatePool (NameSize
, NewNameSize
, Name
);
483 ASSERT (Name
!= NULL
);
484 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
485 NameSize
= NewNameSize
;
488 if (Status
== EFI_NOT_FOUND
) {
491 ASSERT_EFI_ERROR (Status
);
493 if (IsKeyOptionVariable (Name
,&Guid
, &OptionNumber
)) {
494 OptionNumbers
= ReallocatePool (
495 *Count
* sizeof (UINT16
),
496 (*Count
+ 1) * sizeof (UINT16
),
499 ASSERT (OptionNumbers
!= NULL
);
500 for (Index
= 0; Index
< *Count
; Index
++) {
501 if (OptionNumber
< OptionNumbers
[Index
]) {
505 CopyMem (&OptionNumbers
[Index
+ 1], &OptionNumbers
[Index
], (*Count
- Index
) * sizeof (UINT16
));
506 OptionNumbers
[Index
] = OptionNumber
;
513 return OptionNumbers
;
518 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
520 @retval EFI_SUCCESS Hotkey services successfully initialized.
523 InitializeHotkeyService (
528 UINT32 BootOptionSupport
;
529 UINT16
*KeyOptionNumbers
;
530 UINTN KeyOptionCount
;
532 CHAR16 KeyOptionName
[8];
533 EFI_KEY_OPTION
*KeyOption
;
536 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP.
537 // with maximum number of key presses of 3
538 // Do not report the hotkey capability if PcdConInConnectOnDemand is enabled.
540 BootOptionSupport
= EFI_BOOT_OPTION_SUPPORT_APP
;
541 if (!PcdGetBool (PcdConInConnectOnDemand
)) {
542 BootOptionSupport
|= EFI_BOOT_OPTION_SUPPORT_KEY
;
543 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport
, 3);
546 Status
= gRT
->SetVariable (
547 L
"BootOptionSupport",
548 &gEfiGlobalVariableGuid
,
549 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
554 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
556 ASSERT_EFI_ERROR (Status
);
558 KeyOptionNumbers
= HotkeyGetOptionNumbers (&KeyOptionCount
);
559 for (Index
= 0; Index
< KeyOptionCount
; Index
++) {
560 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOptionNumbers
[Index
]);
561 GetEfiGlobalVariable2 (KeyOptionName
, (VOID
**) &KeyOption
, NULL
);
562 ASSERT (KeyOption
!= NULL
);
563 if (IsKeyOptionValid (KeyOption
)) {
564 HotkeyInsertList (KeyOption
);
566 FreePool (KeyOption
);
569 if (KeyOptionNumbers
!= NULL
) {
570 FreePool (KeyOptionNumbers
);
574 // Register Protocol notify for Hotkey service
576 Status
= gBS
->CreateEvent (
583 ASSERT_EFI_ERROR (Status
);
586 // Register for protocol notifications on this event
588 Status
= gBS
->RegisterProtocolNotify (
589 &gEfiSimpleTextInputExProtocolGuid
,
593 ASSERT_EFI_ERROR (Status
);