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