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