2 Provide boot option support for Application "BootMaint"
4 Include file system navigation, system handle selection
6 Boot option manipulation
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
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.
19 #include "BootMaint.h"
20 #include "BBSsupport.h"
23 Create a menu entry give a Menu type.
25 @param MenuType The Menu type to be created.
27 @retval NULL If failed to create the menu.
32 BOpt_CreateMenuEntry (
36 BM_MENU_ENTRY
*MenuEntry
;
40 // Get context size according to menu type
43 case BM_LOAD_CONTEXT_SELECT
:
44 ContextSize
= sizeof (BM_LOAD_CONTEXT
);
47 case BM_FILE_CONTEXT_SELECT
:
48 ContextSize
= sizeof (BM_FILE_CONTEXT
);
51 case BM_CONSOLE_CONTEXT_SELECT
:
52 ContextSize
= sizeof (BM_CONSOLE_CONTEXT
);
55 case BM_TERMINAL_CONTEXT_SELECT
:
56 ContextSize
= sizeof (BM_TERMINAL_CONTEXT
);
59 case BM_HANDLE_CONTEXT_SELECT
:
60 ContextSize
= sizeof (BM_HANDLE_CONTEXT
);
63 case BM_LEGACY_DEV_CONTEXT_SELECT
:
64 ContextSize
= sizeof (BM_LEGACY_DEVICE_CONTEXT
);
72 if (ContextSize
== 0) {
77 // Create new menu entry
79 MenuEntry
= AllocateZeroPool (sizeof (BM_MENU_ENTRY
));
80 if (NULL
== MenuEntry
) {
84 MenuEntry
->VariableContext
= AllocateZeroPool (ContextSize
);
85 if (NULL
== MenuEntry
->VariableContext
) {
86 SafeFreePool (MenuEntry
);
90 MenuEntry
->Signature
= BM_MENU_ENTRY_SIGNATURE
;
91 MenuEntry
->ContextSelection
= MenuType
;
96 Free up all resource allocated for a BM_MENU_ENTRY.
98 @param MenuEntry A pointer to BM_MENU_ENTRY.
102 BOpt_DestroyMenuEntry (
103 BM_MENU_ENTRY
*MenuEntry
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
;
114 // Select by the type in Menu entry for current context type
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
);
125 case BM_FILE_CONTEXT_SELECT
:
126 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
128 if (!FileContext
->IsRoot
) {
129 SafeFreePool (FileContext
->DevicePath
);
131 if (FileContext
->FHandle
!= NULL
) {
132 FileContext
->FHandle
->Close (FileContext
->FHandle
);
136 SafeFreePool (FileContext
->FileName
);
137 SafeFreePool (FileContext
->Info
);
138 SafeFreePool (FileContext
);
141 case BM_CONSOLE_CONTEXT_SELECT
:
142 ConsoleContext
= (BM_CONSOLE_CONTEXT
*) MenuEntry
->VariableContext
;
143 SafeFreePool (ConsoleContext
->DevicePath
);
144 SafeFreePool (ConsoleContext
);
147 case BM_TERMINAL_CONTEXT_SELECT
:
148 TerminalContext
= (BM_TERMINAL_CONTEXT
*) MenuEntry
->VariableContext
;
149 SafeFreePool (TerminalContext
->DevicePath
);
150 SafeFreePool (TerminalContext
);
153 case BM_HANDLE_CONTEXT_SELECT
:
154 HandleContext
= (BM_HANDLE_CONTEXT
*) MenuEntry
->VariableContext
;
155 SafeFreePool (HandleContext
);
158 case BM_LEGACY_DEV_CONTEXT_SELECT
:
159 LegacyDevContext
= (BM_LEGACY_DEVICE_CONTEXT
*) MenuEntry
->VariableContext
;
160 SafeFreePool (LegacyDevContext
);
166 SafeFreePool (MenuEntry
->DisplayString
);
167 if (NULL
!= MenuEntry
->HelpString
) {
168 SafeFreePool (MenuEntry
->HelpString
);
171 SafeFreePool (MenuEntry
);
175 Get the Menu Entry from the list in Menu Entry List.
177 If MenuNumber is great or equal to the number of Menu
178 Entry in the list, then ASSERT.
180 @param MenuOption The Menu Entry List to read the menu entry.
181 @param MenuNumber The index of Menu Entry.
183 @return The Menu Entry.
188 BM_MENU_OPTION
*MenuOption
,
192 BM_MENU_ENTRY
*NewMenuEntry
;
196 ASSERT (MenuNumber
< MenuOption
->MenuNumber
);
198 List
= MenuOption
->Head
.ForwardLink
;
199 for (Index
= 0; Index
< MenuNumber
; Index
++) {
200 List
= List
->ForwardLink
;
203 NewMenuEntry
= CR (List
, BM_MENU_ENTRY
, Link
, BM_MENU_ENTRY_SIGNATURE
);
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.
214 @param CallbackData BMM context data
216 @retval EFI_SUCCESS Success find the file system
217 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
221 BOpt_FindFileSystem (
222 IN BMM_CALLBACK_DATA
*CallbackData
225 UINTN NoBlkIoHandles
;
226 UINTN NoSimpleFsHandles
;
227 UINTN NoLoadFileHandles
;
228 EFI_HANDLE
*BlkIoHandle
;
229 EFI_HANDLE
*SimpleFsHandle
;
230 EFI_HANDLE
*LoadFileHandle
;
232 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
235 BM_MENU_ENTRY
*MenuEntry
;
236 BM_FILE_CONTEXT
*FileContext
;
240 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
242 BBS_BBS_DEVICE_PATH BbsDevicePathNode
;
243 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
244 BOOLEAN RemovableMedia
;
247 NoSimpleFsHandles
= 0;
248 NoLoadFileHandles
= 0;
250 InitializeListHead (&FsOptionMenu
.Head
);
253 // Locate Handles that support BlockIo protocol
255 Status
= gBS
->LocateHandleBuffer (
257 &gEfiBlockIoProtocolGuid
,
262 if (!EFI_ERROR (Status
)) {
264 for (Index
= 0; Index
< NoBlkIoHandles
; Index
++) {
265 Status
= gBS
->HandleProtocol (
267 &gEfiBlockIoProtocolGuid
,
271 if (EFI_ERROR (Status
)) {
276 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
278 if (BlkIo
->Media
->RemovableMedia
) {
279 Buffer
= AllocateZeroPool (BlkIo
->Media
->BlockSize
);
280 if (NULL
== Buffer
) {
281 SafeFreePool (BlkIoHandle
);
282 return EFI_OUT_OF_RESOURCES
;
287 BlkIo
->Media
->MediaId
,
289 BlkIo
->Media
->BlockSize
,
292 SafeFreePool (Buffer
);
295 SafeFreePool (BlkIoHandle
);
299 // Locate Handles that support Simple File System protocol
301 Status
= gBS
->LocateHandleBuffer (
303 &gEfiSimpleFileSystemProtocolGuid
,
308 if (!EFI_ERROR (Status
)) {
310 // Find all the instances of the File System prototocol
312 for (Index
= 0; Index
< NoSimpleFsHandles
; Index
++) {
313 Status
= gBS
->HandleProtocol (
314 SimpleFsHandle
[Index
],
315 &gEfiBlockIoProtocolGuid
,
318 if (EFI_ERROR (Status
)) {
320 // If no block IO exists assume it's NOT a removable media
322 RemovableMedia
= FALSE
;
325 // If block IO exists check to see if it's remobable media
327 RemovableMedia
= BlkIo
->Media
->RemovableMedia
;
331 // Allocate pool for this load option
333 MenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
334 if (NULL
== MenuEntry
) {
335 SafeFreePool (SimpleFsHandle
);
336 return EFI_OUT_OF_RESOURCES
;
339 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
341 FileContext
->Handle
= SimpleFsHandle
[Index
];
342 MenuEntry
->OptionNumber
= Index
;
343 FileContext
->FHandle
= EfiLibOpenRoot (FileContext
->Handle
);
344 if (FileContext
->FHandle
== NULL
) {
345 BOpt_DestroyMenuEntry (MenuEntry
);
349 MenuEntry
->HelpString
= DevicePathToStr (DevicePathFromHandle (FileContext
->Handle
));
350 FileContext
->Info
= EfiLibFileSystemVolumeLabelInfo (FileContext
->FHandle
);
351 FileContext
->FileName
= EfiStrDuplicate (L
"\\");
352 FileContext
->DevicePath
= FileDevicePath (
354 FileContext
->FileName
356 FileContext
->IsDir
= TRUE
;
357 FileContext
->IsRoot
= TRUE
;
358 FileContext
->IsRemovableMedia
= RemovableMedia
;
359 FileContext
->IsLoadFile
= FALSE
;
362 // Get current file system's Volume Label
364 if (FileContext
->Info
== NULL
) {
365 VolumeLabel
= L
"NO FILE SYSTEM INFO";
367 if (FileContext
->Info
->VolumeLabel
== NULL
) {
368 VolumeLabel
= L
"NULL VOLUME LABEL";
370 VolumeLabel
= FileContext
->Info
->VolumeLabel
;
371 if (*VolumeLabel
== 0x0000) {
372 VolumeLabel
= L
"NO VOLUME LABEL";
377 TempStr
= MenuEntry
->HelpString
;
378 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
379 ASSERT (MenuEntry
->DisplayString
!= NULL
);
381 MenuEntry
->DisplayString
,
388 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
392 if (NoSimpleFsHandles
!= 0) {
393 SafeFreePool (SimpleFsHandle
);
396 // Searching for handles that support Load File protocol
398 Status
= gBS
->LocateHandleBuffer (
400 &gEfiLoadFileProtocolGuid
,
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
;
414 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
415 FileContext
->IsRemovableMedia
= FALSE
;
416 FileContext
->IsLoadFile
= TRUE
;
417 FileContext
->Handle
= LoadFileHandle
[Index
];
418 FileContext
->IsRoot
= TRUE
;
420 FileContext
->DevicePath
= DevicePathFromHandle (FileContext
->Handle
);
422 MenuEntry
->HelpString
= DevicePathToStr (FileContext
->DevicePath
);
424 TempStr
= MenuEntry
->HelpString
;
425 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
426 ASSERT (MenuEntry
->DisplayString
!= NULL
);
428 MenuEntry
->DisplayString
,
434 MenuEntry
->OptionNumber
= OptionNumber
;
436 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
440 if (NoLoadFileHandles
!= 0) {
441 SafeFreePool (LoadFileHandle
);
445 // Add Legacy Boot Option Support Here
447 Status
= gBS
->LocateProtocol (
448 &gEfiLegacyBiosProtocolGuid
,
450 (VOID
**) &LegacyBios
452 if (!EFI_ERROR (Status
)) {
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
;
460 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
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
)
472 BbsDevicePathNode
.DeviceType
= DeviceType
;
473 BbsDevicePathNode
.StatusFlag
= 0;
474 BbsDevicePathNode
.String
[0] = 0;
475 DevicePath
= AppendDevicePathNode (
477 (EFI_DEVICE_PATH_PROTOCOL
*) &BbsDevicePathNode
480 FileContext
->DevicePath
= DevicePath
;
481 MenuEntry
->HelpString
= DevicePathToStr (FileContext
->DevicePath
);
483 TempStr
= MenuEntry
->HelpString
;
484 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
485 ASSERT (MenuEntry
->DisplayString
!= NULL
);
487 MenuEntry
->DisplayString
,
492 MenuEntry
->OptionNumber
= OptionNumber
;
494 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
498 // Remember how many file system options are here
500 FsOptionMenu
.MenuNumber
= OptionNumber
;
505 Free resources allocated in Allocate Rountine.
507 @param FreeMenu Menu to be freed
511 BM_MENU_OPTION
*FreeMenu
514 BM_MENU_ENTRY
*MenuEntry
;
515 while (!IsListEmpty (&FreeMenu
->Head
)) {
517 FreeMenu
->Head
.ForwardLink
,
520 BM_MENU_ENTRY_SIGNATURE
522 RemoveEntryList (&MenuEntry
->Link
);
523 BOpt_DestroyMenuEntry (MenuEntry
);
528 Find files under current directory
529 All files and sub-directories in current directory
530 will be stored in DirectoryMenu for future use.
532 @param CallbackData The BMM context data.
533 @param MenuEntry The Menu Entry.
535 @retval EFI_SUCCESS Get files from current dir successfully.
536 @return Other value if can't get files from current dir.
541 IN BMM_CALLBACK_DATA
*CallbackData
,
542 IN BM_MENU_ENTRY
*MenuEntry
545 EFI_FILE_HANDLE NewDir
;
547 EFI_FILE_INFO
*DirInfo
;
550 BM_MENU_ENTRY
*NewMenuEntry
;
551 BM_FILE_CONTEXT
*FileContext
;
552 BM_FILE_CONTEXT
*NewFileContext
;
557 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
558 Dir
= FileContext
->FHandle
;
561 // Open current directory to get files from it
566 FileContext
->FileName
,
570 if (!FileContext
->IsRoot
) {
574 if (EFI_ERROR (Status
)) {
578 DirInfo
= EfiLibFileInfo (NewDir
);
579 if (DirInfo
== NULL
) {
580 return EFI_NOT_FOUND
;
583 if (!(DirInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
584 return EFI_INVALID_PARAMETER
;
587 FileContext
->DevicePath
= FileDevicePath (
589 FileContext
->FileName
592 DirBufferSize
= sizeof (EFI_FILE_INFO
) + 1024;
593 DirInfo
= AllocateZeroPool (DirBufferSize
);
594 if (DirInfo
== NULL
) {
595 return EFI_OUT_OF_RESOURCES
;
598 // Get all files in current directory
599 // Pass 1 to get Directories
600 // Pass 2 to get files that are EFI images
602 for (Pass
= 1; Pass
<= 2; Pass
++) {
603 NewDir
->SetPosition (NewDir
, 0);
605 BufferSize
= DirBufferSize
;
606 Status
= NewDir
->Read (NewDir
, &BufferSize
, DirInfo
);
607 if (EFI_ERROR (Status
) || BufferSize
== 0) {
611 if ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
&& Pass
== 2) ||
612 (!(DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) && Pass
== 1)
615 // Pass 1 is for Directories
616 // Pass 2 is for file names
621 if (!(BOpt_IsEfiImageName (DirInfo
->FileName
) || DirInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
623 // Slip file unless it is a directory entry or a .EFI file
628 NewMenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
629 if (NULL
== NewMenuEntry
) {
630 return EFI_OUT_OF_RESOURCES
;
633 NewFileContext
= (BM_FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
634 NewFileContext
->Handle
= FileContext
->Handle
;
635 NewFileContext
->FileName
= BOpt_AppendFileName (
636 FileContext
->FileName
,
639 NewFileContext
->FHandle
= NewDir
;
640 NewFileContext
->DevicePath
= FileDevicePath (
641 NewFileContext
->Handle
,
642 NewFileContext
->FileName
644 NewMenuEntry
->HelpString
= NULL
;
646 MenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
648 FileOptionStrDepository
651 NewFileContext
->IsDir
= (BOOLEAN
) ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
);
653 if (NewFileContext
->IsDir
) {
654 BufferSize
= StrLen (DirInfo
->FileName
) * 2 + 6;
655 NewMenuEntry
->DisplayString
= AllocateZeroPool (BufferSize
);
658 NewMenuEntry
->DisplayString
,
665 NewMenuEntry
->DisplayString
= EfiStrDuplicate (DirInfo
->FileName
);
668 NewFileContext
->IsRoot
= FALSE
;
669 NewFileContext
->IsLoadFile
= FALSE
;
670 NewFileContext
->IsRemovableMedia
= FALSE
;
672 NewMenuEntry
->OptionNumber
= OptionNumber
;
674 InsertTailList (&DirectoryMenu
.Head
, &NewMenuEntry
->Link
);
678 DirectoryMenu
.MenuNumber
= OptionNumber
;
679 SafeFreePool (DirInfo
);
684 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
686 @retval EFI_SUCCESS The function complete successfully.
687 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
691 BOpt_GetLegacyOptions (
695 BM_MENU_ENTRY
*NewMenuEntry
;
696 BM_LEGACY_DEVICE_CONTEXT
*NewLegacyDevContext
;
698 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
704 CHAR16 DescString
[100];
717 // Initialize Bbs Table Context from BBS info data
719 InitializeListHead (&LegacyFDMenu
.Head
);
720 InitializeListHead (&LegacyHDMenu
.Head
);
721 InitializeListHead (&LegacyCDMenu
.Head
);
722 InitializeListHead (&LegacyNETMenu
.Head
);
723 InitializeListHead (&LegacyBEVMenu
.Head
);
725 Status
= gBS
->LocateProtocol (
726 &gEfiLegacyBiosProtocolGuid
,
728 (VOID
**) &LegacyBios
730 if (!EFI_ERROR (Status
)) {
731 Status
= LegacyBios
->GetBbsInfo (
738 if (EFI_ERROR (Status
)) {
749 for (Index
= 0; Index
< BbsCount
; Index
++) {
750 if ((BBS_IGNORE_ENTRY
== BbsTable
[Index
].BootPriority
) ||
751 (BBS_DO_NOT_BOOT_FROM
== BbsTable
[Index
].BootPriority
)
756 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT
);
757 if (NULL
== NewMenuEntry
) {
761 NewLegacyDevContext
= (BM_LEGACY_DEVICE_CONTEXT
*) NewMenuEntry
->VariableContext
;
762 NewLegacyDevContext
->BbsTable
= &BbsTable
[Index
];
763 NewLegacyDevContext
->Index
= Index
;
764 NewLegacyDevContext
->BbsCount
= BbsCount
;
765 BdsBuildLegacyDevNameString (
771 NewLegacyDevContext
->Description
= AllocateZeroPool (StrSize (DescString
));
772 if (NULL
== NewLegacyDevContext
->Description
) {
776 CopyMem (NewLegacyDevContext
->Description
, DescString
, StrSize (DescString
));
777 NewMenuEntry
->DisplayString
= NewLegacyDevContext
->Description
;
778 NewMenuEntry
->HelpString
= NULL
;
780 switch (BbsTable
[Index
].DeviceType
) {
782 InsertTailList (&LegacyFDMenu
.Head
, &NewMenuEntry
->Link
);
787 InsertTailList (&LegacyHDMenu
.Head
, &NewMenuEntry
->Link
);
792 InsertTailList (&LegacyCDMenu
.Head
, &NewMenuEntry
->Link
);
796 case BBS_EMBED_NETWORK
:
797 InsertTailList (&LegacyNETMenu
.Head
, &NewMenuEntry
->Link
);
802 InsertTailList (&LegacyBEVMenu
.Head
, &NewMenuEntry
->Link
);
808 if (Index
!= BbsCount
) {
809 BOpt_FreeLegacyOptions ();
810 return EFI_OUT_OF_RESOURCES
;
813 LegacyFDMenu
.MenuNumber
= FDNum
;
814 LegacyHDMenu
.MenuNumber
= HDNum
;
815 LegacyCDMenu
.MenuNumber
= CDNum
;
816 LegacyNETMenu
.MenuNumber
= NETNum
;
817 LegacyBEVMenu
.MenuNumber
= BEVNum
;
822 Free out resouce allocated from Legacy Boot Options.
826 BOpt_FreeLegacyOptions (
830 BOpt_FreeMenu (&LegacyFDMenu
);
831 BOpt_FreeMenu (&LegacyHDMenu
);
832 BOpt_FreeMenu (&LegacyCDMenu
);
833 BOpt_FreeMenu (&LegacyNETMenu
);
834 BOpt_FreeMenu (&LegacyBEVMenu
);
839 Build the BootOptionMenu according to BootOrder Variable.
840 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
842 @param CallbackData The BMM context data.
844 @return The number of the Var Boot####.
848 BOpt_GetBootOptions (
849 IN BMM_CALLBACK_DATA
*CallbackData
853 UINT16 BootString
[10];
854 UINT8
*LoadOptionFromVar
;
856 UINTN BootOptionSize
;
857 BOOLEAN BootNextFlag
;
858 UINT16
*BootOrderList
;
859 UINTN BootOrderListSize
;
862 BM_MENU_ENTRY
*NewMenuEntry
;
863 BM_LOAD_CONTEXT
*NewLoadContext
;
864 UINT8
*LoadOptionPtr
;
866 UINTN OptionalDataSize
;
867 UINT8
*LoadOptionEnd
;
868 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
873 BootOrderListSize
= 0;
875 BootOrderList
= NULL
;
877 LoadOptionFromVar
= NULL
;
878 BOpt_FreeMenu (&BootOptionMenu
);
879 InitializeListHead (&BootOptionMenu
.Head
);
882 // Get the BootOrder from the Var
884 BootOrderList
= BdsLibGetVariableAndSize (
886 &gEfiGlobalVariableGuid
,
891 // Get the BootNext from the Var
893 BootNext
= BdsLibGetVariableAndSize (
895 &gEfiGlobalVariableGuid
,
899 if (BootNext
!= NULL
) {
900 if (BootNextSize
!= sizeof (UINT16
)) {
901 SafeFreePool (BootNext
);
906 for (Index
= 0; Index
< BootOrderListSize
/ sizeof (UINT16
); Index
++) {
907 UnicodeSPrint (BootString
, sizeof (BootString
), L
"Boot%04x", BootOrderList
[Index
]);
909 // Get all loadoptions from the VAR
911 LoadOptionFromVar
= BdsLibGetVariableAndSize (
913 &gEfiGlobalVariableGuid
,
916 if (LoadOptionFromVar
== NULL
) {
920 LoadOption
= AllocateZeroPool (BootOptionSize
);
921 if (LoadOption
== NULL
) {
925 CopyMem (LoadOption
, LoadOptionFromVar
, BootOptionSize
);
926 SafeFreePool (LoadOptionFromVar
);
928 if (BootNext
!= NULL
) {
929 BootNextFlag
= (BOOLEAN
) (*BootNext
== BootOrderList
[Index
]);
931 BootNextFlag
= FALSE
;
934 if (0 == (*((UINT32
*) LoadOption
) & LOAD_OPTION_ACTIVE
)) {
935 SafeFreePool (LoadOption
);
939 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
940 // the buffer allocated already should be freed before returning.
942 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT
);
943 if (NULL
== NewMenuEntry
) {
944 return EFI_OUT_OF_RESOURCES
;
947 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
949 LoadOptionPtr
= LoadOption
;
950 LoadOptionEnd
= LoadOption
+ BootOptionSize
;
952 NewMenuEntry
->OptionNumber
= BootOrderList
[Index
];
953 NewLoadContext
->LoadOptionModified
= FALSE
;
954 NewLoadContext
->Deleted
= FALSE
;
955 NewLoadContext
->IsBootNext
= BootNextFlag
;
958 // Is a Legacy Device?
960 Ptr
= (UINT8
*) LoadOption
;
963 // Attribute = *(UINT32 *)Ptr;
965 Ptr
+= sizeof (UINT32
);
968 // FilePathSize = *(UINT16 *)Ptr;
970 Ptr
+= sizeof (UINT16
);
973 // Description = (CHAR16 *)Ptr;
975 Ptr
+= StrSize ((CHAR16
*) Ptr
);
978 // Now Ptr point to Device Path
980 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
981 if ((BBS_DEVICE_PATH
== DevicePath
->Type
) && (BBS_BBS_DP
== DevicePath
->SubType
)) {
982 NewLoadContext
->IsLegacy
= TRUE
;
984 NewLoadContext
->IsLegacy
= FALSE
;
987 // LoadOption is a pointer type of UINT8
988 // for easy use with following LOAD_OPTION
989 // embedded in this struct
991 NewLoadContext
->LoadOption
= LoadOption
;
992 NewLoadContext
->LoadOptionSize
= BootOptionSize
;
994 NewLoadContext
->Attributes
= *(UINT32
*) LoadOptionPtr
;
995 NewLoadContext
->IsActive
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_ACTIVE
);
997 NewLoadContext
->ForceReconnect
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_FORCE_RECONNECT
);
999 LoadOptionPtr
+= sizeof (UINT32
);
1001 NewLoadContext
->FilePathListLength
= *(UINT16
*) LoadOptionPtr
;
1002 LoadOptionPtr
+= sizeof (UINT16
);
1004 StringSize
= StrSize ((UINT16
*) LoadOptionPtr
);
1005 NewLoadContext
->Description
= AllocateZeroPool (StringSize
);
1006 ASSERT (NewLoadContext
->Description
!= NULL
);
1008 NewLoadContext
->Description
,
1009 (UINT16
*) LoadOptionPtr
,
1012 NewMenuEntry
->DisplayString
= NewLoadContext
->Description
;
1014 LoadOptionPtr
+= StringSize
;
1016 NewLoadContext
->FilePathList
= AllocateZeroPool (NewLoadContext
->FilePathListLength
);
1017 ASSERT (NewLoadContext
->FilePathList
!= NULL
);
1019 NewLoadContext
->FilePathList
,
1020 (EFI_DEVICE_PATH_PROTOCOL
*) LoadOptionPtr
,
1021 NewLoadContext
->FilePathListLength
1024 NewMenuEntry
->HelpString
= DevicePathToStr (NewLoadContext
->FilePathList
);
1025 NewMenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
1027 BootOptionStrDepository
1029 NewMenuEntry
->HelpStringToken
= GetStringTokenFromDepository (
1031 BootOptionHelpStrDepository
1033 LoadOptionPtr
+= NewLoadContext
->FilePathListLength
;
1035 if (LoadOptionPtr
< LoadOptionEnd
) {
1036 OptionalDataSize
= BootOptionSize
-
1040 NewLoadContext
->FilePathListLength
;
1042 NewLoadContext
->OptionalData
= AllocateZeroPool (OptionalDataSize
);
1043 ASSERT (NewLoadContext
->OptionalData
!= NULL
);
1045 NewLoadContext
->OptionalData
,
1050 NewLoadContext
->OptionalDataSize
= OptionalDataSize
;
1053 InsertTailList (&BootOptionMenu
.Head
, &NewMenuEntry
->Link
);
1057 SafeFreePool (BootNext
);
1058 SafeFreePool (BootOrderList
);
1059 BootOptionMenu
.MenuNumber
= MenuCount
;
1065 Append file name to existing file name.
1067 @param Str1 The existing file name
1068 @param Str2 The file name to be appended
1070 @return Allocate a new string to hold the appended result.
1071 Caller is responsible to free the returned string.
1075 BOpt_AppendFileName (
1086 Size1
= StrSize (Str1
);
1087 Size2
= StrSize (Str2
);
1088 Str
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
1089 ASSERT (Str
!= NULL
);
1092 if (!((*Str
== '\\') && (*(Str
+ 1) == 0))) {
1093 StrCat (Str
, L
"\\");
1101 if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '.' && *(Ptr
+ 3) == L
'\\') {
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.
1107 StrCpy (LastSlash
, Ptr
+ 3);
1109 } else if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '\\') {
1111 // Convert a "\.\" to a "\"
1113 StrCpy (Ptr
, Ptr
+ 2);
1115 } else if (*Ptr
== '\\') {
1127 Check whether current FileName point to a valid
1130 @param FileName File need to be checked.
1132 @retval TRUE Is Efi Image
1133 @retval FALSE Not a valid Efi Image
1137 BOpt_IsEfiImageName (
1142 // Search for ".efi" extension
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') {
1150 } else if (FileName
[3] == 0x0000) {
1153 } else if (FileName
[2] == 0x0000) {
1156 } else if (FileName
[1] == 0x0000) {
1169 Check whether current FileName point to a valid Efi Application
1171 @param Dir Pointer to current Directory
1172 @param FileName Pointer to current File name.
1174 @retval TRUE Is a valid Efi Application
1175 @retval FALSE not a valid Efi Application
1180 IN EFI_FILE_HANDLE Dir
,
1185 EFI_IMAGE_DOS_HEADER DosHdr
;
1187 EFI_FILE_HANDLE File
;
1189 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
1191 Status
= Dir
->Open (Dir
, &File
, FileName
, EFI_FILE_MODE_READ
, 0);
1193 if (EFI_ERROR (Status
)) {
1197 BufferSize
= sizeof (EFI_IMAGE_DOS_HEADER
);
1198 File
->Read (File
, &BufferSize
, &DosHdr
);
1199 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
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
) {
1212 // Determine PE type and read subsytem
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
;
1222 if (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
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.
1238 @retval EFI_SUCCESS The function complets successfully.
1239 @return Other value if failed to build the DriverMenu.
1247 UINTN NoDevicePathHandles
;
1248 EFI_HANDLE
*DevicePathHandle
;
1251 BM_MENU_ENTRY
*NewMenuEntry
;
1252 BM_HANDLE_CONTEXT
*NewHandleContext
;
1253 EFI_HANDLE CurHandle
;
1255 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFs
;
1256 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1261 InitializeListHead (&DriverMenu
.Head
);
1264 // At first, get all handles that support Device Path
1265 // protocol which is the basic requirement for
1268 Status
= gBS
->LocateHandleBuffer (
1270 &gEfiDevicePathProtocolGuid
,
1272 &NoDevicePathHandles
,
1275 if (EFI_ERROR (Status
)) {
1280 for (Index
= 0; Index
< NoDevicePathHandles
; Index
++) {
1281 CurHandle
= DevicePathHandle
[Index
];
1283 Status
= gBS
->HandleProtocol (
1285 &gEfiSimpleFileSystemProtocolGuid
,
1288 if (Status
== EFI_SUCCESS
) {
1292 Status
= gBS
->HandleProtocol (
1294 &gEfiLoadFileProtocolGuid
,
1297 if (Status
== EFI_SUCCESS
) {
1301 NewMenuEntry
= BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT
);
1302 if (NULL
== NewMenuEntry
) {
1303 SafeFreePool (DevicePathHandle
);
1304 return EFI_OUT_OF_RESOURCES
;
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
;
1314 InsertTailList (&DriverMenu
.Head
, &NewMenuEntry
->Link
);
1317 SafeFreePool (DevicePathHandle
);
1319 DriverMenu
.MenuNumber
= OptionNumber
;
1325 Get the Option Number that has not been allocated for use.
1327 @return The available Option Number.
1331 BOpt_GetBootOptionNumber (
1335 BM_MENU_ENTRY
*NewMenuEntry
;
1336 UINT16
*BootOrderList
;
1337 UINTN BootOrderListSize
;
1342 CHAR16 StrTemp
[100];
1343 UINT16
*OptionBuffer
;
1346 BootOrderListSize
= 0;
1347 BootOrderList
= NULL
;
1349 BootOrderList
= BdsLibGetVariableAndSize (
1351 &gEfiGlobalVariableGuid
,
1354 if (BootOrderList
!= NULL
) {
1356 // already have Boot####
1358 // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);
1360 for (Index
= 0; Index
< BootOrderListSize
/ sizeof (UINT16
); Index
++) {
1362 for (Index2
= 0; Index2
< BootOptionMenu
.MenuNumber
; Index2
++) {
1363 NewMenuEntry
= BOpt_GetMenuEntry (&BootOptionMenu
, Index2
);
1364 if (Index
== NewMenuEntry
->OptionNumber
) {
1371 UnicodeSPrint (StrTemp
, 100, L
"Boot%04x", Index
);
1372 DEBUG((DEBUG_ERROR
,"INdex= %s\n", StrTemp
));
1373 OptionBuffer
= BdsLibGetVariableAndSize (
1375 &gEfiGlobalVariableGuid
,
1378 if (NULL
== OptionBuffer
) {
1386 Number
= (UINT16
) Index
;
1399 Get the Option Number that is not in use.
1401 @return The unused Option Number.
1405 BOpt_GetDriverOptionNumber (
1409 BM_MENU_ENTRY
*NewMenuEntry
;
1410 UINT16
*DriverOrderList
;
1411 UINTN DriverOrderListSize
;
1417 DriverOrderListSize
= 0;
1418 DriverOrderList
= NULL
;
1420 DriverOrderList
= BdsLibGetVariableAndSize (
1422 &gEfiGlobalVariableGuid
,
1423 &DriverOrderListSize
1425 if (DriverOrderList
!= NULL
) {
1427 // already have Driver####
1429 // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);
1431 for (Index
= 0; Index
< DriverOrderListSize
/ sizeof (UINT16
); Index
++) {
1433 for (Index2
= 0; Index2
< DriverOptionMenu
.MenuNumber
; Index2
++) {
1434 NewMenuEntry
= BOpt_GetMenuEntry (&DriverOptionMenu
, Index2
);
1435 if (Index
== NewMenuEntry
->OptionNumber
) {
1448 Number
= (UINT16
) Index
;
1461 Build up all DriverOptionMenu
1463 @param CallbackData The BMM context data.
1465 @return EFI_SUCESS The functin completes successfully.
1466 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1471 BOpt_GetDriverOptions (
1472 IN BMM_CALLBACK_DATA
*CallbackData
1476 UINT16 DriverString
[12];
1477 UINT8
*LoadOptionFromVar
;
1479 UINTN DriverOptionSize
;
1481 UINT16
*DriverOrderList
;
1482 UINTN DriverOrderListSize
;
1483 BM_MENU_ENTRY
*NewMenuEntry
;
1484 BM_LOAD_CONTEXT
*NewLoadContext
;
1485 UINT8
*LoadOptionPtr
;
1487 UINTN OptionalDataSize
;
1488 UINT8
*LoadOptionEnd
;
1490 DriverOrderListSize
= 0;
1491 DriverOrderList
= NULL
;
1492 DriverOptionSize
= 0;
1493 LoadOptionFromVar
= NULL
;
1494 BOpt_FreeMenu (&DriverOptionMenu
);
1495 InitializeListHead (&DriverOptionMenu
.Head
);
1497 // Get the DriverOrder from the Var
1499 DriverOrderList
= BdsLibGetVariableAndSize (
1501 &gEfiGlobalVariableGuid
,
1502 &DriverOrderListSize
1505 for (Index
= 0; Index
< DriverOrderListSize
/ sizeof (UINT16
); Index
++) {
1508 sizeof (DriverString
),
1510 DriverOrderList
[Index
]
1513 // Get all loadoptions from the VAR
1515 LoadOptionFromVar
= BdsLibGetVariableAndSize (
1517 &gEfiGlobalVariableGuid
,
1520 if (LoadOptionFromVar
== NULL
) {
1524 LoadOption
= AllocateZeroPool (DriverOptionSize
);
1525 if (LoadOption
== NULL
) {
1529 CopyMem (LoadOption
, LoadOptionFromVar
, DriverOptionSize
);
1530 SafeFreePool (LoadOptionFromVar
);
1532 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT
);
1533 if (NULL
== NewMenuEntry
) {
1534 return EFI_OUT_OF_RESOURCES
;
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
;
1546 // LoadOption is a pointer type of UINT8
1547 // for easy use with following LOAD_OPTION
1548 // embedded in this struct
1550 NewLoadContext
->LoadOption
= LoadOption
;
1551 NewLoadContext
->LoadOptionSize
= DriverOptionSize
;
1553 NewLoadContext
->Attributes
= *(UINT32
*) LoadOptionPtr
;
1554 NewLoadContext
->IsActive
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_ACTIVE
);
1556 NewLoadContext
->ForceReconnect
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_FORCE_RECONNECT
);
1558 LoadOptionPtr
+= sizeof (UINT32
);
1560 NewLoadContext
->FilePathListLength
= *(UINT16
*) LoadOptionPtr
;
1561 LoadOptionPtr
+= sizeof (UINT16
);
1563 StringSize
= StrSize ((UINT16
*) LoadOptionPtr
);
1564 NewLoadContext
->Description
= AllocateZeroPool (StringSize
);
1565 ASSERT (NewLoadContext
->Description
!= NULL
);
1567 NewLoadContext
->Description
,
1568 (UINT16
*) LoadOptionPtr
,
1571 NewMenuEntry
->DisplayString
= NewLoadContext
->Description
;
1573 LoadOptionPtr
+= StringSize
;
1575 NewLoadContext
->FilePathList
= AllocateZeroPool (NewLoadContext
->FilePathListLength
);
1576 ASSERT (NewLoadContext
->FilePathList
!= NULL
);
1578 NewLoadContext
->FilePathList
,
1579 (EFI_DEVICE_PATH_PROTOCOL
*) LoadOptionPtr
,
1580 NewLoadContext
->FilePathListLength
1583 NewMenuEntry
->HelpString
= DevicePathToStr (NewLoadContext
->FilePathList
);
1584 NewMenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
1586 DriverOptionStrDepository
1588 NewMenuEntry
->HelpStringToken
= GetStringTokenFromDepository (
1590 DriverOptionHelpStrDepository
1592 LoadOptionPtr
+= NewLoadContext
->FilePathListLength
;
1594 if (LoadOptionPtr
< LoadOptionEnd
) {
1595 OptionalDataSize
= DriverOptionSize
-
1599 NewLoadContext
->FilePathListLength
;
1601 NewLoadContext
->OptionalData
= AllocateZeroPool (OptionalDataSize
);
1602 ASSERT (NewLoadContext
->OptionalData
!= NULL
);
1604 NewLoadContext
->OptionalData
,
1609 NewLoadContext
->OptionalDataSize
= OptionalDataSize
;
1612 InsertTailList (&DriverOptionMenu
.Head
, &NewMenuEntry
->Link
);
1616 SafeFreePool (DriverOrderList
);
1617 DriverOptionMenu
.MenuNumber
= Index
;