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