]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Library / BootMaintenanceManagerUiLib / BootOption.c
1 /** @file
2 Provide boot option support for Application "BootMaint"
3
4 Include file system navigation, system handle selection
5
6 Boot option manipulation
7
8 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include "BootMaintenanceManager.h"
14
15 ///
16 /// Define the maximum characters that will be accepted.
17 ///
18 #define MAX_CHAR 480
19
20 /**
21
22 Check whether a reset is needed, if reset is needed, Popup a menu to notice user.
23
24 **/
25 VOID
26 BmmSetupResetReminder (
27 VOID
28 )
29 {
30 EFI_INPUT_KEY Key;
31 CHAR16 *StringBuffer1;
32 CHAR16 *StringBuffer2;
33 EFI_STATUS Status;
34 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
35
36 //
37 // Use BrowserEx2 protocol to check whether reset is required.
38 //
39 Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **)&FormBrowserEx2);
40
41 //
42 // check any reset required change is applied? if yes, reset system
43 //
44 if (!EFI_ERROR (Status) && FormBrowserEx2->IsResetRequired ()) {
45 StringBuffer1 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
46 ASSERT (StringBuffer1 != NULL);
47 StringBuffer2 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
48 ASSERT (StringBuffer2 != NULL);
49 StrCpyS (StringBuffer1, MAX_CHAR, L"Configuration changed. Reset to apply it Now.");
50 StrCpyS (StringBuffer2, MAX_CHAR, L"Press ENTER to reset");
51 //
52 // Popup a menu to notice user
53 //
54 do {
55 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
56 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
57
58 FreePool (StringBuffer1);
59 FreePool (StringBuffer2);
60
61 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
62 }
63 }
64
65 /**
66 Create a menu entry by given menu type.
67
68 @param MenuType The Menu type to be created.
69
70 @retval NULL If failed to create the menu.
71 @return the new menu entry.
72
73 **/
74 BM_MENU_ENTRY *
75 BOpt_CreateMenuEntry (
76 UINTN MenuType
77 )
78 {
79 BM_MENU_ENTRY *MenuEntry;
80 UINTN ContextSize;
81
82 //
83 // Get context size according to menu type
84 //
85 switch (MenuType) {
86 case BM_LOAD_CONTEXT_SELECT:
87 ContextSize = sizeof (BM_LOAD_CONTEXT);
88 break;
89
90 case BM_FILE_CONTEXT_SELECT:
91 ContextSize = sizeof (BM_FILE_CONTEXT);
92 break;
93
94 case BM_CONSOLE_CONTEXT_SELECT:
95 ContextSize = sizeof (BM_CONSOLE_CONTEXT);
96 break;
97
98 case BM_TERMINAL_CONTEXT_SELECT:
99 ContextSize = sizeof (BM_TERMINAL_CONTEXT);
100 break;
101
102 case BM_HANDLE_CONTEXT_SELECT:
103 ContextSize = sizeof (BM_HANDLE_CONTEXT);
104 break;
105
106 default:
107 ContextSize = 0;
108 break;
109 }
110
111 if (ContextSize == 0) {
112 return NULL;
113 }
114
115 //
116 // Create new menu entry
117 //
118 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
119 if (MenuEntry == NULL) {
120 return NULL;
121 }
122
123 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
124 if (MenuEntry->VariableContext == NULL) {
125 FreePool (MenuEntry);
126 return NULL;
127 }
128
129 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
130 MenuEntry->ContextSelection = MenuType;
131 return MenuEntry;
132 }
133
134 /**
135 Free up all resource allocated for a BM_MENU_ENTRY.
136
137 @param MenuEntry A pointer to BM_MENU_ENTRY.
138
139 **/
140 VOID
141 BOpt_DestroyMenuEntry (
142 BM_MENU_ENTRY *MenuEntry
143 )
144 {
145 BM_LOAD_CONTEXT *LoadContext;
146 BM_FILE_CONTEXT *FileContext;
147 BM_CONSOLE_CONTEXT *ConsoleContext;
148 BM_TERMINAL_CONTEXT *TerminalContext;
149 BM_HANDLE_CONTEXT *HandleContext;
150
151 //
152 // Select by the type in Menu entry for current context type
153 //
154 switch (MenuEntry->ContextSelection) {
155 case BM_LOAD_CONTEXT_SELECT:
156 LoadContext = (BM_LOAD_CONTEXT *)MenuEntry->VariableContext;
157 FreePool (LoadContext->FilePathList);
158 if (LoadContext->OptionalData != NULL) {
159 FreePool (LoadContext->OptionalData);
160 }
161
162 FreePool (LoadContext);
163 break;
164
165 case BM_FILE_CONTEXT_SELECT:
166 FileContext = (BM_FILE_CONTEXT *)MenuEntry->VariableContext;
167
168 if (!FileContext->IsRoot) {
169 FreePool (FileContext->DevicePath);
170 } else {
171 if (FileContext->FHandle != NULL) {
172 FileContext->FHandle->Close (FileContext->FHandle);
173 }
174 }
175
176 if (FileContext->FileName != NULL) {
177 FreePool (FileContext->FileName);
178 }
179
180 if (FileContext->Info != NULL) {
181 FreePool (FileContext->Info);
182 }
183
184 FreePool (FileContext);
185 break;
186
187 case BM_CONSOLE_CONTEXT_SELECT:
188 ConsoleContext = (BM_CONSOLE_CONTEXT *)MenuEntry->VariableContext;
189 FreePool (ConsoleContext->DevicePath);
190 FreePool (ConsoleContext);
191 break;
192
193 case BM_TERMINAL_CONTEXT_SELECT:
194 TerminalContext = (BM_TERMINAL_CONTEXT *)MenuEntry->VariableContext;
195 FreePool (TerminalContext->DevicePath);
196 FreePool (TerminalContext);
197 break;
198
199 case BM_HANDLE_CONTEXT_SELECT:
200 HandleContext = (BM_HANDLE_CONTEXT *)MenuEntry->VariableContext;
201 FreePool (HandleContext);
202 break;
203
204 default:
205 break;
206 }
207
208 FreePool (MenuEntry->DisplayString);
209 if (MenuEntry->HelpString != NULL) {
210 FreePool (MenuEntry->HelpString);
211 }
212
213 FreePool (MenuEntry);
214 }
215
216 /**
217 Get the Menu Entry from the list in Menu Entry List.
218
219 If MenuNumber is great or equal to the number of Menu
220 Entry in the list, then ASSERT.
221
222 @param MenuOption The Menu Entry List to read the menu entry.
223 @param MenuNumber The index of Menu Entry.
224
225 @return The Menu Entry.
226
227 **/
228 BM_MENU_ENTRY *
229 BOpt_GetMenuEntry (
230 BM_MENU_OPTION *MenuOption,
231 UINTN MenuNumber
232 )
233 {
234 BM_MENU_ENTRY *NewMenuEntry;
235 UINTN Index;
236 LIST_ENTRY *List;
237
238 ASSERT (MenuNumber < MenuOption->MenuNumber);
239
240 List = MenuOption->Head.ForwardLink;
241 for (Index = 0; Index < MenuNumber; Index++) {
242 List = List->ForwardLink;
243 }
244
245 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
246
247 return NewMenuEntry;
248 }
249
250 /**
251 Free resources allocated in Allocate Rountine.
252
253 @param FreeMenu Menu to be freed
254 **/
255 VOID
256 BOpt_FreeMenu (
257 BM_MENU_OPTION *FreeMenu
258 )
259 {
260 BM_MENU_ENTRY *MenuEntry;
261
262 while (!IsListEmpty (&FreeMenu->Head)) {
263 MenuEntry = CR (
264 FreeMenu->Head.ForwardLink,
265 BM_MENU_ENTRY,
266 Link,
267 BM_MENU_ENTRY_SIGNATURE
268 );
269 RemoveEntryList (&MenuEntry->Link);
270 BOpt_DestroyMenuEntry (MenuEntry);
271 }
272
273 FreeMenu->MenuNumber = 0;
274 }
275
276 /**
277
278 Build the BootOptionMenu according to BootOrder Variable.
279 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
280
281 @param CallbackData The BMM context data.
282
283 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
284 @return EFI_SUCESS Success build boot option menu.
285
286 **/
287 EFI_STATUS
288 BOpt_GetBootOptions (
289 IN BMM_CALLBACK_DATA *CallbackData
290 )
291 {
292 UINTN Index;
293 UINT16 BootString[10];
294 UINT8 *LoadOptionFromVar;
295 UINTN BootOptionSize;
296 BOOLEAN BootNextFlag;
297 UINT16 *BootOrderList;
298 UINTN BootOrderListSize;
299 UINT16 *BootNext;
300 UINTN BootNextSize;
301 BM_MENU_ENTRY *NewMenuEntry;
302 BM_LOAD_CONTEXT *NewLoadContext;
303 UINT8 *LoadOptionPtr;
304 UINTN StringSize;
305 UINTN OptionalDataSize;
306 UINT8 *LoadOptionEnd;
307 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
308 UINTN MenuCount;
309 UINT8 *Ptr;
310 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
311 UINTN BootOptionCount;
312
313 MenuCount = 0;
314 BootOrderListSize = 0;
315 BootNextSize = 0;
316 BootOrderList = NULL;
317 BootNext = NULL;
318 LoadOptionFromVar = NULL;
319 BOpt_FreeMenu (&BootOptionMenu);
320 InitializeListHead (&BootOptionMenu.Head);
321
322 //
323 // Get the BootOrder from the Var
324 //
325 GetEfiGlobalVariable2 (L"BootOrder", (VOID **)&BootOrderList, &BootOrderListSize);
326 if (BootOrderList == NULL) {
327 return EFI_NOT_FOUND;
328 }
329
330 //
331 // Get the BootNext from the Var
332 //
333 GetEfiGlobalVariable2 (L"BootNext", (VOID **)&BootNext, &BootNextSize);
334 if (BootNext != NULL) {
335 if (BootNextSize != sizeof (UINT16)) {
336 FreePool (BootNext);
337 BootNext = NULL;
338 }
339 }
340
341 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
342 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
343 //
344 // Don't display the hidden/inactive boot option
345 //
346 if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
347 continue;
348 }
349
350 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
351 //
352 // Get all loadoptions from the VAR
353 //
354 GetEfiGlobalVariable2 (BootString, (VOID **)&LoadOptionFromVar, &BootOptionSize);
355 if (LoadOptionFromVar == NULL) {
356 continue;
357 }
358
359 if (BootNext != NULL) {
360 BootNextFlag = (BOOLEAN)(*BootNext == BootOrderList[Index]);
361 } else {
362 BootNextFlag = FALSE;
363 }
364
365 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
366 ASSERT (NULL != NewMenuEntry);
367
368 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
369
370 LoadOptionPtr = LoadOptionFromVar;
371 LoadOptionEnd = LoadOptionFromVar + BootOptionSize;
372
373 NewMenuEntry->OptionNumber = BootOrderList[Index];
374 NewLoadContext->Deleted = FALSE;
375 NewLoadContext->IsBootNext = BootNextFlag;
376
377 //
378 // Is a Legacy Device?
379 //
380 Ptr = (UINT8 *)LoadOptionFromVar;
381
382 //
383 // Attribute = *(UINT32 *)Ptr;
384 //
385 Ptr += sizeof (UINT32);
386
387 //
388 // FilePathSize = *(UINT16 *)Ptr;
389 //
390 Ptr += sizeof (UINT16);
391
392 //
393 // Description = (CHAR16 *)Ptr;
394 //
395 Ptr += StrSize ((CHAR16 *)Ptr);
396
397 //
398 // Now Ptr point to Device Path
399 //
400 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Ptr;
401 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
402 NewLoadContext->IsLegacy = TRUE;
403 } else {
404 NewLoadContext->IsLegacy = FALSE;
405 }
406
407 //
408 // LoadOption is a pointer type of UINT8
409 // for easy use with following LOAD_OPTION
410 // embedded in this struct
411 //
412
413 NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;
414
415 LoadOptionPtr += sizeof (UINT32);
416
417 NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;
418 LoadOptionPtr += sizeof (UINT16);
419
420 StringSize = StrSize ((UINT16 *)LoadOptionPtr);
421
422 NewLoadContext->Description = AllocateZeroPool (StrSize ((UINT16 *)LoadOptionPtr));
423 ASSERT (NewLoadContext->Description != NULL);
424 StrCpyS (NewLoadContext->Description, StrSize ((UINT16 *)LoadOptionPtr) / sizeof (UINT16), (UINT16 *)LoadOptionPtr);
425
426 ASSERT (NewLoadContext->Description != NULL);
427 NewMenuEntry->DisplayString = NewLoadContext->Description;
428 NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
429
430 LoadOptionPtr += StringSize;
431
432 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
433 ASSERT (NewLoadContext->FilePathList != NULL);
434 CopyMem (
435 NewLoadContext->FilePathList,
436 (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,
437 NewLoadContext->FilePathListLength
438 );
439
440 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
441 NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
442
443 LoadOptionPtr += NewLoadContext->FilePathListLength;
444
445 if (LoadOptionPtr < LoadOptionEnd) {
446 OptionalDataSize = BootOptionSize -
447 sizeof (UINT32) -
448 sizeof (UINT16) -
449 StringSize -
450 NewLoadContext->FilePathListLength;
451
452 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
453 ASSERT (NewLoadContext->OptionalData != NULL);
454 CopyMem (
455 NewLoadContext->OptionalData,
456 LoadOptionPtr,
457 OptionalDataSize
458 );
459 }
460
461 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
462 MenuCount++;
463 FreePool (LoadOptionFromVar);
464 }
465
466 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
467
468 if (BootNext != NULL) {
469 FreePool (BootNext);
470 }
471
472 if (BootOrderList != NULL) {
473 FreePool (BootOrderList);
474 }
475
476 BootOptionMenu.MenuNumber = MenuCount;
477 return EFI_SUCCESS;
478 }
479
480 /**
481
482 Find drivers that will be added as Driver#### variables from handles
483 in current system environment
484 All valid handles in the system except those consume SimpleFs, LoadFile
485 are stored in DriverMenu for future use.
486
487 @retval EFI_SUCCESS The function complets successfully.
488 @return Other value if failed to build the DriverMenu.
489
490 **/
491 EFI_STATUS
492 BOpt_FindDrivers (
493 VOID
494 )
495 {
496 UINTN NoDevicePathHandles;
497 EFI_HANDLE *DevicePathHandle;
498 UINTN Index;
499 EFI_STATUS Status;
500 BM_MENU_ENTRY *NewMenuEntry;
501 BM_HANDLE_CONTEXT *NewHandleContext;
502 EFI_HANDLE CurHandle;
503 UINTN OptionNumber;
504 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
505 EFI_LOAD_FILE_PROTOCOL *LoadFile;
506
507 SimpleFs = NULL;
508 LoadFile = NULL;
509
510 InitializeListHead (&DriverMenu.Head);
511
512 //
513 // At first, get all handles that support Device Path
514 // protocol which is the basic requirement for
515 // Driver####
516 //
517 Status = gBS->LocateHandleBuffer (
518 ByProtocol,
519 &gEfiDevicePathProtocolGuid,
520 NULL,
521 &NoDevicePathHandles,
522 &DevicePathHandle
523 );
524 if (EFI_ERROR (Status)) {
525 return Status;
526 }
527
528 OptionNumber = 0;
529 for (Index = 0; Index < NoDevicePathHandles; Index++) {
530 CurHandle = DevicePathHandle[Index];
531
532 Status = gBS->HandleProtocol (
533 CurHandle,
534 &gEfiSimpleFileSystemProtocolGuid,
535 (VOID **)&SimpleFs
536 );
537 if (Status == EFI_SUCCESS) {
538 continue;
539 }
540
541 Status = gBS->HandleProtocol (
542 CurHandle,
543 &gEfiLoadFileProtocolGuid,
544 (VOID **)&LoadFile
545 );
546 if (Status == EFI_SUCCESS) {
547 continue;
548 }
549
550 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
551 if (NULL == NewMenuEntry) {
552 FreePool (DevicePathHandle);
553 return EFI_OUT_OF_RESOURCES;
554 }
555
556 NewHandleContext = (BM_HANDLE_CONTEXT *)NewMenuEntry->VariableContext;
557 NewHandleContext->Handle = CurHandle;
558 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
559 NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);
560 NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
561 NewMenuEntry->HelpString = NULL;
562 NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
563 NewMenuEntry->OptionNumber = OptionNumber;
564 OptionNumber++;
565 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
566 }
567
568 if (DevicePathHandle != NULL) {
569 FreePool (DevicePathHandle);
570 }
571
572 DriverMenu.MenuNumber = OptionNumber;
573 return EFI_SUCCESS;
574 }
575
576 /**
577
578 Get the Option Number that has not been allocated for use.
579
580 @param Type The type of Option.
581
582 @return The available Option Number.
583
584 **/
585 UINT16
586 BOpt_GetOptionNumber (
587 CHAR16 *Type
588 )
589 {
590 UINT16 *OrderList;
591 UINTN OrderListSize;
592 UINTN Index;
593 CHAR16 StrTemp[20];
594 UINT16 *OptionBuffer;
595 UINT16 OptionNumber;
596 UINTN OptionSize;
597
598 OrderListSize = 0;
599 OrderList = NULL;
600 OptionNumber = 0;
601 Index = 0;
602
603 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
604
605 GetEfiGlobalVariable2 (StrTemp, (VOID **)&OrderList, &OrderListSize);
606 for (OptionNumber = 0; ; OptionNumber++) {
607 if (OrderList != NULL) {
608 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
609 if (OptionNumber == OrderList[Index]) {
610 break;
611 }
612 }
613 }
614
615 if (Index < OrderListSize / sizeof (UINT16)) {
616 //
617 // The OptionNumber occurs in the OrderList, continue to use next one
618 //
619 continue;
620 }
621
622 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN)OptionNumber);
623 DEBUG ((DEBUG_ERROR, "Option = %s\n", StrTemp));
624 GetEfiGlobalVariable2 (StrTemp, (VOID **)&OptionBuffer, &OptionSize);
625 if (NULL == OptionBuffer) {
626 //
627 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
628 //
629 break;
630 }
631 }
632
633 return OptionNumber;
634 }
635
636 /**
637
638 Get the Option Number for Boot#### that does not used.
639
640 @return The available Option Number.
641
642 **/
643 UINT16
644 BOpt_GetBootOptionNumber (
645 VOID
646 )
647 {
648 return BOpt_GetOptionNumber (L"Boot");
649 }
650
651 /**
652
653 Get the Option Number for Driver#### that does not used.
654
655 @return The unused Option Number.
656
657 **/
658 UINT16
659 BOpt_GetDriverOptionNumber (
660 VOID
661 )
662 {
663 return BOpt_GetOptionNumber (L"Driver");
664 }
665
666 /**
667
668 Build up all DriverOptionMenu
669
670 @param CallbackData The BMM context data.
671
672 @retval EFI_SUCESS The functin completes successfully.
673 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
674 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
675
676 **/
677 EFI_STATUS
678 BOpt_GetDriverOptions (
679 IN BMM_CALLBACK_DATA *CallbackData
680 )
681 {
682 UINTN Index;
683 UINT16 DriverString[12];
684 UINT8 *LoadOptionFromVar;
685 UINTN DriverOptionSize;
686
687 UINT16 *DriverOrderList;
688 UINTN DriverOrderListSize;
689 BM_MENU_ENTRY *NewMenuEntry;
690 BM_LOAD_CONTEXT *NewLoadContext;
691 UINT8 *LoadOptionPtr;
692 UINTN StringSize;
693 UINTN OptionalDataSize;
694 UINT8 *LoadOptionEnd;
695
696 DriverOrderListSize = 0;
697 DriverOrderList = NULL;
698 DriverOptionSize = 0;
699 LoadOptionFromVar = NULL;
700 BOpt_FreeMenu (&DriverOptionMenu);
701 InitializeListHead (&DriverOptionMenu.Head);
702 //
703 // Get the DriverOrder from the Var
704 //
705 GetEfiGlobalVariable2 (L"DriverOrder", (VOID **)&DriverOrderList, &DriverOrderListSize);
706 if (DriverOrderList == NULL) {
707 return EFI_NOT_FOUND;
708 }
709
710 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
711 UnicodeSPrint (
712 DriverString,
713 sizeof (DriverString),
714 L"Driver%04x",
715 DriverOrderList[Index]
716 );
717 //
718 // Get all loadoptions from the VAR
719 //
720 GetEfiGlobalVariable2 (DriverString, (VOID **)&LoadOptionFromVar, &DriverOptionSize);
721 if (LoadOptionFromVar == NULL) {
722 continue;
723 }
724
725 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
726 if (NULL == NewMenuEntry) {
727 return EFI_OUT_OF_RESOURCES;
728 }
729
730 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
731 LoadOptionPtr = LoadOptionFromVar;
732 LoadOptionEnd = LoadOptionFromVar + DriverOptionSize;
733 NewMenuEntry->OptionNumber = DriverOrderList[Index];
734 NewLoadContext->Deleted = FALSE;
735 NewLoadContext->IsLegacy = FALSE;
736
737 //
738 // LoadOption is a pointer type of UINT8
739 // for easy use with following LOAD_OPTION
740 // embedded in this struct
741 //
742
743 NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;
744
745 LoadOptionPtr += sizeof (UINT32);
746
747 NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;
748 LoadOptionPtr += sizeof (UINT16);
749
750 StringSize = StrSize ((UINT16 *)LoadOptionPtr);
751 NewLoadContext->Description = AllocateZeroPool (StringSize);
752 ASSERT (NewLoadContext->Description != NULL);
753 CopyMem (
754 NewLoadContext->Description,
755 (UINT16 *)LoadOptionPtr,
756 StringSize
757 );
758 NewMenuEntry->DisplayString = NewLoadContext->Description;
759 NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
760
761 LoadOptionPtr += StringSize;
762
763 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
764 ASSERT (NewLoadContext->FilePathList != NULL);
765 CopyMem (
766 NewLoadContext->FilePathList,
767 (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,
768 NewLoadContext->FilePathListLength
769 );
770
771 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
772 NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
773
774 LoadOptionPtr += NewLoadContext->FilePathListLength;
775
776 if (LoadOptionPtr < LoadOptionEnd) {
777 OptionalDataSize = DriverOptionSize -
778 sizeof (UINT32) -
779 sizeof (UINT16) -
780 StringSize -
781 NewLoadContext->FilePathListLength;
782
783 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
784 ASSERT (NewLoadContext->OptionalData != NULL);
785 CopyMem (
786 NewLoadContext->OptionalData,
787 LoadOptionPtr,
788 OptionalDataSize
789 );
790 }
791
792 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
793 FreePool (LoadOptionFromVar);
794 }
795
796 if (DriverOrderList != NULL) {
797 FreePool (DriverOrderList);
798 }
799
800 DriverOptionMenu.MenuNumber = Index;
801 return EFI_SUCCESS;
802 }
803
804 /**
805 Get option number according to Boot#### and BootOrder variable.
806 The value is saved as #### + 1.
807
808 @param CallbackData The BMM context data.
809 **/
810 VOID
811 GetBootOrder (
812 IN BMM_CALLBACK_DATA *CallbackData
813 )
814 {
815 BMM_FAKE_NV_DATA *BmmConfig;
816 UINT16 Index;
817 UINT16 OptionOrderIndex;
818 UINTN DeviceType;
819 BM_MENU_ENTRY *NewMenuEntry;
820 BM_LOAD_CONTEXT *NewLoadContext;
821
822 ASSERT (CallbackData != NULL);
823
824 DeviceType = (UINTN)-1;
825 BmmConfig = &CallbackData->BmmFakeNvData;
826 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
827
828 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
829 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
830 Index++)
831 {
832 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
833 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
834
835 if (NewLoadContext->IsLegacy) {
836 if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {
837 DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;
838 } else {
839 //
840 // Only show one legacy boot option for the same device type
841 // assuming the boot options are grouped by the device type
842 //
843 continue;
844 }
845 }
846
847 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);
848 }
849 }
850
851 /**
852 Get driver option order from globalc DriverOptionMenu.
853
854 @param CallbackData The BMM context data.
855
856 **/
857 VOID
858 GetDriverOrder (
859 IN BMM_CALLBACK_DATA *CallbackData
860 )
861 {
862 BMM_FAKE_NV_DATA *BmmConfig;
863 UINT16 Index;
864 UINT16 OptionOrderIndex;
865 UINTN DeviceType;
866 BM_MENU_ENTRY *NewMenuEntry;
867 BM_LOAD_CONTEXT *NewLoadContext;
868
869 ASSERT (CallbackData != NULL);
870
871 DeviceType = (UINTN)-1;
872 BmmConfig = &CallbackData->BmmFakeNvData;
873 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
874
875 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
876 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
877 Index++)
878 {
879 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
880 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
881
882 if (NewLoadContext->IsLegacy) {
883 if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {
884 DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;
885 } else {
886 //
887 // Only show one legacy boot option for the same device type
888 // assuming the boot options are grouped by the device type
889 //
890 continue;
891 }
892 }
893
894 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);
895 }
896 }
897
898 /**
899 Boot the file specified by the input file path info.
900
901 @param FilePath Point to the file path.
902
903 @retval TRUE Exit caller function.
904 @retval FALSE Not exit caller function.
905 **/
906 BOOLEAN
907 EFIAPI
908 BootFromFile (
909 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
910 )
911 {
912 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
913 CHAR16 *FileName;
914
915 FileName = NULL;
916
917 FileName = ExtractFileNameFromDevicePath (FilePath);
918 if (FileName != NULL) {
919 EfiBootManagerInitializeLoadOption (
920 &BootOption,
921 0,
922 LoadOptionTypeBoot,
923 LOAD_OPTION_ACTIVE,
924 FileName,
925 FilePath,
926 NULL,
927 0
928 );
929 //
930 // Since current no boot from removable media directly is allowed */
931 //
932 gST->ConOut->ClearScreen (gST->ConOut);
933 //
934 // Check whether need to reset system.
935 //
936 BmmSetupResetReminder ();
937
938 BmmSetConsoleMode (FALSE);
939 EfiBootManagerBoot (&BootOption);
940 BmmSetConsoleMode (TRUE);
941
942 FreePool (FileName);
943
944 EfiBootManagerFreeLoadOption (&BootOption);
945 }
946
947 return FALSE;
948 }
949
950 /**
951 Display the form base on the selected file.
952
953 @param FilePath Point to the file path.
954 @param FormId The form need to display.
955
956 **/
957 BOOLEAN
958 ReSendForm (
959 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
960 IN EFI_FORM_ID FormId
961 )
962 {
963 gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;
964
965 UpdateOptionPage (&gBootMaintenancePrivate, FormId, FilePath);
966
967 gBootMaintenancePrivate.FormBrowser2->SendForm (
968 gBootMaintenancePrivate.FormBrowser2,
969 &gBootMaintenancePrivate.BmmHiiHandle,
970 1,
971 &mBootMaintGuid,
972 FormId,
973 NULL,
974 NULL
975 );
976 return TRUE;
977 }
978
979 /**
980 Create boot option base on the input file path info.
981
982 @param FilePath Point to the file path.
983
984 @retval TRUE Exit caller function.
985 @retval FALSE Not exit caller function.
986 **/
987 BOOLEAN
988 EFIAPI
989 CreateBootOptionFromFile (
990 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
991 )
992 {
993 return ReSendForm (FilePath, FORM_BOOT_ADD_ID);
994 }
995
996 /**
997 Create driver option base on the input file path info.
998
999 @param FilePath Point to the file path.
1000
1001 @retval TRUE Exit caller function.
1002 @retval FALSE Not exit caller function.
1003
1004 **/
1005 BOOLEAN
1006 EFIAPI
1007 CreateDriverOptionFromFile (
1008 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
1009 )
1010 {
1011 return ReSendForm (FilePath, FORM_DRV_ADD_FILE_ID);
1012 }