]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
[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 *TmpStr;
1084 CHAR16 *Ptr;
1085 CHAR16 *LastSlash;
1086
1087 Size1 = StrSize (Str1);
1088 Size2 = StrSize (Str2);
1089 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
1090 ASSERT (Str != NULL);
1091
1092 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
1093 ASSERT (TmpStr != NULL);
1094
1095 StrCat (Str, Str1);
1096 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
1097 StrCat (Str, L"\\");
1098 }
1099
1100 StrCat (Str, Str2);
1101
1102 Ptr = Str;
1103 LastSlash = Str;
1104 while (*Ptr != 0) {
1105 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
1106 //
1107 // Convert "\Name\..\" to "\"
1108 // DO NOT convert the .. if it is at the end of the string. This will
1109 // break the .. behavior in changing directories.
1110 //
1111
1112 //
1113 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
1114 // that overlap.
1115 //
1116 StrCpy (TmpStr, Ptr + 3);
1117 StrCpy (LastSlash, TmpStr);
1118 Ptr = LastSlash;
1119 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
1120 //
1121 // Convert a "\.\" to a "\"
1122 //
1123
1124 //
1125 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
1126 // that overlap.
1127 //
1128 StrCpy (TmpStr, Ptr + 2);
1129 StrCpy (Ptr, TmpStr);
1130 Ptr = LastSlash;
1131 } else if (*Ptr == '\\') {
1132 LastSlash = Ptr;
1133 }
1134
1135 Ptr++;
1136 }
1137
1138 FreePool (TmpStr);
1139
1140 return Str;
1141 }
1142
1143 /**
1144
1145 Check whether current FileName point to a valid
1146 Efi Image File.
1147
1148 @param FileName File need to be checked.
1149
1150 @retval TRUE Is Efi Image
1151 @retval FALSE Not a valid Efi Image
1152
1153 **/
1154 BOOLEAN
1155 BOpt_IsEfiImageName (
1156 IN UINT16 *FileName
1157 )
1158 {
1159 //
1160 // Search for ".efi" extension
1161 //
1162 while (*FileName != L'\0') {
1163 if (FileName[0] == '.') {
1164 if (FileName[1] == 'e' || FileName[1] == 'E') {
1165 if (FileName[2] == 'f' || FileName[2] == 'F') {
1166 if (FileName[3] == 'i' || FileName[3] == 'I') {
1167 return TRUE;
1168 } else if (FileName[3] == 0x0000) {
1169 return FALSE;
1170 }
1171 } else if (FileName[2] == 0x0000) {
1172 return FALSE;
1173 }
1174 } else if (FileName[1] == 0x0000) {
1175 return FALSE;
1176 }
1177 }
1178
1179 FileName += 1;
1180 }
1181
1182 return FALSE;
1183 }
1184
1185 /**
1186
1187 Check whether current FileName point to a valid Efi Application
1188
1189 @param Dir Pointer to current Directory
1190 @param FileName Pointer to current File name.
1191
1192 @retval TRUE Is a valid Efi Application
1193 @retval FALSE not a valid Efi Application
1194
1195 **/
1196 BOOLEAN
1197 BOpt_IsEfiApp (
1198 IN EFI_FILE_HANDLE Dir,
1199 IN UINT16 *FileName
1200 )
1201 {
1202 UINTN BufferSize;
1203 EFI_IMAGE_DOS_HEADER DosHdr;
1204 UINT16 Subsystem;
1205 EFI_FILE_HANDLE File;
1206 EFI_STATUS Status;
1207 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
1208
1209 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
1210
1211 if (EFI_ERROR (Status)) {
1212 return FALSE;
1213 }
1214
1215 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1216 File->Read (File, &BufferSize, &DosHdr);
1217 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1218 File->Close (File);
1219 return FALSE;
1220 }
1221
1222 File->SetPosition (File, DosHdr.e_lfanew);
1223 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1224 File->Read (File, &BufferSize, &PeHdr);
1225 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
1226 File->Close (File);
1227 return FALSE;
1228 }
1229 //
1230 // Determine PE type and read subsytem
1231 //
1232 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1233 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
1234 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1235 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
1236 } else {
1237 return FALSE;
1238 }
1239
1240 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1241 File->Close (File);
1242 return TRUE;
1243 } else {
1244 File->Close (File);
1245 return FALSE;
1246 }
1247 }
1248
1249 /**
1250
1251 Find drivers that will be added as Driver#### variables from handles
1252 in current system environment
1253 All valid handles in the system except those consume SimpleFs, LoadFile
1254 are stored in DriverMenu for future use.
1255
1256 @retval EFI_SUCCESS The function complets successfully.
1257 @return Other value if failed to build the DriverMenu.
1258
1259 **/
1260 EFI_STATUS
1261 BOpt_FindDrivers (
1262 VOID
1263 )
1264 {
1265 UINTN NoDevicePathHandles;
1266 EFI_HANDLE *DevicePathHandle;
1267 UINTN Index;
1268 EFI_STATUS Status;
1269 BM_MENU_ENTRY *NewMenuEntry;
1270 BM_HANDLE_CONTEXT *NewHandleContext;
1271 EFI_HANDLE CurHandle;
1272 UINTN OptionNumber;
1273 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
1274 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1275
1276 SimpleFs = NULL;
1277 LoadFile = NULL;
1278
1279 InitializeListHead (&DriverMenu.Head);
1280
1281 //
1282 // At first, get all handles that support Device Path
1283 // protocol which is the basic requirement for
1284 // Driver####
1285 //
1286 Status = gBS->LocateHandleBuffer (
1287 ByProtocol,
1288 &gEfiDevicePathProtocolGuid,
1289 NULL,
1290 &NoDevicePathHandles,
1291 &DevicePathHandle
1292 );
1293 if (EFI_ERROR (Status)) {
1294 return Status;
1295 }
1296
1297 OptionNumber = 0;
1298 for (Index = 0; Index < NoDevicePathHandles; Index++) {
1299 CurHandle = DevicePathHandle[Index];
1300
1301 Status = gBS->HandleProtocol (
1302 CurHandle,
1303 &gEfiSimpleFileSystemProtocolGuid,
1304 (VOID **) &SimpleFs
1305 );
1306 if (Status == EFI_SUCCESS) {
1307 continue;
1308 }
1309
1310 Status = gBS->HandleProtocol (
1311 CurHandle,
1312 &gEfiLoadFileProtocolGuid,
1313 (VOID **) &LoadFile
1314 );
1315 if (Status == EFI_SUCCESS) {
1316 continue;
1317 }
1318
1319 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
1320 if (NULL == NewMenuEntry) {
1321 SafeFreePool (DevicePathHandle);
1322 return EFI_OUT_OF_RESOURCES;
1323 }
1324
1325 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
1326 NewHandleContext->Handle = CurHandle;
1327 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
1328 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
1329 NewMenuEntry->HelpString = NULL;
1330 NewMenuEntry->OptionNumber = OptionNumber;
1331 OptionNumber++;
1332 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
1333
1334 }
1335 SafeFreePool (DevicePathHandle);
1336
1337 DriverMenu.MenuNumber = OptionNumber;
1338 return EFI_SUCCESS;
1339 }
1340
1341 /**
1342
1343 Get the Option Number that has not been allocated for use.
1344
1345 @return The available Option Number.
1346
1347 **/
1348 UINT16
1349 BOpt_GetBootOptionNumber (
1350 VOID
1351 )
1352 {
1353 BM_MENU_ENTRY *NewMenuEntry;
1354 UINT16 *BootOrderList;
1355 UINTN BootOrderListSize;
1356 UINT16 Number;
1357 UINTN Index;
1358 UINTN Index2;
1359 BOOLEAN Found;
1360 CHAR16 StrTemp[100];
1361 UINT16 *OptionBuffer;
1362 UINTN OptionSize;
1363
1364 BootOrderListSize = 0;
1365 BootOrderList = NULL;
1366
1367 BootOrderList = BdsLibGetVariableAndSize (
1368 L"BootOrder",
1369 &gEfiGlobalVariableGuid,
1370 &BootOrderListSize
1371 );
1372 if (BootOrderList != NULL) {
1373 //
1374 // already have Boot####
1375 //
1376 // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);
1377 //
1378 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
1379 Found = TRUE;
1380 for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {
1381 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);
1382 if (Index == NewMenuEntry->OptionNumber) {
1383 Found = FALSE;
1384 break;
1385 }
1386 }
1387
1388 if (Found) {
1389 UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);
1390 DEBUG((DEBUG_ERROR,"INdex= %s\n", StrTemp));
1391 OptionBuffer = BdsLibGetVariableAndSize (
1392 StrTemp,
1393 &gEfiGlobalVariableGuid,
1394 &OptionSize
1395 );
1396 if (NULL == OptionBuffer) {
1397 break;
1398 }
1399 }
1400 }
1401 //
1402 // end for Index
1403 //
1404 Number = (UINT16) Index;
1405 } else {
1406 //
1407 // No Boot####
1408 //
1409 Number = 0;
1410 }
1411
1412 return Number;
1413 }
1414
1415 /**
1416
1417 Get the Option Number that is not in use.
1418
1419 @return The unused Option Number.
1420
1421 **/
1422 UINT16
1423 BOpt_GetDriverOptionNumber (
1424 VOID
1425 )
1426 {
1427 BM_MENU_ENTRY *NewMenuEntry;
1428 UINT16 *DriverOrderList;
1429 UINTN DriverOrderListSize;
1430 UINT16 Number;
1431 UINTN Index;
1432 UINTN Index2;
1433 BOOLEAN Found;
1434
1435 DriverOrderListSize = 0;
1436 DriverOrderList = NULL;
1437
1438 DriverOrderList = BdsLibGetVariableAndSize (
1439 L"DriverOrder",
1440 &gEfiGlobalVariableGuid,
1441 &DriverOrderListSize
1442 );
1443 if (DriverOrderList != NULL) {
1444 //
1445 // already have Driver####
1446 //
1447 // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);
1448 //
1449 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1450 Found = TRUE;
1451 for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {
1452 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);
1453 if (Index == NewMenuEntry->OptionNumber) {
1454 Found = FALSE;
1455 break;
1456 }
1457 }
1458
1459 if (Found) {
1460 break;
1461 }
1462 }
1463 //
1464 // end for Index
1465 //
1466 Number = (UINT16) Index;
1467 } else {
1468 //
1469 // No Driver####
1470 //
1471 Number = 0;
1472 }
1473
1474 return Number;
1475 }
1476
1477 /**
1478
1479 Build up all DriverOptionMenu
1480
1481 @param CallbackData The BMM context data.
1482
1483 @return EFI_SUCESS The functin completes successfully.
1484 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1485
1486
1487 **/
1488 EFI_STATUS
1489 BOpt_GetDriverOptions (
1490 IN BMM_CALLBACK_DATA *CallbackData
1491 )
1492 {
1493 UINTN Index;
1494 UINT16 DriverString[12];
1495 UINT8 *LoadOptionFromVar;
1496 UINT8 *LoadOption;
1497 UINTN DriverOptionSize;
1498
1499 UINT16 *DriverOrderList;
1500 UINTN DriverOrderListSize;
1501 BM_MENU_ENTRY *NewMenuEntry;
1502 BM_LOAD_CONTEXT *NewLoadContext;
1503 UINT8 *LoadOptionPtr;
1504 UINTN StringSize;
1505 UINTN OptionalDataSize;
1506 UINT8 *LoadOptionEnd;
1507
1508 DriverOrderListSize = 0;
1509 DriverOrderList = NULL;
1510 DriverOptionSize = 0;
1511 LoadOptionFromVar = NULL;
1512 BOpt_FreeMenu (&DriverOptionMenu);
1513 InitializeListHead (&DriverOptionMenu.Head);
1514 //
1515 // Get the DriverOrder from the Var
1516 //
1517 DriverOrderList = BdsLibGetVariableAndSize (
1518 L"DriverOrder",
1519 &gEfiGlobalVariableGuid,
1520 &DriverOrderListSize
1521 );
1522
1523 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1524 UnicodeSPrint (
1525 DriverString,
1526 sizeof (DriverString),
1527 L"Driver%04x",
1528 DriverOrderList[Index]
1529 );
1530 //
1531 // Get all loadoptions from the VAR
1532 //
1533 LoadOptionFromVar = BdsLibGetVariableAndSize (
1534 DriverString,
1535 &gEfiGlobalVariableGuid,
1536 &DriverOptionSize
1537 );
1538 if (LoadOptionFromVar == NULL) {
1539 continue;
1540 }
1541
1542 LoadOption = AllocateZeroPool (DriverOptionSize);
1543 if (LoadOption == NULL) {
1544 continue;
1545 }
1546
1547 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
1548 SafeFreePool (LoadOptionFromVar);
1549
1550 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
1551 if (NULL == NewMenuEntry) {
1552 return EFI_OUT_OF_RESOURCES;
1553 }
1554
1555 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1556 LoadOptionPtr = LoadOption;
1557 LoadOptionEnd = LoadOption + DriverOptionSize;
1558 NewMenuEntry->OptionNumber = DriverOrderList[Index];
1559 NewLoadContext->LoadOptionModified = FALSE;
1560 NewLoadContext->Deleted = FALSE;
1561 NewLoadContext->IsLegacy = FALSE;
1562
1563 //
1564 // LoadOption is a pointer type of UINT8
1565 // for easy use with following LOAD_OPTION
1566 // embedded in this struct
1567 //
1568 NewLoadContext->LoadOption = LoadOption;
1569 NewLoadContext->LoadOptionSize = DriverOptionSize;
1570
1571 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1572 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1573
1574 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1575
1576 LoadOptionPtr += sizeof (UINT32);
1577
1578 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1579 LoadOptionPtr += sizeof (UINT16);
1580
1581 StringSize = StrSize ((UINT16 *) LoadOptionPtr);
1582 NewLoadContext->Description = AllocateZeroPool (StringSize);
1583 ASSERT (NewLoadContext->Description != NULL);
1584 CopyMem (
1585 NewLoadContext->Description,
1586 (UINT16 *) LoadOptionPtr,
1587 StringSize
1588 );
1589 NewMenuEntry->DisplayString = NewLoadContext->Description;
1590
1591 LoadOptionPtr += StringSize;
1592
1593 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1594 ASSERT (NewLoadContext->FilePathList != NULL);
1595 CopyMem (
1596 NewLoadContext->FilePathList,
1597 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1598 NewLoadContext->FilePathListLength
1599 );
1600
1601 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1602 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1603 CallbackData,
1604 DriverOptionStrDepository
1605 );
1606 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1607 CallbackData,
1608 DriverOptionHelpStrDepository
1609 );
1610 LoadOptionPtr += NewLoadContext->FilePathListLength;
1611
1612 if (LoadOptionPtr < LoadOptionEnd) {
1613 OptionalDataSize = DriverOptionSize -
1614 sizeof (UINT32) -
1615 sizeof (UINT16) -
1616 StringSize -
1617 NewLoadContext->FilePathListLength;
1618
1619 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1620 ASSERT (NewLoadContext->OptionalData != NULL);
1621 CopyMem (
1622 NewLoadContext->OptionalData,
1623 LoadOptionPtr,
1624 OptionalDataSize
1625 );
1626
1627 NewLoadContext->OptionalDataSize = OptionalDataSize;
1628 }
1629
1630 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
1631
1632 }
1633
1634 SafeFreePool (DriverOrderList);
1635 DriverOptionMenu.MenuNumber = Index;
1636 return EFI_SUCCESS;
1637
1638 }
1639