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