2 Load option library functions which relate with creating and processing load options.
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBm.h"
17 GLOBAL_REMOVE_IF_UNREFERENCED
18 CHAR16
*mBmLoadOptionName
[] = {
24 GLOBAL_REMOVE_IF_UNREFERENCED
25 CHAR16
*mBmLoadOptionOrderName
[] = {
26 EFI_DRIVER_ORDER_VARIABLE_NAME
,
27 EFI_SYS_PREP_ORDER_VARIABLE_NAME
,
28 EFI_BOOT_ORDER_VARIABLE_NAME
32 Call Visitor function for each variable in variable storage.
34 @param Visitor Visitor function.
35 @param Context The context passed to Visitor function.
39 VARIABLE_VISITOR Visitor
,
49 NameSize
= sizeof (CHAR16
);
50 Name
= AllocateZeroPool (NameSize
);
51 ASSERT (Name
!= NULL
);
53 NewNameSize
= NameSize
;
54 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
55 if (Status
== EFI_BUFFER_TOO_SMALL
) {
56 Name
= ReallocatePool (NameSize
, NewNameSize
, Name
);
57 ASSERT (Name
!= NULL
);
58 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
59 NameSize
= NewNameSize
;
62 if (Status
== EFI_NOT_FOUND
) {
65 ASSERT_EFI_ERROR (Status
);
67 Visitor (Name
, &Guid
, Context
);
74 Get the Option Number that wasn't used.
76 @param LoadOptionType The load option type.
77 @param FreeOptionNumber Return the minimal free option number.
79 @retval EFI_SUCCESS The option number is found and will be returned.
80 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
81 @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
85 BmGetFreeOptionNumber (
86 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
,
87 OUT UINT16
*FreeOptionNumber
94 UINTN OptionOrderSize
;
97 ASSERT (FreeOptionNumber
!= NULL
);
98 ASSERT (LoadOptionType
== LoadOptionTypeDriver
||
99 LoadOptionType
== LoadOptionTypeBoot
||
100 LoadOptionType
== LoadOptionTypeSysPrep
);
102 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
104 if (LoadOptionType
== LoadOptionTypeBoot
) {
105 GetEfiGlobalVariable2 (L
"BootNext", (VOID
**) &BootNext
, NULL
);
108 for (OptionNumber
= 0;
109 OptionNumber
< OptionOrderSize
/ sizeof (UINT16
)
110 + ((BootNext
!= NULL
) ? 1 : 0);
114 // Search in OptionOrder whether the OptionNumber exists
116 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
117 if (OptionNumber
== OptionOrder
[Index
]) {
123 // We didn't find it in the ****Order array and it doesn't equal to BootNext
124 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
126 if ((Index
== OptionOrderSize
/ sizeof (UINT16
)) &&
127 ((BootNext
== NULL
) || (OptionNumber
!= *BootNext
))
132 if (OptionOrder
!= NULL
) {
133 FreePool (OptionOrder
);
136 if (BootNext
!= NULL
) {
141 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
142 // OptionNumber equals to 0x10000 which is not valid.
144 ASSERT (OptionNumber
<= 0x10000);
145 if (OptionNumber
== 0x10000) {
146 return EFI_OUT_OF_RESOURCES
;
148 *FreeOptionNumber
= (UINT16
) OptionNumber
;
154 Create the Boot####, Driver####, SysPrep####, variable from the load option.
156 @param LoadOption Pointer to the load option.
158 @retval EFI_SUCCESS The variable was created.
159 @retval Others Error status returned by RT->SetVariable.
163 EfiBootManagerLoadOptionToVariable (
164 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Option
170 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
173 UINT32 VariableAttributes
;
175 if ((Option
->OptionNumber
== LoadOptionNumberUnassigned
) ||
176 (Option
->FilePath
== NULL
) ||
177 ((UINT32
) Option
->OptionType
>= LoadOptionTypeMax
)
179 return EFI_INVALID_PARAMETER
;
183 // Convert NULL description to empty description
186 Description
= Option
->Description
;
187 if (Description
== NULL
) {
188 Description
= &NullChar
;
193 UINT16 FilePathListLength;
194 CHAR16 Description[];
195 EFI_DEVICE_PATH_PROTOCOL FilePathList[];
196 UINT8 OptionalData[];
197 TODO: FilePathList[] IS:
198 A packed array of UEFI device paths. The first element of the
199 array is a device path that describes the device and location of the
200 Image for this load option. The FilePathList[0] is specific
201 to the device type. Other device paths may optionally exist in the
202 FilePathList, but their usage is OSV specific. Each element
203 in the array is variable length, and ends at the device path end
206 VariableSize
= sizeof (Option
->Attributes
)
208 + StrSize (Description
)
209 + GetDevicePathSize (Option
->FilePath
)
210 + Option
->OptionalDataSize
;
212 Variable
= AllocatePool (VariableSize
);
213 ASSERT (Variable
!= NULL
);
216 WriteUnaligned32 ((UINT32
*) Ptr
, Option
->Attributes
);
217 Ptr
+= sizeof (Option
->Attributes
);
219 WriteUnaligned16 ((UINT16
*) Ptr
, (UINT16
) GetDevicePathSize (Option
->FilePath
));
220 Ptr
+= sizeof (UINT16
);
222 CopyMem (Ptr
, Description
, StrSize (Description
));
223 Ptr
+= StrSize (Description
);
225 CopyMem (Ptr
, Option
->FilePath
, GetDevicePathSize (Option
->FilePath
));
226 Ptr
+= GetDevicePathSize (Option
->FilePath
);
228 CopyMem (Ptr
, Option
->OptionalData
, Option
->OptionalDataSize
);
230 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[Option
->OptionType
], Option
->OptionNumber
);
232 VariableAttributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
;
234 return gRT
->SetVariable (
236 &gEfiGlobalVariableGuid
,
244 Update order variable .
246 @param OptionOrderName Order variable name which need to be updated.
247 @param OptionNumber Option number for the new option.
248 @param Position Position of the new load option to put in the ****Order variable.
250 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
251 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
252 @retval EFI_STATUS Return the status of gRT->SetVariable ().
256 BmAddOptionNumberToOrderVariable (
257 IN CHAR16
*OptionOrderName
,
258 IN UINT16 OptionNumber
,
265 UINT16
*NewOptionOrder
;
266 UINTN OptionOrderSize
;
268 // Update the option order variable
270 GetEfiGlobalVariable2 (OptionOrderName
, (VOID
**) &OptionOrder
, &OptionOrderSize
);
272 Status
= EFI_SUCCESS
;
273 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
274 if (OptionOrder
[Index
] == OptionNumber
) {
275 Status
= EFI_ALREADY_STARTED
;
280 if (!EFI_ERROR (Status
)) {
281 Position
= MIN (Position
, OptionOrderSize
/ sizeof (UINT16
));
283 NewOptionOrder
= AllocatePool (OptionOrderSize
+ sizeof (UINT16
));
284 ASSERT (NewOptionOrder
!= NULL
);
285 if (OptionOrderSize
!= 0) {
286 CopyMem (NewOptionOrder
, OptionOrder
, Position
* sizeof (UINT16
));
287 CopyMem (&NewOptionOrder
[Position
+ 1], &OptionOrder
[Position
], OptionOrderSize
- Position
* sizeof (UINT16
));
289 NewOptionOrder
[Position
] = OptionNumber
;
291 Status
= gRT
->SetVariable (
293 &gEfiGlobalVariableGuid
,
294 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
295 OptionOrderSize
+ sizeof (UINT16
),
298 FreePool (NewOptionOrder
);
301 if (OptionOrder
!= NULL
) {
302 FreePool (OptionOrder
);
309 This function will register the new Boot####, Driver#### or SysPrep#### option.
310 After the *#### is updated, the *Order will also be updated.
312 @param Option Pointer to load option to add.
313 @param Position Position of the new load option to put in the ****Order variable.
315 @retval EFI_SUCCESS The *#### have been successfully registered.
316 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
317 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
318 Note: this API only adds new load option, no replacement support.
319 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
320 option number specified in the Option is LoadOptionNumberUnassigned.
321 @retval EFI_STATUS Return the status of gRT->SetVariable ().
326 EfiBootManagerAddLoadOptionVariable (
327 IN EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
334 if (Option
== NULL
) {
335 return EFI_INVALID_PARAMETER
;
338 if (Option
->OptionType
!= LoadOptionTypeDriver
&&
339 Option
->OptionType
!= LoadOptionTypeSysPrep
&&
340 Option
->OptionType
!= LoadOptionTypeBoot
342 return EFI_INVALID_PARAMETER
;
346 // Get the free option number if the option number is unassigned
348 if (Option
->OptionNumber
== LoadOptionNumberUnassigned
) {
349 Status
= BmGetFreeOptionNumber (Option
->OptionType
, &OptionNumber
);
350 if (EFI_ERROR (Status
)) {
353 Option
->OptionNumber
= OptionNumber
;
356 if (Option
->OptionNumber
>= LoadOptionNumberMax
) {
357 return EFI_INVALID_PARAMETER
;
360 Status
= BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName
[Option
->OptionType
], (UINT16
) Option
->OptionNumber
, Position
);
361 if (!EFI_ERROR (Status
)) {
363 // Save the Boot#### or Driver#### variable
365 Status
= EfiBootManagerLoadOptionToVariable (Option
);
366 if (EFI_ERROR (Status
)) {
368 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
370 EfiBootManagerDeleteLoadOptionVariable (Option
->OptionNumber
, Option
->OptionType
);
378 Sort the load option. The DriverOrder or BootOrder will be re-created to
379 reflect the new order.
381 @param OptionType Load option type
382 @param CompareFunction The comparator
386 EfiBootManagerSortLoadOptionVariable (
387 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
388 SORT_COMPARE CompareFunction
392 EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
;
393 UINTN LoadOptionCount
;
397 LoadOption
= EfiBootManagerGetLoadOptions (&LoadOptionCount
, OptionType
);
400 // Insertion sort algorithm
405 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
410 // Create new ****Order variable
412 OptionOrder
= AllocatePool (LoadOptionCount
* sizeof (UINT16
));
413 ASSERT (OptionOrder
!= NULL
);
414 for (Index
= 0; Index
< LoadOptionCount
; Index
++) {
415 OptionOrder
[Index
] = (UINT16
) LoadOption
[Index
].OptionNumber
;
418 Status
= gRT
->SetVariable (
419 mBmLoadOptionOrderName
[OptionType
],
420 &gEfiGlobalVariableGuid
,
421 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
422 LoadOptionCount
* sizeof (UINT16
),
426 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
428 ASSERT_EFI_ERROR (Status
);
430 FreePool (OptionOrder
);
431 EfiBootManagerFreeLoadOptions (LoadOption
, LoadOptionCount
);
435 Initialize a load option.
437 @param Option Pointer to the load option to be initialized.
438 @param OptionNumber Option number of the load option.
439 @param OptionType Type of the load option.
440 @param Attributes Attributes of the load option.
441 @param Description Description of the load option.
442 @param FilePath Device path of the load option.
443 @param OptionalData Optional data of the load option.
444 @param OptionalDataSize Size of the optional data of the load option.
446 @retval EFI_SUCCESS The load option was initialized successfully.
447 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
451 EfiBootManagerInitializeLoadOption (
452 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
453 IN UINTN OptionNumber
,
454 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
455 IN UINT32 Attributes
,
456 IN CHAR16
*Description
,
457 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
458 IN UINT8
*OptionalData
, OPTIONAL
459 IN UINT32 OptionalDataSize
462 if ((Option
== NULL
) || (Description
== NULL
) || (FilePath
== NULL
)) {
463 return EFI_INVALID_PARAMETER
;
466 if (((OptionalData
!= NULL
) && (OptionalDataSize
== 0)) ||
467 ((OptionalData
== NULL
) && (OptionalDataSize
!= 0))) {
468 return EFI_INVALID_PARAMETER
;
471 if ((UINT32
) OptionType
>= LoadOptionTypeMax
) {
472 return EFI_INVALID_PARAMETER
;
475 ZeroMem (Option
, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
476 Option
->OptionNumber
= OptionNumber
;
477 Option
->OptionType
= OptionType
;
478 Option
->Attributes
= Attributes
;
479 Option
->Description
= AllocateCopyPool (StrSize (Description
), Description
);
480 Option
->FilePath
= DuplicateDevicePath (FilePath
);
481 if (OptionalData
!= NULL
) {
482 Option
->OptionalData
= AllocateCopyPool (OptionalDataSize
, OptionalData
);
483 Option
->OptionalDataSize
= OptionalDataSize
;
491 Return the index of the load option in the load option array.
493 The function consider two load options are equal when the
494 OptionType, Attributes, Description, FilePath and OptionalData are equal.
496 @param Key Pointer to the load option to be found.
497 @param Array Pointer to the array of load options to be found.
498 @param Count Number of entries in the Array.
500 @retval -1 Key wasn't found in the Array.
501 @retval 0 ~ Count-1 The index of the Key in the Array.
505 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
506 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
512 for (Index
= 0; Index
< Count
; Index
++) {
513 if ((Key
->OptionType
== Array
[Index
].OptionType
) &&
514 (Key
->Attributes
== Array
[Index
].Attributes
) &&
515 (StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
516 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
517 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
518 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0)) {
527 Delete the load option.
529 @param OptionNumber Indicate the option number of load option
530 @param OptionType Indicate the type of load option
532 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
533 @retval EFI_NOT_FOUND The load option cannot be found
534 @retval EFI_SUCCESS The load option was deleted
535 @retval others Status of RT->SetVariable()
539 EfiBootManagerDeleteLoadOptionVariable (
540 IN UINTN OptionNumber
,
541 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
545 UINTN OptionOrderSize
;
549 if (((UINT32
) OptionType
>= LoadOptionTypeMax
) || (OptionNumber
>= LoadOptionNumberMax
)) {
550 return EFI_INVALID_PARAMETER
;
553 Status
= EFI_NOT_FOUND
;
555 if (OptionType
== LoadOptionTypeDriver
|| OptionType
== LoadOptionTypeSysPrep
|| OptionType
== LoadOptionTypeBoot
) {
557 // If the associated *Order exists, just remove the reference in *Order.
559 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[OptionType
], &OptionOrder
, &OptionOrderSize
);
560 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
561 if (OptionOrder
[Index
] == OptionNumber
) {
562 OptionOrderSize
-= sizeof (UINT16
);
563 CopyMem (&OptionOrder
[Index
], &OptionOrder
[Index
+ 1], OptionOrderSize
- Index
* sizeof (UINT16
));
564 Status
= gRT
->SetVariable (
565 mBmLoadOptionOrderName
[OptionType
],
566 &gEfiGlobalVariableGuid
,
567 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
574 if (OptionOrder
!= NULL
) {
575 FreePool (OptionOrder
);
583 Convert a single character to number.
584 It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
586 @param Char The input char which need to convert to int.
593 if ((Char
>= L
'0') && (Char
<= L
'9')) {
594 return (UINTN
) (Char
- L
'0');
597 if ((Char
>= L
'A') && (Char
<= L
'F')) {
598 return (UINTN
) (Char
- L
'A' + 0xA);
606 Returns the size of a device path in bytes.
608 This function returns the size, in bytes, of the device path data structure
609 specified by DevicePath including the end of device path node. If DevicePath
610 is NULL, then 0 is returned. If the length of the device path is bigger than
611 MaxSize, also return 0 to indicate this is an invalidate device path.
613 @param DevicePath A pointer to a device path data structure.
614 @param MaxSize Max valid device path size. If big than this size,
617 @retval 0 An invalid device path.
618 @retval Others The size of a device path in bytes.
622 BmGetDevicePathSizeEx (
623 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
630 if (DevicePath
== NULL
) {
635 // Search for the end of the device path structure
638 while (!IsDevicePathEnd (DevicePath
)) {
639 NodeSize
= DevicePathNodeLength (DevicePath
);
644 if (Size
> MaxSize
) {
647 DevicePath
= NextDevicePathNode (DevicePath
);
649 Size
+= DevicePathNodeLength (DevicePath
);
650 if (Size
> MaxSize
) {
658 Returns the length of a Null-terminated Unicode string. If the length is
659 bigger than MaxStringLen, return length 0 to indicate that this is an
662 This function returns the number of Unicode characters in the Null-terminated
663 Unicode string specified by String.
665 If String is NULL, then ASSERT().
666 If String is not aligned on a 16-bit boundary, then ASSERT().
668 @param String A pointer to a Null-terminated Unicode string.
669 @param MaxStringLen Max string len in this string.
671 @retval 0 An invalid string.
672 @retval Others The length of String.
677 IN CONST CHAR16
*String
,
678 IN UINTN MaxStringLen
683 ASSERT (String
!= NULL
&& MaxStringLen
!= 0);
684 ASSERT (((UINTN
) String
& BIT0
) == 0);
686 for (Length
= 0; *String
!= L
'\0' && MaxStringLen
!= Length
; String
++, Length
+=2);
688 if (*String
!= L
'\0' && MaxStringLen
== Length
) {
696 Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)
698 @param Variable The variable data.
699 @param VariableSize The variable size.
701 @retval TRUE The variable data is correct.
702 @retval FALSE The variable data is corrupted.
712 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
713 UINTN DescriptionSize
;
715 if (VariableSize
<= sizeof (UINT16
) + sizeof (UINT32
)) {
720 // Skip the option attribute
722 Variable
+= sizeof (UINT32
);
725 // Get the option's device path size
727 FilePathSize
= ReadUnaligned16 ((UINT16
*) Variable
);
728 Variable
+= sizeof (UINT16
);
731 // Get the option's description string size
733 DescriptionSize
= BmStrSizeEx ((CHAR16
*) Variable
, VariableSize
- sizeof (UINT16
) - sizeof (UINT32
));
734 Variable
+= DescriptionSize
;
737 // Get the option's device path
739 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Variable
;
742 // Validation boot option variable.
744 if ((FilePathSize
== 0) || (DescriptionSize
== 0)) {
748 if (sizeof (UINT32
) + sizeof (UINT16
) + DescriptionSize
+ FilePathSize
> VariableSize
) {
752 return (BOOLEAN
) (BmGetDevicePathSizeEx (DevicePath
, FilePathSize
) != 0);
756 Check whether the VariableName is a valid load option variable name
757 and return the load option type and option number.
759 @param VariableName The name of the load option variable.
760 @param OptionType Return the load option type.
761 @param OptionNumber Return the load option number.
763 @retval TRUE The variable name is valid; The load option type and
764 load option number is returned.
765 @retval FALSE The variable name is NOT valid.
768 BmIsValidLoadOptionVariableName (
769 IN CHAR16
*VariableName
,
770 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE
*OptionType
,
771 OUT UINT16
*OptionNumber
774 UINTN VariableNameLen
;
778 VariableNameLen
= StrLen (VariableName
);
780 if (VariableNameLen
<= 4) {
784 for (Index
= 0; Index
< sizeof (mBmLoadOptionName
) / sizeof (mBmLoadOptionName
[0]); Index
++) {
785 if ((VariableNameLen
- 4 == StrLen (mBmLoadOptionName
[Index
])) &&
786 (StrnCmp (VariableName
, mBmLoadOptionName
[Index
], VariableNameLen
- 4) == 0)
792 if (Index
== sizeof (mBmLoadOptionName
) / sizeof (mBmLoadOptionName
[0])) {
796 *OptionType
= (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE
) Index
;
798 for (Index
= VariableNameLen
- 4; Index
< VariableNameLen
; Index
++) {
799 Uint
= BmCharToUint (VariableName
[Index
]);
803 *OptionNumber
= (UINT16
) Uint
+ *OptionNumber
* 0x10;
807 return (BOOLEAN
) (Index
== VariableNameLen
);
811 Build the Boot#### or Driver#### option from the VariableName.
813 @param VariableName Variable name of the load option
814 @param VendorGuid Variable GUID of the load option
815 @param Option Return the load option.
817 @retval EFI_SUCCESS Get the option just been created
818 @retval EFI_NOT_FOUND Failed to get the new option
823 EfiBootManagerVariableToLoadOptionEx (
824 IN CHAR16
*VariableName
,
825 IN EFI_GUID
*VendorGuid
,
826 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
835 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
837 UINT32 OptionalDataSize
;
839 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
842 if ((VariableName
== NULL
) || (Option
== NULL
)) {
843 return EFI_INVALID_PARAMETER
;
846 if (!BmIsValidLoadOptionVariableName (VariableName
, &OptionType
, &OptionNumber
)) {
847 return EFI_INVALID_PARAMETER
;
853 GetVariable2 (VariableName
, VendorGuid
, (VOID
**) &Variable
, &VariableSize
);
854 if (Variable
== NULL
) {
855 return EFI_NOT_FOUND
;
859 // Validate *#### variable data.
861 if (!BmValidateOption(Variable
, VariableSize
)) {
863 return EFI_INVALID_PARAMETER
;
867 // Get the option attribute
869 VariablePtr
= Variable
;
870 Attribute
= ReadUnaligned32 ((UINT32
*) VariablePtr
);
871 VariablePtr
+= sizeof (UINT32
);
874 // Get the option's device path size
876 FilePathSize
= ReadUnaligned16 ((UINT16
*) VariablePtr
);
877 VariablePtr
+= sizeof (UINT16
);
880 // Get the option's description string
882 Description
= (CHAR16
*) VariablePtr
;
885 // Get the option's description string size
887 VariablePtr
+= StrSize ((CHAR16
*) VariablePtr
);
890 // Get the option's device path
892 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) VariablePtr
;
893 VariablePtr
+= FilePathSize
;
895 OptionalDataSize
= (UINT32
) (VariableSize
- (UINTN
) (VariablePtr
- Variable
));
896 if (OptionalDataSize
== 0) {
899 OptionalData
= VariablePtr
;
902 Status
= EfiBootManagerInitializeLoadOption (
912 ASSERT_EFI_ERROR (Status
);
914 CopyGuid (&Option
->VendorGuid
, VendorGuid
);
921 Build the Boot#### or Driver#### option from the VariableName.
923 @param VariableName EFI Variable name indicate if it is Boot#### or Driver####
924 @param Option Return the Boot#### or Driver#### option.
926 @retval EFI_SUCCESS Get the option just been created
927 @retval EFI_NOT_FOUND Failed to get the new option
931 EfiBootManagerVariableToLoadOption (
932 IN CHAR16
*VariableName
,
933 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
936 return EfiBootManagerVariableToLoadOptionEx (VariableName
, &gEfiGlobalVariableGuid
, Option
);
940 Returns an array of load options based on the EFI variable
941 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
942 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
944 @param LoadOptionCount Returns number of entries in the array.
945 @param LoadOptionType The type of the load option.
947 @retval NULL No load options exist.
948 @retval !NULL Array of load option entries.
951 EFI_BOOT_MANAGER_LOAD_OPTION
*
953 EfiBootManagerGetLoadOptions (
954 OUT UINTN
*OptionCount
,
955 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
960 UINTN OptionOrderSize
;
963 EFI_BOOT_MANAGER_LOAD_OPTION
*Options
;
964 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
969 if (LoadOptionType
== LoadOptionTypeDriver
|| LoadOptionType
== LoadOptionTypeSysPrep
|| LoadOptionType
== LoadOptionTypeBoot
) {
971 // Read the BootOrder, or DriverOrder variable.
973 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
974 if (OptionOrder
== NULL
) {
978 *OptionCount
= OptionOrderSize
/ sizeof (UINT16
);
980 Options
= AllocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
981 ASSERT (Options
!= NULL
);
984 for (Index
= 0; Index
< *OptionCount
; Index
++) {
985 OptionNumber
= OptionOrder
[Index
];
986 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[LoadOptionType
], OptionNumber
);
988 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &Options
[OptionIndex
]);
989 if (EFI_ERROR (Status
)) {
990 DEBUG ((EFI_D_INFO
, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName
));
991 EfiBootManagerDeleteLoadOptionVariable (OptionNumber
, LoadOptionType
);
993 ASSERT (Options
[OptionIndex
].OptionNumber
== OptionNumber
);
998 if (OptionOrder
!= NULL
) {
999 FreePool (OptionOrder
);
1002 if (OptionIndex
< *OptionCount
) {
1003 Options
= ReallocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), OptionIndex
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), Options
);
1004 ASSERT (Options
!= NULL
);
1005 *OptionCount
= OptionIndex
;
1016 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1018 @param LoadOption Pointer to boot option to Free.
1020 @return EFI_SUCCESS BootOption was freed
1021 @return EFI_NOT_FOUND BootOption == NULL
1026 EfiBootManagerFreeLoadOption (
1027 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1030 if (LoadOption
== NULL
) {
1031 return EFI_NOT_FOUND
;
1034 if (LoadOption
->Description
!= NULL
) {
1035 FreePool (LoadOption
->Description
);
1037 if (LoadOption
->FilePath
!= NULL
) {
1038 FreePool (LoadOption
->FilePath
);
1040 if (LoadOption
->OptionalData
!= NULL
) {
1041 FreePool (LoadOption
->OptionalData
);
1048 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1049 EfiBootManagerGetLoadOptions().
1051 @param Option Pointer to boot option array to free.
1052 @param OptionCount Number of array entries in BootOption
1054 @return EFI_SUCCESS BootOption was freed
1055 @return EFI_NOT_FOUND BootOption == NULL
1060 EfiBootManagerFreeLoadOptions (
1061 IN EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
1062 IN UINTN OptionCount
1067 if (Option
== NULL
) {
1068 return EFI_NOT_FOUND
;
1071 for (Index
= 0;Index
< OptionCount
; Index
++) {
1072 EfiBootManagerFreeLoadOption (&Option
[Index
]);
1081 Return whether the PE header of the load option is valid or not.
1083 @param[in] Type The load option type.
1084 @param[in] FileBuffer The PE file buffer of the load option.
1085 @param[in] FileSize The size of the load option file.
1087 @retval TRUE The PE header of the load option is valid.
1088 @retval FALSE The PE header of the load option is not valid.
1091 BmIsLoadOptionPeHeaderValid (
1092 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type
,
1093 IN VOID
*FileBuffer
,
1097 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1098 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHeader
;
1099 EFI_IMAGE_OPTIONAL_HEADER32
*OptionalHeader
;
1102 if (FileBuffer
== NULL
|| FileSize
== 0) {
1109 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) FileBuffer
;
1110 if (FileSize
>= sizeof (EFI_IMAGE_DOS_HEADER
) &&
1111 FileSize
> DosHeader
->e_lfanew
&& DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
1114 // Read and check PE signature
1116 PeHeader
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) FileBuffer
+ DosHeader
->e_lfanew
);
1117 if (FileSize
>= DosHeader
->e_lfanew
+ sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
) &&
1118 PeHeader
->Pe32
.Signature
== EFI_IMAGE_NT_SIGNATURE
1121 // Check PE32 or PE32+ magic, and machine type
1123 OptionalHeader
= (EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHeader
->Pe32
.OptionalHeader
;
1124 if ((OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
||
1125 OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) &&
1126 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader
->Pe32
.FileHeader
.Machine
)
1129 // Check the Subsystem:
1130 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1131 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1133 Subsystem
= OptionalHeader
->Subsystem
;
1134 if ((Type
== LoadOptionTypeDriver
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
1135 (Type
== LoadOptionTypeDriver
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) ||
1136 (Type
== LoadOptionTypeSysPrep
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) ||
1137 (Type
== LoadOptionTypeBoot
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)
1149 Process (load and execute) the load option.
1151 @param LoadOption Pointer to the load option.
1153 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1154 or the load option file path doesn't point to a valid file.
1155 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1156 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1160 EfiBootManagerProcessLoadOption (
1161 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1165 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1166 EFI_HANDLE ImageHandle
;
1167 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1171 if ((UINT32
) LoadOption
->OptionType
>= LoadOptionTypeMax
) {
1172 return EFI_INVALID_PARAMETER
;
1175 if (LoadOption
->OptionType
== LoadOptionTypeBoot
) {
1176 return EFI_UNSUPPORTED
;
1180 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1181 // the boot manager will not automatically load the option.
1183 if ((LoadOption
->Attributes
& LOAD_OPTION_ACTIVE
) == 0) {
1187 Status
= EFI_INVALID_PARAMETER
;
1190 // Load and start the load option.
1193 DEBUG_INFO
| DEBUG_LOAD
, "Process Load Option (%s%04x) ...\n",
1194 mBmLoadOptionName
[LoadOption
->OptionType
], LoadOption
->OptionNumber
1197 FileBuffer
= BmGetLoadOptionBuffer (LoadOption
->FilePath
, &FilePath
, &FileSize
);
1199 if (FileBuffer
!= NULL
&& CompareMem (LoadOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1200 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1201 BmPrintDp (LoadOption
->FilePath
);
1202 DEBUG ((EFI_D_INFO
, " -> "));
1203 BmPrintDp (FilePath
);
1204 DEBUG ((EFI_D_INFO
, "\n"));
1207 if (BmIsLoadOptionPeHeaderValid (LoadOption
->OptionType
, FileBuffer
, FileSize
)) {
1208 Status
= gBS
->LoadImage (
1217 if (FilePath
!= NULL
) {
1218 FreePool (FilePath
);
1220 if (FileBuffer
!= NULL
) {
1221 FreePool (FileBuffer
);
1224 if (!EFI_ERROR (Status
)) {
1225 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1226 ASSERT_EFI_ERROR (Status
);
1228 ImageInfo
->LoadOptionsSize
= LoadOption
->OptionalDataSize
;
1229 ImageInfo
->LoadOptions
= LoadOption
->OptionalData
;
1231 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1233 gBS
->SetWatchdogTimer (5 * 60, 0, 0, NULL
);
1235 LoadOption
->Status
= gBS
->StartImage (ImageHandle
, &LoadOption
->ExitDataSize
, &LoadOption
->ExitData
);
1237 DEBUG_INFO
| DEBUG_LOAD
, "Load Option (%s%04x) Return Status = %r\n",
1238 mBmLoadOptionName
[LoadOption
->OptionType
], LoadOption
->OptionNumber
, LoadOption
->Status
1242 // Clear the Watchdog Timer after the image returns
1244 gBS
->SetWatchdogTimer (0, 0, 0, NULL
);