]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/UiApp/BootMaint/BootOption.c
1ad93bf6cf502b5709f67e32bbf5e3321fe42ab9
[mirror_edk2.git] / MdeModulePkg / Application / UiApp / BootMaint / 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) 2015, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include "BootMaint.h"
20
21 ///
22 /// Define the maximum characters that will be accepted.
23 ///
24 #define MAX_CHAR 480
25
26 /**
27 Create a menu entry by given menu type.
28
29 @param MenuType The Menu type to be created.
30
31 @retval NULL If failed to create the menu.
32 @return the new menu entry.
33
34 **/
35 BM_MENU_ENTRY *
36 BOpt_CreateMenuEntry (
37 UINTN MenuType
38 )
39 {
40 BM_MENU_ENTRY *MenuEntry;
41 UINTN ContextSize;
42
43 //
44 // Get context size according to menu type
45 //
46 switch (MenuType) {
47 case BM_LOAD_CONTEXT_SELECT:
48 ContextSize = sizeof (BM_LOAD_CONTEXT);
49 break;
50
51 case BM_FILE_CONTEXT_SELECT:
52 ContextSize = sizeof (BM_FILE_CONTEXT);
53 break;
54
55 case BM_CONSOLE_CONTEXT_SELECT:
56 ContextSize = sizeof (BM_CONSOLE_CONTEXT);
57 break;
58
59 case BM_TERMINAL_CONTEXT_SELECT:
60 ContextSize = sizeof (BM_TERMINAL_CONTEXT);
61 break;
62
63 case BM_HANDLE_CONTEXT_SELECT:
64 ContextSize = sizeof (BM_HANDLE_CONTEXT);
65 break;
66
67 default:
68 ContextSize = 0;
69 break;
70 }
71
72 if (ContextSize == 0) {
73 return NULL;
74 }
75
76 //
77 // Create new menu entry
78 //
79 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
80 if (MenuEntry == NULL) {
81 return NULL;
82 }
83
84 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
85 if (MenuEntry->VariableContext == NULL) {
86 FreePool (MenuEntry);
87 return NULL;
88 }
89
90 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
91 MenuEntry->ContextSelection = MenuType;
92 return MenuEntry;
93 }
94
95 /**
96 Free up all resource allocated for a BM_MENU_ENTRY.
97
98 @param MenuEntry A pointer to BM_MENU_ENTRY.
99
100 **/
101 VOID
102 BOpt_DestroyMenuEntry (
103 BM_MENU_ENTRY *MenuEntry
104 )
105 {
106 BM_LOAD_CONTEXT *LoadContext;
107 BM_FILE_CONTEXT *FileContext;
108 BM_CONSOLE_CONTEXT *ConsoleContext;
109 BM_TERMINAL_CONTEXT *TerminalContext;
110 BM_HANDLE_CONTEXT *HandleContext;
111
112 //
113 // Select by the type in Menu entry for current context type
114 //
115 switch (MenuEntry->ContextSelection) {
116 case BM_LOAD_CONTEXT_SELECT:
117 LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
118 FreePool (LoadContext->FilePathList);
119 FreePool (LoadContext->LoadOption);
120 if (LoadContext->OptionalData != NULL) {
121 FreePool (LoadContext->OptionalData);
122 }
123 FreePool (LoadContext);
124 break;
125
126 case BM_FILE_CONTEXT_SELECT:
127 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
128
129 if (!FileContext->IsRoot) {
130 FreePool (FileContext->DevicePath);
131 } else {
132 if (FileContext->FHandle != NULL) {
133 FileContext->FHandle->Close (FileContext->FHandle);
134 }
135 }
136
137 if (FileContext->FileName != NULL) {
138 FreePool (FileContext->FileName);
139 }
140 if (FileContext->Info != NULL) {
141 FreePool (FileContext->Info);
142 }
143 FreePool (FileContext);
144 break;
145
146 case BM_CONSOLE_CONTEXT_SELECT:
147 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
148 FreePool (ConsoleContext->DevicePath);
149 FreePool (ConsoleContext);
150 break;
151
152 case BM_TERMINAL_CONTEXT_SELECT:
153 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
154 FreePool (TerminalContext->DevicePath);
155 FreePool (TerminalContext);
156 break;
157
158 case BM_HANDLE_CONTEXT_SELECT:
159 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
160 FreePool (HandleContext);
161 break;
162
163 default:
164 break;
165 }
166
167 FreePool (MenuEntry->DisplayString);
168 if (MenuEntry->HelpString != NULL) {
169 FreePool (MenuEntry->HelpString);
170 }
171
172 FreePool (MenuEntry);
173 }
174
175 /**
176 Get the Menu Entry from the list in Menu Entry List.
177
178 If MenuNumber is great or equal to the number of Menu
179 Entry in the list, then ASSERT.
180
181 @param MenuOption The Menu Entry List to read the menu entry.
182 @param MenuNumber The index of Menu Entry.
183
184 @return The Menu Entry.
185
186 **/
187 BM_MENU_ENTRY *
188 BOpt_GetMenuEntry (
189 BM_MENU_OPTION *MenuOption,
190 UINTN MenuNumber
191 )
192 {
193 BM_MENU_ENTRY *NewMenuEntry;
194 UINTN Index;
195 LIST_ENTRY *List;
196
197 ASSERT (MenuNumber < MenuOption->MenuNumber);
198
199 List = MenuOption->Head.ForwardLink;
200 for (Index = 0; Index < MenuNumber; Index++) {
201 List = List->ForwardLink;
202 }
203
204 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
205
206 return NewMenuEntry;
207 }
208
209 /**
210 This function build the FsOptionMenu list which records all
211 available file system in the system. They includes all instances
212 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
213 and all type of legacy boot device.
214
215 @param CallbackData BMM context data
216
217 @retval EFI_SUCCESS Success find the file system
218 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
219
220 **/
221 EFI_STATUS
222 BOpt_FindFileSystem (
223 IN BMM_CALLBACK_DATA *CallbackData
224 )
225 {
226 UINTN NoBlkIoHandles;
227 UINTN NoSimpleFsHandles;
228 UINTN NoLoadFileHandles;
229 EFI_HANDLE *BlkIoHandle;
230 EFI_HANDLE *SimpleFsHandle;
231 EFI_HANDLE *LoadFileHandle;
232 UINT16 *VolumeLabel;
233 EFI_BLOCK_IO_PROTOCOL *BlkIo;
234 UINTN Index;
235 EFI_STATUS Status;
236 BM_MENU_ENTRY *MenuEntry;
237 BM_FILE_CONTEXT *FileContext;
238 UINT16 *TempStr;
239 UINTN OptionNumber;
240 VOID *Buffer;
241 BOOLEAN RemovableMedia;
242
243 NoSimpleFsHandles = 0;
244 NoLoadFileHandles = 0;
245 OptionNumber = 0;
246 InitializeListHead (&FsOptionMenu.Head);
247
248 //
249 // Locate Handles that support BlockIo protocol
250 //
251 Status = gBS->LocateHandleBuffer (
252 ByProtocol,
253 &gEfiBlockIoProtocolGuid,
254 NULL,
255 &NoBlkIoHandles,
256 &BlkIoHandle
257 );
258 if (!EFI_ERROR (Status)) {
259
260 for (Index = 0; Index < NoBlkIoHandles; Index++) {
261 Status = gBS->HandleProtocol (
262 BlkIoHandle[Index],
263 &gEfiBlockIoProtocolGuid,
264 (VOID **) &BlkIo
265 );
266
267 if (EFI_ERROR (Status)) {
268 continue;
269 }
270
271 //
272 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
273 //
274 if (BlkIo->Media->RemovableMedia) {
275 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
276 if (NULL == Buffer) {
277 FreePool (BlkIoHandle);
278 return EFI_OUT_OF_RESOURCES;
279 }
280
281 BlkIo->ReadBlocks (
282 BlkIo,
283 BlkIo->Media->MediaId,
284 0,
285 BlkIo->Media->BlockSize,
286 Buffer
287 );
288 FreePool (Buffer);
289 }
290 }
291 FreePool (BlkIoHandle);
292 }
293
294 //
295 // Locate Handles that support Simple File System protocol
296 //
297 Status = gBS->LocateHandleBuffer (
298 ByProtocol,
299 &gEfiSimpleFileSystemProtocolGuid,
300 NULL,
301 &NoSimpleFsHandles,
302 &SimpleFsHandle
303 );
304 if (!EFI_ERROR (Status)) {
305 //
306 // Find all the instances of the File System prototocol
307 //
308 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
309 Status = gBS->HandleProtocol (
310 SimpleFsHandle[Index],
311 &gEfiBlockIoProtocolGuid,
312 (VOID **) &BlkIo
313 );
314 if (EFI_ERROR (Status)) {
315 //
316 // If no block IO exists assume it's NOT a removable media
317 //
318 RemovableMedia = FALSE;
319 } else {
320 //
321 // If block IO exists check to see if it's remobable media
322 //
323 RemovableMedia = BlkIo->Media->RemovableMedia;
324 }
325
326 //
327 // Allocate pool for this load option
328 //
329 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
330 if (NULL == MenuEntry) {
331 FreePool (SimpleFsHandle);
332 return EFI_OUT_OF_RESOURCES;
333 }
334
335 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
336
337 FileContext->Handle = SimpleFsHandle[Index];
338 MenuEntry->OptionNumber = Index;
339 FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);
340 if (FileContext->FHandle == NULL) {
341 BOpt_DestroyMenuEntry (MenuEntry);
342 continue;
343 }
344
345 MenuEntry->HelpString = UiDevicePathToStr (DevicePathFromHandle (FileContext->Handle));
346 FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
347 FileContext->FileName = EfiStrDuplicate (L"\\");
348 FileContext->DevicePath = FileDevicePath (
349 FileContext->Handle,
350 FileContext->FileName
351 );
352 FileContext->IsDir = TRUE;
353 FileContext->IsRoot = TRUE;
354 FileContext->IsRemovableMedia = RemovableMedia;
355 FileContext->IsLoadFile = FALSE;
356
357 //
358 // Get current file system's Volume Label
359 //
360 if (FileContext->Info == NULL) {
361 VolumeLabel = L"NO FILE SYSTEM INFO";
362 } else {
363 if (FileContext->Info->VolumeLabel == NULL) {
364 VolumeLabel = L"NULL VOLUME LABEL";
365 } else {
366 VolumeLabel = FileContext->Info->VolumeLabel;
367 if (*VolumeLabel == 0x0000) {
368 VolumeLabel = L"NO VOLUME LABEL";
369 }
370 }
371 }
372
373 TempStr = MenuEntry->HelpString;
374 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
375 ASSERT (MenuEntry->DisplayString != NULL);
376 UnicodeSPrint (
377 MenuEntry->DisplayString,
378 MAX_CHAR,
379 L"%s, [%s]",
380 VolumeLabel,
381 TempStr
382 );
383 OptionNumber++;
384 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
385 }
386 }
387
388 if (NoSimpleFsHandles != 0) {
389 FreePool (SimpleFsHandle);
390 }
391 //
392 // Searching for handles that support Load File protocol
393 //
394 Status = gBS->LocateHandleBuffer (
395 ByProtocol,
396 &gEfiLoadFileProtocolGuid,
397 NULL,
398 &NoLoadFileHandles,
399 &LoadFileHandle
400 );
401
402 if (!EFI_ERROR (Status)) {
403 for (Index = 0; Index < NoLoadFileHandles; Index++) {
404 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
405 if (NULL == MenuEntry) {
406 FreePool (LoadFileHandle);
407 return EFI_OUT_OF_RESOURCES;
408 }
409
410 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
411 FileContext->IsRemovableMedia = FALSE;
412 FileContext->IsLoadFile = TRUE;
413 FileContext->Handle = LoadFileHandle[Index];
414 FileContext->IsRoot = TRUE;
415
416 FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);
417 FileContext->FileName = UiDevicePathToStr (FileContext->DevicePath);
418
419 MenuEntry->HelpString = UiDevicePathToStr (FileContext->DevicePath);
420
421 TempStr = MenuEntry->HelpString;
422 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
423 ASSERT (MenuEntry->DisplayString != NULL);
424 UnicodeSPrint (
425 MenuEntry->DisplayString,
426 MAX_CHAR,
427 L"Load File [%s]",
428 TempStr
429 );
430
431 MenuEntry->OptionNumber = OptionNumber;
432 OptionNumber++;
433 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
434 }
435 }
436
437 if (NoLoadFileHandles != 0) {
438 FreePool (LoadFileHandle);
439 }
440
441 //
442 // Remember how many file system options are here
443 //
444 FsOptionMenu.MenuNumber = OptionNumber;
445 return EFI_SUCCESS;
446 }
447
448 /**
449 Free resources allocated in Allocate Rountine.
450
451 @param FreeMenu Menu to be freed
452 **/
453 VOID
454 BOpt_FreeMenu (
455 BM_MENU_OPTION *FreeMenu
456 )
457 {
458 BM_MENU_ENTRY *MenuEntry;
459 while (!IsListEmpty (&FreeMenu->Head)) {
460 MenuEntry = CR (
461 FreeMenu->Head.ForwardLink,
462 BM_MENU_ENTRY,
463 Link,
464 BM_MENU_ENTRY_SIGNATURE
465 );
466 RemoveEntryList (&MenuEntry->Link);
467 BOpt_DestroyMenuEntry (MenuEntry);
468 }
469 FreeMenu->MenuNumber = 0;
470 }
471
472 /**
473 Find files under current directory
474 All files and sub-directories in current directory
475 will be stored in DirectoryMenu for future use.
476
477 @param CallbackData The BMM context data.
478 @param MenuEntry The Menu Entry.
479
480 @retval EFI_SUCCESS Get files from current dir successfully.
481 @return Other value if can't get files from current dir.
482
483 **/
484 EFI_STATUS
485 BOpt_FindFiles (
486 IN BMM_CALLBACK_DATA *CallbackData,
487 IN BM_MENU_ENTRY *MenuEntry
488 )
489 {
490 EFI_FILE_HANDLE NewDir;
491 EFI_FILE_HANDLE Dir;
492 EFI_FILE_INFO *DirInfo;
493 UINTN BufferSize;
494 UINTN DirBufferSize;
495 BM_MENU_ENTRY *NewMenuEntry;
496 BM_FILE_CONTEXT *FileContext;
497 BM_FILE_CONTEXT *NewFileContext;
498 UINTN Pass;
499 EFI_STATUS Status;
500 UINTN OptionNumber;
501
502 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
503 Dir = FileContext->FHandle;
504 OptionNumber = 0;
505 //
506 // Open current directory to get files from it
507 //
508 Status = Dir->Open (
509 Dir,
510 &NewDir,
511 FileContext->FileName,
512 EFI_FILE_READ_ONLY,
513 0
514 );
515 if (!FileContext->IsRoot) {
516 Dir->Close (Dir);
517 }
518
519 if (EFI_ERROR (Status)) {
520 return Status;
521 }
522
523 DirInfo = EfiLibFileInfo (NewDir);
524 if (DirInfo == NULL) {
525 return EFI_NOT_FOUND;
526 }
527
528 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
529 return EFI_INVALID_PARAMETER;
530 }
531
532 FileContext->DevicePath = FileDevicePath (
533 FileContext->Handle,
534 FileContext->FileName
535 );
536
537 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
538 DirInfo = AllocateZeroPool (DirBufferSize);
539 if (DirInfo == NULL) {
540 return EFI_OUT_OF_RESOURCES;
541 }
542 //
543 // Get all files in current directory
544 // Pass 1 to get Directories
545 // Pass 2 to get files that are EFI images
546 //
547 for (Pass = 1; Pass <= 2; Pass++) {
548 NewDir->SetPosition (NewDir, 0);
549 for (;;) {
550 BufferSize = DirBufferSize;
551 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
552 if (EFI_ERROR (Status) || BufferSize == 0) {
553 break;
554 }
555
556 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
557 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
558 ) {
559 //
560 // Pass 1 is for Directories
561 // Pass 2 is for file names
562 //
563 continue;
564 }
565
566 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {
567 //
568 // Slip file unless it is a directory entry or a .EFI file
569 //
570 continue;
571 }
572
573 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
574 if (NULL == NewMenuEntry) {
575 return EFI_OUT_OF_RESOURCES;
576 }
577
578 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
579 NewFileContext->Handle = FileContext->Handle;
580 NewFileContext->FileName = BOpt_AppendFileName (
581 FileContext->FileName,
582 DirInfo->FileName
583 );
584 NewFileContext->FHandle = NewDir;
585 NewFileContext->DevicePath = FileDevicePath (
586 NewFileContext->Handle,
587 NewFileContext->FileName
588 );
589 NewMenuEntry->HelpString = NULL;
590
591 MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
592 CallbackData,
593 FileOptionStrDepository
594 );
595
596 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
597
598 if (NewFileContext->IsDir) {
599 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
600 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
601
602 UnicodeSPrint (
603 NewMenuEntry->DisplayString,
604 BufferSize,
605 L"<%s>",
606 DirInfo->FileName
607 );
608
609 } else {
610 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
611 }
612
613 NewFileContext->IsRoot = FALSE;
614 NewFileContext->IsLoadFile = FALSE;
615 NewFileContext->IsRemovableMedia = FALSE;
616
617 NewMenuEntry->OptionNumber = OptionNumber;
618 OptionNumber++;
619 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
620 }
621 }
622
623 DirectoryMenu.MenuNumber = OptionNumber;
624 FreePool (DirInfo);
625 return EFI_SUCCESS;
626 }
627
628 /**
629
630 Build the BootOptionMenu according to BootOrder Variable.
631 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
632
633 @param CallbackData The BMM context data.
634
635 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
636 @return EFI_SUCESS Success build boot option menu.
637
638 **/
639 EFI_STATUS
640 BOpt_GetBootOptions (
641 IN BMM_CALLBACK_DATA *CallbackData
642 )
643 {
644 UINTN Index;
645 UINT16 BootString[10];
646 UINT8 *LoadOptionFromVar;
647 UINT8 *LoadOption;
648 UINTN BootOptionSize;
649 BOOLEAN BootNextFlag;
650 UINT16 *BootOrderList;
651 UINTN BootOrderListSize;
652 UINT16 *BootNext;
653 UINTN BootNextSize;
654 BM_MENU_ENTRY *NewMenuEntry;
655 BM_LOAD_CONTEXT *NewLoadContext;
656 UINT8 *LoadOptionPtr;
657 UINTN StringSize;
658 UINTN OptionalDataSize;
659 UINT8 *LoadOptionEnd;
660 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
661 UINTN MenuCount;
662 UINT8 *Ptr;
663 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
664 UINTN BootOptionCount;
665
666 MenuCount = 0;
667 BootOrderListSize = 0;
668 BootNextSize = 0;
669 BootOrderList = NULL;
670 BootNext = NULL;
671 LoadOptionFromVar = NULL;
672 BOpt_FreeMenu (&BootOptionMenu);
673 InitializeListHead (&BootOptionMenu.Head);
674
675 //
676 // Get the BootOrder from the Var
677 //
678 GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);
679 if (BootOrderList == NULL) {
680 return EFI_NOT_FOUND;
681 }
682
683 //
684 // Get the BootNext from the Var
685 //
686 GetEfiGlobalVariable2 (L"BootNext", (VOID **) &BootNext, &BootNextSize);
687 if (BootNext != NULL) {
688 if (BootNextSize != sizeof (UINT16)) {
689 FreePool (BootNext);
690 BootNext = NULL;
691 }
692 }
693 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
694 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
695 //
696 // Don't display the hidden/inactive boot option
697 //
698 if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
699 continue;
700 }
701
702 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
703 //
704 // Get all loadoptions from the VAR
705 //
706 GetEfiGlobalVariable2 (BootString, (VOID **) &LoadOptionFromVar, &BootOptionSize);
707 if (LoadOptionFromVar == NULL) {
708 continue;
709 }
710
711 LoadOption = AllocateZeroPool (BootOptionSize);
712 if (LoadOption == NULL) {
713 continue;
714 }
715
716 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
717 FreePool (LoadOptionFromVar);
718
719 if (BootNext != NULL) {
720 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
721 } else {
722 BootNextFlag = FALSE;
723 }
724
725 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
726 ASSERT (NULL != NewMenuEntry);
727
728 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
729
730 LoadOptionPtr = LoadOption;
731 LoadOptionEnd = LoadOption + BootOptionSize;
732
733 NewMenuEntry->OptionNumber = BootOrderList[Index];
734 NewLoadContext->LoadOptionModified = FALSE;
735 NewLoadContext->Deleted = FALSE;
736 NewLoadContext->IsBootNext = BootNextFlag;
737
738 //
739 // Is a Legacy Device?
740 //
741 Ptr = (UINT8 *) LoadOption;
742
743 //
744 // Attribute = *(UINT32 *)Ptr;
745 //
746 Ptr += sizeof (UINT32);
747
748 //
749 // FilePathSize = *(UINT16 *)Ptr;
750 //
751 Ptr += sizeof (UINT16);
752
753 //
754 // Description = (CHAR16 *)Ptr;
755 //
756 Ptr += StrSize ((CHAR16 *) Ptr);
757
758 //
759 // Now Ptr point to Device Path
760 //
761 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
762 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
763 NewLoadContext->IsLegacy = TRUE;
764 } else {
765 NewLoadContext->IsLegacy = FALSE;
766 }
767 //
768 // LoadOption is a pointer type of UINT8
769 // for easy use with following LOAD_OPTION
770 // embedded in this struct
771 //
772 NewLoadContext->LoadOption = LoadOption;
773 NewLoadContext->LoadOptionSize = BootOptionSize;
774
775 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
776 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
777
778 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
779
780 LoadOptionPtr += sizeof (UINT32);
781
782 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
783 LoadOptionPtr += sizeof (UINT16);
784
785 StringSize = StrSize((UINT16*)LoadOptionPtr);
786
787 NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));
788 ASSERT (NewLoadContext->Description != NULL);
789 StrCpy (NewLoadContext->Description, (UINT16*)LoadOptionPtr);
790
791 ASSERT (NewLoadContext->Description != NULL);
792 NewMenuEntry->DisplayString = NewLoadContext->Description;
793
794 LoadOptionPtr += StringSize;
795
796 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
797 ASSERT (NewLoadContext->FilePathList != NULL);
798 CopyMem (
799 NewLoadContext->FilePathList,
800 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
801 NewLoadContext->FilePathListLength
802 );
803
804 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
805 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
806 CallbackData,
807 BootOptionStrDepository
808 );
809 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
810 CallbackData,
811 BootOptionHelpStrDepository
812 );
813 LoadOptionPtr += NewLoadContext->FilePathListLength;
814
815 if (LoadOptionPtr < LoadOptionEnd) {
816 OptionalDataSize = BootOptionSize -
817 sizeof (UINT32) -
818 sizeof (UINT16) -
819 StringSize -
820 NewLoadContext->FilePathListLength;
821
822 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
823 ASSERT (NewLoadContext->OptionalData != NULL);
824 CopyMem (
825 NewLoadContext->OptionalData,
826 LoadOptionPtr,
827 OptionalDataSize
828 );
829
830 NewLoadContext->OptionalDataSize = OptionalDataSize;
831 }
832
833 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
834 MenuCount++;
835 }
836 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
837
838 if (BootNext != NULL) {
839 FreePool (BootNext);
840 }
841 if (BootOrderList != NULL) {
842 FreePool (BootOrderList);
843 }
844 BootOptionMenu.MenuNumber = MenuCount;
845 return EFI_SUCCESS;
846 }
847
848 /**
849
850 Append file name to existing file name.
851
852 @param Str1 The existing file name
853 @param Str2 The file name to be appended
854
855 @return Allocate a new string to hold the appended result.
856 Caller is responsible to free the returned string.
857
858 **/
859 CHAR16 *
860 BOpt_AppendFileName (
861 IN CHAR16 *Str1,
862 IN CHAR16 *Str2
863 )
864 {
865 UINTN Size1;
866 UINTN Size2;
867 CHAR16 *Str;
868 CHAR16 *TmpStr;
869 CHAR16 *Ptr;
870 CHAR16 *LastSlash;
871
872 Size1 = StrSize (Str1);
873 Size2 = StrSize (Str2);
874 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
875 ASSERT (Str != NULL);
876
877 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
878 ASSERT (TmpStr != NULL);
879
880 StrCat (Str, Str1);
881 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
882 StrCat (Str, L"\\");
883 }
884
885 StrCat (Str, Str2);
886
887 Ptr = Str;
888 LastSlash = Str;
889 while (*Ptr != 0) {
890 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
891 //
892 // Convert "\Name\..\" to "\"
893 // DO NOT convert the .. if it is at the end of the string. This will
894 // break the .. behavior in changing directories.
895 //
896
897 //
898 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
899 // that overlap.
900 //
901 StrCpy (TmpStr, Ptr + 3);
902 StrCpy (LastSlash, TmpStr);
903 Ptr = LastSlash;
904 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
905 //
906 // Convert a "\.\" to a "\"
907 //
908
909 //
910 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
911 // that overlap.
912 //
913 StrCpy (TmpStr, Ptr + 2);
914 StrCpy (Ptr, TmpStr);
915 Ptr = LastSlash;
916 } else if (*Ptr == '\\') {
917 LastSlash = Ptr;
918 }
919
920 Ptr++;
921 }
922
923 FreePool (TmpStr);
924
925 return Str;
926 }
927
928 /**
929
930 Check whether current FileName point to a valid
931 Efi Image File.
932
933 @param FileName File need to be checked.
934
935 @retval TRUE Is Efi Image
936 @retval FALSE Not a valid Efi Image
937
938 **/
939 BOOLEAN
940 BOpt_IsEfiImageName (
941 IN UINT16 *FileName
942 )
943 {
944 //
945 // Search for ".efi" extension
946 //
947 while (*FileName != L'\0') {
948 if (FileName[0] == '.') {
949 if (FileName[1] == 'e' || FileName[1] == 'E') {
950 if (FileName[2] == 'f' || FileName[2] == 'F') {
951 if (FileName[3] == 'i' || FileName[3] == 'I') {
952 return TRUE;
953 } else if (FileName[3] == 0x0000) {
954 return FALSE;
955 }
956 } else if (FileName[2] == 0x0000) {
957 return FALSE;
958 }
959 } else if (FileName[1] == 0x0000) {
960 return FALSE;
961 }
962 }
963
964 FileName += 1;
965 }
966
967 return FALSE;
968 }
969
970 /**
971
972 Check whether current FileName point to a valid Efi Application
973
974 @param Dir Pointer to current Directory
975 @param FileName Pointer to current File name.
976
977 @retval TRUE Is a valid Efi Application
978 @retval FALSE not a valid Efi Application
979
980 **/
981 BOOLEAN
982 BOpt_IsEfiApp (
983 IN EFI_FILE_HANDLE Dir,
984 IN UINT16 *FileName
985 )
986 {
987 UINTN BufferSize;
988 EFI_IMAGE_DOS_HEADER DosHdr;
989 UINT16 Subsystem;
990 EFI_FILE_HANDLE File;
991 EFI_STATUS Status;
992 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
993
994 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
995
996 if (EFI_ERROR (Status)) {
997 return FALSE;
998 }
999
1000 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1001 File->Read (File, &BufferSize, &DosHdr);
1002 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1003 File->Close (File);
1004 return FALSE;
1005 }
1006
1007 File->SetPosition (File, DosHdr.e_lfanew);
1008 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1009 File->Read (File, &BufferSize, &PeHdr);
1010 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
1011 File->Close (File);
1012 return FALSE;
1013 }
1014 //
1015 // Determine PE type and read subsytem
1016 //
1017 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1018 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
1019 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1020 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
1021 } else {
1022 return FALSE;
1023 }
1024
1025 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1026 File->Close (File);
1027 return TRUE;
1028 } else {
1029 File->Close (File);
1030 return FALSE;
1031 }
1032 }
1033
1034 /**
1035
1036 Find drivers that will be added as Driver#### variables from handles
1037 in current system environment
1038 All valid handles in the system except those consume SimpleFs, LoadFile
1039 are stored in DriverMenu for future use.
1040
1041 @retval EFI_SUCCESS The function complets successfully.
1042 @return Other value if failed to build the DriverMenu.
1043
1044 **/
1045 EFI_STATUS
1046 BOpt_FindDrivers (
1047 VOID
1048 )
1049 {
1050 UINTN NoDevicePathHandles;
1051 EFI_HANDLE *DevicePathHandle;
1052 UINTN Index;
1053 EFI_STATUS Status;
1054 BM_MENU_ENTRY *NewMenuEntry;
1055 BM_HANDLE_CONTEXT *NewHandleContext;
1056 EFI_HANDLE CurHandle;
1057 UINTN OptionNumber;
1058 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
1059 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1060
1061 SimpleFs = NULL;
1062 LoadFile = NULL;
1063
1064 InitializeListHead (&DriverMenu.Head);
1065
1066 //
1067 // At first, get all handles that support Device Path
1068 // protocol which is the basic requirement for
1069 // Driver####
1070 //
1071 Status = gBS->LocateHandleBuffer (
1072 ByProtocol,
1073 &gEfiDevicePathProtocolGuid,
1074 NULL,
1075 &NoDevicePathHandles,
1076 &DevicePathHandle
1077 );
1078 if (EFI_ERROR (Status)) {
1079 return Status;
1080 }
1081
1082 OptionNumber = 0;
1083 for (Index = 0; Index < NoDevicePathHandles; Index++) {
1084 CurHandle = DevicePathHandle[Index];
1085
1086 Status = gBS->HandleProtocol (
1087 CurHandle,
1088 &gEfiSimpleFileSystemProtocolGuid,
1089 (VOID **) &SimpleFs
1090 );
1091 if (Status == EFI_SUCCESS) {
1092 continue;
1093 }
1094
1095 Status = gBS->HandleProtocol (
1096 CurHandle,
1097 &gEfiLoadFileProtocolGuid,
1098 (VOID **) &LoadFile
1099 );
1100 if (Status == EFI_SUCCESS) {
1101 continue;
1102 }
1103
1104 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
1105 if (NULL == NewMenuEntry) {
1106 FreePool (DevicePathHandle);
1107 return EFI_OUT_OF_RESOURCES;
1108 }
1109
1110 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
1111 NewHandleContext->Handle = CurHandle;
1112 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
1113 NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);
1114 NewMenuEntry->HelpString = NULL;
1115 NewMenuEntry->OptionNumber = OptionNumber;
1116 OptionNumber++;
1117 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
1118
1119 }
1120
1121 if (DevicePathHandle != NULL) {
1122 FreePool (DevicePathHandle);
1123 }
1124
1125 DriverMenu.MenuNumber = OptionNumber;
1126 return EFI_SUCCESS;
1127 }
1128
1129 /**
1130
1131 Get the Option Number that has not been allocated for use.
1132
1133 @param Type The type of Option.
1134
1135 @return The available Option Number.
1136
1137 **/
1138 UINT16
1139 BOpt_GetOptionNumber (
1140 CHAR16 *Type
1141 )
1142 {
1143 UINT16 *OrderList;
1144 UINTN OrderListSize;
1145 UINTN Index;
1146 CHAR16 StrTemp[20];
1147 UINT16 *OptionBuffer;
1148 UINT16 OptionNumber;
1149 UINTN OptionSize;
1150
1151 OrderListSize = 0;
1152 OrderList = NULL;
1153 OptionNumber = 0;
1154 Index = 0;
1155
1156 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
1157
1158 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &OrderListSize);
1159 for (OptionNumber = 0; ; OptionNumber++) {
1160 if (OrderList != NULL) {
1161 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
1162 if (OptionNumber == OrderList[Index]) {
1163 break;
1164 }
1165 }
1166 }
1167
1168 if (Index < OrderListSize / sizeof (UINT16)) {
1169 //
1170 // The OptionNumber occurs in the OrderList, continue to use next one
1171 //
1172 continue;
1173 }
1174 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);
1175 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));
1176 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &OptionSize);
1177 if (NULL == OptionBuffer) {
1178 //
1179 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
1180 //
1181 break;
1182 }
1183 }
1184
1185 return OptionNumber;
1186 }
1187
1188 /**
1189
1190 Get the Option Number for Boot#### that does not used.
1191
1192 @return The available Option Number.
1193
1194 **/
1195 UINT16
1196 BOpt_GetBootOptionNumber (
1197 VOID
1198 )
1199 {
1200 return BOpt_GetOptionNumber (L"Boot");
1201 }
1202
1203 /**
1204
1205 Get the Option Number for Driver#### that does not used.
1206
1207 @return The unused Option Number.
1208
1209 **/
1210 UINT16
1211 BOpt_GetDriverOptionNumber (
1212 VOID
1213 )
1214 {
1215 return BOpt_GetOptionNumber (L"Driver");
1216 }
1217
1218 /**
1219
1220 Build up all DriverOptionMenu
1221
1222 @param CallbackData The BMM context data.
1223
1224 @retval EFI_SUCESS The functin completes successfully.
1225 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1226 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
1227
1228 **/
1229 EFI_STATUS
1230 BOpt_GetDriverOptions (
1231 IN BMM_CALLBACK_DATA *CallbackData
1232 )
1233 {
1234 UINTN Index;
1235 UINT16 DriverString[12];
1236 UINT8 *LoadOptionFromVar;
1237 UINT8 *LoadOption;
1238 UINTN DriverOptionSize;
1239
1240 UINT16 *DriverOrderList;
1241 UINTN DriverOrderListSize;
1242 BM_MENU_ENTRY *NewMenuEntry;
1243 BM_LOAD_CONTEXT *NewLoadContext;
1244 UINT8 *LoadOptionPtr;
1245 UINTN StringSize;
1246 UINTN OptionalDataSize;
1247 UINT8 *LoadOptionEnd;
1248
1249 DriverOrderListSize = 0;
1250 DriverOrderList = NULL;
1251 DriverOptionSize = 0;
1252 LoadOptionFromVar = NULL;
1253 BOpt_FreeMenu (&DriverOptionMenu);
1254 InitializeListHead (&DriverOptionMenu.Head);
1255 //
1256 // Get the DriverOrder from the Var
1257 //
1258 GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
1259 if (DriverOrderList == NULL) {
1260 return EFI_NOT_FOUND;
1261 }
1262
1263 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1264 UnicodeSPrint (
1265 DriverString,
1266 sizeof (DriverString),
1267 L"Driver%04x",
1268 DriverOrderList[Index]
1269 );
1270 //
1271 // Get all loadoptions from the VAR
1272 //
1273 GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);
1274 if (LoadOptionFromVar == NULL) {
1275 continue;
1276 }
1277
1278 LoadOption = AllocateZeroPool (DriverOptionSize);
1279 if (LoadOption == NULL) {
1280 continue;
1281 }
1282
1283 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
1284 FreePool (LoadOptionFromVar);
1285
1286 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
1287 if (NULL == NewMenuEntry) {
1288 return EFI_OUT_OF_RESOURCES;
1289 }
1290
1291 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1292 LoadOptionPtr = LoadOption;
1293 LoadOptionEnd = LoadOption + DriverOptionSize;
1294 NewMenuEntry->OptionNumber = DriverOrderList[Index];
1295 NewLoadContext->LoadOptionModified = FALSE;
1296 NewLoadContext->Deleted = FALSE;
1297 NewLoadContext->IsLegacy = FALSE;
1298
1299 //
1300 // LoadOption is a pointer type of UINT8
1301 // for easy use with following LOAD_OPTION
1302 // embedded in this struct
1303 //
1304 NewLoadContext->LoadOption = LoadOption;
1305 NewLoadContext->LoadOptionSize = DriverOptionSize;
1306
1307 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1308 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1309
1310 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1311
1312 LoadOptionPtr += sizeof (UINT32);
1313
1314 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1315 LoadOptionPtr += sizeof (UINT16);
1316
1317 StringSize = StrSize ((UINT16 *) LoadOptionPtr);
1318 NewLoadContext->Description = AllocateZeroPool (StringSize);
1319 ASSERT (NewLoadContext->Description != NULL);
1320 CopyMem (
1321 NewLoadContext->Description,
1322 (UINT16 *) LoadOptionPtr,
1323 StringSize
1324 );
1325 NewMenuEntry->DisplayString = NewLoadContext->Description;
1326
1327 LoadOptionPtr += StringSize;
1328
1329 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1330 ASSERT (NewLoadContext->FilePathList != NULL);
1331 CopyMem (
1332 NewLoadContext->FilePathList,
1333 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1334 NewLoadContext->FilePathListLength
1335 );
1336
1337 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
1338 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1339 CallbackData,
1340 DriverOptionStrDepository
1341 );
1342 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1343 CallbackData,
1344 DriverOptionHelpStrDepository
1345 );
1346 LoadOptionPtr += NewLoadContext->FilePathListLength;
1347
1348 if (LoadOptionPtr < LoadOptionEnd) {
1349 OptionalDataSize = DriverOptionSize -
1350 sizeof (UINT32) -
1351 sizeof (UINT16) -
1352 StringSize -
1353 NewLoadContext->FilePathListLength;
1354
1355 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1356 ASSERT (NewLoadContext->OptionalData != NULL);
1357 CopyMem (
1358 NewLoadContext->OptionalData,
1359 LoadOptionPtr,
1360 OptionalDataSize
1361 );
1362
1363 NewLoadContext->OptionalDataSize = OptionalDataSize;
1364 }
1365
1366 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
1367
1368 }
1369
1370 if (DriverOrderList != NULL) {
1371 FreePool (DriverOrderList);
1372 }
1373 DriverOptionMenu.MenuNumber = Index;
1374 return EFI_SUCCESS;
1375
1376 }
1377
1378 /**
1379 Get option number according to Boot#### and BootOrder variable.
1380 The value is saved as #### + 1.
1381
1382 @param CallbackData The BMM context data.
1383 **/
1384 VOID
1385 GetBootOrder (
1386 IN BMM_CALLBACK_DATA *CallbackData
1387 )
1388 {
1389 BMM_FAKE_NV_DATA *BmmConfig;
1390 UINT16 Index;
1391 UINT16 OptionOrderIndex;
1392 UINTN DeviceType;
1393 BM_MENU_ENTRY *NewMenuEntry;
1394 BM_LOAD_CONTEXT *NewLoadContext;
1395
1396 ASSERT (CallbackData != NULL);
1397
1398 DeviceType = (UINTN) -1;
1399 BmmConfig = &CallbackData->BmmFakeNvData;
1400 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
1401
1402 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
1403 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
1404 Index++) {
1405 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
1406 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1407
1408 if (NewLoadContext->IsLegacy) {
1409 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
1410 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
1411 } else {
1412 //
1413 // Only show one legacy boot option for the same device type
1414 // assuming the boot options are grouped by the device type
1415 //
1416 continue;
1417 }
1418 }
1419 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
1420 }
1421 }
1422
1423 /**
1424 Get driver option order from globalc DriverOptionMenu.
1425
1426 @param CallbackData The BMM context data.
1427
1428 **/
1429 VOID
1430 GetDriverOrder (
1431 IN BMM_CALLBACK_DATA *CallbackData
1432 )
1433 {
1434 BMM_FAKE_NV_DATA *BmmConfig;
1435 UINT16 Index;
1436 UINT16 OptionOrderIndex;
1437 UINTN DeviceType;
1438 BM_MENU_ENTRY *NewMenuEntry;
1439 BM_LOAD_CONTEXT *NewLoadContext;
1440
1441
1442 ASSERT (CallbackData != NULL);
1443
1444 DeviceType = (UINTN) -1;
1445 BmmConfig = &CallbackData->BmmFakeNvData;
1446 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
1447
1448 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
1449 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
1450 Index++) {
1451 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
1452 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1453
1454 if (NewLoadContext->IsLegacy) {
1455 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
1456 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
1457 } else {
1458 //
1459 // Only show one legacy boot option for the same device type
1460 // assuming the boot options are grouped by the device type
1461 //
1462 continue;
1463 }
1464 }
1465 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
1466 }
1467 }
1468
1469