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