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 BOOLEAN RemovableMedia
;
243 NoSimpleFsHandles
= 0;
244 NoLoadFileHandles
= 0;
246 InitializeListHead (&FsOptionMenu
.Head
);
249 // Locate Handles that support BlockIo protocol
251 Status
= gBS
->LocateHandleBuffer (
253 &gEfiBlockIoProtocolGuid
,
258 if (!EFI_ERROR (Status
)) {
260 for (Index
= 0; Index
< NoBlkIoHandles
; Index
++) {
261 Status
= gBS
->HandleProtocol (
263 &gEfiBlockIoProtocolGuid
,
267 if (EFI_ERROR (Status
)) {
272 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
274 if (BlkIo
->Media
->RemovableMedia
) {
275 Buffer
= AllocateZeroPool (BlkIo
->Media
->BlockSize
);
276 if (NULL
== Buffer
) {
277 FreePool (BlkIoHandle
);
278 return EFI_OUT_OF_RESOURCES
;
283 BlkIo
->Media
->MediaId
,
285 BlkIo
->Media
->BlockSize
,
291 FreePool (BlkIoHandle
);
295 // Locate Handles that support Simple File System protocol
297 Status
= gBS
->LocateHandleBuffer (
299 &gEfiSimpleFileSystemProtocolGuid
,
304 if (!EFI_ERROR (Status
)) {
306 // Find all the instances of the File System prototocol
308 for (Index
= 0; Index
< NoSimpleFsHandles
; Index
++) {
309 Status
= gBS
->HandleProtocol (
310 SimpleFsHandle
[Index
],
311 &gEfiBlockIoProtocolGuid
,
314 if (EFI_ERROR (Status
)) {
316 // If no block IO exists assume it's NOT a removable media
318 RemovableMedia
= FALSE
;
321 // If block IO exists check to see if it's remobable media
323 RemovableMedia
= BlkIo
->Media
->RemovableMedia
;
327 // Allocate pool for this load option
329 MenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
330 if (NULL
== MenuEntry
) {
331 FreePool (SimpleFsHandle
);
332 return EFI_OUT_OF_RESOURCES
;
335 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
337 FileContext
->Handle
= SimpleFsHandle
[Index
];
338 MenuEntry
->OptionNumber
= Index
;
339 FileContext
->FHandle
= EfiLibOpenRoot (FileContext
->Handle
);
340 if (FileContext
->FHandle
== NULL
) {
341 BOpt_DestroyMenuEntry (MenuEntry
);
345 MenuEntry
->HelpString
= UiDevicePathToStr (DevicePathFromHandle (FileContext
->Handle
));
346 FileContext
->Info
= EfiLibFileSystemVolumeLabelInfo (FileContext
->FHandle
);
347 FileContext
->FileName
= EfiStrDuplicate (L
"\\");
348 FileContext
->DevicePath
= FileDevicePath (
350 FileContext
->FileName
352 FileContext
->IsDir
= TRUE
;
353 FileContext
->IsRoot
= TRUE
;
354 FileContext
->IsRemovableMedia
= RemovableMedia
;
355 FileContext
->IsLoadFile
= FALSE
;
358 // Get current file system's Volume Label
360 if (FileContext
->Info
== NULL
) {
361 VolumeLabel
= L
"NO FILE SYSTEM INFO";
363 if (FileContext
->Info
->VolumeLabel
== NULL
) {
364 VolumeLabel
= L
"NULL VOLUME LABEL";
366 VolumeLabel
= FileContext
->Info
->VolumeLabel
;
367 if (*VolumeLabel
== 0x0000) {
368 VolumeLabel
= L
"NO VOLUME LABEL";
373 TempStr
= MenuEntry
->HelpString
;
374 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
375 ASSERT (MenuEntry
->DisplayString
!= NULL
);
377 MenuEntry
->DisplayString
,
384 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
388 if (NoSimpleFsHandles
!= 0) {
389 FreePool (SimpleFsHandle
);
392 // Searching for handles that support Load File protocol
394 Status
= gBS
->LocateHandleBuffer (
396 &gEfiLoadFileProtocolGuid
,
402 if (!EFI_ERROR (Status
)) {
403 for (Index
= 0; Index
< NoLoadFileHandles
; Index
++) {
404 MenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
405 if (NULL
== MenuEntry
) {
406 FreePool (LoadFileHandle
);
407 return EFI_OUT_OF_RESOURCES
;
410 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
411 FileContext
->IsRemovableMedia
= FALSE
;
412 FileContext
->IsLoadFile
= TRUE
;
413 FileContext
->Handle
= LoadFileHandle
[Index
];
414 FileContext
->IsRoot
= TRUE
;
416 FileContext
->DevicePath
= DevicePathFromHandle (FileContext
->Handle
);
417 FileContext
->FileName
= UiDevicePathToStr (FileContext
->DevicePath
);
419 MenuEntry
->HelpString
= UiDevicePathToStr (FileContext
->DevicePath
);
421 TempStr
= MenuEntry
->HelpString
;
422 MenuEntry
->DisplayString
= AllocateZeroPool (MAX_CHAR
);
423 ASSERT (MenuEntry
->DisplayString
!= NULL
);
425 MenuEntry
->DisplayString
,
431 MenuEntry
->OptionNumber
= OptionNumber
;
433 InsertTailList (&FsOptionMenu
.Head
, &MenuEntry
->Link
);
437 if (NoLoadFileHandles
!= 0) {
438 FreePool (LoadFileHandle
);
442 // Remember how many file system options are here
444 FsOptionMenu
.MenuNumber
= OptionNumber
;
449 Free resources allocated in Allocate Rountine.
451 @param FreeMenu Menu to be freed
455 BM_MENU_OPTION
*FreeMenu
458 BM_MENU_ENTRY
*MenuEntry
;
459 while (!IsListEmpty (&FreeMenu
->Head
)) {
461 FreeMenu
->Head
.ForwardLink
,
464 BM_MENU_ENTRY_SIGNATURE
466 RemoveEntryList (&MenuEntry
->Link
);
467 BOpt_DestroyMenuEntry (MenuEntry
);
469 FreeMenu
->MenuNumber
= 0;
473 Find files under current directory
474 All files and sub-directories in current directory
475 will be stored in DirectoryMenu for future use.
477 @param CallbackData The BMM context data.
478 @param MenuEntry The Menu Entry.
480 @retval EFI_SUCCESS Get files from current dir successfully.
481 @return Other value if can't get files from current dir.
486 IN BMM_CALLBACK_DATA
*CallbackData
,
487 IN BM_MENU_ENTRY
*MenuEntry
490 EFI_FILE_HANDLE NewDir
;
492 EFI_FILE_INFO
*DirInfo
;
495 BM_MENU_ENTRY
*NewMenuEntry
;
496 BM_FILE_CONTEXT
*FileContext
;
497 BM_FILE_CONTEXT
*NewFileContext
;
502 FileContext
= (BM_FILE_CONTEXT
*) MenuEntry
->VariableContext
;
503 Dir
= FileContext
->FHandle
;
506 // Open current directory to get files from it
511 FileContext
->FileName
,
515 if (!FileContext
->IsRoot
) {
519 if (EFI_ERROR (Status
)) {
523 DirInfo
= EfiLibFileInfo (NewDir
);
524 if (DirInfo
== NULL
) {
525 return EFI_NOT_FOUND
;
528 if ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0) {
529 return EFI_INVALID_PARAMETER
;
532 FileContext
->DevicePath
= FileDevicePath (
534 FileContext
->FileName
537 DirBufferSize
= sizeof (EFI_FILE_INFO
) + 1024;
538 DirInfo
= AllocateZeroPool (DirBufferSize
);
539 if (DirInfo
== NULL
) {
540 return EFI_OUT_OF_RESOURCES
;
543 // Get all files in current directory
544 // Pass 1 to get Directories
545 // Pass 2 to get files that are EFI images
547 for (Pass
= 1; Pass
<= 2; Pass
++) {
548 NewDir
->SetPosition (NewDir
, 0);
550 BufferSize
= DirBufferSize
;
551 Status
= NewDir
->Read (NewDir
, &BufferSize
, DirInfo
);
552 if (EFI_ERROR (Status
) || BufferSize
== 0) {
556 if (((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0 && Pass
== 2) ||
557 ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == 0 && Pass
== 1)
560 // Pass 1 is for Directories
561 // Pass 2 is for file names
566 if (!(BOpt_IsEfiImageName (DirInfo
->FileName
) || (DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) != 0)) {
568 // Slip file unless it is a directory entry or a .EFI file
573 NewMenuEntry
= BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT
);
574 if (NULL
== NewMenuEntry
) {
575 return EFI_OUT_OF_RESOURCES
;
578 NewFileContext
= (BM_FILE_CONTEXT
*) NewMenuEntry
->VariableContext
;
579 NewFileContext
->Handle
= FileContext
->Handle
;
580 NewFileContext
->FileName
= BOpt_AppendFileName (
581 FileContext
->FileName
,
584 NewFileContext
->FHandle
= NewDir
;
585 NewFileContext
->DevicePath
= FileDevicePath (
586 NewFileContext
->Handle
,
587 NewFileContext
->FileName
589 NewMenuEntry
->HelpString
= NULL
;
591 MenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
593 FileOptionStrDepository
596 NewFileContext
->IsDir
= (BOOLEAN
) ((DirInfo
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
);
598 if (NewFileContext
->IsDir
) {
599 BufferSize
= StrLen (DirInfo
->FileName
) * 2 + 6;
600 NewMenuEntry
->DisplayString
= AllocateZeroPool (BufferSize
);
603 NewMenuEntry
->DisplayString
,
610 NewMenuEntry
->DisplayString
= EfiStrDuplicate (DirInfo
->FileName
);
613 NewFileContext
->IsRoot
= FALSE
;
614 NewFileContext
->IsLoadFile
= FALSE
;
615 NewFileContext
->IsRemovableMedia
= FALSE
;
617 NewMenuEntry
->OptionNumber
= OptionNumber
;
619 InsertTailList (&DirectoryMenu
.Head
, &NewMenuEntry
->Link
);
623 DirectoryMenu
.MenuNumber
= OptionNumber
;
630 Build the BootOptionMenu according to BootOrder Variable.
631 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
633 @param CallbackData The BMM context data.
635 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
636 @return EFI_SUCESS Success build boot option menu.
640 BOpt_GetBootOptions (
641 IN BMM_CALLBACK_DATA
*CallbackData
645 UINT16 BootString
[10];
646 UINT8
*LoadOptionFromVar
;
648 UINTN BootOptionSize
;
649 BOOLEAN BootNextFlag
;
650 UINT16
*BootOrderList
;
651 UINTN BootOrderListSize
;
654 BM_MENU_ENTRY
*NewMenuEntry
;
655 BM_LOAD_CONTEXT
*NewLoadContext
;
656 UINT8
*LoadOptionPtr
;
658 UINTN OptionalDataSize
;
659 UINT8
*LoadOptionEnd
;
660 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
663 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
664 UINTN BootOptionCount
;
667 BootOrderListSize
= 0;
669 BootOrderList
= NULL
;
671 LoadOptionFromVar
= NULL
;
672 BOpt_FreeMenu (&BootOptionMenu
);
673 InitializeListHead (&BootOptionMenu
.Head
);
676 // Get the BootOrder from the Var
678 GetEfiGlobalVariable2 (L
"BootOrder", (VOID
**) &BootOrderList
, &BootOrderListSize
);
679 if (BootOrderList
== NULL
) {
680 return EFI_NOT_FOUND
;
684 // Get the BootNext from the Var
686 GetEfiGlobalVariable2 (L
"BootNext", (VOID
**) &BootNext
, &BootNextSize
);
687 if (BootNext
!= NULL
) {
688 if (BootNextSize
!= sizeof (UINT16
)) {
693 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
694 for (Index
= 0; Index
< BootOrderListSize
/ sizeof (UINT16
); Index
++) {
696 // Don't display the hidden/inactive boot option
698 if (((BootOption
[Index
].Attributes
& LOAD_OPTION_HIDDEN
) != 0) || ((BootOption
[Index
].Attributes
& LOAD_OPTION_ACTIVE
) == 0)) {
702 UnicodeSPrint (BootString
, sizeof (BootString
), L
"Boot%04x", BootOrderList
[Index
]);
704 // Get all loadoptions from the VAR
706 GetEfiGlobalVariable2 (BootString
, (VOID
**) &LoadOptionFromVar
, &BootOptionSize
);
707 if (LoadOptionFromVar
== NULL
) {
711 LoadOption
= AllocateZeroPool (BootOptionSize
);
712 if (LoadOption
== NULL
) {
716 CopyMem (LoadOption
, LoadOptionFromVar
, BootOptionSize
);
717 FreePool (LoadOptionFromVar
);
719 if (BootNext
!= NULL
) {
720 BootNextFlag
= (BOOLEAN
) (*BootNext
== BootOrderList
[Index
]);
722 BootNextFlag
= FALSE
;
725 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT
);
726 ASSERT (NULL
!= NewMenuEntry
);
728 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
730 LoadOptionPtr
= LoadOption
;
731 LoadOptionEnd
= LoadOption
+ BootOptionSize
;
733 NewMenuEntry
->OptionNumber
= BootOrderList
[Index
];
734 NewLoadContext
->LoadOptionModified
= FALSE
;
735 NewLoadContext
->Deleted
= FALSE
;
736 NewLoadContext
->IsBootNext
= BootNextFlag
;
739 // Is a Legacy Device?
741 Ptr
= (UINT8
*) LoadOption
;
744 // Attribute = *(UINT32 *)Ptr;
746 Ptr
+= sizeof (UINT32
);
749 // FilePathSize = *(UINT16 *)Ptr;
751 Ptr
+= sizeof (UINT16
);
754 // Description = (CHAR16 *)Ptr;
756 Ptr
+= StrSize ((CHAR16
*) Ptr
);
759 // Now Ptr point to Device Path
761 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
762 if ((BBS_DEVICE_PATH
== DevicePath
->Type
) && (BBS_BBS_DP
== DevicePath
->SubType
)) {
763 NewLoadContext
->IsLegacy
= TRUE
;
765 NewLoadContext
->IsLegacy
= FALSE
;
768 // LoadOption is a pointer type of UINT8
769 // for easy use with following LOAD_OPTION
770 // embedded in this struct
772 NewLoadContext
->LoadOption
= LoadOption
;
773 NewLoadContext
->LoadOptionSize
= BootOptionSize
;
775 NewLoadContext
->Attributes
= *(UINT32
*) LoadOptionPtr
;
776 NewLoadContext
->IsActive
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_ACTIVE
);
778 NewLoadContext
->ForceReconnect
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_FORCE_RECONNECT
);
780 LoadOptionPtr
+= sizeof (UINT32
);
782 NewLoadContext
->FilePathListLength
= *(UINT16
*) LoadOptionPtr
;
783 LoadOptionPtr
+= sizeof (UINT16
);
785 StringSize
= StrSize((UINT16
*)LoadOptionPtr
);
787 NewLoadContext
->Description
= AllocateZeroPool (StrSize((UINT16
*)LoadOptionPtr
));
788 ASSERT (NewLoadContext
->Description
!= NULL
);
789 StrCpy (NewLoadContext
->Description
, (UINT16
*)LoadOptionPtr
);
791 ASSERT (NewLoadContext
->Description
!= NULL
);
792 NewMenuEntry
->DisplayString
= NewLoadContext
->Description
;
794 LoadOptionPtr
+= StringSize
;
796 NewLoadContext
->FilePathList
= AllocateZeroPool (NewLoadContext
->FilePathListLength
);
797 ASSERT (NewLoadContext
->FilePathList
!= NULL
);
799 NewLoadContext
->FilePathList
,
800 (EFI_DEVICE_PATH_PROTOCOL
*) LoadOptionPtr
,
801 NewLoadContext
->FilePathListLength
804 NewMenuEntry
->HelpString
= UiDevicePathToStr (NewLoadContext
->FilePathList
);
805 NewMenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
807 BootOptionStrDepository
809 NewMenuEntry
->HelpStringToken
= GetStringTokenFromDepository (
811 BootOptionHelpStrDepository
813 LoadOptionPtr
+= NewLoadContext
->FilePathListLength
;
815 if (LoadOptionPtr
< LoadOptionEnd
) {
816 OptionalDataSize
= BootOptionSize
-
820 NewLoadContext
->FilePathListLength
;
822 NewLoadContext
->OptionalData
= AllocateZeroPool (OptionalDataSize
);
823 ASSERT (NewLoadContext
->OptionalData
!= NULL
);
825 NewLoadContext
->OptionalData
,
830 NewLoadContext
->OptionalDataSize
= OptionalDataSize
;
833 InsertTailList (&BootOptionMenu
.Head
, &NewMenuEntry
->Link
);
836 EfiBootManagerFreeLoadOptions (BootOption
, BootOptionCount
);
838 if (BootNext
!= NULL
) {
841 if (BootOrderList
!= NULL
) {
842 FreePool (BootOrderList
);
844 BootOptionMenu
.MenuNumber
= MenuCount
;
850 Append file name to existing file name.
852 @param Str1 The existing file name
853 @param Str2 The file name to be appended
855 @return Allocate a new string to hold the appended result.
856 Caller is responsible to free the returned string.
860 BOpt_AppendFileName (
872 Size1
= StrSize (Str1
);
873 Size2
= StrSize (Str2
);
874 Str
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
875 ASSERT (Str
!= NULL
);
877 TmpStr
= AllocateZeroPool (Size1
+ Size2
+ sizeof (CHAR16
));
878 ASSERT (TmpStr
!= NULL
);
881 if (!((*Str
== '\\') && (*(Str
+ 1) == 0))) {
890 if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '.' && *(Ptr
+ 3) == L
'\\') {
892 // Convert "\Name\..\" to "\"
893 // DO NOT convert the .. if it is at the end of the string. This will
894 // break the .. behavior in changing directories.
898 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
901 StrCpy (TmpStr
, Ptr
+ 3);
902 StrCpy (LastSlash
, TmpStr
);
904 } else if (*Ptr
== '\\' && *(Ptr
+ 1) == '.' && *(Ptr
+ 2) == '\\') {
906 // Convert a "\.\" to a "\"
910 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
913 StrCpy (TmpStr
, Ptr
+ 2);
914 StrCpy (Ptr
, TmpStr
);
916 } else if (*Ptr
== '\\') {
930 Check whether current FileName point to a valid
933 @param FileName File need to be checked.
935 @retval TRUE Is Efi Image
936 @retval FALSE Not a valid Efi Image
940 BOpt_IsEfiImageName (
945 // Search for ".efi" extension
947 while (*FileName
!= L
'\0') {
948 if (FileName
[0] == '.') {
949 if (FileName
[1] == 'e' || FileName
[1] == 'E') {
950 if (FileName
[2] == 'f' || FileName
[2] == 'F') {
951 if (FileName
[3] == 'i' || FileName
[3] == 'I') {
953 } else if (FileName
[3] == 0x0000) {
956 } else if (FileName
[2] == 0x0000) {
959 } else if (FileName
[1] == 0x0000) {
972 Check whether current FileName point to a valid Efi Application
974 @param Dir Pointer to current Directory
975 @param FileName Pointer to current File name.
977 @retval TRUE Is a valid Efi Application
978 @retval FALSE not a valid Efi Application
983 IN EFI_FILE_HANDLE Dir
,
988 EFI_IMAGE_DOS_HEADER DosHdr
;
990 EFI_FILE_HANDLE File
;
992 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
994 Status
= Dir
->Open (Dir
, &File
, FileName
, EFI_FILE_MODE_READ
, 0);
996 if (EFI_ERROR (Status
)) {
1000 BufferSize
= sizeof (EFI_IMAGE_DOS_HEADER
);
1001 File
->Read (File
, &BufferSize
, &DosHdr
);
1002 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
1007 File
->SetPosition (File
, DosHdr
.e_lfanew
);
1008 BufferSize
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
1009 File
->Read (File
, &BufferSize
, &PeHdr
);
1010 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1015 // Determine PE type and read subsytem
1017 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1018 Subsystem
= PeHdr
.Pe32
.OptionalHeader
.Subsystem
;
1019 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1020 Subsystem
= PeHdr
.Pe32Plus
.OptionalHeader
.Subsystem
;
1025 if (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1036 Find drivers that will be added as Driver#### variables from handles
1037 in current system environment
1038 All valid handles in the system except those consume SimpleFs, LoadFile
1039 are stored in DriverMenu for future use.
1041 @retval EFI_SUCCESS The function complets successfully.
1042 @return Other value if failed to build the DriverMenu.
1050 UINTN NoDevicePathHandles
;
1051 EFI_HANDLE
*DevicePathHandle
;
1054 BM_MENU_ENTRY
*NewMenuEntry
;
1055 BM_HANDLE_CONTEXT
*NewHandleContext
;
1056 EFI_HANDLE CurHandle
;
1058 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFs
;
1059 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1064 InitializeListHead (&DriverMenu
.Head
);
1067 // At first, get all handles that support Device Path
1068 // protocol which is the basic requirement for
1071 Status
= gBS
->LocateHandleBuffer (
1073 &gEfiDevicePathProtocolGuid
,
1075 &NoDevicePathHandles
,
1078 if (EFI_ERROR (Status
)) {
1083 for (Index
= 0; Index
< NoDevicePathHandles
; Index
++) {
1084 CurHandle
= DevicePathHandle
[Index
];
1086 Status
= gBS
->HandleProtocol (
1088 &gEfiSimpleFileSystemProtocolGuid
,
1091 if (Status
== EFI_SUCCESS
) {
1095 Status
= gBS
->HandleProtocol (
1097 &gEfiLoadFileProtocolGuid
,
1100 if (Status
== EFI_SUCCESS
) {
1104 NewMenuEntry
= BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT
);
1105 if (NULL
== NewMenuEntry
) {
1106 FreePool (DevicePathHandle
);
1107 return EFI_OUT_OF_RESOURCES
;
1110 NewHandleContext
= (BM_HANDLE_CONTEXT
*) NewMenuEntry
->VariableContext
;
1111 NewHandleContext
->Handle
= CurHandle
;
1112 NewHandleContext
->DevicePath
= DevicePathFromHandle (CurHandle
);
1113 NewMenuEntry
->DisplayString
= UiDevicePathToStr (NewHandleContext
->DevicePath
);
1114 NewMenuEntry
->HelpString
= NULL
;
1115 NewMenuEntry
->OptionNumber
= OptionNumber
;
1117 InsertTailList (&DriverMenu
.Head
, &NewMenuEntry
->Link
);
1121 if (DevicePathHandle
!= NULL
) {
1122 FreePool (DevicePathHandle
);
1125 DriverMenu
.MenuNumber
= OptionNumber
;
1131 Get the Option Number that has not been allocated for use.
1133 @param Type The type of Option.
1135 @return The available Option Number.
1139 BOpt_GetOptionNumber (
1144 UINTN OrderListSize
;
1147 UINT16
*OptionBuffer
;
1148 UINT16 OptionNumber
;
1156 UnicodeSPrint (StrTemp
, sizeof (StrTemp
), L
"%sOrder", Type
);
1158 GetEfiGlobalVariable2 (StrTemp
, (VOID
**) &OrderList
, &OrderListSize
);
1159 for (OptionNumber
= 0; ; OptionNumber
++) {
1160 if (OrderList
!= NULL
) {
1161 for (Index
= 0; Index
< OrderListSize
/ sizeof (UINT16
); Index
++) {
1162 if (OptionNumber
== OrderList
[Index
]) {
1168 if (Index
< OrderListSize
/ sizeof (UINT16
)) {
1170 // The OptionNumber occurs in the OrderList, continue to use next one
1174 UnicodeSPrint (StrTemp
, sizeof (StrTemp
), L
"%s%04x", Type
, (UINTN
) OptionNumber
);
1175 DEBUG((EFI_D_ERROR
,"Option = %s\n", StrTemp
));
1176 GetEfiGlobalVariable2 (StrTemp
, (VOID
**) &OptionBuffer
, &OptionSize
);
1177 if (NULL
== OptionBuffer
) {
1179 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
1185 return OptionNumber
;
1190 Get the Option Number for Boot#### that does not used.
1192 @return The available Option Number.
1196 BOpt_GetBootOptionNumber (
1200 return BOpt_GetOptionNumber (L
"Boot");
1205 Get the Option Number for Driver#### that does not used.
1207 @return The unused Option Number.
1211 BOpt_GetDriverOptionNumber (
1215 return BOpt_GetOptionNumber (L
"Driver");
1220 Build up all DriverOptionMenu
1222 @param CallbackData The BMM context data.
1224 @retval EFI_SUCESS The functin completes successfully.
1225 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1226 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
1230 BOpt_GetDriverOptions (
1231 IN BMM_CALLBACK_DATA
*CallbackData
1235 UINT16 DriverString
[12];
1236 UINT8
*LoadOptionFromVar
;
1238 UINTN DriverOptionSize
;
1240 UINT16
*DriverOrderList
;
1241 UINTN DriverOrderListSize
;
1242 BM_MENU_ENTRY
*NewMenuEntry
;
1243 BM_LOAD_CONTEXT
*NewLoadContext
;
1244 UINT8
*LoadOptionPtr
;
1246 UINTN OptionalDataSize
;
1247 UINT8
*LoadOptionEnd
;
1249 DriverOrderListSize
= 0;
1250 DriverOrderList
= NULL
;
1251 DriverOptionSize
= 0;
1252 LoadOptionFromVar
= NULL
;
1253 BOpt_FreeMenu (&DriverOptionMenu
);
1254 InitializeListHead (&DriverOptionMenu
.Head
);
1256 // Get the DriverOrder from the Var
1258 GetEfiGlobalVariable2 (L
"DriverOrder", (VOID
**) &DriverOrderList
, &DriverOrderListSize
);
1259 if (DriverOrderList
== NULL
) {
1260 return EFI_NOT_FOUND
;
1263 for (Index
= 0; Index
< DriverOrderListSize
/ sizeof (UINT16
); Index
++) {
1266 sizeof (DriverString
),
1268 DriverOrderList
[Index
]
1271 // Get all loadoptions from the VAR
1273 GetEfiGlobalVariable2 (DriverString
, (VOID
**) &LoadOptionFromVar
, &DriverOptionSize
);
1274 if (LoadOptionFromVar
== NULL
) {
1278 LoadOption
= AllocateZeroPool (DriverOptionSize
);
1279 if (LoadOption
== NULL
) {
1283 CopyMem (LoadOption
, LoadOptionFromVar
, DriverOptionSize
);
1284 FreePool (LoadOptionFromVar
);
1286 NewMenuEntry
= BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT
);
1287 if (NULL
== NewMenuEntry
) {
1288 return EFI_OUT_OF_RESOURCES
;
1291 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
1292 LoadOptionPtr
= LoadOption
;
1293 LoadOptionEnd
= LoadOption
+ DriverOptionSize
;
1294 NewMenuEntry
->OptionNumber
= DriverOrderList
[Index
];
1295 NewLoadContext
->LoadOptionModified
= FALSE
;
1296 NewLoadContext
->Deleted
= FALSE
;
1297 NewLoadContext
->IsLegacy
= FALSE
;
1300 // LoadOption is a pointer type of UINT8
1301 // for easy use with following LOAD_OPTION
1302 // embedded in this struct
1304 NewLoadContext
->LoadOption
= LoadOption
;
1305 NewLoadContext
->LoadOptionSize
= DriverOptionSize
;
1307 NewLoadContext
->Attributes
= *(UINT32
*) LoadOptionPtr
;
1308 NewLoadContext
->IsActive
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_ACTIVE
);
1310 NewLoadContext
->ForceReconnect
= (BOOLEAN
) (NewLoadContext
->Attributes
& LOAD_OPTION_FORCE_RECONNECT
);
1312 LoadOptionPtr
+= sizeof (UINT32
);
1314 NewLoadContext
->FilePathListLength
= *(UINT16
*) LoadOptionPtr
;
1315 LoadOptionPtr
+= sizeof (UINT16
);
1317 StringSize
= StrSize ((UINT16
*) LoadOptionPtr
);
1318 NewLoadContext
->Description
= AllocateZeroPool (StringSize
);
1319 ASSERT (NewLoadContext
->Description
!= NULL
);
1321 NewLoadContext
->Description
,
1322 (UINT16
*) LoadOptionPtr
,
1325 NewMenuEntry
->DisplayString
= NewLoadContext
->Description
;
1327 LoadOptionPtr
+= StringSize
;
1329 NewLoadContext
->FilePathList
= AllocateZeroPool (NewLoadContext
->FilePathListLength
);
1330 ASSERT (NewLoadContext
->FilePathList
!= NULL
);
1332 NewLoadContext
->FilePathList
,
1333 (EFI_DEVICE_PATH_PROTOCOL
*) LoadOptionPtr
,
1334 NewLoadContext
->FilePathListLength
1337 NewMenuEntry
->HelpString
= UiDevicePathToStr (NewLoadContext
->FilePathList
);
1338 NewMenuEntry
->DisplayStringToken
= GetStringTokenFromDepository (
1340 DriverOptionStrDepository
1342 NewMenuEntry
->HelpStringToken
= GetStringTokenFromDepository (
1344 DriverOptionHelpStrDepository
1346 LoadOptionPtr
+= NewLoadContext
->FilePathListLength
;
1348 if (LoadOptionPtr
< LoadOptionEnd
) {
1349 OptionalDataSize
= DriverOptionSize
-
1353 NewLoadContext
->FilePathListLength
;
1355 NewLoadContext
->OptionalData
= AllocateZeroPool (OptionalDataSize
);
1356 ASSERT (NewLoadContext
->OptionalData
!= NULL
);
1358 NewLoadContext
->OptionalData
,
1363 NewLoadContext
->OptionalDataSize
= OptionalDataSize
;
1366 InsertTailList (&DriverOptionMenu
.Head
, &NewMenuEntry
->Link
);
1370 if (DriverOrderList
!= NULL
) {
1371 FreePool (DriverOrderList
);
1373 DriverOptionMenu
.MenuNumber
= Index
;
1379 Get option number according to Boot#### and BootOrder variable.
1380 The value is saved as #### + 1.
1382 @param CallbackData The BMM context data.
1386 IN BMM_CALLBACK_DATA
*CallbackData
1389 BMM_FAKE_NV_DATA
*BmmConfig
;
1391 UINT16 OptionOrderIndex
;
1393 BM_MENU_ENTRY
*NewMenuEntry
;
1394 BM_LOAD_CONTEXT
*NewLoadContext
;
1396 ASSERT (CallbackData
!= NULL
);
1398 DeviceType
= (UINTN
) -1;
1399 BmmConfig
= &CallbackData
->BmmFakeNvData
;
1400 ZeroMem (BmmConfig
->BootOptionOrder
, sizeof (BmmConfig
->BootOptionOrder
));
1402 for (Index
= 0, OptionOrderIndex
= 0; ((Index
< BootOptionMenu
.MenuNumber
) &&
1403 (OptionOrderIndex
< (sizeof (BmmConfig
->BootOptionOrder
) / sizeof (BmmConfig
->BootOptionOrder
[0]))));
1405 NewMenuEntry
= BOpt_GetMenuEntry (&BootOptionMenu
, Index
);
1406 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
1408 if (NewLoadContext
->IsLegacy
) {
1409 if (((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
!= DeviceType
) {
1410 DeviceType
= ((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
;
1413 // Only show one legacy boot option for the same device type
1414 // assuming the boot options are grouped by the device type
1419 BmmConfig
->BootOptionOrder
[OptionOrderIndex
++] = (UINT32
) (NewMenuEntry
->OptionNumber
+ 1);
1424 Get driver option order from globalc DriverOptionMenu.
1426 @param CallbackData The BMM context data.
1431 IN BMM_CALLBACK_DATA
*CallbackData
1434 BMM_FAKE_NV_DATA
*BmmConfig
;
1436 UINT16 OptionOrderIndex
;
1438 BM_MENU_ENTRY
*NewMenuEntry
;
1439 BM_LOAD_CONTEXT
*NewLoadContext
;
1442 ASSERT (CallbackData
!= NULL
);
1444 DeviceType
= (UINTN
) -1;
1445 BmmConfig
= &CallbackData
->BmmFakeNvData
;
1446 ZeroMem (BmmConfig
->DriverOptionOrder
, sizeof (BmmConfig
->DriverOptionOrder
));
1448 for (Index
= 0, OptionOrderIndex
= 0; ((Index
< DriverOptionMenu
.MenuNumber
) &&
1449 (OptionOrderIndex
< (sizeof (BmmConfig
->DriverOptionOrder
) / sizeof (BmmConfig
->DriverOptionOrder
[0]))));
1451 NewMenuEntry
= BOpt_GetMenuEntry (&DriverOptionMenu
, Index
);
1452 NewLoadContext
= (BM_LOAD_CONTEXT
*) NewMenuEntry
->VariableContext
;
1454 if (NewLoadContext
->IsLegacy
) {
1455 if (((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
!= DeviceType
) {
1456 DeviceType
= ((BBS_BBS_DEVICE_PATH
*) NewLoadContext
->FilePathList
)->DeviceType
;
1459 // Only show one legacy boot option for the same device type
1460 // assuming the boot options are grouped by the device type
1465 BmmConfig
->DriverOptionOrder
[OptionOrderIndex
++] = (UINT32
) (NewMenuEntry
->OptionNumber
+ 1);