TianoCore EDK2 master
Loading...
Searching...
No Matches
BmHotkey.c
Go to the documentation of this file.
1
10#include "InternalBm.h"
11
12//
13// Lock for linked list
14//
15EFI_LOCK mBmHotkeyLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
16LIST_ENTRY mBmHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);
17EFI_EVENT mBmHotkeyTriggered = NULL;
18BOOLEAN mBmHotkeyServiceStarted = FALSE;
19UINTN mBmHotkeySupportCount = 0;
20
21//
22// Set OptionNumber as unassigned value to indicate the option isn't initialized
23//
24EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption = { LoadOptionNumberUnassigned };
25
26EFI_BOOT_MANAGER_KEY_OPTION *mBmContinueKeyOption = NULL;
27VOID *mBmTxtInExRegistration = NULL;
28
39 )
40{
42 + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
43}
44
55BOOLEAN
58 IN UINTN KeyOptionSize
59 )
60{
61 UINT16 OptionName[BM_OPTION_NAME_LEN];
62 UINT8 *BootOption;
63 UINTN BootOptionSize;
64 UINT32 Crc;
65
66 if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {
67 return FALSE;
68 }
69
70 //
71 // Check whether corresponding Boot Option exist
72 //
74 OptionName,
75 sizeof (OptionName),
76 L"%s%04x",
77 mBmLoadOptionName[LoadOptionTypeBoot],
78 KeyOption->BootOption
79 );
80 GetEfiGlobalVariable2 (OptionName, (VOID **)&BootOption, &BootOptionSize);
81
82 if (BootOption == NULL) {
83 return FALSE;
84 }
85
86 //
87 // Check CRC for Boot Option
88 //
89 gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);
90 FreePool (BootOption);
91
92 return (BOOLEAN)(KeyOption->BootOptionCrc == Crc);
93}
94
106BOOLEAN
108 CHAR16 *Name,
109 EFI_GUID *Guid,
110 UINT16 *OptionNumber
111 )
112{
113 UINTN Index;
114 UINTN Uint;
115
116 if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
117 (StrSize (Name) != sizeof (L"Key####")) ||
118 (StrnCmp (Name, L"Key", 3) != 0)
119 )
120 {
121 return FALSE;
122 }
123
124 *OptionNumber = 0;
125 for (Index = 3; Index < 7; Index++) {
126 Uint = BmCharToUint (Name[Index]);
127 if (Uint == -1) {
128 return FALSE;
129 } else {
130 *OptionNumber = (UINT16)Uint + *OptionNumber * 0x10;
131 }
132 }
133
134 return TRUE;
135}
136
137typedef struct {
138 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
139 UINTN KeyOptionCount;
141
149VOID
151 CHAR16 *Name,
152 EFI_GUID *Guid,
153 VOID *Context
154 )
155{
156 UINTN Index;
158 VOID *KeyOption;
159 UINT16 OptionNumber;
160 UINTN KeyOptionSize;
161
162 Param = (BM_COLLECT_KEY_OPTIONS_PARAM *)Context;
163
164 if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {
165 GetEfiGlobalVariable2 (Name, &KeyOption, &KeyOptionSize);
166 ASSERT (KeyOption != NULL);
167 if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {
168 Param->KeyOptions = ReallocatePool (
169 Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
170 (Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
171 Param->KeyOptions
172 );
173 ASSERT (Param->KeyOptions != NULL);
174 //
175 // Insert the key option in order
176 //
177 for (Index = 0; Index < Param->KeyOptionCount; Index++) {
178 if (OptionNumber < Param->KeyOptions[Index].OptionNumber) {
179 break;
180 }
181 }
182
183 CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
184 CopyMem (&Param->KeyOptions[Index], KeyOption, KeyOptionSize);
185 Param->KeyOptions[Index].OptionNumber = OptionNumber;
186 Param->KeyOptionCount++;
187 }
188
189 FreePool (KeyOption);
190 }
191}
192
203 OUT UINTN *Count
204 )
205{
207
208 if (Count == NULL) {
209 return NULL;
210 }
211
212 Param.KeyOptions = NULL;
213 Param.KeyOptionCount = 0;
214
215 BmForEachVariable (BmCollectKeyOptions, (VOID *)&Param);
216
217 *Count = Param.KeyOptionCount;
218
219 return Param.KeyOptions;
220}
221
231BOOLEAN
233 IN UINT32 Value,
234 IN UINT32 Bit
235 )
236{
237 return (BOOLEAN)((Value & Bit) != 0);
238}
239
252 IN UINT32 Modifier,
253 IN VA_LIST Args,
255 )
256{
257 EFI_INPUT_KEY *Key;
258
259 if (KeyOption == NULL) {
260 return EFI_INVALID_PARAMETER;
261 }
262
263 Key = NULL;
264 while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {
265 Key = VA_ARG (Args, EFI_INPUT_KEY *);
266 if (Key == NULL) {
267 break;
268 }
269
270 CopyMem (
271 &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],
272 Key,
273 sizeof (EFI_INPUT_KEY)
274 );
275 KeyOption->KeyData.Options.InputKeyCount++;
276 }
277
278 if (Key != NULL) {
279 //
280 // Too many keys
281 //
282 return EFI_INVALID_PARAMETER;
283 }
284
285 if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
286 | EFI_BOOT_MANAGER_CONTROL_PRESSED
287 | EFI_BOOT_MANAGER_ALT_PRESSED
288 | EFI_BOOT_MANAGER_LOGO_PRESSED
289 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
290 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
291 )) != 0)
292 {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {
297 KeyOption->KeyData.Options.ShiftPressed = 1;
298 }
299
300 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {
301 KeyOption->KeyData.Options.ControlPressed = 1;
302 }
303
304 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {
305 KeyOption->KeyData.Options.AltPressed = 1;
306 }
307
308 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {
309 KeyOption->KeyData.Options.LogoPressed = 1;
310 }
311
312 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {
313 KeyOption->KeyData.Options.MenuPressed = 1;
314 }
315
316 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {
317 KeyOption->KeyData.Options.SysReqPressed = 1;
318 }
319
320 return EFI_SUCCESS;
321}
322
326VOID
327EFIAPI
329 VOID
330 )
331{
332 if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
333 EfiBootManagerBoot (&mBmHotkeyBootOption);
334 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);
335 mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
336 }
337}
338
350EFIAPI
352 IN EFI_KEY_DATA *KeyData
353 )
354{
355 LIST_ENTRY *Link;
356 BM_HOTKEY *Hotkey;
357 CHAR16 OptionName[BM_OPTION_NAME_LEN];
358 EFI_STATUS Status;
359 EFI_KEY_DATA *HotkeyData;
360
361 if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
362 //
363 // Do not process sequential hotkey stroke until the current boot option returns
364 //
365 return EFI_SUCCESS;
366 }
367
368 DEBUG ((DEBUG_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));
369
370 EfiAcquireLock (&mBmHotkeyLock);
371 for ( Link = GetFirstNode (&mBmHotkeyList)
372 ; !IsNull (&mBmHotkeyList, Link)
373 ; Link = GetNextNode (&mBmHotkeyList, Link)
374 )
375 {
376 Hotkey = BM_HOTKEY_FROM_LINK (Link);
377
378 //
379 // Is this Key Stroke we are waiting for?
380 //
381 ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
382 HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
383 if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
384 (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
385 (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?
386 (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
387 )
388 )
389 {
390 //
391 // Receive an expecting key stroke, transit to next waiting state
392 //
393 Hotkey->WaitingKey++;
394
395 if (Hotkey->WaitingKey == Hotkey->CodeCount) {
396 //
397 // Reset to initial waiting state
398 //
399 Hotkey->WaitingKey = 0;
400 //
401 // Received the whole key stroke sequence
402 //
403 Status = gBS->SignalEvent (mBmHotkeyTriggered);
404 ASSERT_EFI_ERROR (Status);
405
406 if (!Hotkey->IsContinue) {
407 //
408 // Launch its BootOption
409 //
411 OptionName,
412 sizeof (OptionName),
413 L"%s%04x",
414 mBmLoadOptionName[LoadOptionTypeBoot],
415 Hotkey->BootOption
416 );
417 Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);
418 DEBUG ((DEBUG_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));
419 if (EFI_ERROR (Status)) {
420 mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
421 }
422 } else {
423 DEBUG ((DEBUG_INFO, "[Bds]Continue key pressed!\n"));
424 }
425 }
426 } else {
427 //
428 // Receive an unexpected key stroke, reset to initial waiting state
429 //
430 Hotkey->WaitingKey = 0;
431 }
432 }
433
434 EfiReleaseLock (&mBmHotkeyLock);
435
436 return EFI_SUCCESS;
437}
438
451 OUT UINTN *Count
452 )
453{
454 EFI_STATUS Status;
455 EFI_HANDLE *Handles;
456
457 Handles = NULL;
458 *Count = 0;
459
460 if (gST->ConsoleInHandle != NULL) {
461 Status = gBS->OpenProtocol (
463 &gEfiSimpleTextInputExProtocolGuid,
464 NULL,
466 NULL,
467 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
468 );
469 if (!EFI_ERROR (Status)) {
470 Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);
471 if (Handles != NULL) {
472 *Count = 1;
473 }
474 }
475 } else {
476 Status = gBS->LocateHandleBuffer (
478 &gEfiSimpleTextInputExProtocolGuid,
479 NULL,
480 Count,
481 &Handles
482 );
483 }
484
485 return Handles;
486}
487
498 IN BM_HOTKEY *Hotkey
499 )
500{
501 EFI_STATUS Status;
502 UINTN Index;
503 UINTN KeyIndex;
504 EFI_HANDLE *Handles;
505 UINTN HandleCount;
507 VOID *NotifyHandle;
508
509 Handles = BmGetActiveConsoleIn (&HandleCount);
510 for (Index = 0; Index < HandleCount; Index++) {
511 Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);
512 ASSERT_EFI_ERROR (Status);
513 for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
514 Status = TxtInEx->RegisterKeyNotify (
515 TxtInEx,
516 &Hotkey->KeyData[KeyIndex],
518 &NotifyHandle
519 );
520 if (!EFI_ERROR (Status)) {
521 Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);
522 DEBUG ((DEBUG_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));
523 }
524 }
525 }
526
527 if (Handles != NULL) {
528 FreePool (Handles);
529 }
530
531 return EFI_SUCCESS;
532}
533
546 IN BM_HOTKEY *Hotkey
547 )
548{
549 EFI_STATUS Status;
550 UINTN Index;
551 VOID *NotifyHandle;
552
553 for (Index = 0; Index < Hotkey->CodeCount; Index++) {
554 Status = TxtInEx->RegisterKeyNotify (
555 TxtInEx,
556 &Hotkey->KeyData[Index],
558 &NotifyHandle
559 );
560 DEBUG ((
561 DEBUG_INFO,
562 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
563 Hotkey->KeyData[Index].Key.ScanCode,
564 Hotkey->KeyData[Index].Key.UnicodeChar,
565 Hotkey->KeyData[Index].KeyState.KeyShiftState,
566 Hotkey->KeyData[Index].KeyState.KeyToggleState,
567 Status
568 ));
569 if (EFI_ERROR (Status)) {
570 //
571 // some of the hotkey registry failed
572 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
573 //
574 break;
575 }
576 }
577
578 return EFI_SUCCESS;
579}
580
590VOID
592 IN UINTN Depth,
594 IN UINT32 KeyShiftState,
595 IN UINT32 *KeyShiftStates,
596 IN UINTN *KeyShiftStateCount
597 )
598{
599 switch (Depth) {
600 case 0:
601 if (KeyOption->KeyData.Options.ShiftPressed) {
602 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
603 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
604 } else {
605 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
606 }
607
608 break;
609
610 case 1:
611 if (KeyOption->KeyData.Options.ControlPressed) {
612 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
613 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
614 } else {
615 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
616 }
617
618 break;
619
620 case 2:
621 if (KeyOption->KeyData.Options.AltPressed) {
622 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
623 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
624 } else {
625 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
626 }
627
628 break;
629 case 3:
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);
633 } else {
634 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
635 }
636
637 break;
638 case 4:
639 if (KeyOption->KeyData.Options.MenuPressed) {
640 KeyShiftState |= EFI_MENU_KEY_PRESSED;
641 }
642
643 if (KeyOption->KeyData.Options.SysReqPressed) {
644 KeyShiftState |= EFI_SYS_REQ_PRESSED;
645 }
646
647 KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;
648 (*KeyShiftStateCount)++;
649 break;
650 }
651}
652
662 )
663{
664 EFI_STATUS Status;
666 EFI_HANDLE *Handles;
667 UINTN HandleCount;
668 UINTN HandleIndex;
669 UINTN Index;
670 BM_HOTKEY *Hotkey;
671 UINTN KeyIndex;
672 //
673 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
674 //
675 UINT32 KeyShiftStates[16];
676 UINTN KeyShiftStateCount;
677
678 if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {
679 return EFI_UNSUPPORTED;
680 }
681
682 KeyShiftStateCount = 0;
683 BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);
684 ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));
685
686 EfiAcquireLock (&mBmHotkeyLock);
687
688 Handles = BmGetActiveConsoleIn (&HandleCount);
689
690 for (Index = 0; Index < KeyShiftStateCount; Index++) {
691 Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));
692 ASSERT (Hotkey != NULL);
693
694 Hotkey->Signature = BM_HOTKEY_SIGNATURE;
695 Hotkey->BootOption = KeyOption->BootOption;
696 Hotkey->IsContinue = (BOOLEAN)(KeyOption == mBmContinueKeyOption);
697 Hotkey->CodeCount = (UINT8)KeyOption->KeyData.Options.InputKeyCount;
698
699 for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
700 CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));
701 Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];
702 }
703
704 InsertTailList (&mBmHotkeyList, &Hotkey->Link);
705
706 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
707 Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);
708 ASSERT_EFI_ERROR (Status);
709 BmRegisterHotkeyNotify (TxtInEx, Hotkey);
710 }
711 }
712
713 if (Handles != NULL) {
714 FreePool (Handles);
715 }
716
717 EfiReleaseLock (&mBmHotkeyLock);
718
719 return EFI_SUCCESS;
720}
721
729VOID
730EFIAPI
732 IN EFI_EVENT Event,
733 IN VOID *Context
734 )
735{
736 EFI_STATUS Status;
737 UINTN BufferSize;
738 EFI_HANDLE Handle;
740 LIST_ENTRY *Link;
741
742 while (TRUE) {
743 BufferSize = sizeof (EFI_HANDLE);
744 Status = gBS->LocateHandle (
746 NULL,
747 mBmTxtInExRegistration,
748 &BufferSize,
749 &Handle
750 );
751 if (EFI_ERROR (Status)) {
752 //
753 // If no more notification events exist
754 //
755 return;
756 }
757
758 Status = gBS->HandleProtocol (
759 Handle,
760 &gEfiSimpleTextInputExProtocolGuid,
761 (VOID **)&TxtInEx
762 );
763 ASSERT_EFI_ERROR (Status);
764
765 //
766 // Register the hot key notification for the existing items in the list
767 //
768 EfiAcquireLock (&mBmHotkeyLock);
769 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {
770 BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));
771 }
772
773 EfiReleaseLock (&mBmHotkeyLock);
774 }
775}
776
789 IN UINTN KeyOptionCount
790 )
791{
792 if (KeyOptions != NULL) {
793 FreePool (KeyOptions);
794 return EFI_SUCCESS;
795 } else {
796 return EFI_NOT_FOUND;
797 }
798}
799
812EFIAPI
814 IN UINT32 Modifier,
815 ...
816 )
817{
818 EFI_STATUS Status;
820 VA_LIST Args;
821
822 if (mBmContinueKeyOption != NULL) {
823 return EFI_ALREADY_STARTED;
824 }
825
826 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
827 VA_START (Args, Modifier);
828 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
829 VA_END (Args);
830
831 if (!EFI_ERROR (Status)) {
832 mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);
833 ASSERT (mBmContinueKeyOption != NULL);
834 if (mBmHotkeyServiceStarted) {
835 BmProcessKeyOption (mBmContinueKeyOption);
836 }
837 }
838
839 return Status;
840}
841
848VOID
849EFIAPI
851 IN EFI_EVENT Event,
852 IN VOID *Context
853 )
854{
855 LIST_ENTRY *Link;
856 BM_HOTKEY *Hotkey;
857
858 DEBUG ((DEBUG_INFO, "[Bds]Stop Hotkey Service!\n"));
859 gBS->CloseEvent (Event);
860
861 EfiAcquireLock (&mBmHotkeyLock);
862 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
863 Hotkey = BM_HOTKEY_FROM_LINK (Link);
865 Link = RemoveEntryList (Link);
866 FreePool (Hotkey);
867 }
868
869 EfiReleaseLock (&mBmHotkeyLock);
870}
871
881EFIAPI
883 IN EFI_EVENT *HotkeyTriggered
884 )
885{
886 EFI_STATUS Status;
887 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
888 UINTN KeyOptionCount;
889 UINTN Index;
890 EFI_EVENT Event;
891 UINT32 *BootOptionSupport;
892
894 if (BootOptionSupport != NULL) {
895 if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY) != 0) {
896 mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));
897 }
898
899 FreePool (BootOptionSupport);
900 }
901
902 if (mBmHotkeySupportCount == 0) {
903 DEBUG ((DEBUG_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
904 return EFI_UNSUPPORTED;
905 }
906
907 Status = gBS->CreateEvent (
908 EVT_NOTIFY_WAIT,
909 TPL_CALLBACK,
911 NULL,
912 &mBmHotkeyTriggered
913 );
914 ASSERT_EFI_ERROR (Status);
915
916 if (HotkeyTriggered != NULL) {
917 *HotkeyTriggered = mBmHotkeyTriggered;
918 }
919
920 KeyOptions = BmGetKeyOptions (&KeyOptionCount);
921 for (Index = 0; Index < KeyOptionCount; Index++) {
922 BmProcessKeyOption (&KeyOptions[Index]);
923 }
924
925 BmFreeKeyOptions (KeyOptions, KeyOptionCount);
926
927 if (mBmContinueKeyOption != NULL) {
928 BmProcessKeyOption (mBmContinueKeyOption);
929 }
930
931 //
932 // Hook hotkey on every future SimpleTextInputEx instance when
933 // SystemTable.ConsoleInHandle == NULL, which means the console
934 // manager (ConSplitter) is absent.
935 //
936 if (gST->ConsoleInHandle == NULL) {
938 &gEfiSimpleTextInputExProtocolGuid,
939 TPL_CALLBACK,
941 NULL,
942 &mBmTxtInExRegistration
943 );
944 }
945
947 TPL_CALLBACK,
949 NULL,
950 &Event
951 );
952 ASSERT_EFI_ERROR (Status);
953
954 mBmHotkeyServiceStarted = TRUE;
955 return Status;
956}
957
971EFIAPI
973 OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption OPTIONAL,
974 IN UINT16 BootOptionNumber,
975 IN UINT32 Modifier,
976 ...
977 )
978{
979 EFI_STATUS Status;
980 VA_LIST Args;
981 VOID *BootOption;
982 UINTN BootOptionSize;
983 CHAR16 BootOptionName[BM_OPTION_NAME_LEN];
985 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
986 UINTN KeyOptionCount;
987 UINTN Index;
988 UINTN KeyOptionNumber;
989 CHAR16 KeyOptionName[sizeof ("Key####")];
990
992 BootOptionName,
993 sizeof (BootOptionName),
994 L"%s%04x",
995 mBmLoadOptionName[LoadOptionTypeBoot],
996 BootOptionNumber
997 );
998 GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);
999
1000 if (BootOption == NULL) {
1001 return EFI_NOT_FOUND;
1002 }
1003
1004 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
1005 KeyOption.BootOption = BootOptionNumber;
1006 Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);
1007 ASSERT_EFI_ERROR (Status);
1008 FreePool (BootOption);
1009
1010 VA_START (Args, Modifier);
1011 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
1012 VA_END (Args);
1013 if (EFI_ERROR (Status)) {
1014 return Status;
1015 }
1016
1017 KeyOptionNumber = LoadOptionNumberUnassigned;
1018 //
1019 // Check if the hot key sequence was defined already
1020 //
1021 KeyOptions = BmGetKeyOptions (&KeyOptionCount);
1022 for (Index = 0; Index < KeyOptionCount; Index++) {
1023 if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
1024 (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0))
1025 {
1026 break;
1027 }
1028
1029 if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&
1030 (KeyOptions[Index].OptionNumber > Index)
1031 )
1032 {
1033 KeyOptionNumber = Index;
1034 }
1035 }
1036
1037 BmFreeKeyOptions (KeyOptions, KeyOptionCount);
1038
1039 if (Index < KeyOptionCount) {
1040 return EFI_ALREADY_STARTED;
1041 }
1042
1043 if (KeyOptionNumber == LoadOptionNumberUnassigned) {
1044 KeyOptionNumber = KeyOptionCount;
1045 }
1046
1047 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);
1048
1049 Status = gRT->SetVariable (
1050 KeyOptionName,
1051 &gEfiGlobalVariableGuid,
1052 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1053 BmSizeOfKeyOption (&KeyOption),
1054 &KeyOption
1055 );
1056 if (!EFI_ERROR (Status)) {
1057 //
1058 // Return the Key Option in case needed by caller
1059 //
1060 if (AddedOption != NULL) {
1061 CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
1062 }
1063
1064 //
1065 // Register the newly added hot key
1066 // Calling this function before EfiBootManagerStartHotkeyService doesn't
1067 // need to call BmProcessKeyOption
1068 //
1069 if (mBmHotkeyServiceStarted) {
1070 BmProcessKeyOption (&KeyOption);
1071 }
1072 }
1073
1074 return Status;
1075}
1076
1088EFIAPI
1090 IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption OPTIONAL,
1091 IN UINT32 Modifier,
1092 ...
1093 )
1094{
1095 EFI_STATUS Status;
1096 UINTN Index;
1097 VA_LIST Args;
1099 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
1100 UINTN KeyOptionCount;
1101 LIST_ENTRY *Link;
1102 BM_HOTKEY *Hotkey;
1103 UINT32 ShiftState;
1104 BOOLEAN Match;
1105 CHAR16 KeyOptionName[sizeof ("Key####")];
1106
1107 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
1108 VA_START (Args, Modifier);
1109 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
1110 VA_END (Args);
1111
1112 if (EFI_ERROR (Status)) {
1113 return Status;
1114 }
1115
1116 EfiAcquireLock (&mBmHotkeyLock);
1117 //
1118 // Delete the key option from active hot key list
1119 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
1120 //
1121 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
1122 Hotkey = BM_HOTKEY_FROM_LINK (Link);
1123 Match = (BOOLEAN)(Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);
1124
1125 for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {
1126 ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;
1127 if (
1128 (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||
1129 (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||
1130 (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||
1131 (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||
1132 (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||
1133 (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||
1134 (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)
1135 )
1136 {
1137 //
1138 // Break when any field doesn't match
1139 //
1140 Match = FALSE;
1141 break;
1142 }
1143 }
1144
1145 if (Match) {
1146 Link = RemoveEntryList (Link);
1147 FreePool (Hotkey);
1148 } else {
1149 Link = GetNextNode (&mBmHotkeyList, Link);
1150 }
1151 }
1152
1153 //
1154 // Delete the key option from the variable
1155 //
1156 Status = EFI_NOT_FOUND;
1157 KeyOptions = BmGetKeyOptions (&KeyOptionCount);
1158 for (Index = 0; Index < KeyOptionCount; Index++) {
1159 if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
1160 (CompareMem (
1161 KeyOptions[Index].Keys,
1162 KeyOption.Keys,
1163 KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)
1164 ) == 0)
1165 )
1166 {
1167 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);
1168 Status = gRT->SetVariable (
1169 KeyOptionName,
1170 &gEfiGlobalVariableGuid,
1171 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1172 0,
1173 NULL
1174 );
1175 //
1176 // Return the deleted key option in case needed by caller
1177 //
1178 if (DeletedOption != NULL) {
1179 CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
1180 }
1181
1182 break;
1183 }
1184 }
1185
1186 BmFreeKeyOptions (KeyOptions, KeyOptionCount);
1187
1188 EfiReleaseLock (&mBmHotkeyLock);
1189
1190 return Status;
1191}
UINT64 UINTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
UINTN EFIAPI StrSize(IN CONST CHAR16 *String)
Definition: String.c:72
INTN EFIAPI LowBitSet32(IN UINT32 Operand)
Definition: LowBitSet32.c:26
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
INTN EFIAPI StrnCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString, IN UINTN Length)
Definition: String.c:162
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS BmInitializeKeyFields(IN UINT32 Modifier, IN VA_LIST Args, OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption)
Definition: BmHotkey.c:251
BOOLEAN BmIsKeyOptionVariable(CHAR16 *Name, EFI_GUID *Guid, UINT16 *OptionNumber)
Definition: BmHotkey.c:107
BOOLEAN BmBitSet(IN UINT32 Value, IN UINT32 Bit)
Definition: BmHotkey.c:232
BOOLEAN BmIsKeyOptionValid(IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption, IN UINTN KeyOptionSize)
Definition: BmHotkey.c:56
EFI_STATUS EFIAPI EfiBootManagerStartHotkeyService(IN EFI_EVENT *HotkeyTriggered)
Definition: BmHotkey.c:882
VOID BmGenerateKeyShiftState(IN UINTN Depth, IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption, IN UINT32 KeyShiftState, IN UINT32 *KeyShiftStates, IN UINTN *KeyShiftStateCount)
Definition: BmHotkey.c:591
EFI_STATUS BmFreeKeyOptions(IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions, IN UINTN KeyOptionCount)
Definition: BmHotkey.c:787
EFI_STATUS EFIAPI BmHotkeyCallback(IN EFI_KEY_DATA *KeyData)
Definition: BmHotkey.c:351
VOID EFIAPI EfiBootManagerHotkeyBoot(VOID)
Definition: BmHotkey.c:328
VOID EFIAPI BmTxtInExCallback(IN EFI_EVENT Event, IN VOID *Context)
Definition: BmHotkey.c:731
UINTN BmSizeOfKeyOption(IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption)
Definition: BmHotkey.c:37
EFI_STATUS EFIAPI EfiBootManagerRegisterContinueKeyOption(IN UINT32 Modifier,...)
Definition: BmHotkey.c:813
EFI_HANDLE * BmGetActiveConsoleIn(OUT UINTN *Count)
Definition: BmHotkey.c:450
EFI_BOOT_MANAGER_KEY_OPTION * BmGetKeyOptions(OUT UINTN *Count)
Definition: BmHotkey.c:202
VOID BmCollectKeyOptions(CHAR16 *Name, EFI_GUID *Guid, VOID *Context)
Definition: BmHotkey.c:150
EFI_STATUS EFIAPI EfiBootManagerDeleteKeyOptionVariable(IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption OPTIONAL, IN UINT32 Modifier,...)
Definition: BmHotkey.c:1089
EFI_STATUS BmRegisterHotkeyNotify(IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx, IN BM_HOTKEY *Hotkey)
Definition: BmHotkey.c:544
EFI_STATUS BmProcessKeyOption(IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption)
Definition: BmHotkey.c:660
VOID EFIAPI BmStopHotkeyService(IN EFI_EVENT Event, IN VOID *Context)
Definition: BmHotkey.c:850
EFI_STATUS BmUnregisterHotkeyNotify(IN BM_HOTKEY *Hotkey)
Definition: BmHotkey.c:497
EFI_STATUS EFIAPI EfiBootManagerAddKeyOptionVariable(OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption OPTIONAL, IN UINT16 BootOptionNumber, IN UINT32 Modifier,...)
Definition: BmHotkey.c:972
VOID BmForEachVariable(BM_VARIABLE_VISITOR Visitor, VOID *Context)
Definition: BmLoadOption.c:37
UINTN BmCharToUint(IN CHAR16 Char)
Definition: BmMisc.c:404
VOID *EFIAPI ReallocatePool(IN UINTN OldSize, IN UINTN NewSize, IN VOID *OldBuffer OPTIONAL)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI AllocateCopyPool(IN UINTN AllocationSize, IN CONST VOID *Buffer)
#define EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
UINTN EFIAPI UnicodeSPrint(OUT CHAR16 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR16 *FormatString,...)
Definition: PrintLib.c:408
EFI_RUNTIME_SERVICES * gRT
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define VA_ARG(Marker, TYPE)
Definition: Base.h:679
#define VA_START(Marker, Parameter)
Definition: Base.h:661
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
CHAR8 * VA_LIST
Definition: Base.h:643
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define VA_END(Marker)
Definition: Base.h:691
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
STATIC BOOLEAN Match(IN CONST CHAR16 *Translated, IN UINTN TranslatedLength, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
VOID EFIAPI EfiBootManagerBoot(IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption)
Definition: BmBoot.c:1846
EFI_STATUS EFIAPI EfiBootManagerFreeLoadOption(IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption)
EFI_STATUS EFIAPI EfiBootManagerVariableToLoadOption(IN CHAR16 *VariableName, IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption)
Definition: BmLoadOption.c:998
EFI_SYSTEM_TABLE * gST
EFI_HANDLE gImageHandle
EFI_BOOT_SERVICES * gBS
#define EFI_INITIALIZE_LOCK_VARIABLE(Priority)
Definition: UefiLib.h:313
VOID EFIAPI EfiReleaseLock(IN EFI_LOCK *Lock)
Definition: UefiLib.c:499
EFI_STATUS EFIAPI GetEfiGlobalVariable2(IN CONST CHAR16 *Name, OUT VOID **Value, OUT UINTN *Size OPTIONAL)
Definition: UefiLib.c:1470
VOID EFIAPI EfiEventEmptyFunction(IN EFI_EVENT Event, IN VOID *Context)
Definition: UefiLib.c:354
VOID EFIAPI EfiAcquireLock(IN EFI_LOCK *Lock)
Definition: UefiLib.c:434
EFI_STATUS EFIAPI EfiCreateEventReadyToBootEx(IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, IN VOID *NotifyContext OPTIONAL, OUT EFI_EVENT *ReadyToBootEvent)
Definition: UefiNotTiano.c:164
EFI_EVENT EFIAPI EfiCreateProtocolNotifyEvent(IN EFI_GUID *ProtocolGuid, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext OPTIONAL, OUT VOID **Registration)
Definition: UefiLib.c:134
#define EFI_VARIABLE_NON_VOLATILE
@ ByProtocol
Definition: UefiSpec.h:1518
@ ByRegisterNotify
Definition: UefiSpec.h:1513
UINT32 KeyShiftState
EFI_INPUT_KEY Key
EFI_KEY_STATE KeyState
EFI_HANDLE ConsoleInHandle
Definition: UefiSpec.h:2048
Definition: Base.h:213
UINT32 ControlPressed
Definition: UefiSpec.h:2194
UINT32 SysReqPressed
Definition: UefiSpec.h:2210
UINT32 MenuPressed
Definition: UefiSpec.h:2206
UINT32 LogoPressed
Definition: UefiSpec.h:2202
UINT32 InputKeyCount
Definition: UefiSpec.h:2217
UINT32 ShiftPressed
Definition: UefiSpec.h:2190