2 Provide boot option support for Application "BootMaint"
4 Include file system navigation, system handle selection
6 Boot option manipulation
8 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
9 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"
22 /// Define the maximum characters that will be accepted.
27 Create a menu entry by given menu type.
29 @param MenuType The Menu type to be created.
31 @retval NULL If failed to create the menu.
32 @return the new menu entry.
36 BOpt_CreateMenuEntry (
40 BM_MENU_ENTRY
*MenuEntry
;
44 // Get context size according to menu type
47 case BM_LOAD_CONTEXT_SELECT
:
48 ContextSize
= sizeof (BM_LOAD_CONTEXT
);
51 case BM_FILE_CONTEXT_SELECT
:
52 ContextSize
= sizeof (BM_FILE_CONTEXT
);
55 case BM_CONSOLE_CONTEXT_SELECT
:
56 ContextSize
= sizeof (BM_CONSOLE_CONTEXT
);
59 case BM_TERMINAL_CONTEXT_SELECT
:
60 ContextSize
= sizeof (BM_TERMINAL_CONTEXT
);
63 case BM_HANDLE_CONTEXT_SELECT
:
64 ContextSize
= sizeof (BM_HANDLE_CONTEXT
);
72 if (ContextSize
== 0) {
77 // Create new menu entry
79 MenuEntry
= AllocateZeroPool (sizeof (BM_MENU_ENTRY
));
80 if (MenuEntry
== NULL
) {
84 MenuEntry
->VariableContext
= AllocateZeroPool (ContextSize
);
85 if (MenuEntry
->VariableContext
== NULL
) {
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
;
113 // Select by the type in Menu entry for current context type
115 switch (MenuEntry
->ContextSelection
) {
116 case BM_LOAD_CONTEXT_SELECT
:
117 LoadContext
= (BM_LOAD_CONTEXT
*) MenuEntry
->VariableContext
;
118 FreePool (LoadContext
->FilePathList
);
119 FreePool (LoadContext
->LoadOption
);
120 if (LoadContext
->OptionalData
!= NULL
) {
121 FreePool (LoadContext
->OptionalData
);
123 FreePool (LoadContext
);
126 case BM_FILE_CONTEXT_SELECT
:
127 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
129 if (!FileContext
->IsRoot
) {
130 FreePool (FileContext
->DevicePath
);
132 if (FileContext
->FHandle
!= NULL
) {
133 FileContext
->FHandle
->Close (FileContext
->FHandle
);
137 if (FileContext
->FileName
!= NULL
) {
138 FreePool (FileContext
->FileName
);
140 if (FileContext
->Info
!= NULL
) {
141 FreePool (FileContext
->Info
);
143 FreePool (FileContext
);
146 case BM_CONSOLE_CONTEXT_SELECT
:
147 ConsoleContext
= (BM_CONSOLE_CONTEXT
*) MenuEntry
->VariableContext
;
148 FreePool (ConsoleContext
->DevicePath
);
149 FreePool (ConsoleContext
);
152 case BM_TERMINAL_CONTEXT_SELECT
:
153 TerminalContext
= (BM_TERMINAL_CONTEXT
*) MenuEntry
->VariableContext
;
154 FreePool (TerminalContext
->DevicePath
);
155 FreePool (TerminalContext
);
158 case BM_HANDLE_CONTEXT_SELECT
:
159 HandleContext
= (BM_HANDLE_CONTEXT
*) MenuEntry
->VariableContext
;
160 FreePool (HandleContext
);
167 FreePool (MenuEntry
->DisplayString
);
168 if (MenuEntry
->HelpString
!= NULL
) {
169 FreePool (MenuEntry
->HelpString
);
172 FreePool (MenuEntry
);
176 Get the Menu Entry from the list in Menu Entry List.
178 If MenuNumber is great or equal to the number of Menu
179 Entry in the list, then ASSERT.
181 @param MenuOption The Menu Entry List to read the menu entry.
182 @param MenuNumber The index of Menu Entry.
184 @return The Menu Entry.
189 BM_MENU_OPTION
*MenuOption
,
193 BM_MENU_ENTRY
*NewMenuEntry
;
197 ASSERT (MenuNumber
< MenuOption
->MenuNumber
);
199 List
= MenuOption
->Head
.ForwardLink
;
200 for (Index
= 0; Index
< MenuNumber
; Index
++) {
201 List
= List
->ForwardLink
;
204 NewMenuEntry
= CR (List
, BM_MENU_ENTRY
, Link
, BM_MENU_ENTRY_SIGNATURE
);
210 This function build the FsOptionMenu list which records all
211 available file system in the system. They includes all instances
212 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
213 and all type of legacy boot device.
215 @param CallbackData BMM context data
217 @retval EFI_SUCCESS Success find the file system
218 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
222 BOpt_FindFileSystem (
223 IN BMM_CALLBACK_DATA
*CallbackData
226 UINTN NoBlkIoHandles
;
227 UINTN NoSimpleFsHandles
;
228 UINTN NoLoadFileHandles
;
229 EFI_HANDLE
*BlkIoHandle
;
230 EFI_HANDLE
*SimpleFsHandle
;
231 EFI_HANDLE
*LoadFileHandle
;
233 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
236 BM_MENU_ENTRY
*MenuEntry
;
237 BM_FILE_CONTEXT
*FileContext
;
241 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
243 BBS_BBS_DEVICE_PATH BbsDevicePathNode
;
244 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
245 BOOLEAN RemovableMedia
;
248 NoSimpleFsHandles
= 0;
249 NoLoadFileHandles
= 0;
251 InitializeListHead (&FsOptionMenu
.Head
);
254 // Locate Handles that support BlockIo protocol
256 Status
= gBS
->LocateHandleBuffer (
258 &gEfiBlockIoProtocolGuid
,
263 if (!EFI_ERROR (Status
)) {
265 for (Index
= 0; Index
< NoBlkIoHandles
; Index
++) {
266 Status
= gBS
->HandleProtocol (
268 &gEfiBlockIoProtocolGuid
,
272 if (EFI_ERROR (Status
)) {
277 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
279 if (BlkIo
->Media
->RemovableMedia
) {
280 Buffer
= AllocateZeroPool (BlkIo
->Media
->BlockSize
);
281 if (NULL
== Buffer
) {
282 FreePool (BlkIoHandle
);
283 return EFI_OUT_OF_RESOURCES
;
288 BlkIo
->Media
->MediaId
,
290 BlkIo
->Media
->BlockSize
,
296 FreePool (BlkIoHandle
);
300 // Locate Handles that support Simple File System protocol
302 Status
= gBS
->LocateHandleBuffer (
304 &gEfiSimpleFileSystemProtocolGuid
,
309 if (!EFI_ERROR (Status
)) {
311 // Find all the instances of the File System prototocol
313 for (Index
= 0; Index
< NoSimpleFsHandles
; Index
++) {
314 Status
= gBS
->HandleProtocol (
315 SimpleFsHandle
[Index
],
316 &gEfiBlockIoProtocolGuid
,
319 if (EFI_ERROR (Status
)) {
321 // If no block IO exists assume it's NOT a removable media
323 RemovableMedia
= FALSE
;
326 // If block IO exists check to see if it's remobable media
328 RemovableMedia
= BlkIo
->Media
->RemovableMedia
;
332 // Allocate pool for this load option
334 MenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
335 if (NULL
== MenuEntry
) {
336 FreePool (SimpleFsHandle
);
337 return EFI_OUT_OF_RESOURCES
;
340 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
342 FileContext
->Handle
= SimpleFsHandle
[Index
];
343 MenuEntry
->OptionNumber
= Index
;
344 FileContext
->FHandle
= EfiLibOpenRoot (FileContext
->Handle
);
345 if (FileContext
->FHandle
== NULL
) {
346 BOpt_DestroyMenuEntry (MenuEntry
);
350 MenuEntry
->HelpString
= UiDevicePathToStr (DevicePathFromHandle (FileContext
->Handle
));
351 FileContext
->Info
= EfiLibFileSystemVolumeLabelInfo (FileContext
->FHandle
);
352 FileContext
->FileName
= EfiStrDuplicate (L
"\\");
353 FileContext
->DevicePath
= FileDevicePath (
355 FileContext
->FileName
357 FileContext
->IsDir
= TRUE
;
358 FileContext
->IsRoot
= TRUE
;
359 FileContext
->IsRemovableMedia
= RemovableMedia
;
360 FileContext
->IsLoadFile
= FALSE
;
363 // Get current file system's Volume Label
365 if (FileContext
->Info
== NULL
) {
366 VolumeLabel
= L
"NO FILE SYSTEM INFO";
368 if (FileContext
->Info
->VolumeLabel
== NULL
) {
369 VolumeLabel
= L
"NULL VOLUME LABEL";
371 VolumeLabel
= FileContext
->Info
->VolumeLabel
;
372 if (*VolumeLabel
== 0x0000) {
373 VolumeLabel
= L
"NO VOLUME LABEL";
378 TempStr
= MenuEntry
->HelpString
;
379 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
380 ASSERT (MenuEntry
->DisplayString
!= NULL
);
382 MenuEntry
->DisplayString
,
389 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
393 if (NoSimpleFsHandles
!= 0) {
394 FreePool (SimpleFsHandle
);
397 // Searching for handles that support Load File protocol
399 Status
= gBS
->LocateHandleBuffer (
401 &gEfiLoadFileProtocolGuid
,
407 if (!EFI_ERROR (Status
)) {
408 for (Index
= 0; Index
< NoLoadFileHandles
; Index
++) {
409 MenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
410 if (NULL
== MenuEntry
) {
411 FreePool (LoadFileHandle
);
412 return EFI_OUT_OF_RESOURCES
;
415 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
416 FileContext
->IsRemovableMedia
= FALSE
;
417 FileContext
->IsLoadFile
= TRUE
;
418 FileContext
->Handle
= LoadFileHandle
[Index
];
419 FileContext
->IsRoot
= TRUE
;
421 FileContext
->DevicePath
= DevicePathFromHandle (FileContext
->Handle
);
422 FileContext
->FileName
= UiDevicePathToStr (FileContext
->DevicePath
);
424 MenuEntry
->HelpString
= UiDevicePathToStr (FileContext
->DevicePath
);
426 TempStr
= MenuEntry
->HelpString
;
427 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
428 ASSERT (MenuEntry
->DisplayString
!= NULL
);
430 MenuEntry
->DisplayString
,
436 MenuEntry
->OptionNumber
= OptionNumber
;
438 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
442 if (NoLoadFileHandles
!= 0) {
443 FreePool (LoadFileHandle
);
447 // Add Legacy Boot Option Support Here
449 Status
= gBS
->LocateProtocol (
450 &gEfiLegacyBiosProtocolGuid
,
452 (VOID
**) &LegacyBios
454 if (!EFI_ERROR (Status
)) {
456 for (Index
= BBS_TYPE_FLOPPY
; Index
<= BBS_TYPE_EMBEDDED_NETWORK
; Index
++) {
457 MenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
458 if (NULL
== MenuEntry
) {
459 return EFI_OUT_OF_RESOURCES
;
462 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
464 FileContext
->IsRemovableMedia
= FALSE
;
465 FileContext
->IsLoadFile
= TRUE
;
466 FileContext
->IsBootLegacy
= TRUE
;
467 DeviceType
= (UINT16
) Index
;
468 BbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
469 BbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
470 SetDevicePathNodeLength (
471 &BbsDevicePathNode
.Header
,
472 sizeof (BBS_BBS_DEVICE_PATH
)
474 BbsDevicePathNode
.DeviceType
= DeviceType
;
475 BbsDevicePathNode
.StatusFlag
= 0;
476 BbsDevicePathNode
.String
[0] = 0;
477 DevicePath
= AppendDevicePathNode (
479 (EFI_DEVICE_PATH_PROTOCOL
*) &BbsDevicePathNode
482 FileContext
->DevicePath
= DevicePath
;
483 MenuEntry
->HelpString
= UiDevicePathToStr (FileContext
->DevicePath
);
485 TempStr
= MenuEntry
->HelpString
;
486 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
487 ASSERT (MenuEntry
->DisplayString
!= NULL
);
489 MenuEntry
->DisplayString
,
494 MenuEntry
->OptionNumber
= OptionNumber
;
496 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
500 // Remember how many file system options are here
502 FsOptionMenu
.MenuNumber
= OptionNumber
;
507 Free resources allocated in Allocate Rountine.
509 @param FreeMenu Menu to be freed
513 BM_MENU_OPTION
*FreeMenu
516 BM_MENU_ENTRY
*MenuEntry
;
517 while (!IsListEmpty (&FreeMenu
->Head
)) {
519 FreeMenu
->Head
.ForwardLink
,
522 BM_MENU_ENTRY_SIGNATURE
524 RemoveEntryList (&MenuEntry
->Link
);
525 BOpt_DestroyMenuEntry (MenuEntry
);
527 FreeMenu
->MenuNumber
= 0;
531 Find files under current directory
532 All files and sub-directories in current directory
533 will be stored in DirectoryMenu for future use.
535 @param CallbackData The BMM context data.
536 @param MenuEntry The Menu Entry.
538 @retval EFI_SUCCESS Get files from current dir successfully.
539 @return Other value if can't get files from current dir.
544 IN BMM_CALLBACK_DATA
*CallbackData
,
545 IN BM_MENU_ENTRY
*MenuEntry
548 EFI_FILE_HANDLE NewDir
;
550 EFI_FILE_INFO
*DirInfo
;
553 BM_MENU_ENTRY
*NewMenuEntry
;
554 BM_FILE_CONTEXT
*FileContext
;
555 BM_FILE_CONTEXT
*NewFileContext
;
560 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
561 Dir
= FileContext
->FHandle
;
564 // Open current directory to get files from it
569 FileContext
->FileName
,
573 if (!FileContext
->IsRoot
) {
577 if (EFI_ERROR (Status
)) {
581 DirInfo
= EfiLibFileInfo (NewDir
);
582 if (DirInfo
== NULL
) {
583 return EFI_NOT_FOUND
;
586 if ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0) {
587 return EFI_INVALID_PARAMETER
;
590 FileContext
->DevicePath
= FileDevicePath (
592 FileContext
->FileName
595 DirBufferSize
= sizeof (EFI_FILE_INFO
) + 1024;
596 DirInfo
= AllocateZeroPool (DirBufferSize
);
597 if (DirInfo
== NULL
) {
598 return EFI_OUT_OF_RESOURCES
;
601 // Get all files in current directory
602 // Pass 1 to get Directories
603 // Pass 2 to get files that are EFI images
605 for (Pass
= 1; Pass
<= 2; Pass
++) {
606 NewDir
->SetPosition (NewDir
, 0);
608 BufferSize
= DirBufferSize
;
609 Status
= NewDir
->Read (NewDir
, &BufferSize
, DirInfo
);
610 if (EFI_ERROR (Status
) || BufferSize
== 0) {
614 if (((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0 && Pass
== 2) ||
615 ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0 && Pass
== 1)
618 // Pass 1 is for Directories
619 // Pass 2 is for file names
624 if (!(BOpt_IsEfiImageName (DirInfo
->FileName
) || (DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0)) {
626 // Slip file unless it is a directory entry or a .EFI file
631 NewMenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
632 if (NULL
== NewMenuEntry
) {
633 return EFI_OUT_OF_RESOURCES
;
636 NewFileContext
= (BM_FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
637 NewFileContext
->Handle
= FileContext
->Handle
;
638 NewFileContext
->FileName
= BOpt_AppendFileName (
639 FileContext
->FileName
,
642 NewFileContext
->FHandle
= NewDir
;
643 NewFileContext
->DevicePath
= FileDevicePath (
644 NewFileContext
->Handle
,
645 NewFileContext
->FileName
647 NewMenuEntry
->HelpString
= NULL
;
649 MenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
651 FileOptionStrDepository
654 NewFileContext
->IsDir
= (BOOLEAN
) ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
);
656 if (NewFileContext
->IsDir
) {
657 BufferSize
= StrLen (DirInfo
->FileName
) * 2 + 6;
658 NewMenuEntry
->DisplayString
= AllocateZeroPool (BufferSize
);
661 NewMenuEntry
->DisplayString
,
668 NewMenuEntry
->DisplayString
= EfiStrDuplicate (DirInfo
->FileName
);
671 NewFileContext
->IsRoot
= FALSE
;
672 NewFileContext
->IsLoadFile
= FALSE
;
673 NewFileContext
->IsRemovableMedia
= FALSE
;
675 NewMenuEntry
->OptionNumber
= OptionNumber
;
677 InsertTailList (&DirectoryMenu
.Head
, &NewMenuEntry
->Link
);
681 DirectoryMenu
.MenuNumber
= OptionNumber
;
688 Build the BootOptionMenu according to BootOrder Variable.
689 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
691 @param CallbackData The BMM context data.
693 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
694 @return EFI_SUCESS Success build boot option menu.
698 BOpt_GetBootOptions (
699 IN BMM_CALLBACK_DATA
*CallbackData
703 UINT16 BootString
[10];
704 UINT8
*LoadOptionFromVar
;
706 UINTN BootOptionSize
;
707 BOOLEAN BootNextFlag
;
708 UINT16
*BootOrderList
;
709 UINTN BootOrderListSize
;
712 BM_MENU_ENTRY
*NewMenuEntry
;
713 BM_LOAD_CONTEXT
*NewLoadContext
;
714 UINT8
*LoadOptionPtr
;
716 UINTN OptionalDataSize
;
717 UINT8
*LoadOptionEnd
;
718 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
721 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
722 UINTN BootOptionCount
;
725 BootOrderListSize
= 0;
727 BootOrderList
= NULL
;
729 LoadOptionFromVar
= NULL
;
730 BOpt_FreeMenu (&BootOptionMenu
);
731 InitializeListHead (&BootOptionMenu
.Head
);
734 // Get the BootOrder from the Var
736 GetEfiGlobalVariable2 (L
"BootOrder", (VOID
**) &BootOrderList
, &BootOrderListSize
);
737 if (BootOrderList
== NULL
) {
738 return EFI_NOT_FOUND
;
742 // Get the BootNext from the Var
744 GetEfiGlobalVariable2 (L
"BootNext", (VOID
**) &BootNext
, &BootNextSize
);
745 if (BootNext
!= NULL
) {
746 if (BootNextSize
!= sizeof (UINT16
)) {
751 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
752 for (Index
= 0; Index
< BootOrderListSize
/ sizeof (UINT16
); Index
++) {
754 // Don't display the hidden/inactive boot option
756 if (((BootOption
[Index
].Attributes
& LOAD_OPTION_HIDDEN
) != 0) || ((BootOption
[Index
].Attributes
& LOAD_OPTION_ACTIVE
) == 0)) {
760 UnicodeSPrint (BootString
, sizeof (BootString
), L
"Boot%04x", BootOrderList
[Index
]);
762 // Get all loadoptions from the VAR
764 GetEfiGlobalVariable2 (BootString
, (VOID
**) &LoadOptionFromVar
, &BootOptionSize
);
765 if (LoadOptionFromVar
== NULL
) {
769 LoadOption
= AllocateZeroPool (BootOptionSize
);
770 if (LoadOption
== NULL
) {
774 CopyMem (LoadOption
, LoadOptionFromVar
, BootOptionSize
);
775 FreePool (LoadOptionFromVar
);
777 if (BootNext
!= NULL
) {
778 BootNextFlag
= (BOOLEAN
) (*BootNext
== BootOrderList
[Index
]);
780 BootNextFlag
= FALSE
;
783 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT
);
784 ASSERT (NULL
!= NewMenuEntry
);
786 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
788 LoadOptionPtr
= LoadOption
;
789 LoadOptionEnd
= LoadOption
+ BootOptionSize
;
791 NewMenuEntry
->OptionNumber
= BootOrderList
[Index
];
792 NewLoadContext
->LoadOptionModified
= FALSE
;
793 NewLoadContext
->Deleted
= FALSE
;
794 NewLoadContext
->IsBootNext
= BootNextFlag
;
797 // Is a Legacy Device?
799 Ptr
= (UINT8
*) LoadOption
;
802 // Attribute = *(UINT32 *)Ptr;
804 Ptr
+= sizeof (UINT32
);
807 // FilePathSize = *(UINT16 *)Ptr;
809 Ptr
+= sizeof (UINT16
);
812 // Description = (CHAR16 *)Ptr;
814 Ptr
+= StrSize ((CHAR16
*) Ptr
);
817 // Now Ptr point to Device Path
819 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
820 if ((BBS_DEVICE_PATH
== DevicePath
->Type
) && (BBS_BBS_DP
== DevicePath
->SubType
)) {
821 NewLoadContext
->IsLegacy
= TRUE
;
823 NewLoadContext
->IsLegacy
= FALSE
;
826 // LoadOption is a pointer type of UINT8
827 // for easy use with following LOAD_OPTION
828 // embedded in this struct
830 NewLoadContext
->LoadOption
= LoadOption
;
831 NewLoadContext
->LoadOptionSize
= BootOptionSize
;
833 NewLoadContext
->Attributes
= *(UINT32
*) LoadOptionPtr
;
834 NewLoadContext
->IsActive
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_ACTIVE
);
836 NewLoadContext
->ForceReconnect
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_FORCE_RECONNECT
);
838 LoadOptionPtr
+= sizeof (UINT32
);
840 NewLoadContext
->FilePathListLength
= *(UINT16
*) LoadOptionPtr
;
841 LoadOptionPtr
+= sizeof (UINT16
);
843 StringSize
= StrSize((UINT16
*)LoadOptionPtr
);
845 NewLoadContext
->Description
= AllocateZeroPool (StrSize((UINT16
*)LoadOptionPtr
));
846 ASSERT (NewLoadContext
->Description
!= NULL
);
847 StrCpy (NewLoadContext
->Description
, (UINT16
*)LoadOptionPtr
);
849 ASSERT (NewLoadContext
->Description
!= NULL
);
850 NewMenuEntry
->DisplayString
= NewLoadContext
->Description
;
852 LoadOptionPtr
+= StringSize
;
854 NewLoadContext
->FilePathList
= AllocateZeroPool (NewLoadContext
->FilePathListLength
);
855 ASSERT (NewLoadContext
->FilePathList
!= NULL
);
857 NewLoadContext
->FilePathList
,
858 (EFI_DEVICE_PATH_PROTOCOL
*) LoadOptionPtr
,
859 NewLoadContext
->FilePathListLength
862 NewMenuEntry
->HelpString
= UiDevicePathToStr (NewLoadContext
->FilePathList
);
863 NewMenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
865 BootOptionStrDepository
867 NewMenuEntry
->HelpStringToken
= GetStringTokenFromDepository (
869 BootOptionHelpStrDepository
871 LoadOptionPtr
+= NewLoadContext
->FilePathListLength
;
873 if (LoadOptionPtr
< LoadOptionEnd
) {
874 OptionalDataSize
= BootOptionSize
-
878 NewLoadContext
->FilePathListLength
;
880 NewLoadContext
->OptionalData
= AllocateZeroPool (OptionalDataSize
);
881 ASSERT (NewLoadContext
->OptionalData
!= NULL
);
883 NewLoadContext
->OptionalData
,
888 NewLoadContext
->OptionalDataSize
= OptionalDataSize
;
891 InsertTailList (&BootOptionMenu
.Head
, &NewMenuEntry
->Link
);
894 EfiBootManagerFreeLoadOptions (BootOption
, BootOptionCount
);
896 if (BootNext
!= NULL
) {
899 if (BootOrderList
!= NULL
) {
900 FreePool (BootOrderList
);
902 BootOptionMenu
.MenuNumber
= MenuCount
;
908 Append file name to existing file name.
910 @param Str1 The existing file name
911 @param Str2 The file name to be appended
913 @return Allocate a new string to hold the appended result.
914 Caller is responsible to free the returned string.
918 BOpt_AppendFileName (
930 Size1
= StrSize (Str1
);
931 Size2
= StrSize (Str2
);
932 Str
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
933 ASSERT (Str
!= NULL
);
935 TmpStr
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
936 ASSERT (TmpStr
!= NULL
);
939 if (!((*Str
== '\\') && (*(Str
+ 1) == 0))) {
948 if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '.' && *(Ptr
+ 3) == L
'\\') {
950 // Convert "\Name\..\" to "\"
951 // DO NOT convert the .. if it is at the end of the string. This will
952 // break the .. behavior in changing directories.
956 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
959 StrCpy (TmpStr
, Ptr
+ 3);
960 StrCpy (LastSlash
, TmpStr
);
962 } else if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '\\') {
964 // Convert a "\.\" to a "\"
968 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
971 StrCpy (TmpStr
, Ptr
+ 2);
972 StrCpy (Ptr
, TmpStr
);
974 } else if (*Ptr
== '\\') {
988 Check whether current FileName point to a valid
991 @param FileName File need to be checked.
993 @retval TRUE Is Efi Image
994 @retval FALSE Not a valid Efi Image
998 BOpt_IsEfiImageName (
1003 // Search for ".efi" extension
1005 while (*FileName
!= L
'\0') {
1006 if (FileName
[0] == '.') {
1007 if (FileName
[1] == 'e' || FileName
[1] == 'E') {
1008 if (FileName
[2] == 'f' || FileName
[2] == 'F') {
1009 if (FileName
[3] == 'i' || FileName
[3] == 'I') {
1011 } else if (FileName
[3] == 0x0000) {
1014 } else if (FileName
[2] == 0x0000) {
1017 } else if (FileName
[1] == 0x0000) {
1030 Check whether current FileName point to a valid Efi Application
1032 @param Dir Pointer to current Directory
1033 @param FileName Pointer to current File name.
1035 @retval TRUE Is a valid Efi Application
1036 @retval FALSE not a valid Efi Application
1041 IN EFI_FILE_HANDLE Dir
,
1046 EFI_IMAGE_DOS_HEADER DosHdr
;
1048 EFI_FILE_HANDLE File
;
1050 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
1052 Status
= Dir
->Open (Dir
, &File
, FileName
, EFI_FILE_MODE_READ
, 0);
1054 if (EFI_ERROR (Status
)) {
1058 BufferSize
= sizeof (EFI_IMAGE_DOS_HEADER
);
1059 File
->Read (File
, &BufferSize
, &DosHdr
);
1060 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
1065 File
->SetPosition (File
, DosHdr
.e_lfanew
);
1066 BufferSize
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
1067 File
->Read (File
, &BufferSize
, &PeHdr
);
1068 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1073 // Determine PE type and read subsytem
1075 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1076 Subsystem
= PeHdr
.Pe32
.OptionalHeader
.Subsystem
;
1077 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1078 Subsystem
= PeHdr
.Pe32Plus
.OptionalHeader
.Subsystem
;
1083 if (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1094 Find drivers that will be added as Driver#### variables from handles
1095 in current system environment
1096 All valid handles in the system except those consume SimpleFs, LoadFile
1097 are stored in DriverMenu for future use.
1099 @retval EFI_SUCCESS The function complets successfully.
1100 @return Other value if failed to build the DriverMenu.
1108 UINTN NoDevicePathHandles
;
1109 EFI_HANDLE
*DevicePathHandle
;
1112 BM_MENU_ENTRY
*NewMenuEntry
;
1113 BM_HANDLE_CONTEXT
*NewHandleContext
;
1114 EFI_HANDLE CurHandle
;
1116 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFs
;
1117 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1122 InitializeListHead (&DriverMenu
.Head
);
1125 // At first, get all handles that support Device Path
1126 // protocol which is the basic requirement for
1129 Status
= gBS
->LocateHandleBuffer (
1131 &gEfiDevicePathProtocolGuid
,
1133 &NoDevicePathHandles
,
1136 if (EFI_ERROR (Status
)) {
1141 for (Index
= 0; Index
< NoDevicePathHandles
; Index
++) {
1142 CurHandle
= DevicePathHandle
[Index
];
1144 Status
= gBS
->HandleProtocol (
1146 &gEfiSimpleFileSystemProtocolGuid
,
1149 if (Status
== EFI_SUCCESS
) {
1153 Status
= gBS
->HandleProtocol (
1155 &gEfiLoadFileProtocolGuid
,
1158 if (Status
== EFI_SUCCESS
) {
1162 NewMenuEntry
= BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT
);
1163 if (NULL
== NewMenuEntry
) {
1164 FreePool (DevicePathHandle
);
1165 return EFI_OUT_OF_RESOURCES
;
1168 NewHandleContext
= (BM_HANDLE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1169 NewHandleContext
->Handle
= CurHandle
;
1170 NewHandleContext
->DevicePath
= DevicePathFromHandle (CurHandle
);
1171 NewMenuEntry
->DisplayString
= UiDevicePathToStr (NewHandleContext
->DevicePath
);
1172 NewMenuEntry
->HelpString
= NULL
;
1173 NewMenuEntry
->OptionNumber
= OptionNumber
;
1175 InsertTailList (&DriverMenu
.Head
, &NewMenuEntry
->Link
);
1179 if (DevicePathHandle
!= NULL
) {
1180 FreePool (DevicePathHandle
);
1183 DriverMenu
.MenuNumber
= OptionNumber
;
1189 Get the Option Number that has not been allocated for use.
1191 @param Type The type of Option.
1193 @return The available Option Number.
1197 BOpt_GetOptionNumber (
1202 UINTN OrderListSize
;
1205 UINT16
*OptionBuffer
;
1206 UINT16 OptionNumber
;
1214 UnicodeSPrint (StrTemp
, sizeof (StrTemp
), L
"%sOrder", Type
);
1216 GetEfiGlobalVariable2 (StrTemp
, (VOID
**) &OrderList
, &OrderListSize
);
1217 for (OptionNumber
= 0; ; OptionNumber
++) {
1218 if (OrderList
!= NULL
) {
1219 for (Index
= 0; Index
< OrderListSize
/ sizeof (UINT16
); Index
++) {
1220 if (OptionNumber
== OrderList
[Index
]) {
1226 if (Index
< OrderListSize
/ sizeof (UINT16
)) {
1228 // The OptionNumber occurs in the OrderList, continue to use next one
1232 UnicodeSPrint (StrTemp
, sizeof (StrTemp
), L
"%s%04x", Type
, (UINTN
) OptionNumber
);
1233 DEBUG((EFI_D_ERROR
,"Option = %s\n", StrTemp
));
1234 GetEfiGlobalVariable2 (StrTemp
, (VOID
**) &OptionBuffer
, &OptionSize
);
1235 if (NULL
== OptionBuffer
) {
1237 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
1243 return OptionNumber
;
1248 Get the Option Number for Boot#### that does not used.
1250 @return The available Option Number.
1254 BOpt_GetBootOptionNumber (
1258 return BOpt_GetOptionNumber (L
"Boot");
1263 Get the Option Number for Driver#### that does not used.
1265 @return The unused Option Number.
1269 BOpt_GetDriverOptionNumber (
1273 return BOpt_GetOptionNumber (L
"Driver");
1278 Build up all DriverOptionMenu
1280 @param CallbackData The BMM context data.
1282 @retval EFI_SUCESS The functin completes successfully.
1283 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1284 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
1288 BOpt_GetDriverOptions (
1289 IN BMM_CALLBACK_DATA
*CallbackData
1293 UINT16 DriverString
[12];
1294 UINT8
*LoadOptionFromVar
;
1296 UINTN DriverOptionSize
;
1298 UINT16
*DriverOrderList
;
1299 UINTN DriverOrderListSize
;
1300 BM_MENU_ENTRY
*NewMenuEntry
;
1301 BM_LOAD_CONTEXT
*NewLoadContext
;
1302 UINT8
*LoadOptionPtr
;
1304 UINTN OptionalDataSize
;
1305 UINT8
*LoadOptionEnd
;
1307 DriverOrderListSize
= 0;
1308 DriverOrderList
= NULL
;
1309 DriverOptionSize
= 0;
1310 LoadOptionFromVar
= NULL
;
1311 BOpt_FreeMenu (&DriverOptionMenu
);
1312 InitializeListHead (&DriverOptionMenu
.Head
);
1314 // Get the DriverOrder from the Var
1316 GetEfiGlobalVariable2 (L
"DriverOrder", (VOID
**) &DriverOrderList
, &DriverOrderListSize
);
1317 if (DriverOrderList
== NULL
) {
1318 return EFI_NOT_FOUND
;
1321 for (Index
= 0; Index
< DriverOrderListSize
/ sizeof (UINT16
); Index
++) {
1324 sizeof (DriverString
),
1326 DriverOrderList
[Index
]
1329 // Get all loadoptions from the VAR
1331 GetEfiGlobalVariable2 (DriverString
, (VOID
**) &LoadOptionFromVar
, &DriverOptionSize
);
1332 if (LoadOptionFromVar
== NULL
) {
1336 LoadOption
= AllocateZeroPool (DriverOptionSize
);
1337 if (LoadOption
== NULL
) {
1341 CopyMem (LoadOption
, LoadOptionFromVar
, DriverOptionSize
);
1342 FreePool (LoadOptionFromVar
);
1344 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT
);
1345 if (NULL
== NewMenuEntry
) {
1346 return EFI_OUT_OF_RESOURCES
;
1349 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
1350 LoadOptionPtr
= LoadOption
;
1351 LoadOptionEnd
= LoadOption
+ DriverOptionSize
;
1352 NewMenuEntry
->OptionNumber
= DriverOrderList
[Index
];
1353 NewLoadContext
->LoadOptionModified
= FALSE
;
1354 NewLoadContext
->Deleted
= FALSE
;
1355 NewLoadContext
->IsLegacy
= FALSE
;
1358 // LoadOption is a pointer type of UINT8
1359 // for easy use with following LOAD_OPTION
1360 // embedded in this struct
1362 NewLoadContext
->LoadOption
= LoadOption
;
1363 NewLoadContext
->LoadOptionSize
= DriverOptionSize
;
1365 NewLoadContext
->Attributes
= *(UINT32
*) LoadOptionPtr
;
1366 NewLoadContext
->IsActive
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_ACTIVE
);
1368 NewLoadContext
->ForceReconnect
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_FORCE_RECONNECT
);
1370 LoadOptionPtr
+= sizeof (UINT32
);
1372 NewLoadContext
->FilePathListLength
= *(UINT16
*) LoadOptionPtr
;
1373 LoadOptionPtr
+= sizeof (UINT16
);
1375 StringSize
= StrSize ((UINT16
*) LoadOptionPtr
);
1376 NewLoadContext
->Description
= AllocateZeroPool (StringSize
);
1377 ASSERT (NewLoadContext
->Description
!= NULL
);
1379 NewLoadContext
->Description
,
1380 (UINT16
*) LoadOptionPtr
,
1383 NewMenuEntry
->DisplayString
= NewLoadContext
->Description
;
1385 LoadOptionPtr
+= StringSize
;
1387 NewLoadContext
->FilePathList
= AllocateZeroPool (NewLoadContext
->FilePathListLength
);
1388 ASSERT (NewLoadContext
->FilePathList
!= NULL
);
1390 NewLoadContext
->FilePathList
,
1391 (EFI_DEVICE_PATH_PROTOCOL
*) LoadOptionPtr
,
1392 NewLoadContext
->FilePathListLength
1395 NewMenuEntry
->HelpString
= UiDevicePathToStr (NewLoadContext
->FilePathList
);
1396 NewMenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
1398 DriverOptionStrDepository
1400 NewMenuEntry
->HelpStringToken
= GetStringTokenFromDepository (
1402 DriverOptionHelpStrDepository
1404 LoadOptionPtr
+= NewLoadContext
->FilePathListLength
;
1406 if (LoadOptionPtr
< LoadOptionEnd
) {
1407 OptionalDataSize
= DriverOptionSize
-
1411 NewLoadContext
->FilePathListLength
;
1413 NewLoadContext
->OptionalData
= AllocateZeroPool (OptionalDataSize
);
1414 ASSERT (NewLoadContext
->OptionalData
!= NULL
);
1416 NewLoadContext
->OptionalData
,
1421 NewLoadContext
->OptionalDataSize
= OptionalDataSize
;
1424 InsertTailList (&DriverOptionMenu
.Head
, &NewMenuEntry
->Link
);
1428 if (DriverOrderList
!= NULL
) {
1429 FreePool (DriverOrderList
);
1431 DriverOptionMenu
.MenuNumber
= Index
;
1437 Get option number according to Boot#### and BootOrder variable.
1438 The value is saved as #### + 1.
1440 @param CallbackData The BMM context data.
1444 IN BMM_CALLBACK_DATA
*CallbackData
1447 BMM_FAKE_NV_DATA
*BmmConfig
;
1449 UINT16 OptionOrderIndex
;
1451 BM_MENU_ENTRY
*NewMenuEntry
;
1452 BM_LOAD_CONTEXT
*NewLoadContext
;
1454 ASSERT (CallbackData
!= NULL
);
1456 DeviceType
= (UINTN
) -1;
1457 BmmConfig
= &CallbackData
->BmmFakeNvData
;
1458 ZeroMem (BmmConfig
->BootOptionOrder
, sizeof (BmmConfig
->BootOptionOrder
));
1460 for (Index
= 0, OptionOrderIndex
= 0; ((Index
< BootOptionMenu
.MenuNumber
) &&
1461 (OptionOrderIndex
< (sizeof (BmmConfig
->BootOptionOrder
) / sizeof (BmmConfig
->BootOptionOrder
[0]))));
1463 NewMenuEntry
= BOpt_GetMenuEntry (&BootOptionMenu
, Index
);
1464 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
1466 if (NewLoadContext
->IsLegacy
) {
1467 if (((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
!= DeviceType
) {
1468 DeviceType
= ((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
;
1471 // Only show one legacy boot option for the same device type
1472 // assuming the boot options are grouped by the device type
1477 BmmConfig
->BootOptionOrder
[OptionOrderIndex
++] = (UINT32
) (NewMenuEntry
->OptionNumber
+ 1);
1482 Get driver option order from globalc DriverOptionMenu.
1484 @param CallbackData The BMM context data.
1489 IN BMM_CALLBACK_DATA
*CallbackData
1492 BMM_FAKE_NV_DATA
*BmmConfig
;
1494 UINT16 OptionOrderIndex
;
1496 BM_MENU_ENTRY
*NewMenuEntry
;
1497 BM_LOAD_CONTEXT
*NewLoadContext
;
1500 ASSERT (CallbackData
!= NULL
);
1502 DeviceType
= (UINTN
) -1;
1503 BmmConfig
= &CallbackData
->BmmFakeNvData
;
1504 ZeroMem (BmmConfig
->DriverOptionOrder
, sizeof (BmmConfig
->DriverOptionOrder
));
1506 for (Index
= 0, OptionOrderIndex
= 0; ((Index
< DriverOptionMenu
.MenuNumber
) &&
1507 (OptionOrderIndex
< (sizeof (BmmConfig
->DriverOptionOrder
) / sizeof (BmmConfig
->DriverOptionOrder
[0]))));
1509 NewMenuEntry
= BOpt_GetMenuEntry (&DriverOptionMenu
, Index
);
1510 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
1512 if (NewLoadContext
->IsLegacy
) {
1513 if (((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
!= DeviceType
) {
1514 DeviceType
= ((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
;
1517 // Only show one legacy boot option for the same device type
1518 // assuming the boot options are grouped by the device type
1523 BmmConfig
->DriverOptionOrder
[OptionOrderIndex
++] = (UINT32
) (NewMenuEntry
->OptionNumber
+ 1);