]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[mirror_edk2.git] / MdeModulePkg / 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 - 2008, 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 give a 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 menu.
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 (NULL == MenuEntry) {
81 return MenuEntry;
82 }
83
84 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
85 if (NULL == MenuEntry->VariableContext) {
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 (NULL != MenuEntry->HelpString) {
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
428 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
429
430 TempStr = MenuEntry->HelpString;
431 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
432 ASSERT (MenuEntry->DisplayString != NULL);
433 UnicodeSPrint (
434 MenuEntry->DisplayString,
435 MAX_CHAR,
436 L"Load File [%s]",
437 TempStr
438 );
439
440 MenuEntry->OptionNumber = OptionNumber;
441 OptionNumber++;
442 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
443 }
444 }
445
446 if (NoLoadFileHandles != 0) {
447 FreePool (LoadFileHandle);
448 }
449
450 //
451 // Add Legacy Boot Option Support Here
452 //
453 Status = gBS->LocateProtocol (
454 &gEfiLegacyBiosProtocolGuid,
455 NULL,
456 (VOID **) &LegacyBios
457 );
458 if (!EFI_ERROR (Status)) {
459
460 for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
461 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
462 if (NULL == MenuEntry) {
463 return EFI_OUT_OF_RESOURCES;
464 }
465
466 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
467
468 FileContext->IsRemovableMedia = FALSE;
469 FileContext->IsLoadFile = TRUE;
470 FileContext->IsBootLegacy = TRUE;
471 DeviceType = (UINT16) Index;
472 BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
473 BbsDevicePathNode.Header.SubType = BBS_BBS_DP;
474 SetDevicePathNodeLength (
475 &BbsDevicePathNode.Header,
476 sizeof (BBS_BBS_DEVICE_PATH)
477 );
478 BbsDevicePathNode.DeviceType = DeviceType;
479 BbsDevicePathNode.StatusFlag = 0;
480 BbsDevicePathNode.String[0] = 0;
481 DevicePath = AppendDevicePathNode (
482 EndDevicePath,
483 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
484 );
485
486 FileContext->DevicePath = DevicePath;
487 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
488
489 TempStr = MenuEntry->HelpString;
490 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
491 ASSERT (MenuEntry->DisplayString != NULL);
492 UnicodeSPrint (
493 MenuEntry->DisplayString,
494 MAX_CHAR,
495 L"Boot Legacy [%s]",
496 TempStr
497 );
498 MenuEntry->OptionNumber = OptionNumber;
499 OptionNumber++;
500 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
501 }
502 }
503 //
504 // Remember how many file system options are here
505 //
506 FsOptionMenu.MenuNumber = OptionNumber;
507 return EFI_SUCCESS;
508 }
509
510 /**
511 Free resources allocated in Allocate Rountine.
512
513 @param FreeMenu Menu to be freed
514 **/
515 VOID
516 BOpt_FreeMenu (
517 BM_MENU_OPTION *FreeMenu
518 )
519 {
520 BM_MENU_ENTRY *MenuEntry;
521 while (!IsListEmpty (&FreeMenu->Head)) {
522 MenuEntry = CR (
523 FreeMenu->Head.ForwardLink,
524 BM_MENU_ENTRY,
525 Link,
526 BM_MENU_ENTRY_SIGNATURE
527 );
528 RemoveEntryList (&MenuEntry->Link);
529 BOpt_DestroyMenuEntry (MenuEntry);
530 }
531 }
532
533 /**
534 Find files under current directory
535 All files and sub-directories in current directory
536 will be stored in DirectoryMenu for future use.
537
538 @param CallbackData The BMM context data.
539 @param MenuEntry The Menu Entry.
540
541 @retval EFI_SUCCESS Get files from current dir successfully.
542 @return Other value if can't get files from current dir.
543
544 **/
545 EFI_STATUS
546 BOpt_FindFiles (
547 IN BMM_CALLBACK_DATA *CallbackData,
548 IN BM_MENU_ENTRY *MenuEntry
549 )
550 {
551 EFI_FILE_HANDLE NewDir;
552 EFI_FILE_HANDLE Dir;
553 EFI_FILE_INFO *DirInfo;
554 UINTN BufferSize;
555 UINTN DirBufferSize;
556 BM_MENU_ENTRY *NewMenuEntry;
557 BM_FILE_CONTEXT *FileContext;
558 BM_FILE_CONTEXT *NewFileContext;
559 UINTN Pass;
560 EFI_STATUS Status;
561 UINTN OptionNumber;
562
563 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
564 Dir = FileContext->FHandle;
565 OptionNumber = 0;
566 //
567 // Open current directory to get files from it
568 //
569 Status = Dir->Open (
570 Dir,
571 &NewDir,
572 FileContext->FileName,
573 EFI_FILE_READ_ONLY,
574 0
575 );
576 if (!FileContext->IsRoot) {
577 Dir->Close (Dir);
578 }
579
580 if (EFI_ERROR (Status)) {
581 return Status;
582 }
583
584 DirInfo = EfiLibFileInfo (NewDir);
585 if (DirInfo == NULL) {
586 return EFI_NOT_FOUND;
587 }
588
589 if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) {
590 return EFI_INVALID_PARAMETER;
591 }
592
593 FileContext->DevicePath = FileDevicePath (
594 FileContext->Handle,
595 FileContext->FileName
596 );
597
598 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
599 DirInfo = AllocateZeroPool (DirBufferSize);
600 if (DirInfo == NULL) {
601 return EFI_OUT_OF_RESOURCES;
602 }
603 //
604 // Get all files in current directory
605 // Pass 1 to get Directories
606 // Pass 2 to get files that are EFI images
607 //
608 for (Pass = 1; Pass <= 2; Pass++) {
609 NewDir->SetPosition (NewDir, 0);
610 for (;;) {
611 BufferSize = DirBufferSize;
612 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
613 if (EFI_ERROR (Status) || BufferSize == 0) {
614 break;
615 }
616
617 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) ||
618 (!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1)
619 ) {
620 //
621 // Pass 1 is for Directories
622 // Pass 2 is for file names
623 //
624 continue;
625 }
626
627 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) {
628 //
629 // Slip file unless it is a directory entry or a .EFI file
630 //
631 continue;
632 }
633
634 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
635 if (NULL == NewMenuEntry) {
636 return EFI_OUT_OF_RESOURCES;
637 }
638
639 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
640 NewFileContext->Handle = FileContext->Handle;
641 NewFileContext->FileName = BOpt_AppendFileName (
642 FileContext->FileName,
643 DirInfo->FileName
644 );
645 NewFileContext->FHandle = NewDir;
646 NewFileContext->DevicePath = FileDevicePath (
647 NewFileContext->Handle,
648 NewFileContext->FileName
649 );
650 NewMenuEntry->HelpString = NULL;
651
652 MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
653 CallbackData,
654 FileOptionStrDepository
655 );
656
657 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
658
659 if (NewFileContext->IsDir) {
660 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
661 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
662
663 UnicodeSPrint (
664 NewMenuEntry->DisplayString,
665 BufferSize,
666 L"<%s>",
667 DirInfo->FileName
668 );
669
670 } else {
671 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
672 }
673
674 NewFileContext->IsRoot = FALSE;
675 NewFileContext->IsLoadFile = FALSE;
676 NewFileContext->IsRemovableMedia = FALSE;
677
678 NewMenuEntry->OptionNumber = OptionNumber;
679 OptionNumber++;
680 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
681 }
682 }
683
684 DirectoryMenu.MenuNumber = OptionNumber;
685 FreePool (DirInfo);
686 return EFI_SUCCESS;
687 }
688
689 /**
690 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
691
692 @retval EFI_SUCCESS The function complete successfully.
693 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
694
695 **/
696 EFI_STATUS
697 BOpt_GetLegacyOptions (
698 VOID
699 )
700 {
701 BM_MENU_ENTRY *NewMenuEntry;
702 BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
703 EFI_STATUS Status;
704 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
705 UINT16 HddCount;
706 HDD_INFO *HddInfo;
707 UINT16 BbsCount;
708 BBS_TABLE *BbsTable;
709 UINTN Index;
710 CHAR16 DescString[100];
711 UINTN FDNum;
712 UINTN HDNum;
713 UINTN CDNum;
714 UINTN NETNum;
715 UINTN BEVNum;
716
717 NewMenuEntry = NULL;
718 HddInfo = NULL;
719 BbsTable = NULL;
720 BbsCount = 0;
721
722 //
723 // Initialize Bbs Table Context from BBS info data
724 //
725 InitializeListHead (&LegacyFDMenu.Head);
726 InitializeListHead (&LegacyHDMenu.Head);
727 InitializeListHead (&LegacyCDMenu.Head);
728 InitializeListHead (&LegacyNETMenu.Head);
729 InitializeListHead (&LegacyBEVMenu.Head);
730
731 Status = gBS->LocateProtocol (
732 &gEfiLegacyBiosProtocolGuid,
733 NULL,
734 (VOID **) &LegacyBios
735 );
736 if (!EFI_ERROR (Status)) {
737 Status = LegacyBios->GetBbsInfo (
738 LegacyBios,
739 &HddCount,
740 &HddInfo,
741 &BbsCount,
742 &BbsTable
743 );
744 if (EFI_ERROR (Status)) {
745 return Status;
746 }
747 }
748
749 FDNum = 0;
750 HDNum = 0;
751 CDNum = 0;
752 NETNum = 0;
753 BEVNum = 0;
754
755 for (Index = 0; Index < BbsCount; Index++) {
756 if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
757 (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
758 ) {
759 continue;
760 }
761
762 NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
763 if (NULL == NewMenuEntry) {
764 break;
765 }
766
767 NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
768 NewLegacyDevContext->BbsTable = &BbsTable[Index];
769 NewLegacyDevContext->Index = Index;
770 NewLegacyDevContext->BbsCount = BbsCount;
771 BdsBuildLegacyDevNameString (
772 &BbsTable[Index],
773 Index,
774 sizeof (DescString),
775 DescString
776 );
777 NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString));
778 if (NULL == NewLegacyDevContext->Description) {
779 break;
780 }
781
782 CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString));
783 NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
784 NewMenuEntry->HelpString = NULL;
785
786 switch (BbsTable[Index].DeviceType) {
787 case BBS_FLOPPY:
788 InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
789 FDNum++;
790 break;
791
792 case BBS_HARDDISK:
793 InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
794 HDNum++;
795 break;
796
797 case BBS_CDROM:
798 InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
799 CDNum++;
800 break;
801
802 case BBS_EMBED_NETWORK:
803 InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
804 NETNum++;
805 break;
806
807 case BBS_BEV_DEVICE:
808 InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
809 BEVNum++;
810 break;
811 }
812 }
813
814 if (Index != BbsCount) {
815 BOpt_FreeLegacyOptions ();
816 return EFI_OUT_OF_RESOURCES;
817 }
818
819 LegacyFDMenu.MenuNumber = FDNum;
820 LegacyHDMenu.MenuNumber = HDNum;
821 LegacyCDMenu.MenuNumber = CDNum;
822 LegacyNETMenu.MenuNumber = NETNum;
823 LegacyBEVMenu.MenuNumber = BEVNum;
824 return EFI_SUCCESS;
825 }
826
827 /**
828 Free out resouce allocated from Legacy Boot Options.
829
830 **/
831 VOID
832 BOpt_FreeLegacyOptions (
833 VOID
834 )
835 {
836 BOpt_FreeMenu (&LegacyFDMenu);
837 BOpt_FreeMenu (&LegacyHDMenu);
838 BOpt_FreeMenu (&LegacyCDMenu);
839 BOpt_FreeMenu (&LegacyNETMenu);
840 BOpt_FreeMenu (&LegacyBEVMenu);
841 }
842
843 /**
844
845 Build the BootOptionMenu according to BootOrder Variable.
846 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
847
848 @param CallbackData The BMM context data.
849
850 @return The number of the Var Boot####.
851
852 **/
853 EFI_STATUS
854 BOpt_GetBootOptions (
855 IN BMM_CALLBACK_DATA *CallbackData
856 )
857 {
858 UINTN Index;
859 UINT16 BootString[10];
860 UINT8 *LoadOptionFromVar;
861 UINT8 *LoadOption;
862 UINTN BootOptionSize;
863 BOOLEAN BootNextFlag;
864 UINT16 *BootOrderList;
865 UINTN BootOrderListSize;
866 UINT16 *BootNext;
867 UINTN BootNextSize;
868 BM_MENU_ENTRY *NewMenuEntry;
869 BM_LOAD_CONTEXT *NewLoadContext;
870 UINT8 *LoadOptionPtr;
871 UINTN StringSize;
872 UINTN OptionalDataSize;
873 UINT8 *LoadOptionEnd;
874 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
875 UINTN MenuCount;
876 UINT8 *Ptr;
877
878 MenuCount = 0;
879 BootOrderListSize = 0;
880 BootNextSize = 0;
881 BootOrderList = NULL;
882 BootNext = NULL;
883 LoadOptionFromVar = NULL;
884 BOpt_FreeMenu (&BootOptionMenu);
885 InitializeListHead (&BootOptionMenu.Head);
886
887 //
888 // Get the BootOrder from the Var
889 //
890 BootOrderList = BdsLibGetVariableAndSize (
891 L"BootOrder",
892 &gEfiGlobalVariableGuid,
893 &BootOrderListSize
894 );
895
896 //
897 // Get the BootNext from the Var
898 //
899 BootNext = BdsLibGetVariableAndSize (
900 L"BootNext",
901 &gEfiGlobalVariableGuid,
902 &BootNextSize
903 );
904
905 if (BootNext != NULL) {
906 if (BootNextSize != sizeof (UINT16)) {
907 FreePool (BootNext);
908 BootNext = NULL;
909 }
910 }
911
912 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
913 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
914 //
915 // Get all loadoptions from the VAR
916 //
917 LoadOptionFromVar = BdsLibGetVariableAndSize (
918 BootString,
919 &gEfiGlobalVariableGuid,
920 &BootOptionSize
921 );
922 if (LoadOptionFromVar == NULL) {
923 continue;
924 }
925
926 LoadOption = AllocateZeroPool (BootOptionSize);
927 if (LoadOption == NULL) {
928 continue;
929 }
930
931 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
932 FreePool (LoadOptionFromVar);
933
934 if (BootNext != NULL) {
935 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
936 } else {
937 BootNextFlag = FALSE;
938 }
939
940 if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
941 FreePool (LoadOption);
942 continue;
943 }
944 //
945 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
946 // the buffer allocated already should be freed before returning.
947 //
948 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
949 if (NULL == NewMenuEntry) {
950 return EFI_OUT_OF_RESOURCES;
951 }
952
953 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
954
955 LoadOptionPtr = LoadOption;
956 LoadOptionEnd = LoadOption + BootOptionSize;
957
958 NewMenuEntry->OptionNumber = BootOrderList[Index];
959 NewLoadContext->LoadOptionModified = FALSE;
960 NewLoadContext->Deleted = FALSE;
961 NewLoadContext->IsBootNext = BootNextFlag;
962
963 //
964 // Is a Legacy Device?
965 //
966 Ptr = (UINT8 *) LoadOption;
967
968 //
969 // Attribute = *(UINT32 *)Ptr;
970 //
971 Ptr += sizeof (UINT32);
972
973 //
974 // FilePathSize = *(UINT16 *)Ptr;
975 //
976 Ptr += sizeof (UINT16);
977
978 //
979 // Description = (CHAR16 *)Ptr;
980 //
981 Ptr += StrSize ((CHAR16 *) Ptr);
982
983 //
984 // Now Ptr point to Device Path
985 //
986 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
987 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
988 NewLoadContext->IsLegacy = TRUE;
989 } else {
990 NewLoadContext->IsLegacy = FALSE;
991 }
992 //
993 // LoadOption is a pointer type of UINT8
994 // for easy use with following LOAD_OPTION
995 // embedded in this struct
996 //
997 NewLoadContext->LoadOption = LoadOption;
998 NewLoadContext->LoadOptionSize = BootOptionSize;
999
1000 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1001 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1002
1003 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1004
1005 LoadOptionPtr += sizeof (UINT32);
1006
1007 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1008 LoadOptionPtr += sizeof (UINT16);
1009
1010 StringSize = StrSize ((UINT16 *) LoadOptionPtr);
1011 NewLoadContext->Description = AllocateZeroPool (StringSize);
1012 ASSERT (NewLoadContext->Description != NULL);
1013 CopyMem (
1014 NewLoadContext->Description,
1015 (UINT16 *) LoadOptionPtr,
1016 StringSize
1017 );
1018 NewMenuEntry->DisplayString = NewLoadContext->Description;
1019
1020 LoadOptionPtr += StringSize;
1021
1022 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1023 ASSERT (NewLoadContext->FilePathList != NULL);
1024 CopyMem (
1025 NewLoadContext->FilePathList,
1026 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1027 NewLoadContext->FilePathListLength
1028 );
1029
1030 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1031 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1032 CallbackData,
1033 BootOptionStrDepository
1034 );
1035 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1036 CallbackData,
1037 BootOptionHelpStrDepository
1038 );
1039 LoadOptionPtr += NewLoadContext->FilePathListLength;
1040
1041 if (LoadOptionPtr < LoadOptionEnd) {
1042 OptionalDataSize = BootOptionSize -
1043 sizeof (UINT32) -
1044 sizeof (UINT16) -
1045 StringSize -
1046 NewLoadContext->FilePathListLength;
1047
1048 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1049 ASSERT (NewLoadContext->OptionalData != NULL);
1050 CopyMem (
1051 NewLoadContext->OptionalData,
1052 LoadOptionPtr,
1053 OptionalDataSize
1054 );
1055
1056 NewLoadContext->OptionalDataSize = OptionalDataSize;
1057 }
1058
1059 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
1060 MenuCount++;
1061 }
1062
1063 if (BootNext != NULL) {
1064 FreePool (BootNext);
1065 }
1066 if (BootOrderList != NULL) {
1067 FreePool (BootOrderList);
1068 }
1069 BootOptionMenu.MenuNumber = MenuCount;
1070 return MenuCount;
1071 }
1072
1073 /**
1074
1075 Append file name to existing file name.
1076
1077 @param Str1 The existing file name
1078 @param Str2 The file name to be appended
1079
1080 @return Allocate a new string to hold the appended result.
1081 Caller is responsible to free the returned string.
1082
1083 **/
1084 CHAR16 *
1085 BOpt_AppendFileName (
1086 IN CHAR16 *Str1,
1087 IN CHAR16 *Str2
1088 )
1089 {
1090 UINTN Size1;
1091 UINTN Size2;
1092 CHAR16 *Str;
1093 CHAR16 *TmpStr;
1094 CHAR16 *Ptr;
1095 CHAR16 *LastSlash;
1096
1097 Size1 = StrSize (Str1);
1098 Size2 = StrSize (Str2);
1099 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
1100 ASSERT (Str != NULL);
1101
1102 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
1103 ASSERT (TmpStr != NULL);
1104
1105 StrCat (Str, Str1);
1106 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
1107 StrCat (Str, L"\\");
1108 }
1109
1110 StrCat (Str, Str2);
1111
1112 Ptr = Str;
1113 LastSlash = Str;
1114 while (*Ptr != 0) {
1115 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
1116 //
1117 // Convert "\Name\..\" to "\"
1118 // DO NOT convert the .. if it is at the end of the string. This will
1119 // break the .. behavior in changing directories.
1120 //
1121
1122 //
1123 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
1124 // that overlap.
1125 //
1126 StrCpy (TmpStr, Ptr + 3);
1127 StrCpy (LastSlash, TmpStr);
1128 Ptr = LastSlash;
1129 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
1130 //
1131 // Convert a "\.\" to a "\"
1132 //
1133
1134 //
1135 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
1136 // that overlap.
1137 //
1138 StrCpy (TmpStr, Ptr + 2);
1139 StrCpy (Ptr, TmpStr);
1140 Ptr = LastSlash;
1141 } else if (*Ptr == '\\') {
1142 LastSlash = Ptr;
1143 }
1144
1145 Ptr++;
1146 }
1147
1148 FreePool (TmpStr);
1149
1150 return Str;
1151 }
1152
1153 /**
1154
1155 Check whether current FileName point to a valid
1156 Efi Image File.
1157
1158 @param FileName File need to be checked.
1159
1160 @retval TRUE Is Efi Image
1161 @retval FALSE Not a valid Efi Image
1162
1163 **/
1164 BOOLEAN
1165 BOpt_IsEfiImageName (
1166 IN UINT16 *FileName
1167 )
1168 {
1169 //
1170 // Search for ".efi" extension
1171 //
1172 while (*FileName != L'\0') {
1173 if (FileName[0] == '.') {
1174 if (FileName[1] == 'e' || FileName[1] == 'E') {
1175 if (FileName[2] == 'f' || FileName[2] == 'F') {
1176 if (FileName[3] == 'i' || FileName[3] == 'I') {
1177 return TRUE;
1178 } else if (FileName[3] == 0x0000) {
1179 return FALSE;
1180 }
1181 } else if (FileName[2] == 0x0000) {
1182 return FALSE;
1183 }
1184 } else if (FileName[1] == 0x0000) {
1185 return FALSE;
1186 }
1187 }
1188
1189 FileName += 1;
1190 }
1191
1192 return FALSE;
1193 }
1194
1195 /**
1196
1197 Check whether current FileName point to a valid Efi Application
1198
1199 @param Dir Pointer to current Directory
1200 @param FileName Pointer to current File name.
1201
1202 @retval TRUE Is a valid Efi Application
1203 @retval FALSE not a valid Efi Application
1204
1205 **/
1206 BOOLEAN
1207 BOpt_IsEfiApp (
1208 IN EFI_FILE_HANDLE Dir,
1209 IN UINT16 *FileName
1210 )
1211 {
1212 UINTN BufferSize;
1213 EFI_IMAGE_DOS_HEADER DosHdr;
1214 UINT16 Subsystem;
1215 EFI_FILE_HANDLE File;
1216 EFI_STATUS Status;
1217 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
1218
1219 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
1220
1221 if (EFI_ERROR (Status)) {
1222 return FALSE;
1223 }
1224
1225 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1226 File->Read (File, &BufferSize, &DosHdr);
1227 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1228 File->Close (File);
1229 return FALSE;
1230 }
1231
1232 File->SetPosition (File, DosHdr.e_lfanew);
1233 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1234 File->Read (File, &BufferSize, &PeHdr);
1235 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
1236 File->Close (File);
1237 return FALSE;
1238 }
1239 //
1240 // Determine PE type and read subsytem
1241 //
1242 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1243 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
1244 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1245 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
1246 } else {
1247 return FALSE;
1248 }
1249
1250 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1251 File->Close (File);
1252 return TRUE;
1253 } else {
1254 File->Close (File);
1255 return FALSE;
1256 }
1257 }
1258
1259 /**
1260
1261 Find drivers that will be added as Driver#### variables from handles
1262 in current system environment
1263 All valid handles in the system except those consume SimpleFs, LoadFile
1264 are stored in DriverMenu for future use.
1265
1266 @retval EFI_SUCCESS The function complets successfully.
1267 @return Other value if failed to build the DriverMenu.
1268
1269 **/
1270 EFI_STATUS
1271 BOpt_FindDrivers (
1272 VOID
1273 )
1274 {
1275 UINTN NoDevicePathHandles;
1276 EFI_HANDLE *DevicePathHandle;
1277 UINTN Index;
1278 EFI_STATUS Status;
1279 BM_MENU_ENTRY *NewMenuEntry;
1280 BM_HANDLE_CONTEXT *NewHandleContext;
1281 EFI_HANDLE CurHandle;
1282 UINTN OptionNumber;
1283 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
1284 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1285
1286 SimpleFs = NULL;
1287 LoadFile = NULL;
1288
1289 InitializeListHead (&DriverMenu.Head);
1290
1291 //
1292 // At first, get all handles that support Device Path
1293 // protocol which is the basic requirement for
1294 // Driver####
1295 //
1296 Status = gBS->LocateHandleBuffer (
1297 ByProtocol,
1298 &gEfiDevicePathProtocolGuid,
1299 NULL,
1300 &NoDevicePathHandles,
1301 &DevicePathHandle
1302 );
1303 if (EFI_ERROR (Status)) {
1304 return Status;
1305 }
1306
1307 OptionNumber = 0;
1308 for (Index = 0; Index < NoDevicePathHandles; Index++) {
1309 CurHandle = DevicePathHandle[Index];
1310
1311 Status = gBS->HandleProtocol (
1312 CurHandle,
1313 &gEfiSimpleFileSystemProtocolGuid,
1314 (VOID **) &SimpleFs
1315 );
1316 if (Status == EFI_SUCCESS) {
1317 continue;
1318 }
1319
1320 Status = gBS->HandleProtocol (
1321 CurHandle,
1322 &gEfiLoadFileProtocolGuid,
1323 (VOID **) &LoadFile
1324 );
1325 if (Status == EFI_SUCCESS) {
1326 continue;
1327 }
1328
1329 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
1330 if (NULL == NewMenuEntry) {
1331 FreePool (DevicePathHandle);
1332 return EFI_OUT_OF_RESOURCES;
1333 }
1334
1335 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
1336 NewHandleContext->Handle = CurHandle;
1337 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
1338 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
1339 NewMenuEntry->HelpString = NULL;
1340 NewMenuEntry->OptionNumber = OptionNumber;
1341 OptionNumber++;
1342 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
1343
1344 }
1345
1346 if (DevicePathHandle != NULL) {
1347 FreePool (DevicePathHandle);
1348 }
1349
1350 DriverMenu.MenuNumber = OptionNumber;
1351 return EFI_SUCCESS;
1352 }
1353
1354 /**
1355
1356 Get the Option Number that has not been allocated for use.
1357
1358 @return The available Option Number.
1359
1360 **/
1361 UINT16
1362 BOpt_GetBootOptionNumber (
1363 VOID
1364 )
1365 {
1366 BM_MENU_ENTRY *NewMenuEntry;
1367 UINT16 *BootOrderList;
1368 UINTN BootOrderListSize;
1369 UINT16 Number;
1370 UINTN Index;
1371 UINTN Index2;
1372 BOOLEAN Found;
1373 CHAR16 StrTemp[100];
1374 UINT16 *OptionBuffer;
1375 UINTN OptionSize;
1376
1377 BootOrderListSize = 0;
1378 BootOrderList = NULL;
1379
1380 BootOrderList = BdsLibGetVariableAndSize (
1381 L"BootOrder",
1382 &gEfiGlobalVariableGuid,
1383 &BootOrderListSize
1384 );
1385 if (BootOrderList != NULL) {
1386 //
1387 // already have Boot####
1388 //
1389 // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);
1390 //
1391 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
1392 Found = TRUE;
1393 for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {
1394 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);
1395 if (Index == NewMenuEntry->OptionNumber) {
1396 Found = FALSE;
1397 break;
1398 }
1399 }
1400
1401 if (Found) {
1402 UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);
1403 DEBUG((DEBUG_ERROR,"INdex= %s\n", StrTemp));
1404 OptionBuffer = BdsLibGetVariableAndSize (
1405 StrTemp,
1406 &gEfiGlobalVariableGuid,
1407 &OptionSize
1408 );
1409 if (NULL == OptionBuffer) {
1410 break;
1411 }
1412 }
1413 }
1414 //
1415 // end for Index
1416 //
1417 Number = (UINT16) Index;
1418 } else {
1419 //
1420 // No Boot####
1421 //
1422 Number = 0;
1423 }
1424
1425 return Number;
1426 }
1427
1428 /**
1429
1430 Get the Option Number that is not in use.
1431
1432 @return The unused Option Number.
1433
1434 **/
1435 UINT16
1436 BOpt_GetDriverOptionNumber (
1437 VOID
1438 )
1439 {
1440 BM_MENU_ENTRY *NewMenuEntry;
1441 UINT16 *DriverOrderList;
1442 UINTN DriverOrderListSize;
1443 UINT16 Number;
1444 UINTN Index;
1445 UINTN Index2;
1446 BOOLEAN Found;
1447
1448 DriverOrderListSize = 0;
1449 DriverOrderList = NULL;
1450
1451 DriverOrderList = BdsLibGetVariableAndSize (
1452 L"DriverOrder",
1453 &gEfiGlobalVariableGuid,
1454 &DriverOrderListSize
1455 );
1456 if (DriverOrderList != NULL) {
1457 //
1458 // already have Driver####
1459 //
1460 // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);
1461 //
1462 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1463 Found = TRUE;
1464 for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {
1465 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);
1466 if (Index == NewMenuEntry->OptionNumber) {
1467 Found = FALSE;
1468 break;
1469 }
1470 }
1471
1472 if (Found) {
1473 break;
1474 }
1475 }
1476 //
1477 // end for Index
1478 //
1479 Number = (UINT16) Index;
1480 } else {
1481 //
1482 // No Driver####
1483 //
1484 Number = 0;
1485 }
1486
1487 return Number;
1488 }
1489
1490 /**
1491
1492 Build up all DriverOptionMenu
1493
1494 @param CallbackData The BMM context data.
1495
1496 @return EFI_SUCESS The functin completes successfully.
1497 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1498
1499
1500 **/
1501 EFI_STATUS
1502 BOpt_GetDriverOptions (
1503 IN BMM_CALLBACK_DATA *CallbackData
1504 )
1505 {
1506 UINTN Index;
1507 UINT16 DriverString[12];
1508 UINT8 *LoadOptionFromVar;
1509 UINT8 *LoadOption;
1510 UINTN DriverOptionSize;
1511
1512 UINT16 *DriverOrderList;
1513 UINTN DriverOrderListSize;
1514 BM_MENU_ENTRY *NewMenuEntry;
1515 BM_LOAD_CONTEXT *NewLoadContext;
1516 UINT8 *LoadOptionPtr;
1517 UINTN StringSize;
1518 UINTN OptionalDataSize;
1519 UINT8 *LoadOptionEnd;
1520
1521 DriverOrderListSize = 0;
1522 DriverOrderList = NULL;
1523 DriverOptionSize = 0;
1524 LoadOptionFromVar = NULL;
1525 BOpt_FreeMenu (&DriverOptionMenu);
1526 InitializeListHead (&DriverOptionMenu.Head);
1527 //
1528 // Get the DriverOrder from the Var
1529 //
1530 DriverOrderList = BdsLibGetVariableAndSize (
1531 L"DriverOrder",
1532 &gEfiGlobalVariableGuid,
1533 &DriverOrderListSize
1534 );
1535
1536 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1537 UnicodeSPrint (
1538 DriverString,
1539 sizeof (DriverString),
1540 L"Driver%04x",
1541 DriverOrderList[Index]
1542 );
1543 //
1544 // Get all loadoptions from the VAR
1545 //
1546 LoadOptionFromVar = BdsLibGetVariableAndSize (
1547 DriverString,
1548 &gEfiGlobalVariableGuid,
1549 &DriverOptionSize
1550 );
1551 if (LoadOptionFromVar == NULL) {
1552 continue;
1553 }
1554
1555 LoadOption = AllocateZeroPool (DriverOptionSize);
1556 if (LoadOption == NULL) {
1557 continue;
1558 }
1559
1560 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
1561 FreePool (LoadOptionFromVar);
1562
1563 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
1564 if (NULL == NewMenuEntry) {
1565 return EFI_OUT_OF_RESOURCES;
1566 }
1567
1568 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1569 LoadOptionPtr = LoadOption;
1570 LoadOptionEnd = LoadOption + DriverOptionSize;
1571 NewMenuEntry->OptionNumber = DriverOrderList[Index];
1572 NewLoadContext->LoadOptionModified = FALSE;
1573 NewLoadContext->Deleted = FALSE;
1574 NewLoadContext->IsLegacy = FALSE;
1575
1576 //
1577 // LoadOption is a pointer type of UINT8
1578 // for easy use with following LOAD_OPTION
1579 // embedded in this struct
1580 //
1581 NewLoadContext->LoadOption = LoadOption;
1582 NewLoadContext->LoadOptionSize = DriverOptionSize;
1583
1584 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1585 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1586
1587 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1588
1589 LoadOptionPtr += sizeof (UINT32);
1590
1591 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1592 LoadOptionPtr += sizeof (UINT16);
1593
1594 StringSize = StrSize ((UINT16 *) LoadOptionPtr);
1595 NewLoadContext->Description = AllocateZeroPool (StringSize);
1596 ASSERT (NewLoadContext->Description != NULL);
1597 CopyMem (
1598 NewLoadContext->Description,
1599 (UINT16 *) LoadOptionPtr,
1600 StringSize
1601 );
1602 NewMenuEntry->DisplayString = NewLoadContext->Description;
1603
1604 LoadOptionPtr += StringSize;
1605
1606 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1607 ASSERT (NewLoadContext->FilePathList != NULL);
1608 CopyMem (
1609 NewLoadContext->FilePathList,
1610 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1611 NewLoadContext->FilePathListLength
1612 );
1613
1614 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1615 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1616 CallbackData,
1617 DriverOptionStrDepository
1618 );
1619 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1620 CallbackData,
1621 DriverOptionHelpStrDepository
1622 );
1623 LoadOptionPtr += NewLoadContext->FilePathListLength;
1624
1625 if (LoadOptionPtr < LoadOptionEnd) {
1626 OptionalDataSize = DriverOptionSize -
1627 sizeof (UINT32) -
1628 sizeof (UINT16) -
1629 StringSize -
1630 NewLoadContext->FilePathListLength;
1631
1632 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1633 ASSERT (NewLoadContext->OptionalData != NULL);
1634 CopyMem (
1635 NewLoadContext->OptionalData,
1636 LoadOptionPtr,
1637 OptionalDataSize
1638 );
1639
1640 NewLoadContext->OptionalDataSize = OptionalDataSize;
1641 }
1642
1643 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
1644
1645 }
1646
1647 if (DriverOrderList != NULL) {
1648 FreePool (DriverOrderList);
1649 }
1650 DriverOptionMenu.MenuNumber = Index;
1651 return EFI_SUCCESS;
1652
1653 }
1654