]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
96fe935d6b15d2893c228efd76935200c919f5dd
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / 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) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include "BootMaint.h"
14 #include "BBSsupport.h"
15
16 /**
17 Create a menu entry by given menu type.
18
19 @param MenuType The Menu type to be created.
20
21 @retval NULL If failed to create the menu.
22 @return the new menu entry.
23
24 **/
25 BM_MENU_ENTRY *
26 BOpt_CreateMenuEntry (
27 UINTN MenuType
28 )
29 {
30 BM_MENU_ENTRY *MenuEntry;
31 UINTN ContextSize;
32
33 //
34 // Get context size according to menu type
35 //
36 switch (MenuType) {
37 case BM_LOAD_CONTEXT_SELECT:
38 ContextSize = sizeof (BM_LOAD_CONTEXT);
39 break;
40
41 case BM_FILE_CONTEXT_SELECT:
42 ContextSize = sizeof (BM_FILE_CONTEXT);
43 break;
44
45 case BM_CONSOLE_CONTEXT_SELECT:
46 ContextSize = sizeof (BM_CONSOLE_CONTEXT);
47 break;
48
49 case BM_TERMINAL_CONTEXT_SELECT:
50 ContextSize = sizeof (BM_TERMINAL_CONTEXT);
51 break;
52
53 case BM_HANDLE_CONTEXT_SELECT:
54 ContextSize = sizeof (BM_HANDLE_CONTEXT);
55 break;
56
57 case BM_LEGACY_DEV_CONTEXT_SELECT:
58 ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);
59 break;
60
61 default:
62 ContextSize = 0;
63 break;
64 }
65
66 if (ContextSize == 0) {
67 return NULL;
68 }
69
70 //
71 // Create new menu entry
72 //
73 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
74 if (MenuEntry == NULL) {
75 return NULL;
76 }
77
78 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
79 if (MenuEntry->VariableContext == NULL) {
80 FreePool (MenuEntry);
81 return NULL;
82 }
83
84 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
85 MenuEntry->ContextSelection = MenuType;
86 return MenuEntry;
87 }
88
89 /**
90 Free up all resource allocated for a BM_MENU_ENTRY.
91
92 @param MenuEntry A pointer to BM_MENU_ENTRY.
93
94 **/
95 VOID
96 BOpt_DestroyMenuEntry (
97 BM_MENU_ENTRY *MenuEntry
98 )
99 {
100 BM_LOAD_CONTEXT *LoadContext;
101 BM_FILE_CONTEXT *FileContext;
102 BM_CONSOLE_CONTEXT *ConsoleContext;
103 BM_TERMINAL_CONTEXT *TerminalContext;
104 BM_HANDLE_CONTEXT *HandleContext;
105 BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext;
106
107 //
108 // Select by the type in Menu entry for current context type
109 //
110 switch (MenuEntry->ContextSelection) {
111 case BM_LOAD_CONTEXT_SELECT:
112 LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
113 FreePool (LoadContext->FilePathList);
114 FreePool (LoadContext->LoadOption);
115 if (LoadContext->OptionalData != NULL) {
116 FreePool (LoadContext->OptionalData);
117 }
118 FreePool (LoadContext);
119 break;
120
121 case BM_FILE_CONTEXT_SELECT:
122 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
123
124 if (!FileContext->IsRoot) {
125 FreePool (FileContext->DevicePath);
126 } else {
127 if (FileContext->FHandle != NULL) {
128 FileContext->FHandle->Close (FileContext->FHandle);
129 }
130 }
131
132 if (FileContext->FileName != NULL) {
133 FreePool (FileContext->FileName);
134 }
135 if (FileContext->Info != NULL) {
136 FreePool (FileContext->Info);
137 }
138 FreePool (FileContext);
139 break;
140
141 case BM_CONSOLE_CONTEXT_SELECT:
142 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
143 FreePool (ConsoleContext->DevicePath);
144 FreePool (ConsoleContext);
145 break;
146
147 case BM_TERMINAL_CONTEXT_SELECT:
148 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
149 FreePool (TerminalContext->DevicePath);
150 FreePool (TerminalContext);
151 break;
152
153 case BM_HANDLE_CONTEXT_SELECT:
154 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
155 FreePool (HandleContext);
156 break;
157
158 case BM_LEGACY_DEV_CONTEXT_SELECT:
159 LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;
160 FreePool (LegacyDevContext);
161
162 default:
163 break;
164 }
165
166 FreePool (MenuEntry->DisplayString);
167 if (MenuEntry->HelpString != NULL) {
168 FreePool (MenuEntry->HelpString);
169 }
170
171 FreePool (MenuEntry);
172 }
173
174 /**
175 Get the Menu Entry from the list in Menu Entry List.
176
177 If MenuNumber is great or equal to the number of Menu
178 Entry in the list, then ASSERT.
179
180 @param MenuOption The Menu Entry List to read the menu entry.
181 @param MenuNumber The index of Menu Entry.
182
183 @return The Menu Entry.
184
185 **/
186 BM_MENU_ENTRY *
187 BOpt_GetMenuEntry (
188 BM_MENU_OPTION *MenuOption,
189 UINTN MenuNumber
190 )
191 {
192 BM_MENU_ENTRY *NewMenuEntry;
193 UINTN Index;
194 LIST_ENTRY *List;
195
196 ASSERT (MenuNumber < MenuOption->MenuNumber);
197
198 List = MenuOption->Head.ForwardLink;
199 for (Index = 0; Index < MenuNumber; Index++) {
200 List = List->ForwardLink;
201 }
202
203 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
204
205 return NewMenuEntry;
206 }
207
208 /**
209 This function build the FsOptionMenu list which records all
210 available file system in the system. They includes all instances
211 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
212 and all type of legacy boot device.
213
214 @param CallbackData BMM context data
215
216 @retval EFI_SUCCESS Success find the file system
217 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
218
219 **/
220 EFI_STATUS
221 BOpt_FindFileSystem (
222 IN BMM_CALLBACK_DATA *CallbackData
223 )
224 {
225 UINTN NoBlkIoHandles;
226 UINTN NoSimpleFsHandles;
227 UINTN NoLoadFileHandles;
228 EFI_HANDLE *BlkIoHandle;
229 EFI_HANDLE *SimpleFsHandle;
230 EFI_HANDLE *LoadFileHandle;
231 UINT16 *VolumeLabel;
232 EFI_BLOCK_IO_PROTOCOL *BlkIo;
233 UINTN Index;
234 EFI_STATUS Status;
235 BM_MENU_ENTRY *MenuEntry;
236 BM_FILE_CONTEXT *FileContext;
237 UINT16 *TempStr;
238 UINTN OptionNumber;
239 VOID *Buffer;
240 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
241 UINT16 DeviceType;
242 BBS_BBS_DEVICE_PATH BbsDevicePathNode;
243 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
244 BOOLEAN RemovableMedia;
245
246
247 NoSimpleFsHandles = 0;
248 NoLoadFileHandles = 0;
249 OptionNumber = 0;
250 InitializeListHead (&FsOptionMenu.Head);
251
252 //
253 // Locate Handles that support BlockIo protocol
254 //
255 Status = gBS->LocateHandleBuffer (
256 ByProtocol,
257 &gEfiBlockIoProtocolGuid,
258 NULL,
259 &NoBlkIoHandles,
260 &BlkIoHandle
261 );
262 if (!EFI_ERROR (Status)) {
263
264 for (Index = 0; Index < NoBlkIoHandles; Index++) {
265 Status = gBS->HandleProtocol (
266 BlkIoHandle[Index],
267 &gEfiBlockIoProtocolGuid,
268 (VOID **) &BlkIo
269 );
270
271 if (EFI_ERROR (Status)) {
272 continue;
273 }
274
275 //
276 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
277 //
278 if (BlkIo->Media->RemovableMedia) {
279 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
280 if (NULL == Buffer) {
281 FreePool (BlkIoHandle);
282 return EFI_OUT_OF_RESOURCES;
283 }
284
285 BlkIo->ReadBlocks (
286 BlkIo,
287 BlkIo->Media->MediaId,
288 0,
289 BlkIo->Media->BlockSize,
290 Buffer
291 );
292 FreePool (Buffer);
293 }
294 }
295 FreePool (BlkIoHandle);
296 }
297
298 //
299 // Locate Handles that support Simple File System protocol
300 //
301 Status = gBS->LocateHandleBuffer (
302 ByProtocol,
303 &gEfiSimpleFileSystemProtocolGuid,
304 NULL,
305 &NoSimpleFsHandles,
306 &SimpleFsHandle
307 );
308 if (!EFI_ERROR (Status)) {
309 //
310 // Find all the instances of the File System prototocol
311 //
312 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
313 Status = gBS->HandleProtocol (
314 SimpleFsHandle[Index],
315 &gEfiBlockIoProtocolGuid,
316 (VOID **) &BlkIo
317 );
318 if (EFI_ERROR (Status)) {
319 //
320 // If no block IO exists assume it's NOT a removable media
321 //
322 RemovableMedia = FALSE;
323 } else {
324 //
325 // If block IO exists check to see if it's remobable media
326 //
327 RemovableMedia = BlkIo->Media->RemovableMedia;
328 }
329
330 //
331 // Allocate pool for this load option
332 //
333 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
334 if (NULL == MenuEntry) {
335 FreePool (SimpleFsHandle);
336 return EFI_OUT_OF_RESOURCES;
337 }
338
339 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
340
341 FileContext->Handle = SimpleFsHandle[Index];
342 MenuEntry->OptionNumber = Index;
343 FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);
344 if (FileContext->FHandle == NULL) {
345 BOpt_DestroyMenuEntry (MenuEntry);
346 continue;
347 }
348
349 MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
350 FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
351 FileContext->FileName = EfiStrDuplicate (L"\\");
352 FileContext->DevicePath = FileDevicePath (
353 FileContext->Handle,
354 FileContext->FileName
355 );
356 FileContext->IsDir = TRUE;
357 FileContext->IsRoot = TRUE;
358 FileContext->IsRemovableMedia = RemovableMedia;
359 FileContext->IsLoadFile = FALSE;
360
361 //
362 // Get current file system's Volume Label
363 //
364 if (FileContext->Info == NULL) {
365 VolumeLabel = L"NO FILE SYSTEM INFO";
366 } else {
367 VolumeLabel = FileContext->Info->VolumeLabel;
368 if (*VolumeLabel == 0x0000) {
369 VolumeLabel = L"NO VOLUME LABEL";
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 = DevicePathToStr (FileContext->DevicePath);
418
419 MenuEntry->HelpString = DevicePathToStr (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 // Add Legacy Boot Option Support Here
443 //
444 Status = gBS->LocateProtocol (
445 &gEfiLegacyBiosProtocolGuid,
446 NULL,
447 (VOID **) &LegacyBios
448 );
449 if (!EFI_ERROR (Status)) {
450
451 for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
452 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
453 if (NULL == MenuEntry) {
454 return EFI_OUT_OF_RESOURCES;
455 }
456
457 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
458
459 FileContext->IsRemovableMedia = FALSE;
460 FileContext->IsLoadFile = TRUE;
461 FileContext->IsBootLegacy = TRUE;
462 DeviceType = (UINT16) Index;
463 BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
464 BbsDevicePathNode.Header.SubType = BBS_BBS_DP;
465 SetDevicePathNodeLength (
466 &BbsDevicePathNode.Header,
467 sizeof (BBS_BBS_DEVICE_PATH)
468 );
469 BbsDevicePathNode.DeviceType = DeviceType;
470 BbsDevicePathNode.StatusFlag = 0;
471 BbsDevicePathNode.String[0] = 0;
472 DevicePath = AppendDevicePathNode (
473 EndDevicePath,
474 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
475 );
476
477 FileContext->DevicePath = DevicePath;
478 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
479
480 TempStr = MenuEntry->HelpString;
481 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
482 ASSERT (MenuEntry->DisplayString != NULL);
483 UnicodeSPrint (
484 MenuEntry->DisplayString,
485 MAX_CHAR,
486 L"Boot Legacy [%s]",
487 TempStr
488 );
489 MenuEntry->OptionNumber = OptionNumber;
490 OptionNumber++;
491 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
492 }
493 }
494 //
495 // Remember how many file system options are here
496 //
497 FsOptionMenu.MenuNumber = OptionNumber;
498 return EFI_SUCCESS;
499 }
500
501 /**
502 Free resources allocated in Allocate Rountine.
503
504 @param FreeMenu Menu to be freed
505 **/
506 VOID
507 BOpt_FreeMenu (
508 BM_MENU_OPTION *FreeMenu
509 )
510 {
511 BM_MENU_ENTRY *MenuEntry;
512 while (!IsListEmpty (&FreeMenu->Head)) {
513 MenuEntry = CR (
514 FreeMenu->Head.ForwardLink,
515 BM_MENU_ENTRY,
516 Link,
517 BM_MENU_ENTRY_SIGNATURE
518 );
519 RemoveEntryList (&MenuEntry->Link);
520 BOpt_DestroyMenuEntry (MenuEntry);
521 }
522 FreeMenu->MenuNumber = 0;
523 }
524
525 /**
526 Find files under current directory
527 All files and sub-directories in current directory
528 will be stored in DirectoryMenu for future use.
529
530 @param CallbackData The BMM context data.
531 @param MenuEntry The Menu Entry.
532
533 @retval EFI_SUCCESS Get files from current dir successfully.
534 @return Other value if can't get files from current dir.
535
536 **/
537 EFI_STATUS
538 BOpt_FindFiles (
539 IN BMM_CALLBACK_DATA *CallbackData,
540 IN BM_MENU_ENTRY *MenuEntry
541 )
542 {
543 EFI_FILE_HANDLE NewDir;
544 EFI_FILE_HANDLE Dir;
545 EFI_FILE_INFO *DirInfo;
546 UINTN BufferSize;
547 UINTN DirBufferSize;
548 BM_MENU_ENTRY *NewMenuEntry;
549 BM_FILE_CONTEXT *FileContext;
550 BM_FILE_CONTEXT *NewFileContext;
551 UINTN Pass;
552 EFI_STATUS Status;
553 UINTN OptionNumber;
554
555 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
556 Dir = FileContext->FHandle;
557 OptionNumber = 0;
558 //
559 // Open current directory to get files from it
560 //
561 Status = Dir->Open (
562 Dir,
563 &NewDir,
564 FileContext->FileName,
565 EFI_FILE_READ_ONLY,
566 0
567 );
568 if (!FileContext->IsRoot) {
569 Dir->Close (Dir);
570 }
571
572 if (EFI_ERROR (Status)) {
573 return Status;
574 }
575
576 DirInfo = EfiLibFileInfo (NewDir);
577 if (DirInfo == NULL) {
578 return EFI_NOT_FOUND;
579 }
580
581 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
582 return EFI_INVALID_PARAMETER;
583 }
584
585 FileContext->DevicePath = FileDevicePath (
586 FileContext->Handle,
587 FileContext->FileName
588 );
589
590 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
591 DirInfo = AllocateZeroPool (DirBufferSize);
592 if (DirInfo == NULL) {
593 return EFI_OUT_OF_RESOURCES;
594 }
595 //
596 // Get all files in current directory
597 // Pass 1 to get Directories
598 // Pass 2 to get files that are EFI images
599 //
600 for (Pass = 1; Pass <= 2; Pass++) {
601 NewDir->SetPosition (NewDir, 0);
602 for (;;) {
603 BufferSize = DirBufferSize;
604 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
605 if (EFI_ERROR (Status) || BufferSize == 0) {
606 break;
607 }
608
609 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
610 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
611 ) {
612 //
613 // Pass 1 is for Directories
614 // Pass 2 is for file names
615 //
616 continue;
617 }
618
619 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {
620 //
621 // Slip file unless it is a directory entry or a .EFI file
622 //
623 continue;
624 }
625
626 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
627 if (NULL == NewMenuEntry) {
628 return EFI_OUT_OF_RESOURCES;
629 }
630
631 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
632 NewFileContext->Handle = FileContext->Handle;
633 NewFileContext->FileName = BOpt_AppendFileName (
634 FileContext->FileName,
635 DirInfo->FileName
636 );
637 NewFileContext->FHandle = NewDir;
638 NewFileContext->DevicePath = FileDevicePath (
639 NewFileContext->Handle,
640 NewFileContext->FileName
641 );
642 NewMenuEntry->HelpString = NULL;
643
644 MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
645 CallbackData,
646 FileOptionStrDepository
647 );
648
649 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
650
651 if (NewFileContext->IsDir) {
652 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
653 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
654
655 UnicodeSPrint (
656 NewMenuEntry->DisplayString,
657 BufferSize,
658 L"<%s>",
659 DirInfo->FileName
660 );
661
662 } else {
663 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
664 }
665
666 NewFileContext->IsRoot = FALSE;
667 NewFileContext->IsLoadFile = FALSE;
668 NewFileContext->IsRemovableMedia = FALSE;
669
670 NewMenuEntry->OptionNumber = OptionNumber;
671 OptionNumber++;
672 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
673 }
674 }
675
676 DirectoryMenu.MenuNumber = OptionNumber;
677 FreePool (DirInfo);
678 return EFI_SUCCESS;
679 }
680
681 /**
682 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
683
684 @retval EFI_SUCCESS The function complete successfully.
685 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
686
687 **/
688 EFI_STATUS
689 BOpt_GetLegacyOptions (
690 VOID
691 )
692 {
693 BM_MENU_ENTRY *NewMenuEntry;
694 BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
695 EFI_STATUS Status;
696 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
697 UINT16 HddCount;
698 HDD_INFO *HddInfo;
699 UINT16 BbsCount;
700 BBS_TABLE *BbsTable;
701 UINT16 Index;
702 CHAR16 DescString[100];
703 UINTN FDNum;
704 UINTN HDNum;
705 UINTN CDNum;
706 UINTN NETNum;
707 UINTN BEVNum;
708
709 NewMenuEntry = NULL;
710 HddInfo = NULL;
711 BbsTable = NULL;
712 BbsCount = 0;
713
714 //
715 // Initialize Bbs Table Context from BBS info data
716 //
717 InitializeListHead (&LegacyFDMenu.Head);
718 InitializeListHead (&LegacyHDMenu.Head);
719 InitializeListHead (&LegacyCDMenu.Head);
720 InitializeListHead (&LegacyNETMenu.Head);
721 InitializeListHead (&LegacyBEVMenu.Head);
722
723 Status = gBS->LocateProtocol (
724 &gEfiLegacyBiosProtocolGuid,
725 NULL,
726 (VOID **) &LegacyBios
727 );
728 if (!EFI_ERROR (Status)) {
729 Status = LegacyBios->GetBbsInfo (
730 LegacyBios,
731 &HddCount,
732 &HddInfo,
733 &BbsCount,
734 &BbsTable
735 );
736 if (EFI_ERROR (Status)) {
737 return Status;
738 }
739 }
740
741 FDNum = 0;
742 HDNum = 0;
743 CDNum = 0;
744 NETNum = 0;
745 BEVNum = 0;
746
747 for (Index = 0; Index < BbsCount; Index++) {
748 if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
749 (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
750 ) {
751 continue;
752 }
753
754 NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
755 if (NULL == NewMenuEntry) {
756 break;
757 }
758
759 NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
760 NewLegacyDevContext->BbsEntry = &BbsTable[Index];
761 NewLegacyDevContext->BbsIndex = Index;
762 NewLegacyDevContext->BbsCount = BbsCount;
763 BdsBuildLegacyDevNameString (
764 &BbsTable[Index],
765 Index,
766 sizeof (DescString),
767 DescString
768 );
769 NewLegacyDevContext->Description = AllocateCopyPool (StrSize (DescString), DescString);
770 if (NULL == NewLegacyDevContext->Description) {
771 break;
772 }
773
774 NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
775 NewMenuEntry->HelpString = NULL;
776
777 switch (BbsTable[Index].DeviceType) {
778 case BBS_FLOPPY:
779 InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
780 FDNum++;
781 break;
782
783 case BBS_HARDDISK:
784 InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
785 HDNum++;
786 break;
787
788 case BBS_CDROM:
789 InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
790 CDNum++;
791 break;
792
793 case BBS_EMBED_NETWORK:
794 InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
795 NETNum++;
796 break;
797
798 case BBS_BEV_DEVICE:
799 InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
800 BEVNum++;
801 break;
802 }
803 }
804
805 if (Index != BbsCount) {
806 BOpt_FreeLegacyOptions ();
807 return EFI_OUT_OF_RESOURCES;
808 }
809
810 LegacyFDMenu.MenuNumber = FDNum;
811 LegacyHDMenu.MenuNumber = HDNum;
812 LegacyCDMenu.MenuNumber = CDNum;
813 LegacyNETMenu.MenuNumber = NETNum;
814 LegacyBEVMenu.MenuNumber = BEVNum;
815 return EFI_SUCCESS;
816 }
817
818 /**
819 Free out resouce allocated from Legacy Boot Options.
820
821 **/
822 VOID
823 BOpt_FreeLegacyOptions (
824 VOID
825 )
826 {
827 BOpt_FreeMenu (&LegacyFDMenu);
828 BOpt_FreeMenu (&LegacyHDMenu);
829 BOpt_FreeMenu (&LegacyCDMenu);
830 BOpt_FreeMenu (&LegacyNETMenu);
831 BOpt_FreeMenu (&LegacyBEVMenu);
832 }
833
834 /**
835
836 Build the BootOptionMenu according to BootOrder Variable.
837 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
838
839 @param CallbackData The BMM context data.
840
841 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
842 @return EFI_SUCESS Success build boot option menu.
843
844 **/
845 EFI_STATUS
846 BOpt_GetBootOptions (
847 IN BMM_CALLBACK_DATA *CallbackData
848 )
849 {
850 UINTN Index;
851 UINT16 BootString[10];
852 UINT8 *LoadOptionFromVar;
853 UINT8 *LoadOption;
854 UINTN BootOptionSize;
855 BOOLEAN BootNextFlag;
856 UINT16 *BootOrderList;
857 UINTN BootOrderListSize;
858 UINT16 *BootNext;
859 UINTN BootNextSize;
860 BM_MENU_ENTRY *NewMenuEntry;
861 BM_LOAD_CONTEXT *NewLoadContext;
862 UINT8 *LoadOptionPtr;
863 UINTN StringSize;
864 UINTN OptionalDataSize;
865 UINT8 *LoadOptionEnd;
866 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
867 UINTN MenuCount;
868 UINT8 *Ptr;
869
870 MenuCount = 0;
871 BootOrderListSize = 0;
872 BootNextSize = 0;
873 BootOrderList = NULL;
874 BootNext = NULL;
875 LoadOptionFromVar = NULL;
876 BOpt_FreeMenu (&BootOptionMenu);
877 InitializeListHead (&BootOptionMenu.Head);
878
879 //
880 // Get the BootOrder from the Var
881 //
882 BootOrderList = BdsLibGetVariableAndSize (
883 L"BootOrder",
884 &gEfiGlobalVariableGuid,
885 &BootOrderListSize
886 );
887 if (BootOrderList == NULL) {
888 return EFI_NOT_FOUND;
889 }
890
891 //
892 // Get the BootNext from the Var
893 //
894 BootNext = BdsLibGetVariableAndSize (
895 L"BootNext",
896 &gEfiGlobalVariableGuid,
897 &BootNextSize
898 );
899
900 if (BootNext != NULL) {
901 if (BootNextSize != sizeof (UINT16)) {
902 FreePool (BootNext);
903 BootNext = NULL;
904 }
905 }
906
907 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
908 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
909 //
910 // Get all loadoptions from the VAR
911 //
912 LoadOptionFromVar = BdsLibGetVariableAndSize (
913 BootString,
914 &gEfiGlobalVariableGuid,
915 &BootOptionSize
916 );
917 if (LoadOptionFromVar == NULL) {
918 continue;
919 }
920
921 LoadOption = AllocateZeroPool (BootOptionSize);
922 if (LoadOption == NULL) {
923 continue;
924 }
925
926 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
927 FreePool (LoadOptionFromVar);
928
929 if (BootNext != NULL) {
930 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
931 } else {
932 BootNextFlag = FALSE;
933 }
934
935 if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
936 FreePool (LoadOption);
937 continue;
938 }
939 //
940 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
941 // the buffer allocated already should be freed before returning.
942 //
943 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
944 if (NULL == NewMenuEntry) {
945 return EFI_OUT_OF_RESOURCES;
946 }
947
948 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
949
950 LoadOptionPtr = LoadOption;
951 LoadOptionEnd = LoadOption + BootOptionSize;
952
953 NewMenuEntry->OptionNumber = BootOrderList[Index];
954 NewLoadContext->LoadOptionModified = FALSE;
955 NewLoadContext->Deleted = FALSE;
956 NewLoadContext->IsBootNext = BootNextFlag;
957
958 //
959 // Is a Legacy Device?
960 //
961 Ptr = (UINT8 *) LoadOption;
962
963 //
964 // Attribute = *(UINT32 *)Ptr;
965 //
966 Ptr += sizeof (UINT32);
967
968 //
969 // FilePathSize = *(UINT16 *)Ptr;
970 //
971 Ptr += sizeof (UINT16);
972
973 //
974 // Description = (CHAR16 *)Ptr;
975 //
976 Ptr += StrSize ((CHAR16 *) Ptr);
977
978 //
979 // Now Ptr point to Device Path
980 //
981 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
982 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
983 NewLoadContext->IsLegacy = TRUE;
984 } else {
985 NewLoadContext->IsLegacy = FALSE;
986 }
987 //
988 // LoadOption is a pointer type of UINT8
989 // for easy use with following LOAD_OPTION
990 // embedded in this struct
991 //
992 NewLoadContext->LoadOption = LoadOption;
993 NewLoadContext->LoadOptionSize = BootOptionSize;
994
995 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
996 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
997
998 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
999
1000 LoadOptionPtr += sizeof (UINT32);
1001
1002 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1003 LoadOptionPtr += sizeof (UINT16);
1004
1005 StringSize = StrSize((UINT16*)LoadOptionPtr);
1006
1007 NewLoadContext->Description = AllocateCopyPool (StrSize((UINT16*)LoadOptionPtr), LoadOptionPtr);
1008 ASSERT (NewLoadContext->Description != NULL);
1009
1010 NewMenuEntry->DisplayString = NewLoadContext->Description;
1011
1012 LoadOptionPtr += StringSize;
1013
1014 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1015 ASSERT (NewLoadContext->FilePathList != NULL);
1016 CopyMem (
1017 NewLoadContext->FilePathList,
1018 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1019 NewLoadContext->FilePathListLength
1020 );
1021
1022 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1023 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1024 CallbackData,
1025 BootOptionStrDepository
1026 );
1027 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1028 CallbackData,
1029 BootOptionHelpStrDepository
1030 );
1031 LoadOptionPtr += NewLoadContext->FilePathListLength;
1032
1033 if (LoadOptionPtr < LoadOptionEnd) {
1034 OptionalDataSize = BootOptionSize -
1035 sizeof (UINT32) -
1036 sizeof (UINT16) -
1037 StringSize -
1038 NewLoadContext->FilePathListLength;
1039
1040 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1041 ASSERT (NewLoadContext->OptionalData != NULL);
1042 CopyMem (
1043 NewLoadContext->OptionalData,
1044 LoadOptionPtr,
1045 OptionalDataSize
1046 );
1047
1048 NewLoadContext->OptionalDataSize = OptionalDataSize;
1049 }
1050
1051 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
1052 MenuCount++;
1053 }
1054
1055 if (BootNext != NULL) {
1056 FreePool (BootNext);
1057 }
1058 if (BootOrderList != NULL) {
1059 FreePool (BootOrderList);
1060 }
1061 BootOptionMenu.MenuNumber = MenuCount;
1062 return EFI_SUCCESS;
1063 }
1064
1065 /**
1066
1067 Append file name to existing file name.
1068
1069 @param Str1 The existing file name
1070 @param Str2 The file name to be appended
1071
1072 @return Allocate a new string to hold the appended result.
1073 Caller is responsible to free the returned string.
1074
1075 **/
1076 CHAR16 *
1077 BOpt_AppendFileName (
1078 IN CHAR16 *Str1,
1079 IN CHAR16 *Str2
1080 )
1081 {
1082 UINTN Size1;
1083 UINTN Size2;
1084 UINTN MaxLen;
1085 CHAR16 *Str;
1086 CHAR16 *TmpStr;
1087 CHAR16 *Ptr;
1088 CHAR16 *LastSlash;
1089
1090 Size1 = StrSize (Str1);
1091 Size2 = StrSize (Str2);
1092 MaxLen = (Size1 + Size2 + sizeof (CHAR16)) / sizeof (CHAR16);
1093 Str = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1094 ASSERT (Str != NULL);
1095
1096 TmpStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1097 ASSERT (TmpStr != NULL);
1098
1099 StrCatS (Str, MaxLen, Str1);
1100 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
1101 StrCatS (Str, MaxLen, L"\\");
1102 }
1103
1104 StrCatS (Str, MaxLen, Str2);
1105
1106 Ptr = Str;
1107 LastSlash = Str;
1108 while (*Ptr != 0) {
1109 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
1110 //
1111 // Convert "\Name\..\" to "\"
1112 // DO NOT convert the .. if it is at the end of the string. This will
1113 // break the .. behavior in changing directories.
1114 //
1115
1116 //
1117 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
1118 // that overlap.
1119 //
1120 StrCpyS (TmpStr, MaxLen, Ptr + 3);
1121 StrCpyS (LastSlash, MaxLen - ((UINTN) LastSlash - (UINTN) Str) / sizeof (CHAR16), TmpStr);
1122 Ptr = LastSlash;
1123 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
1124 //
1125 // Convert a "\.\" to a "\"
1126 //
1127
1128 //
1129 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
1130 // that overlap.
1131 //
1132 StrCpyS (TmpStr, MaxLen, Ptr + 2);
1133 StrCpyS (Ptr, MaxLen - ((UINTN) Ptr - (UINTN) Str) / sizeof (CHAR16), TmpStr);
1134 Ptr = LastSlash;
1135 } else if (*Ptr == '\\') {
1136 LastSlash = Ptr;
1137 }
1138
1139 Ptr++;
1140 }
1141
1142 FreePool (TmpStr);
1143
1144 return Str;
1145 }
1146
1147 /**
1148
1149 Check whether current FileName point to a valid
1150 Efi Image File.
1151
1152 @param FileName File need to be checked.
1153
1154 @retval TRUE Is Efi Image
1155 @retval FALSE Not a valid Efi Image
1156
1157 **/
1158 BOOLEAN
1159 BOpt_IsEfiImageName (
1160 IN UINT16 *FileName
1161 )
1162 {
1163 //
1164 // Search for ".efi" extension
1165 //
1166 while (*FileName != L'\0') {
1167 if (FileName[0] == '.') {
1168 if (FileName[1] == 'e' || FileName[1] == 'E') {
1169 if (FileName[2] == 'f' || FileName[2] == 'F') {
1170 if (FileName[3] == 'i' || FileName[3] == 'I') {
1171 return TRUE;
1172 } else if (FileName[3] == 0x0000) {
1173 return FALSE;
1174 }
1175 } else if (FileName[2] == 0x0000) {
1176 return FALSE;
1177 }
1178 } else if (FileName[1] == 0x0000) {
1179 return FALSE;
1180 }
1181 }
1182
1183 FileName += 1;
1184 }
1185
1186 return FALSE;
1187 }
1188
1189
1190
1191 /**
1192
1193 Find drivers that will be added as Driver#### variables from handles
1194 in current system environment
1195 All valid handles in the system except those consume SimpleFs, LoadFile
1196 are stored in DriverMenu for future use.
1197
1198 @retval EFI_SUCCESS The function complets successfully.
1199 @return Other value if failed to build the DriverMenu.
1200
1201 **/
1202 EFI_STATUS
1203 BOpt_FindDrivers (
1204 VOID
1205 )
1206 {
1207 UINTN NoDevicePathHandles;
1208 EFI_HANDLE *DevicePathHandle;
1209 UINTN Index;
1210 EFI_STATUS Status;
1211 BM_MENU_ENTRY *NewMenuEntry;
1212 BM_HANDLE_CONTEXT *NewHandleContext;
1213 EFI_HANDLE CurHandle;
1214 UINTN OptionNumber;
1215 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
1216 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1217
1218 SimpleFs = NULL;
1219 LoadFile = NULL;
1220
1221 InitializeListHead (&DriverMenu.Head);
1222
1223 //
1224 // At first, get all handles that support Device Path
1225 // protocol which is the basic requirement for
1226 // Driver####
1227 //
1228 Status = gBS->LocateHandleBuffer (
1229 ByProtocol,
1230 &gEfiDevicePathProtocolGuid,
1231 NULL,
1232 &NoDevicePathHandles,
1233 &DevicePathHandle
1234 );
1235 if (EFI_ERROR (Status)) {
1236 return Status;
1237 }
1238
1239 OptionNumber = 0;
1240 for (Index = 0; Index < NoDevicePathHandles; Index++) {
1241 CurHandle = DevicePathHandle[Index];
1242
1243 Status = gBS->HandleProtocol (
1244 CurHandle,
1245 &gEfiSimpleFileSystemProtocolGuid,
1246 (VOID **) &SimpleFs
1247 );
1248 if (Status == EFI_SUCCESS) {
1249 continue;
1250 }
1251
1252 Status = gBS->HandleProtocol (
1253 CurHandle,
1254 &gEfiLoadFileProtocolGuid,
1255 (VOID **) &LoadFile
1256 );
1257 if (Status == EFI_SUCCESS) {
1258 continue;
1259 }
1260
1261 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
1262 if (NULL == NewMenuEntry) {
1263 FreePool (DevicePathHandle);
1264 return EFI_OUT_OF_RESOURCES;
1265 }
1266
1267 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
1268 NewHandleContext->Handle = CurHandle;
1269 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
1270 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
1271 NewMenuEntry->HelpString = NULL;
1272 NewMenuEntry->OptionNumber = OptionNumber;
1273 OptionNumber++;
1274 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
1275
1276 }
1277
1278 if (DevicePathHandle != NULL) {
1279 FreePool (DevicePathHandle);
1280 }
1281
1282 DriverMenu.MenuNumber = OptionNumber;
1283 return EFI_SUCCESS;
1284 }
1285
1286 /**
1287
1288 Get the Option Number that has not been allocated for use.
1289
1290 @param Type The type of Option.
1291
1292 @return The available Option Number.
1293
1294 **/
1295 UINT16
1296 BOpt_GetOptionNumber (
1297 CHAR16 *Type
1298 )
1299 {
1300 UINT16 *OrderList;
1301 UINTN OrderListSize;
1302 UINTN Index;
1303 CHAR16 StrTemp[20];
1304 UINT16 *OptionBuffer;
1305 UINT16 OptionNumber;
1306 UINTN OptionSize;
1307
1308 OrderListSize = 0;
1309 OrderList = NULL;
1310 OptionNumber = 0;
1311 Index = 0;
1312
1313 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
1314
1315 OrderList = BdsLibGetVariableAndSize (
1316 StrTemp,
1317 &gEfiGlobalVariableGuid,
1318 &OrderListSize
1319 );
1320
1321 for (OptionNumber = 0; ; OptionNumber++) {
1322 if (OrderList != NULL) {
1323 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
1324 if (OptionNumber == OrderList[Index]) {
1325 break;
1326 }
1327 }
1328 }
1329
1330 if (Index < OrderListSize / sizeof (UINT16)) {
1331 //
1332 // The OptionNumber occurs in the OrderList, continue to use next one
1333 //
1334 continue;
1335 }
1336 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);
1337 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));
1338 OptionBuffer = BdsLibGetVariableAndSize (
1339 StrTemp,
1340 &gEfiGlobalVariableGuid,
1341 &OptionSize
1342 );
1343 if (NULL == OptionBuffer) {
1344 //
1345 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
1346 //
1347 break;
1348 }
1349 }
1350
1351 return OptionNumber;
1352 }
1353
1354 /**
1355
1356 Get the Option Number for Boot#### that does not used.
1357
1358 @return The available Option Number.
1359
1360 **/
1361 UINT16
1362 BOpt_GetBootOptionNumber (
1363 VOID
1364 )
1365 {
1366 return BOpt_GetOptionNumber (L"Boot");
1367 }
1368
1369 /**
1370
1371 Get the Option Number for Driver#### that does not used.
1372
1373 @return The unused Option Number.
1374
1375 **/
1376 UINT16
1377 BOpt_GetDriverOptionNumber (
1378 VOID
1379 )
1380 {
1381 return BOpt_GetOptionNumber (L"Driver");
1382 }
1383
1384 /**
1385
1386 Build up all DriverOptionMenu
1387
1388 @param CallbackData The BMM context data.
1389
1390 @retval EFI_SUCESS The functin completes successfully.
1391 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1392 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
1393
1394 **/
1395 EFI_STATUS
1396 BOpt_GetDriverOptions (
1397 IN BMM_CALLBACK_DATA *CallbackData
1398 )
1399 {
1400 UINTN Index;
1401 UINT16 DriverString[12];
1402 UINT8 *LoadOptionFromVar;
1403 UINT8 *LoadOption;
1404 UINTN DriverOptionSize;
1405
1406 UINT16 *DriverOrderList;
1407 UINTN DriverOrderListSize;
1408 BM_MENU_ENTRY *NewMenuEntry;
1409 BM_LOAD_CONTEXT *NewLoadContext;
1410 UINT8 *LoadOptionPtr;
1411 UINTN StringSize;
1412 UINTN OptionalDataSize;
1413 UINT8 *LoadOptionEnd;
1414
1415 DriverOrderListSize = 0;
1416 DriverOrderList = NULL;
1417 DriverOptionSize = 0;
1418 LoadOptionFromVar = NULL;
1419 BOpt_FreeMenu (&DriverOptionMenu);
1420 InitializeListHead (&DriverOptionMenu.Head);
1421 //
1422 // Get the DriverOrder from the Var
1423 //
1424 DriverOrderList = BdsLibGetVariableAndSize (
1425 L"DriverOrder",
1426 &gEfiGlobalVariableGuid,
1427 &DriverOrderListSize
1428 );
1429 if (DriverOrderList == NULL) {
1430 return EFI_NOT_FOUND;
1431 }
1432
1433 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1434 UnicodeSPrint (
1435 DriverString,
1436 sizeof (DriverString),
1437 L"Driver%04x",
1438 DriverOrderList[Index]
1439 );
1440 //
1441 // Get all loadoptions from the VAR
1442 //
1443 LoadOptionFromVar = BdsLibGetVariableAndSize (
1444 DriverString,
1445 &gEfiGlobalVariableGuid,
1446 &DriverOptionSize
1447 );
1448 if (LoadOptionFromVar == NULL) {
1449 continue;
1450 }
1451
1452 LoadOption = AllocateZeroPool (DriverOptionSize);
1453 if (LoadOption == NULL) {
1454 continue;
1455 }
1456
1457 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
1458 FreePool (LoadOptionFromVar);
1459
1460 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
1461 if (NULL == NewMenuEntry) {
1462 return EFI_OUT_OF_RESOURCES;
1463 }
1464
1465 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1466 LoadOptionPtr = LoadOption;
1467 LoadOptionEnd = LoadOption + DriverOptionSize;
1468 NewMenuEntry->OptionNumber = DriverOrderList[Index];
1469 NewLoadContext->LoadOptionModified = FALSE;
1470 NewLoadContext->Deleted = FALSE;
1471 NewLoadContext->IsLegacy = FALSE;
1472
1473 //
1474 // LoadOption is a pointer type of UINT8
1475 // for easy use with following LOAD_OPTION
1476 // embedded in this struct
1477 //
1478 NewLoadContext->LoadOption = LoadOption;
1479 NewLoadContext->LoadOptionSize = DriverOptionSize;
1480
1481 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1482 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1483
1484 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1485
1486 LoadOptionPtr += sizeof (UINT32);
1487
1488 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1489 LoadOptionPtr += sizeof (UINT16);
1490
1491 StringSize = StrSize ((UINT16 *) LoadOptionPtr);
1492 NewLoadContext->Description = AllocateZeroPool (StringSize);
1493 ASSERT (NewLoadContext->Description != NULL);
1494 CopyMem (
1495 NewLoadContext->Description,
1496 (UINT16 *) LoadOptionPtr,
1497 StringSize
1498 );
1499 NewMenuEntry->DisplayString = NewLoadContext->Description;
1500
1501 LoadOptionPtr += StringSize;
1502
1503 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1504 ASSERT (NewLoadContext->FilePathList != NULL);
1505 CopyMem (
1506 NewLoadContext->FilePathList,
1507 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1508 NewLoadContext->FilePathListLength
1509 );
1510
1511 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1512 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1513 CallbackData,
1514 DriverOptionStrDepository
1515 );
1516 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1517 CallbackData,
1518 DriverOptionHelpStrDepository
1519 );
1520 LoadOptionPtr += NewLoadContext->FilePathListLength;
1521
1522 if (LoadOptionPtr < LoadOptionEnd) {
1523 OptionalDataSize = DriverOptionSize -
1524 sizeof (UINT32) -
1525 sizeof (UINT16) -
1526 StringSize -
1527 NewLoadContext->FilePathListLength;
1528
1529 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1530 ASSERT (NewLoadContext->OptionalData != NULL);
1531 CopyMem (
1532 NewLoadContext->OptionalData,
1533 LoadOptionPtr,
1534 OptionalDataSize
1535 );
1536
1537 NewLoadContext->OptionalDataSize = OptionalDataSize;
1538 }
1539
1540 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
1541
1542 }
1543
1544 if (DriverOrderList != NULL) {
1545 FreePool (DriverOrderList);
1546 }
1547 DriverOptionMenu.MenuNumber = Index;
1548 return EFI_SUCCESS;
1549
1550 }
1551
1552 /**
1553 Get option number according to Boot#### and BootOrder variable.
1554 The value is saved as #### + 1.
1555
1556 @param CallbackData The BMM context data.
1557 **/
1558 VOID
1559 GetBootOrder (
1560 IN BMM_CALLBACK_DATA *CallbackData
1561 )
1562 {
1563 BMM_FAKE_NV_DATA *BmmConfig;
1564 UINT16 Index;
1565 UINT16 OptionOrderIndex;
1566 UINTN DeviceType;
1567 BM_MENU_ENTRY *NewMenuEntry;
1568 BM_LOAD_CONTEXT *NewLoadContext;
1569
1570 ASSERT (CallbackData != NULL);
1571
1572 DeviceType = (UINTN) -1;
1573 BmmConfig = &CallbackData->BmmFakeNvData;
1574 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
1575
1576 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
1577 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
1578 Index++) {
1579 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
1580 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1581
1582 if (NewLoadContext->IsLegacy) {
1583 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
1584 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
1585 } else {
1586 //
1587 // Only show one legacy boot option for the same device type
1588 // assuming the boot options are grouped by the device type
1589 //
1590 continue;
1591 }
1592 }
1593 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
1594 }
1595 }
1596
1597 /**
1598 According to LegacyDevOrder variable to get legacy FD\HD\CD\NET\BEV
1599 devices list .
1600
1601 @param CallbackData The BMM context data.
1602 **/
1603 VOID
1604 GetLegacyDeviceOrder (
1605 IN BMM_CALLBACK_DATA *CallbackData
1606 )
1607 {
1608 UINTN Index;
1609 UINTN OptionIndex;
1610 UINT16 PageIdList[5];
1611 UINTN PageNum;
1612 UINTN VarSize;
1613 UINT8 *VarData;
1614 UINT8 *WorkingVarData;
1615 LEGACY_DEV_ORDER_ENTRY *DevOrder;
1616 UINT16 VarDevOrder;
1617 UINT8 *DisMap;
1618 BM_MENU_OPTION *OptionMenu;
1619 BBS_TYPE BbsType;
1620 UINT8 *LegacyOrder;
1621 UINT8 *OldData;
1622 UINTN Pos;
1623 UINTN Bit;
1624
1625 ASSERT (CallbackData != NULL);
1626
1627 PageIdList[0] = FORM_SET_FD_ORDER_ID;
1628 PageIdList[1] = FORM_SET_HD_ORDER_ID;
1629 PageIdList[2] = FORM_SET_CD_ORDER_ID;
1630 PageIdList[3] = FORM_SET_NET_ORDER_ID;
1631 PageIdList[4] = FORM_SET_BEV_ORDER_ID;
1632 OptionMenu = NULL;
1633 BbsType = 0;
1634 LegacyOrder = NULL;
1635 OldData = NULL;
1636 DisMap = ZeroMem (CallbackData->BmmFakeNvData.DisableMap, sizeof (CallbackData->BmmFakeNvData.DisableMap));
1637 PageNum = ARRAY_SIZE (PageIdList);
1638 VarData = BdsLibGetVariableAndSize (
1639 VAR_LEGACY_DEV_ORDER,
1640 &gEfiLegacyDevOrderVariableGuid,
1641 &VarSize
1642 );
1643
1644 for (Index = 0; Index < PageNum; Index++) {
1645 switch (PageIdList[Index]) {
1646
1647 case FORM_SET_FD_ORDER_ID:
1648 OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
1649 BbsType = BBS_FLOPPY;
1650 LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
1651 OldData = CallbackData->BmmOldFakeNVData.LegacyFD;
1652 break;
1653
1654 case FORM_SET_HD_ORDER_ID:
1655 OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
1656 BbsType = BBS_HARDDISK;
1657 LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
1658 OldData = CallbackData->BmmOldFakeNVData.LegacyHD;
1659 break;
1660
1661 case FORM_SET_CD_ORDER_ID:
1662 OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
1663 BbsType = BBS_CDROM;
1664 LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
1665 OldData = CallbackData->BmmOldFakeNVData.LegacyCD;
1666 break;
1667
1668 case FORM_SET_NET_ORDER_ID:
1669 OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
1670 BbsType = BBS_EMBED_NETWORK;
1671 LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
1672 OldData = CallbackData->BmmOldFakeNVData.LegacyNET;
1673 break;
1674
1675 default:
1676 ASSERT (PageIdList[Index] == FORM_SET_BEV_ORDER_ID);
1677 OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
1678 BbsType = BBS_BEV_DEVICE;
1679 LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
1680 OldData = CallbackData->BmmOldFakeNVData.LegacyBEV;
1681 break;
1682 }
1683
1684 if (NULL != VarData) {
1685 WorkingVarData = VarData;
1686 DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
1687 while (WorkingVarData < VarData + VarSize) {
1688 if (DevOrder->BbsType == BbsType) {
1689 break;
1690 }
1691
1692 WorkingVarData = (UINT8 *)((UINTN)WorkingVarData + sizeof (BBS_TYPE));
1693 WorkingVarData += *(UINT16 *) WorkingVarData;
1694 DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
1695 }
1696 for (OptionIndex = 0; OptionIndex < OptionMenu->MenuNumber; OptionIndex++) {
1697 VarDevOrder = *(UINT16 *) ((UINTN) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + OptionIndex * sizeof (UINT16));
1698 if (0xFF00 == (VarDevOrder & 0xFF00)) {
1699 LegacyOrder[OptionIndex] = 0xFF;
1700 Pos = (VarDevOrder & 0xFF) / 8;
1701 Bit = 7 - ((VarDevOrder & 0xFF) % 8);
1702 DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
1703 } else {
1704 LegacyOrder[OptionIndex] = (UINT8) (VarDevOrder & 0xFF);
1705 }
1706 }
1707 CopyMem (OldData, LegacyOrder, 100);
1708 }
1709 }
1710 }
1711
1712 /**
1713 Get driver option order from globalc DriverOptionMenu.
1714
1715 @param CallbackData The BMM context data.
1716
1717 **/
1718 VOID
1719 GetDriverOrder (
1720 IN BMM_CALLBACK_DATA *CallbackData
1721 )
1722 {
1723 BMM_FAKE_NV_DATA *BmmConfig;
1724 UINT16 Index;
1725 UINT16 OptionOrderIndex;
1726 UINTN DeviceType;
1727 BM_MENU_ENTRY *NewMenuEntry;
1728 BM_LOAD_CONTEXT *NewLoadContext;
1729
1730 ASSERT (CallbackData != NULL);
1731
1732 DeviceType = (UINTN) -1;
1733 BmmConfig = &CallbackData->BmmFakeNvData;
1734 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
1735
1736 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
1737 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
1738 Index++) {
1739 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
1740 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1741
1742 if (NewLoadContext->IsLegacy) {
1743 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
1744 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
1745 } else {
1746 //
1747 // Only show one legacy boot option for the same device type
1748 // assuming the boot options are grouped by the device type
1749 //
1750 continue;
1751 }
1752 }
1753 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
1754 }
1755 }