]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmHotkey.c
CommitLineData
067ed98a
RN
1/** @file\r
2 Hotkey library functions.\r
3\r
d1102dba 4Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
065e587c 5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
067ed98a
RN
7\r
8**/\r
9\r
10#include "InternalBm.h"\r
11\r
12//\r
13// Lock for linked list\r
14//\r
1436aea4
MK
15EFI_LOCK mBmHotkeyLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
16LIST_ENTRY mBmHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);\r
17EFI_EVENT mBmHotkeyTriggered = NULL;\r
18BOOLEAN mBmHotkeyServiceStarted = FALSE;\r
19UINTN mBmHotkeySupportCount = 0;\r
067ed98a
RN
20\r
21//\r
22// Set OptionNumber as unassigned value to indicate the option isn't initialized\r
23//\r
1436aea4 24EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption = { LoadOptionNumberUnassigned };\r
067ed98a 25\r
1436aea4
MK
26EFI_BOOT_MANAGER_KEY_OPTION *mBmContinueKeyOption = NULL;\r
27VOID *mBmTxtInExRegistration = NULL;\r
121300c4
RN
28\r
29/**\r
30 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.\r
31\r
32 @param KeyOption The input key option info.\r
33\r
34 @retval The buffer size of the key option data.\r
35**/\r
36UINTN\r
37BmSizeOfKeyOption (\r
7320b8ed 38 IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
121300c4
RN
39 )\r
40{\r
41 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)\r
1436aea4 42 + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);\r
121300c4
RN
43}\r
44\r
067ed98a
RN
45/**\r
46\r
47 Check whether the input key option is valid.\r
48\r
121300c4
RN
49 @param KeyOption Key option.\r
50 @param KeyOptionSize Size of the key option.\r
067ed98a
RN
51\r
52 @retval TRUE Input key option is valid.\r
53 @retval FALSE Input key option is not valid.\r
54**/\r
55BOOLEAN\r
56BmIsKeyOptionValid (\r
1436aea4
MK
57 IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,\r
58 IN UINTN KeyOptionSize\r
59 )\r
067ed98a 60{\r
1436aea4
MK
61 UINT16 OptionName[BM_OPTION_NAME_LEN];\r
62 UINT8 *BootOption;\r
63 UINTN BootOptionSize;\r
64 UINT32 Crc;\r
067ed98a 65\r
121300c4
RN
66 if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {\r
67 return FALSE;\r
68 }\r
69\r
067ed98a
RN
70 //\r
71 // Check whether corresponding Boot Option exist\r
72 //\r
121300c4 73 UnicodeSPrint (\r
1436aea4
MK
74 OptionName,\r
75 sizeof (OptionName),\r
76 L"%s%04x",\r
77 mBmLoadOptionName[LoadOptionTypeBoot],\r
78 KeyOption->BootOption\r
121300c4 79 );\r
1436aea4 80 GetEfiGlobalVariable2 (OptionName, (VOID **)&BootOption, &BootOptionSize);\r
067ed98a
RN
81\r
82 if (BootOption == NULL) {\r
83 return FALSE;\r
84 }\r
85\r
86 //\r
87 // Check CRC for Boot Option\r
88 //\r
89 gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);\r
90 FreePool (BootOption);\r
91\r
1436aea4 92 return (BOOLEAN)(KeyOption->BootOptionCrc == Crc);\r
067ed98a
RN
93}\r
94\r
95/**\r
96\r
97 Check whether the input variable is an key option variable.\r
98\r
99 @param Name Input variable name.\r
100 @param Guid Input variable guid.\r
101 @param OptionNumber The option number of this key option variable.\r
102\r
103 @retval TRUE Input variable is a key option variable.\r
104 @retval FALSE Input variable is not a key option variable.\r
105**/\r
106BOOLEAN\r
107BmIsKeyOptionVariable (\r
1436aea4
MK
108 CHAR16 *Name,\r
109 EFI_GUID *Guid,\r
110 UINT16 *OptionNumber\r
067ed98a
RN
111 )\r
112{\r
1436aea4
MK
113 UINTN Index;\r
114 UINTN Uint;\r
d1102dba 115\r
067ed98a
RN
116 if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||\r
117 (StrSize (Name) != sizeof (L"Key####")) ||\r
118 (StrnCmp (Name, L"Key", 3) != 0)\r
1436aea4
MK
119 )\r
120 {\r
067ed98a
RN
121 return FALSE;\r
122 }\r
123\r
124 *OptionNumber = 0;\r
125 for (Index = 3; Index < 7; Index++) {\r
418e8cd9
RN
126 Uint = BmCharToUint (Name[Index]);\r
127 if (Uint == -1) {\r
067ed98a 128 return FALSE;\r
418e8cd9 129 } else {\r
1436aea4 130 *OptionNumber = (UINT16)Uint + *OptionNumber * 0x10;\r
067ed98a
RN
131 }\r
132 }\r
133\r
134 return TRUE;\r
135}\r
136\r
121300c4 137typedef struct {\r
1436aea4
MK
138 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
139 UINTN KeyOptionCount;\r
121300c4 140} BM_COLLECT_KEY_OPTIONS_PARAM;\r
067ed98a 141\r
121300c4
RN
142/**\r
143 Visitor function to collect the key options from NV storage.\r
067ed98a 144\r
121300c4
RN
145 @param Name Variable name.\r
146 @param Guid Variable GUID.\r
147 @param Context The same context passed to BmForEachVariable.\r
067ed98a 148**/\r
121300c4
RN
149VOID\r
150BmCollectKeyOptions (\r
1436aea4
MK
151 CHAR16 *Name,\r
152 EFI_GUID *Guid,\r
153 VOID *Context\r
067ed98a
RN
154 )\r
155{\r
1436aea4
MK
156 UINTN Index;\r
157 BM_COLLECT_KEY_OPTIONS_PARAM *Param;\r
158 VOID *KeyOption;\r
159 UINT16 OptionNumber;\r
160 UINTN KeyOptionSize;\r
121300c4 161\r
1436aea4 162 Param = (BM_COLLECT_KEY_OPTIONS_PARAM *)Context;\r
121300c4
RN
163\r
164 if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {\r
7320b8ed 165 GetEfiGlobalVariable2 (Name, &KeyOption, &KeyOptionSize);\r
121300c4 166 ASSERT (KeyOption != NULL);\r
121300c4
RN
167 if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {\r
168 Param->KeyOptions = ReallocatePool (\r
169 Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
170 (Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
171 Param->KeyOptions\r
172 );\r
173 ASSERT (Param->KeyOptions != NULL);\r
174 //\r
175 // Insert the key option in order\r
176 //\r
177 for (Index = 0; Index < Param->KeyOptionCount; Index++) {\r
7320b8ed 178 if (OptionNumber < Param->KeyOptions[Index].OptionNumber) {\r
121300c4
RN
179 break;\r
180 }\r
181 }\r
1436aea4 182\r
121300c4 183 CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
7320b8ed
RN
184 CopyMem (&Param->KeyOptions[Index], KeyOption, KeyOptionSize);\r
185 Param->KeyOptions[Index].OptionNumber = OptionNumber;\r
121300c4
RN
186 Param->KeyOptionCount++;\r
187 }\r
1436aea4 188\r
121300c4
RN
189 FreePool (KeyOption);\r
190 }\r
067ed98a
RN
191}\r
192\r
193/**\r
194 Return the array of key options.\r
195\r
196 @param Count Return the number of key options.\r
197\r
198 @retval NULL No key option.\r
199 @retval Other Pointer to the key options.\r
200**/\r
201EFI_BOOT_MANAGER_KEY_OPTION *\r
202BmGetKeyOptions (\r
1436aea4 203 OUT UINTN *Count\r
067ed98a
RN
204 )\r
205{\r
1436aea4 206 BM_COLLECT_KEY_OPTIONS_PARAM Param;\r
067ed98a
RN
207\r
208 if (Count == NULL) {\r
209 return NULL;\r
210 }\r
211\r
1436aea4 212 Param.KeyOptions = NULL;\r
121300c4 213 Param.KeyOptionCount = 0;\r
067ed98a 214\r
1436aea4 215 BmForEachVariable (BmCollectKeyOptions, (VOID *)&Param);\r
067ed98a 216\r
121300c4 217 *Count = Param.KeyOptionCount;\r
067ed98a 218\r
121300c4 219 return Param.KeyOptions;\r
067ed98a
RN
220}\r
221\r
067ed98a
RN
222/**\r
223 Check whether the bit is set in the value.\r
224\r
225 @param Value The value need to be check.\r
226 @param Bit The bit filed need to be check.\r
227\r
228 @retval TRUE The bit is set.\r
229 @retval FALSE The bit is not set.\r
230**/\r
231BOOLEAN\r
232BmBitSet (\r
1436aea4
MK
233 IN UINT32 Value,\r
234 IN UINT32 Bit\r
067ed98a
RN
235 )\r
236{\r
1436aea4 237 return (BOOLEAN)((Value & Bit) != 0);\r
067ed98a
RN
238}\r
239\r
240/**\r
241 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.\r
242\r
243 @param Modifier Input key info.\r
244 @param Args Va_list info.\r
245 @param KeyOption Key info which need to update.\r
246\r
247 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].\r
248 @return EFI_INVALID_PARAMETER Input parameter error.\r
249**/\r
250EFI_STATUS\r
251BmInitializeKeyFields (\r
1436aea4
MK
252 IN UINT32 Modifier,\r
253 IN VA_LIST Args,\r
254 OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
067ed98a
RN
255 )\r
256{\r
1436aea4 257 EFI_INPUT_KEY *Key;\r
067ed98a
RN
258\r
259 if (KeyOption == NULL) {\r
260 return EFI_INVALID_PARAMETER;\r
261 }\r
262\r
263 Key = NULL;\r
264 while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {\r
265 Key = VA_ARG (Args, EFI_INPUT_KEY *);\r
266 if (Key == NULL) {\r
267 break;\r
268 }\r
1436aea4 269\r
067ed98a
RN
270 CopyMem (\r
271 &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],\r
272 Key,\r
273 sizeof (EFI_INPUT_KEY)\r
274 );\r
275 KeyOption->KeyData.Options.InputKeyCount++;\r
276 }\r
277\r
278 if (Key != NULL) {\r
279 //\r
280 // Too many keys\r
281 //\r
282 return EFI_INVALID_PARAMETER;\r
283 }\r
284\r
285 if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED\r
1436aea4
MK
286 | EFI_BOOT_MANAGER_CONTROL_PRESSED\r
287 | EFI_BOOT_MANAGER_ALT_PRESSED\r
288 | EFI_BOOT_MANAGER_LOGO_PRESSED\r
289 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED\r
290 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED\r
291 )) != 0)\r
292 {\r
067ed98a
RN
293 return EFI_INVALID_PARAMETER;\r
294 }\r
295\r
296 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {\r
297 KeyOption->KeyData.Options.ShiftPressed = 1;\r
298 }\r
1436aea4 299\r
067ed98a
RN
300 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {\r
301 KeyOption->KeyData.Options.ControlPressed = 1;\r
302 }\r
1436aea4 303\r
067ed98a
RN
304 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {\r
305 KeyOption->KeyData.Options.AltPressed = 1;\r
306 }\r
1436aea4 307\r
067ed98a
RN
308 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {\r
309 KeyOption->KeyData.Options.LogoPressed = 1;\r
310 }\r
1436aea4 311\r
067ed98a
RN
312 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {\r
313 KeyOption->KeyData.Options.MenuPressed = 1;\r
314 }\r
1436aea4 315\r
067ed98a
RN
316 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {\r
317 KeyOption->KeyData.Options.SysReqPressed = 1;\r
318 }\r
319\r
320 return EFI_SUCCESS;\r
321}\r
322\r
323/**\r
324 Try to boot the boot option triggered by hot key.\r
325**/\r
326VOID\r
327EFIAPI\r
328EfiBootManagerHotkeyBoot (\r
329 VOID\r
330 )\r
331{\r
332 if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {\r
333 EfiBootManagerBoot (&mBmHotkeyBootOption);\r
334 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);\r
335 mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;\r
336 }\r
337}\r
338\r
339/**\r
340 This is the common notification function for HotKeys, it will be registered\r
341 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.\r
342\r
343 @param KeyData A pointer to a buffer that is filled in with the keystroke\r
344 information for the key that was pressed.\r
345\r
346 @retval EFI_SUCCESS KeyData is successfully processed.\r
347 @return EFI_NOT_FOUND Fail to find boot option variable.\r
348**/\r
349EFI_STATUS\r
350EFIAPI\r
351BmHotkeyCallback (\r
1436aea4
MK
352 IN EFI_KEY_DATA *KeyData\r
353 )\r
067ed98a 354{\r
1436aea4
MK
355 LIST_ENTRY *Link;\r
356 BM_HOTKEY *Hotkey;\r
357 CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
358 EFI_STATUS Status;\r
359 EFI_KEY_DATA *HotkeyData;\r
067ed98a
RN
360\r
361 if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {\r
362 //\r
363 // Do not process sequential hotkey stroke until the current boot option returns\r
364 //\r
365 return EFI_SUCCESS;\r
366 }\r
367\r
87000d77 368 DEBUG ((DEBUG_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));\r
067ed98a
RN
369\r
370 EfiAcquireLock (&mBmHotkeyLock);\r
371 for ( Link = GetFirstNode (&mBmHotkeyList)\r
1436aea4
MK
372 ; !IsNull (&mBmHotkeyList, Link)\r
373 ; Link = GetNextNode (&mBmHotkeyList, Link)\r
374 )\r
375 {\r
067ed98a
RN
376 Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
377\r
378 //\r
379 // Is this Key Stroke we are waiting for?\r
380 //\r
381 ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));\r
382 HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];\r
383 if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&\r
384 (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&\r
d1102dba 385 (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?\r
1436aea4 386 (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE\r
067ed98a 387 )\r
1436aea4
MK
388 )\r
389 {\r
067ed98a
RN
390 //\r
391 // Receive an expecting key stroke, transit to next waiting state\r
392 //\r
393 Hotkey->WaitingKey++;\r
394\r
395 if (Hotkey->WaitingKey == Hotkey->CodeCount) {\r
396 //\r
397 // Reset to initial waiting state\r
398 //\r
399 Hotkey->WaitingKey = 0;\r
400 //\r
401 // Received the whole key stroke sequence\r
402 //\r
403 Status = gBS->SignalEvent (mBmHotkeyTriggered);\r
404 ASSERT_EFI_ERROR (Status);\r
405\r
406 if (!Hotkey->IsContinue) {\r
407 //\r
408 // Launch its BootOption\r
409 //\r
121300c4 410 UnicodeSPrint (\r
1436aea4
MK
411 OptionName,\r
412 sizeof (OptionName),\r
413 L"%s%04x",\r
414 mBmLoadOptionName[LoadOptionTypeBoot],\r
415 Hotkey->BootOption\r
121300c4 416 );\r
067ed98a 417 Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);\r
87000d77 418 DEBUG ((DEBUG_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));\r
067ed98a
RN
419 if (EFI_ERROR (Status)) {\r
420 mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;\r
421 }\r
422 } else {\r
87000d77 423 DEBUG ((DEBUG_INFO, "[Bds]Continue key pressed!\n"));\r
067ed98a
RN
424 }\r
425 }\r
426 } else {\r
427 //\r
428 // Receive an unexpected key stroke, reset to initial waiting state\r
429 //\r
430 Hotkey->WaitingKey = 0;\r
431 }\r
067ed98a 432 }\r
1436aea4 433\r
067ed98a
RN
434 EfiReleaseLock (&mBmHotkeyLock);\r
435\r
436 return EFI_SUCCESS;\r
437}\r
438\r
2d15a830
RN
439/**\r
440 Return the active Simple Text Input Ex handle array.\r
441 If the SystemTable.ConsoleInHandle is NULL, the function returns all\r
442 founded Simple Text Input Ex handles.\r
443 Otherwise, it just returns the ConsoleInHandle.\r
444\r
445 @param Count Return the handle count.\r
446\r
447 @retval The active console handles.\r
448**/\r
449EFI_HANDLE *\r
450BmGetActiveConsoleIn (\r
1436aea4 451 OUT UINTN *Count\r
2d15a830
RN
452 )\r
453{\r
1436aea4
MK
454 EFI_STATUS Status;\r
455 EFI_HANDLE *Handles;\r
2d15a830 456\r
b99e9ca9
RN
457 Handles = NULL;\r
458 *Count = 0;\r
459\r
2d15a830
RN
460 if (gST->ConsoleInHandle != NULL) {\r
461 Status = gBS->OpenProtocol (\r
462 gST->ConsoleInHandle,\r
463 &gEfiSimpleTextInputExProtocolGuid,\r
464 NULL,\r
465 gImageHandle,\r
466 NULL,\r
467 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
468 );\r
469 if (!EFI_ERROR (Status)) {\r
065e587c
TP
470 Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);\r
471 if (Handles != NULL) {\r
472 *Count = 1;\r
473 }\r
2d15a830
RN
474 }\r
475 } else {\r
476 Status = gBS->LocateHandleBuffer (\r
477 ByProtocol,\r
478 &gEfiSimpleTextInputExProtocolGuid,\r
479 NULL,\r
480 Count,\r
481 &Handles\r
482 );\r
483 }\r
2d15a830
RN
484\r
485 return Handles;\r
486}\r
487\r
067ed98a
RN
488/**\r
489 Unregister hotkey notify list.\r
490\r
491 @param Hotkey Hotkey list.\r
492\r
493 @retval EFI_SUCCESS Unregister hotkey notify success.\r
494 @retval Others Unregister hotkey notify failed.\r
495**/\r
496EFI_STATUS\r
497BmUnregisterHotkeyNotify (\r
1436aea4 498 IN BM_HOTKEY *Hotkey\r
067ed98a
RN
499 )\r
500{\r
1436aea4
MK
501 EFI_STATUS Status;\r
502 UINTN Index;\r
503 UINTN KeyIndex;\r
504 EFI_HANDLE *Handles;\r
505 UINTN HandleCount;\r
506 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;\r
507 VOID *NotifyHandle;\r
067ed98a 508\r
2d15a830 509 Handles = BmGetActiveConsoleIn (&HandleCount);\r
067ed98a 510 for (Index = 0; Index < HandleCount; Index++) {\r
1436aea4 511 Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);\r
067ed98a
RN
512 ASSERT_EFI_ERROR (Status);\r
513 for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {\r
514 Status = TxtInEx->RegisterKeyNotify (\r
515 TxtInEx,\r
516 &Hotkey->KeyData[KeyIndex],\r
517 BmHotkeyCallback,\r
518 &NotifyHandle\r
519 );\r
520 if (!EFI_ERROR (Status)) {\r
521 Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);\r
87000d77 522 DEBUG ((DEBUG_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));\r
067ed98a
RN
523 }\r
524 }\r
525 }\r
526\r
2d15a830
RN
527 if (Handles != NULL) {\r
528 FreePool (Handles);\r
529 }\r
530\r
067ed98a
RN
531 return EFI_SUCCESS;\r
532}\r
533\r
534/**\r
535 Register hotkey notify list.\r
536\r
537 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.\r
538 @param Hotkey Hotkey list.\r
539\r
540 @retval EFI_SUCCESS Register hotkey notify success.\r
541 @retval Others Register hotkey notify failed.\r
542**/\r
543EFI_STATUS\r
544BmRegisterHotkeyNotify (\r
545 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx,\r
546 IN BM_HOTKEY *Hotkey\r
547 )\r
548{\r
1436aea4
MK
549 EFI_STATUS Status;\r
550 UINTN Index;\r
551 VOID *NotifyHandle;\r
067ed98a
RN
552\r
553 for (Index = 0; Index < Hotkey->CodeCount; Index++) {\r
554 Status = TxtInEx->RegisterKeyNotify (\r
555 TxtInEx,\r
556 &Hotkey->KeyData[Index],\r
557 BmHotkeyCallback,\r
558 &NotifyHandle\r
559 );\r
560 DEBUG ((\r
87000d77 561 DEBUG_INFO,\r
067ed98a
RN
562 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",\r
563 Hotkey->KeyData[Index].Key.ScanCode,\r
564 Hotkey->KeyData[Index].Key.UnicodeChar,\r
565 Hotkey->KeyData[Index].KeyState.KeyShiftState,\r
566 Hotkey->KeyData[Index].KeyState.KeyToggleState,\r
567 Status\r
568 ));\r
569 if (EFI_ERROR (Status)) {\r
570 //\r
571 // some of the hotkey registry failed\r
572 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R\r
573 //\r
574 break;\r
575 }\r
576 }\r
577\r
578 return EFI_SUCCESS;\r
579}\r
580\r
581/**\r
582 Generate key shift state base on the input key option info.\r
583\r
584 @param Depth Which key is checked.\r
585 @param KeyOption Input key option info.\r
586 @param KeyShiftState Input key shift state.\r
587 @param KeyShiftStates Return possible key shift state array.\r
588 @param KeyShiftStateCount Possible key shift state count.\r
589**/\r
590VOID\r
591BmGenerateKeyShiftState (\r
1436aea4
MK
592 IN UINTN Depth,\r
593 IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,\r
594 IN UINT32 KeyShiftState,\r
595 IN UINT32 *KeyShiftStates,\r
596 IN UINTN *KeyShiftStateCount\r
067ed98a
RN
597 )\r
598{\r
599 switch (Depth) {\r
1436aea4
MK
600 case 0:\r
601 if (KeyOption->KeyData.Options.ShiftPressed) {\r
602 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
603 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
604 } else {\r
605 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
606 }\r
067ed98a 607\r
1436aea4 608 break;\r
067ed98a 609\r
1436aea4
MK
610 case 1:\r
611 if (KeyOption->KeyData.Options.ControlPressed) {\r
612 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
613 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
614 } else {\r
615 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
616 }\r
617\r
618 break;\r
619\r
620 case 2:\r
621 if (KeyOption->KeyData.Options.AltPressed) {\r
622 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
623 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
624 } else {\r
625 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
626 }\r
627\r
628 break;\r
629 case 3:\r
630 if (KeyOption->KeyData.Options.LogoPressed) {\r
631 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
632 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
633 } else {\r
634 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
635 }\r
636\r
637 break;\r
638 case 4:\r
639 if (KeyOption->KeyData.Options.MenuPressed) {\r
640 KeyShiftState |= EFI_MENU_KEY_PRESSED;\r
641 }\r
642\r
643 if (KeyOption->KeyData.Options.SysReqPressed) {\r
644 KeyShiftState |= EFI_SYS_REQ_PRESSED;\r
645 }\r
646\r
647 KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;\r
648 (*KeyShiftStateCount)++;\r
649 break;\r
067ed98a
RN
650 }\r
651}\r
652\r
653/**\r
654 Add it to hot key database, register it to existing TxtInEx.\r
655 New TxtInEx will be automatically registered with all the hot key in dababase\r
656\r
657 @param KeyOption Input key option info.\r
658**/\r
659EFI_STATUS\r
660BmProcessKeyOption (\r
1436aea4 661 IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
067ed98a
RN
662 )\r
663{\r
1436aea4
MK
664 EFI_STATUS Status;\r
665 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;\r
666 EFI_HANDLE *Handles;\r
667 UINTN HandleCount;\r
668 UINTN HandleIndex;\r
669 UINTN Index;\r
670 BM_HOTKEY *Hotkey;\r
671 UINTN KeyIndex;\r
067ed98a
RN
672 //\r
673 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX\r
674 //\r
1436aea4
MK
675 UINT32 KeyShiftStates[16];\r
676 UINTN KeyShiftStateCount;\r
067ed98a
RN
677\r
678 if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {\r
679 return EFI_UNSUPPORTED;\r
680 }\r
681\r
682 KeyShiftStateCount = 0;\r
683 BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);\r
f0209935 684 ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));\r
067ed98a
RN
685\r
686 EfiAcquireLock (&mBmHotkeyLock);\r
687\r
2d15a830
RN
688 Handles = BmGetActiveConsoleIn (&HandleCount);\r
689\r
067ed98a
RN
690 for (Index = 0; Index < KeyShiftStateCount; Index++) {\r
691 Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));\r
692 ASSERT (Hotkey != NULL);\r
693\r
694 Hotkey->Signature = BM_HOTKEY_SIGNATURE;\r
695 Hotkey->BootOption = KeyOption->BootOption;\r
1436aea4
MK
696 Hotkey->IsContinue = (BOOLEAN)(KeyOption == mBmContinueKeyOption);\r
697 Hotkey->CodeCount = (UINT8)KeyOption->KeyData.Options.InputKeyCount;\r
067ed98a
RN
698\r
699 for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {\r
700 CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));\r
701 Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];\r
702 }\r
1436aea4 703\r
067ed98a
RN
704 InsertTailList (&mBmHotkeyList, &Hotkey->Link);\r
705\r
067ed98a 706 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
1436aea4 707 Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);\r
067ed98a
RN
708 ASSERT_EFI_ERROR (Status);\r
709 BmRegisterHotkeyNotify (TxtInEx, Hotkey);\r
710 }\r
711 }\r
712\r
2d15a830
RN
713 if (Handles != NULL) {\r
714 FreePool (Handles);\r
715 }\r
1436aea4 716\r
067ed98a
RN
717 EfiReleaseLock (&mBmHotkeyLock);\r
718\r
719 return EFI_SUCCESS;\r
720}\r
721\r
722/**\r
723 Callback function for SimpleTextInEx protocol install events\r
724\r
725 @param Event the event that is signaled.\r
726 @param Context not used here.\r
727\r
728**/\r
729VOID\r
730EFIAPI\r
731BmTxtInExCallback (\r
1436aea4
MK
732 IN EFI_EVENT Event,\r
733 IN VOID *Context\r
067ed98a
RN
734 )\r
735{\r
736 EFI_STATUS Status;\r
737 UINTN BufferSize;\r
738 EFI_HANDLE Handle;\r
739 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;\r
740 LIST_ENTRY *Link;\r
741\r
742 while (TRUE) {\r
743 BufferSize = sizeof (EFI_HANDLE);\r
1436aea4
MK
744 Status = gBS->LocateHandle (\r
745 ByRegisterNotify,\r
746 NULL,\r
747 mBmTxtInExRegistration,\r
748 &BufferSize,\r
749 &Handle\r
750 );\r
067ed98a
RN
751 if (EFI_ERROR (Status)) {\r
752 //\r
753 // If no more notification events exist\r
754 //\r
1436aea4 755 return;\r
067ed98a
RN
756 }\r
757\r
758 Status = gBS->HandleProtocol (\r
759 Handle,\r
760 &gEfiSimpleTextInputExProtocolGuid,\r
1436aea4 761 (VOID **)&TxtInEx\r
067ed98a
RN
762 );\r
763 ASSERT_EFI_ERROR (Status);\r
764\r
765 //\r
766 // Register the hot key notification for the existing items in the list\r
767 //\r
768 EfiAcquireLock (&mBmHotkeyLock);\r
769 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {\r
770 BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));\r
771 }\r
1436aea4 772\r
067ed98a
RN
773 EfiReleaseLock (&mBmHotkeyLock);\r
774 }\r
775}\r
776\r
777/**\r
778 Free the key options returned from BmGetKeyOptions.\r
779\r
780 @param KeyOptions Pointer to the key options.\r
781 @param KeyOptionCount Number of the key options.\r
782\r
783 @retval EFI_SUCCESS The key options are freed.\r
784 @retval EFI_NOT_FOUND KeyOptions is NULL.\r
785**/\r
786EFI_STATUS\r
787BmFreeKeyOptions (\r
1436aea4
MK
788 IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions,\r
789 IN UINTN KeyOptionCount\r
067ed98a
RN
790 )\r
791{\r
792 if (KeyOptions != NULL) {\r
793 FreePool (KeyOptions);\r
794 return EFI_SUCCESS;\r
795 } else {\r
796 return EFI_NOT_FOUND;\r
797 }\r
798}\r
799\r
800/**\r
801 Register the key option to exit the waiting of the Boot Manager timeout.\r
802 Platform should ensure that the continue key option isn't conflict with\r
803 other boot key options.\r
804\r
805 @param Modifier Key shift state.\r
806 @param ... Parameter list of pointer of EFI_INPUT_KEY.\r
807\r
808 @retval EFI_SUCCESS Successfully register the continue key option.\r
809 @retval EFI_ALREADY_STARTED The continue key option is already registered.\r
810**/\r
811EFI_STATUS\r
812EFIAPI\r
813EfiBootManagerRegisterContinueKeyOption (\r
1436aea4 814 IN UINT32 Modifier,\r
067ed98a
RN
815 ...\r
816 )\r
817{\r
818 EFI_STATUS Status;\r
819 EFI_BOOT_MANAGER_KEY_OPTION KeyOption;\r
820 VA_LIST Args;\r
d1102dba 821\r
067ed98a
RN
822 if (mBmContinueKeyOption != NULL) {\r
823 return EFI_ALREADY_STARTED;\r
824 }\r
825\r
826 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
827 VA_START (Args, Modifier);\r
828 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
829 VA_END (Args);\r
830\r
831 if (!EFI_ERROR (Status)) {\r
832 mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);\r
833 ASSERT (mBmContinueKeyOption != NULL);\r
834 if (mBmHotkeyServiceStarted) {\r
835 BmProcessKeyOption (mBmContinueKeyOption);\r
836 }\r
837 }\r
838\r
839 return Status;\r
840}\r
841\r
842/**\r
843 Stop the hotkey processing.\r
d1102dba 844\r
067ed98a
RN
845 @param Event Event pointer related to hotkey service.\r
846 @param Context Context pass to this function.\r
847**/\r
848VOID\r
849EFIAPI\r
850BmStopHotkeyService (\r
1436aea4
MK
851 IN EFI_EVENT Event,\r
852 IN VOID *Context\r
067ed98a
RN
853 )\r
854{\r
1436aea4
MK
855 LIST_ENTRY *Link;\r
856 BM_HOTKEY *Hotkey;\r
067ed98a 857\r
87000d77 858 DEBUG ((DEBUG_INFO, "[Bds]Stop Hotkey Service!\n"));\r
067ed98a
RN
859 gBS->CloseEvent (Event);\r
860\r
861 EfiAcquireLock (&mBmHotkeyLock);\r
862 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {\r
863 Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
864 BmUnregisterHotkeyNotify (Hotkey);\r
1436aea4 865 Link = RemoveEntryList (Link);\r
067ed98a
RN
866 FreePool (Hotkey);\r
867 }\r
1436aea4 868\r
067ed98a
RN
869 EfiReleaseLock (&mBmHotkeyLock);\r
870}\r
871\r
872/**\r
873 Start the hot key service so that the key press can trigger the boot option.\r
874\r
d1102dba 875 @param HotkeyTriggered Return the waitable event and it will be signaled\r
067ed98a
RN
876 when a valid hot key is pressed.\r
877\r
878 @retval EFI_SUCCESS The hot key service is started.\r
879**/\r
880EFI_STATUS\r
881EFIAPI\r
882EfiBootManagerStartHotkeyService (\r
1436aea4 883 IN EFI_EVENT *HotkeyTriggered\r
067ed98a
RN
884 )\r
885{\r
886 EFI_STATUS Status;\r
887 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
888 UINTN KeyOptionCount;\r
889 UINTN Index;\r
890 EFI_EVENT Event;\r
891 UINT32 *BootOptionSupport;\r
892\r
1436aea4 893 GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **)&BootOptionSupport, NULL);\r
a0a03415
RN
894 if (BootOptionSupport != NULL) {\r
895 if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY) != 0) {\r
896 mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));\r
897 }\r
1436aea4 898\r
a0a03415 899 FreePool (BootOptionSupport);\r
067ed98a 900 }\r
067ed98a
RN
901\r
902 if (mBmHotkeySupportCount == 0) {\r
87000d77 903 DEBUG ((DEBUG_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));\r
067ed98a
RN
904 return EFI_UNSUPPORTED;\r
905 }\r
906\r
907 Status = gBS->CreateEvent (\r
908 EVT_NOTIFY_WAIT,\r
909 TPL_CALLBACK,\r
ac72474d 910 EfiEventEmptyFunction,\r
067ed98a
RN
911 NULL,\r
912 &mBmHotkeyTriggered\r
913 );\r
914 ASSERT_EFI_ERROR (Status);\r
915\r
916 if (HotkeyTriggered != NULL) {\r
917 *HotkeyTriggered = mBmHotkeyTriggered;\r
918 }\r
919\r
920 KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
1436aea4 921 for (Index = 0; Index < KeyOptionCount; Index++) {\r
067ed98a
RN
922 BmProcessKeyOption (&KeyOptions[Index]);\r
923 }\r
1436aea4 924\r
067ed98a
RN
925 BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
926\r
927 if (mBmContinueKeyOption != NULL) {\r
928 BmProcessKeyOption (mBmContinueKeyOption);\r
929 }\r
930\r
2d15a830
RN
931 //\r
932 // Hook hotkey on every future SimpleTextInputEx instance when\r
933 // SystemTable.ConsoleInHandle == NULL, which means the console\r
934 // manager (ConSplitter) is absent.\r
935 //\r
936 if (gST->ConsoleInHandle == NULL) {\r
937 EfiCreateProtocolNotifyEvent (\r
938 &gEfiSimpleTextInputExProtocolGuid,\r
939 TPL_CALLBACK,\r
940 BmTxtInExCallback,\r
941 NULL,\r
942 &mBmTxtInExRegistration\r
943 );\r
944 }\r
067ed98a
RN
945\r
946 Status = EfiCreateEventReadyToBootEx (\r
947 TPL_CALLBACK,\r
948 BmStopHotkeyService,\r
949 NULL,\r
950 &Event\r
951 );\r
952 ASSERT_EFI_ERROR (Status);\r
953\r
067ed98a
RN
954 mBmHotkeyServiceStarted = TRUE;\r
955 return Status;\r
956}\r
957\r
958/**\r
959 Add the key option.\r
960 It adds the key option variable and the key option takes affect immediately.\r
961\r
962 @param AddedOption Return the added key option.\r
963 @param BootOptionNumber The boot option number for the key option.\r
964 @param Modifier Key shift state.\r
965 @param ... Parameter list of pointer of EFI_INPUT_KEY.\r
966\r
967 @retval EFI_SUCCESS The key option is added.\r
968 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.\r
969**/\r
970EFI_STATUS\r
971EFIAPI\r
972EfiBootManagerAddKeyOptionVariable (\r
1436aea4
MK
973 OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption OPTIONAL,\r
974 IN UINT16 BootOptionNumber,\r
975 IN UINT32 Modifier,\r
067ed98a
RN
976 ...\r
977 )\r
978{\r
1436aea4
MK
979 EFI_STATUS Status;\r
980 VA_LIST Args;\r
981 VOID *BootOption;\r
982 UINTN BootOptionSize;\r
983 CHAR16 BootOptionName[BM_OPTION_NAME_LEN];\r
984 EFI_BOOT_MANAGER_KEY_OPTION KeyOption;\r
985 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
986 UINTN KeyOptionCount;\r
987 UINTN Index;\r
988 UINTN KeyOptionNumber;\r
989 CHAR16 KeyOptionName[sizeof ("Key####")];\r
067ed98a 990\r
121300c4 991 UnicodeSPrint (\r
1436aea4
MK
992 BootOptionName,\r
993 sizeof (BootOptionName),\r
994 L"%s%04x",\r
995 mBmLoadOptionName[LoadOptionTypeBoot],\r
996 BootOptionNumber\r
121300c4 997 );\r
067ed98a
RN
998 GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);\r
999\r
1000 if (BootOption == NULL) {\r
1001 return EFI_NOT_FOUND;\r
1002 }\r
1003\r
1004 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1005 KeyOption.BootOption = BootOptionNumber;\r
1436aea4 1006 Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);\r
067ed98a
RN
1007 ASSERT_EFI_ERROR (Status);\r
1008 FreePool (BootOption);\r
1009\r
1010 VA_START (Args, Modifier);\r
1011 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
1012 VA_END (Args);\r
1013 if (EFI_ERROR (Status)) {\r
1014 return Status;\r
1015 }\r
1016\r
1017 KeyOptionNumber = LoadOptionNumberUnassigned;\r
1018 //\r
1019 // Check if the hot key sequence was defined already\r
1020 //\r
1021 KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
1022 for (Index = 0; Index < KeyOptionCount; Index++) {\r
1023 if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&\r
1436aea4
MK
1024 (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0))\r
1025 {\r
067ed98a
RN
1026 break;\r
1027 }\r
1028\r
1029 if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&\r
1030 (KeyOptions[Index].OptionNumber > Index)\r
1436aea4
MK
1031 )\r
1032 {\r
067ed98a
RN
1033 KeyOptionNumber = Index;\r
1034 }\r
1035 }\r
1436aea4 1036\r
067ed98a
RN
1037 BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
1038\r
1039 if (Index < KeyOptionCount) {\r
1040 return EFI_ALREADY_STARTED;\r
1041 }\r
1042\r
1043 if (KeyOptionNumber == LoadOptionNumberUnassigned) {\r
1044 KeyOptionNumber = KeyOptionCount;\r
1045 }\r
1046\r
1047 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);\r
1048\r
1049 Status = gRT->SetVariable (\r
1050 KeyOptionName,\r
1051 &gEfiGlobalVariableGuid,\r
1052 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1053 BmSizeOfKeyOption (&KeyOption),\r
1054 &KeyOption\r
1055 );\r
1056 if (!EFI_ERROR (Status)) {\r
1057 //\r
1058 // Return the Key Option in case needed by caller\r
1059 //\r
1060 if (AddedOption != NULL) {\r
1061 CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1062 }\r
1063\r
1064 //\r
1065 // Register the newly added hot key\r
1066 // Calling this function before EfiBootManagerStartHotkeyService doesn't\r
1067 // need to call BmProcessKeyOption\r
1068 //\r
1069 if (mBmHotkeyServiceStarted) {\r
1070 BmProcessKeyOption (&KeyOption);\r
1071 }\r
1072 }\r
1073\r
1074 return Status;\r
1075}\r
1076\r
1077/**\r
1078 Delete the Key Option variable and unregister the hot key\r
1079\r
1080 @param DeletedOption Return the deleted key options.\r
1081 @param Modifier Key shift state.\r
1082 @param ... Parameter list of pointer of EFI_INPUT_KEY.\r
1083\r
1084 @retval EFI_SUCCESS The key option is deleted.\r
1085 @retval EFI_NOT_FOUND The key option cannot be found.\r
1086**/\r
1087EFI_STATUS\r
1088EFIAPI\r
1089EfiBootManagerDeleteKeyOptionVariable (\r
1436aea4
MK
1090 IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption OPTIONAL,\r
1091 IN UINT32 Modifier,\r
067ed98a
RN
1092 ...\r
1093 )\r
1094{\r
1436aea4
MK
1095 EFI_STATUS Status;\r
1096 UINTN Index;\r
1097 VA_LIST Args;\r
1098 EFI_BOOT_MANAGER_KEY_OPTION KeyOption;\r
1099 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
1100 UINTN KeyOptionCount;\r
1101 LIST_ENTRY *Link;\r
1102 BM_HOTKEY *Hotkey;\r
1103 UINT32 ShiftState;\r
1104 BOOLEAN Match;\r
1105 CHAR16 KeyOptionName[sizeof ("Key####")];\r
067ed98a
RN
1106\r
1107 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1108 VA_START (Args, Modifier);\r
1109 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
1110 VA_END (Args);\r
1111\r
1112 if (EFI_ERROR (Status)) {\r
1113 return Status;\r
1114 }\r
1115\r
1116 EfiAcquireLock (&mBmHotkeyLock);\r
1117 //\r
1118 // Delete the key option from active hot key list\r
1119 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT\r
1120 //\r
1121 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {\r
1122 Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
1436aea4 1123 Match = (BOOLEAN)(Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);\r
067ed98a
RN
1124\r
1125 for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {\r
1126 ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;\r
1127 if (\r
1436aea4
MK
1128 (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||\r
1129 (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||\r
1130 (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||\r
1131 (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||\r
1132 (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||\r
1133 (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||\r
1134 (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)\r
1135 )\r
1136 {\r
067ed98a
RN
1137 //\r
1138 // Break when any field doesn't match\r
1139 //\r
1140 Match = FALSE;\r
1141 break;\r
1142 }\r
1143 }\r
1144\r
1145 if (Match) {\r
1146 Link = RemoveEntryList (Link);\r
1147 FreePool (Hotkey);\r
1148 } else {\r
1149 Link = GetNextNode (&mBmHotkeyList, Link);\r
1150 }\r
1151 }\r
1152\r
1153 //\r
1154 // Delete the key option from the variable\r
1155 //\r
1156 Status = EFI_NOT_FOUND;\r
1157 KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
1158 for (Index = 0; Index < KeyOptionCount; Index++) {\r
1159 if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&\r
1160 (CompareMem (\r
1436aea4
MK
1161 KeyOptions[Index].Keys,\r
1162 KeyOption.Keys,\r
1163 KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)\r
1164 ) == 0)\r
1165 )\r
1166 {\r
067ed98a
RN
1167 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);\r
1168 Status = gRT->SetVariable (\r
1436aea4
MK
1169 KeyOptionName,\r
1170 &gEfiGlobalVariableGuid,\r
1171 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1172 0,\r
1173 NULL\r
1174 );\r
067ed98a
RN
1175 //\r
1176 // Return the deleted key option in case needed by caller\r
1177 //\r
1178 if (DeletedOption != NULL) {\r
1179 CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1180 }\r
1436aea4 1181\r
067ed98a
RN
1182 break;\r
1183 }\r
1184 }\r
1436aea4 1185\r
067ed98a
RN
1186 BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
1187\r
1188 EfiReleaseLock (&mBmHotkeyLock);\r
1189\r
1190 return Status;\r
1191}\r