2 Load option library functions which relate with creating and processing load options.
4 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "InternalBm.h"
12 GLOBAL_REMOVE_IF_UNREFERENCED
13 CHAR16
*mBmLoadOptionName
[] = {
20 GLOBAL_REMOVE_IF_UNREFERENCED
21 CHAR16
*mBmLoadOptionOrderName
[] = {
22 EFI_DRIVER_ORDER_VARIABLE_NAME
,
23 EFI_SYS_PREP_ORDER_VARIABLE_NAME
,
24 EFI_BOOT_ORDER_VARIABLE_NAME
,
25 NULL
// PlatformRecovery#### doesn't have associated *Order variable
29 Call Visitor function for each variable in variable storage.
31 @param Visitor Visitor function.
32 @param Context The context passed to Visitor function.
36 BM_VARIABLE_VISITOR Visitor
,
46 NameSize
= sizeof (CHAR16
);
47 Name
= AllocateZeroPool (NameSize
);
48 ASSERT (Name
!= NULL
);
50 NewNameSize
= NameSize
;
51 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
52 if (Status
== EFI_BUFFER_TOO_SMALL
) {
53 Name
= ReallocatePool (NameSize
, NewNameSize
, Name
);
54 ASSERT (Name
!= NULL
);
55 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
56 NameSize
= NewNameSize
;
59 if (Status
== EFI_NOT_FOUND
) {
62 ASSERT_EFI_ERROR (Status
);
64 Visitor (Name
, &Guid
, Context
);
71 Get the Option Number that wasn't used.
73 @param LoadOptionType The load option type.
74 @param FreeOptionNumber Return the minimal free option number.
76 @retval EFI_SUCCESS The option number is found and will be returned.
77 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
78 @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
82 BmGetFreeOptionNumber (
83 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
,
84 OUT UINT16
*FreeOptionNumber
91 UINTN OptionOrderSize
;
94 ASSERT (FreeOptionNumber
!= NULL
);
95 ASSERT (LoadOptionType
== LoadOptionTypeDriver
||
96 LoadOptionType
== LoadOptionTypeBoot
||
97 LoadOptionType
== LoadOptionTypeSysPrep
);
99 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
100 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
103 if (LoadOptionType
== LoadOptionTypeBoot
) {
104 GetEfiGlobalVariable2 (L
"BootNext", (VOID
**) &BootNext
, NULL
);
107 for (OptionNumber
= 0;
108 OptionNumber
< OptionOrderSize
/ sizeof (UINT16
)
109 + ((BootNext
!= NULL
) ? 1 : 0);
113 // Search in OptionOrder whether the OptionNumber exists
115 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
116 if (OptionNumber
== OptionOrder
[Index
]) {
122 // We didn't find it in the ****Order array and it doesn't equal to BootNext
123 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
125 if ((Index
== OptionOrderSize
/ sizeof (UINT16
)) &&
126 ((BootNext
== NULL
) || (OptionNumber
!= *BootNext
))
131 if (OptionOrder
!= NULL
) {
132 FreePool (OptionOrder
);
135 if (BootNext
!= NULL
) {
140 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
141 // OptionNumber equals to 0x10000 which is not valid.
143 ASSERT (OptionNumber
<= 0x10000);
144 if (OptionNumber
== 0x10000) {
145 return EFI_OUT_OF_RESOURCES
;
147 *FreeOptionNumber
= (UINT16
) OptionNumber
;
153 Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable
154 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
171 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
174 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
175 UINT32 VariableAttributes
;
177 if ((Option
->OptionNumber
== LoadOptionNumberUnassigned
) ||
178 (Option
->FilePath
== NULL
) ||
179 ((UINT32
) Option
->OptionType
>= LoadOptionTypeMax
)
181 return EFI_INVALID_PARAMETER
;
185 // Convert NULL description to empty description
188 Description
= Option
->Description
;
189 if (Description
== NULL
) {
190 Description
= &NullChar
;
195 UINT16 FilePathListLength;
196 CHAR16 Description[];
197 EFI_DEVICE_PATH_PROTOCOL FilePathList[];
198 UINT8 OptionalData[];
199 TODO: FilePathList[] IS:
200 A packed array of UEFI device paths. The first element of the
201 array is a device path that describes the device and location of the
202 Image for this load option. The FilePathList[0] is specific
203 to the device type. Other device paths may optionally exist in the
204 FilePathList, but their usage is OSV specific. Each element
205 in the array is variable length, and ends at the device path end
208 VariableSize
= sizeof (Option
->Attributes
)
210 + StrSize (Description
)
211 + GetDevicePathSize (Option
->FilePath
)
212 + Option
->OptionalDataSize
;
214 Variable
= AllocatePool (VariableSize
);
215 ASSERT (Variable
!= NULL
);
218 WriteUnaligned32 ((UINT32
*) Ptr
, Option
->Attributes
);
219 Ptr
+= sizeof (Option
->Attributes
);
221 WriteUnaligned16 ((UINT16
*) Ptr
, (UINT16
) GetDevicePathSize (Option
->FilePath
));
222 Ptr
+= sizeof (UINT16
);
224 CopyMem (Ptr
, Description
, StrSize (Description
));
225 Ptr
+= StrSize (Description
);
227 CopyMem (Ptr
, Option
->FilePath
, GetDevicePathSize (Option
->FilePath
));
228 Ptr
+= GetDevicePathSize (Option
->FilePath
);
230 CopyMem (Ptr
, Option
->OptionalData
, Option
->OptionalDataSize
);
232 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[Option
->OptionType
], Option
->OptionNumber
);
234 VariableAttributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
;
235 if (Option
->OptionType
== LoadOptionTypePlatformRecovery
) {
237 // Lock the PlatformRecovery####
239 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
240 if (!EFI_ERROR (Status
)) {
241 Status
= VariableLock
->RequestToLock (VariableLock
, OptionName
, &gEfiGlobalVariableGuid
);
242 ASSERT_EFI_ERROR (Status
);
244 VariableAttributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
247 Status
= gRT
->SetVariable (
249 &gEfiGlobalVariableGuid
,
260 Update order variable .
262 @param OptionOrderName Order variable name which need to be updated.
263 @param OptionNumber Option number for the new option.
264 @param Position Position of the new load option to put in the ****Order variable.
266 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
267 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
268 @retval EFI_STATUS Return the status of gRT->SetVariable ().
272 BmAddOptionNumberToOrderVariable (
273 IN CHAR16
*OptionOrderName
,
274 IN UINT16 OptionNumber
,
281 UINT16
*NewOptionOrder
;
282 UINTN OptionOrderSize
;
284 // Update the option order variable
286 GetEfiGlobalVariable2 (OptionOrderName
, (VOID
**) &OptionOrder
, &OptionOrderSize
);
287 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
289 Status
= EFI_SUCCESS
;
290 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
291 if (OptionOrder
[Index
] == OptionNumber
) {
292 Status
= EFI_ALREADY_STARTED
;
297 if (!EFI_ERROR (Status
)) {
298 Position
= MIN (Position
, OptionOrderSize
/ sizeof (UINT16
));
300 NewOptionOrder
= AllocatePool (OptionOrderSize
+ sizeof (UINT16
));
301 ASSERT (NewOptionOrder
!= NULL
);
302 if (OptionOrderSize
!= 0) {
303 CopyMem (NewOptionOrder
, OptionOrder
, Position
* sizeof (UINT16
));
304 CopyMem (&NewOptionOrder
[Position
+ 1], &OptionOrder
[Position
], OptionOrderSize
- Position
* sizeof (UINT16
));
306 NewOptionOrder
[Position
] = OptionNumber
;
308 Status
= gRT
->SetVariable (
310 &gEfiGlobalVariableGuid
,
311 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
312 OptionOrderSize
+ sizeof (UINT16
),
315 FreePool (NewOptionOrder
);
318 if (OptionOrder
!= NULL
) {
319 FreePool (OptionOrder
);
326 This function will register the new Boot####, Driver#### or SysPrep#### option.
327 After the *#### is updated, the *Order will also be updated.
329 @param Option Pointer to load option to add. If on input
330 Option->OptionNumber is LoadOptionNumberUnassigned,
331 then on output Option->OptionNumber is updated to
332 the number of the new Boot####,
333 Driver#### or SysPrep#### option.
334 @param Position Position of the new load option to put in the ****Order variable.
336 @retval EFI_SUCCESS The *#### have been successfully registered.
337 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
338 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
339 Note: this API only adds new load option, no replacement support.
340 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
341 option number specified in the Option is LoadOptionNumberUnassigned.
342 @return Status codes of gRT->SetVariable ().
347 EfiBootManagerAddLoadOptionVariable (
348 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
355 if (Option
== NULL
) {
356 return EFI_INVALID_PARAMETER
;
359 if (Option
->OptionType
!= LoadOptionTypeDriver
&&
360 Option
->OptionType
!= LoadOptionTypeSysPrep
&&
361 Option
->OptionType
!= LoadOptionTypeBoot
363 return EFI_INVALID_PARAMETER
;
367 // Get the free option number if the option number is unassigned
369 if (Option
->OptionNumber
== LoadOptionNumberUnassigned
) {
370 Status
= BmGetFreeOptionNumber (Option
->OptionType
, &OptionNumber
);
371 if (EFI_ERROR (Status
)) {
374 Option
->OptionNumber
= OptionNumber
;
377 if (Option
->OptionNumber
>= LoadOptionNumberMax
) {
378 return EFI_INVALID_PARAMETER
;
381 Status
= BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName
[Option
->OptionType
], (UINT16
) Option
->OptionNumber
, Position
);
382 if (!EFI_ERROR (Status
)) {
384 // Save the Boot#### or Driver#### variable
386 Status
= EfiBootManagerLoadOptionToVariable (Option
);
387 if (EFI_ERROR (Status
)) {
389 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
391 EfiBootManagerDeleteLoadOptionVariable (Option
->OptionNumber
, Option
->OptionType
);
399 Sort the load option. The DriverOrder or BootOrder will be re-created to
400 reflect the new order.
402 @param OptionType Load option type
403 @param CompareFunction The comparator
407 EfiBootManagerSortLoadOptionVariable (
408 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
409 SORT_COMPARE CompareFunction
413 EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
;
414 UINTN LoadOptionCount
;
418 LoadOption
= EfiBootManagerGetLoadOptions (&LoadOptionCount
, OptionType
);
421 // Insertion sort algorithm
426 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
431 // Create new ****Order variable
433 OptionOrder
= AllocatePool (LoadOptionCount
* sizeof (UINT16
));
434 ASSERT (OptionOrder
!= NULL
);
435 for (Index
= 0; Index
< LoadOptionCount
; Index
++) {
436 OptionOrder
[Index
] = (UINT16
) LoadOption
[Index
].OptionNumber
;
439 Status
= gRT
->SetVariable (
440 mBmLoadOptionOrderName
[OptionType
],
441 &gEfiGlobalVariableGuid
,
442 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
443 LoadOptionCount
* sizeof (UINT16
),
447 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
449 ASSERT_EFI_ERROR (Status
);
451 FreePool (OptionOrder
);
452 EfiBootManagerFreeLoadOptions (LoadOption
, LoadOptionCount
);
456 Initialize a load option.
458 @param Option Pointer to the load option to be initialized.
459 @param OptionNumber Option number of the load option.
460 @param OptionType Type of the load option.
461 @param Attributes Attributes of the load option.
462 @param Description Description of the load option.
463 @param FilePath Device path of the load option.
464 @param OptionalData Optional data of the load option.
465 @param OptionalDataSize Size of the optional data of the load option.
467 @retval EFI_SUCCESS The load option was initialized successfully.
468 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
472 EfiBootManagerInitializeLoadOption (
473 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
474 IN UINTN OptionNumber
,
475 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
476 IN UINT32 Attributes
,
477 IN CHAR16
*Description
,
478 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
479 IN UINT8
*OptionalData
, OPTIONAL
480 IN UINT32 OptionalDataSize
483 if ((Option
== NULL
) || (Description
== NULL
) || (FilePath
== NULL
)) {
484 return EFI_INVALID_PARAMETER
;
487 if (((OptionalData
!= NULL
) && (OptionalDataSize
== 0)) ||
488 ((OptionalData
== NULL
) && (OptionalDataSize
!= 0))) {
489 return EFI_INVALID_PARAMETER
;
492 if ((UINT32
) OptionType
>= LoadOptionTypeMax
) {
493 return EFI_INVALID_PARAMETER
;
496 ZeroMem (Option
, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
497 Option
->OptionNumber
= OptionNumber
;
498 Option
->OptionType
= OptionType
;
499 Option
->Attributes
= Attributes
;
500 Option
->Description
= AllocateCopyPool (StrSize (Description
), Description
);
501 Option
->FilePath
= DuplicateDevicePath (FilePath
);
502 if (OptionalData
!= NULL
) {
503 Option
->OptionalData
= AllocateCopyPool (OptionalDataSize
, OptionalData
);
504 Option
->OptionalDataSize
= OptionalDataSize
;
512 Return the index of the load option in the load option array.
514 The function consider two load options are equal when the
515 OptionType, Attributes, Description, FilePath and OptionalData are equal.
517 @param Key Pointer to the load option to be found.
518 @param Array Pointer to the array of load options to be found.
519 @param Count Number of entries in the Array.
521 @retval -1 Key wasn't found in the Array.
522 @retval 0 ~ Count-1 The index of the Key in the Array.
526 EfiBootManagerFindLoadOption (
527 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
528 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
534 for (Index
= 0; Index
< Count
; Index
++) {
535 if ((Key
->OptionType
== Array
[Index
].OptionType
) &&
536 (Key
->Attributes
== Array
[Index
].Attributes
) &&
537 (StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
538 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
539 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
540 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0)) {
549 Delete the load option.
551 @param OptionNumber Indicate the option number of load option
552 @param OptionType Indicate the type of load option
554 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
555 @retval EFI_NOT_FOUND The load option cannot be found
556 @retval EFI_SUCCESS The load option was deleted
557 @retval others Status of RT->SetVariable()
561 EfiBootManagerDeleteLoadOptionVariable (
562 IN UINTN OptionNumber
,
563 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
567 UINTN OptionOrderSize
;
569 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
571 if (((UINT32
) OptionType
>= LoadOptionTypeMax
) || (OptionNumber
>= LoadOptionNumberMax
)) {
572 return EFI_INVALID_PARAMETER
;
575 if (OptionType
== LoadOptionTypeDriver
|| OptionType
== LoadOptionTypeSysPrep
|| OptionType
== LoadOptionTypeBoot
) {
577 // If the associated *Order exists, firstly remove the reference in *Order for
578 // Driver####, SysPrep#### and Boot####.
580 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[OptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
581 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
583 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
584 if (OptionOrder
[Index
] == OptionNumber
) {
585 OptionOrderSize
-= sizeof (UINT16
);
586 CopyMem (&OptionOrder
[Index
], &OptionOrder
[Index
+ 1], OptionOrderSize
- Index
* sizeof (UINT16
));
588 mBmLoadOptionOrderName
[OptionType
],
589 &gEfiGlobalVariableGuid
,
590 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
597 if (OptionOrder
!= NULL
) {
598 FreePool (OptionOrder
);
603 // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.
605 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[OptionType
], OptionNumber
);
606 return gRT
->SetVariable (
608 &gEfiGlobalVariableGuid
,
616 Returns the size of a device path in bytes.
618 This function returns the size, in bytes, of the device path data structure
619 specified by DevicePath including the end of device path node. If DevicePath
620 is NULL, then 0 is returned. If the length of the device path is bigger than
621 MaxSize, also return 0 to indicate this is an invalidate device path.
623 @param DevicePath A pointer to a device path data structure.
624 @param MaxSize Max valid device path size. If big than this size,
627 @retval 0 An invalid device path.
628 @retval Others The size of a device path in bytes.
632 BmGetDevicePathSizeEx (
633 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
640 if (DevicePath
== NULL
) {
645 // Search for the end of the device path structure
648 while (!IsDevicePathEnd (DevicePath
)) {
649 NodeSize
= DevicePathNodeLength (DevicePath
);
654 if (Size
> MaxSize
) {
657 DevicePath
= NextDevicePathNode (DevicePath
);
659 Size
+= DevicePathNodeLength (DevicePath
);
660 if (Size
> MaxSize
) {
668 Returns the length of a Null-terminated Unicode string. If the length is
669 bigger than MaxStringLen, return length 0 to indicate that this is an
672 This function returns the number of Unicode characters in the Null-terminated
673 Unicode string specified by String.
675 If String is NULL, then ASSERT().
676 If String is not aligned on a 16-bit boundary, then ASSERT().
678 @param String A pointer to a Null-terminated Unicode string.
679 @param MaxStringLen Max string len in this string.
681 @retval 0 An invalid string.
682 @retval Others The length of String.
687 IN CONST CHAR16
*String
,
688 IN UINTN MaxStringLen
693 ASSERT (String
!= NULL
&& MaxStringLen
!= 0);
694 ASSERT (((UINTN
) String
& BIT0
) == 0);
696 for (Length
= 0; *String
!= L
'\0' && MaxStringLen
!= Length
; String
++, Length
+=2);
698 if (*String
!= L
'\0' && MaxStringLen
== Length
) {
706 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####
707 variable (VendorGuid/Name)
709 @param Variable The variable data.
710 @param VariableSize The variable size.
712 @retval TRUE The variable data is correct.
713 @retval FALSE The variable data is corrupted.
723 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
724 UINTN DescriptionSize
;
726 if (VariableSize
<= sizeof (UINT16
) + sizeof (UINT32
)) {
731 // Skip the option attribute
733 Variable
+= sizeof (UINT32
);
736 // Get the option's device path size
738 FilePathSize
= ReadUnaligned16 ((UINT16
*) Variable
);
739 Variable
+= sizeof (UINT16
);
742 // Get the option's description string size
744 DescriptionSize
= BmStrSizeEx ((CHAR16
*) Variable
, VariableSize
- sizeof (UINT16
) - sizeof (UINT32
));
745 Variable
+= DescriptionSize
;
748 // Get the option's device path
750 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Variable
;
753 // Validation boot option variable.
755 if ((FilePathSize
== 0) || (DescriptionSize
== 0)) {
759 if (sizeof (UINT32
) + sizeof (UINT16
) + DescriptionSize
+ FilePathSize
> VariableSize
) {
763 return (BOOLEAN
) (BmGetDevicePathSizeEx (DevicePath
, FilePathSize
) != 0);
767 Check whether the VariableName is a valid load option variable name
768 and return the load option type and option number.
770 @param VariableName The name of the load option variable.
771 @param OptionType Return the load option type.
772 @param OptionNumber Return the load option number.
774 @retval TRUE The variable name is valid; The load option type and
775 load option number is returned.
776 @retval FALSE The variable name is NOT valid.
780 EfiBootManagerIsValidLoadOptionVariableName (
781 IN CHAR16
*VariableName
,
782 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE
*OptionType OPTIONAL
,
783 OUT UINT16
*OptionNumber OPTIONAL
786 UINTN VariableNameLen
;
789 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType
;
790 UINT16 LocalOptionNumber
;
792 if (VariableName
== NULL
) {
796 VariableNameLen
= StrLen (VariableName
);
799 // Return FALSE when the variable name length is too small.
801 if (VariableNameLen
<= 4) {
806 // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery.
808 for (LocalOptionType
= 0; LocalOptionType
< ARRAY_SIZE (mBmLoadOptionName
); LocalOptionType
++) {
809 if ((VariableNameLen
- 4 == StrLen (mBmLoadOptionName
[LocalOptionType
])) &&
810 (StrnCmp (VariableName
, mBmLoadOptionName
[LocalOptionType
], VariableNameLen
- 4) == 0)
815 if (LocalOptionType
== ARRAY_SIZE (mBmLoadOptionName
)) {
820 // Return FALSE when the last four characters are not hex digits.
822 LocalOptionNumber
= 0;
823 for (Index
= VariableNameLen
- 4; Index
< VariableNameLen
; Index
++) {
824 Uint
= BmCharToUint (VariableName
[Index
]);
828 LocalOptionNumber
= (UINT16
) Uint
+ LocalOptionNumber
* 0x10;
831 if (Index
!= VariableNameLen
) {
835 if (OptionType
!= NULL
) {
836 *OptionType
= LocalOptionType
;
839 if (OptionNumber
!= NULL
) {
840 *OptionNumber
= LocalOptionNumber
;
847 Build the Boot#### or Driver#### option from the VariableName.
849 @param VariableName Variable name of the load option
850 @param VendorGuid Variable GUID of the load option
851 @param Option Return the load option.
853 @retval EFI_SUCCESS Get the option just been created
854 @retval EFI_NOT_FOUND Failed to get the new option
859 EfiBootManagerVariableToLoadOptionEx (
860 IN CHAR16
*VariableName
,
861 IN EFI_GUID
*VendorGuid
,
862 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
871 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
873 UINT32 OptionalDataSize
;
875 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
878 if ((VariableName
== NULL
) || (Option
== NULL
)) {
879 return EFI_INVALID_PARAMETER
;
882 if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName
, &OptionType
, &OptionNumber
)) {
883 return EFI_INVALID_PARAMETER
;
889 GetVariable2 (VariableName
, VendorGuid
, (VOID
**) &Variable
, &VariableSize
);
890 if (Variable
== NULL
) {
891 return EFI_NOT_FOUND
;
895 // Validate *#### variable data.
897 if (!BmValidateOption(Variable
, VariableSize
)) {
899 return EFI_INVALID_PARAMETER
;
903 // Get the option attribute
905 VariablePtr
= Variable
;
906 Attribute
= ReadUnaligned32 ((UINT32
*) VariablePtr
);
907 VariablePtr
+= sizeof (UINT32
);
910 // Get the option's device path size
912 FilePathSize
= ReadUnaligned16 ((UINT16
*) VariablePtr
);
913 VariablePtr
+= sizeof (UINT16
);
916 // Get the option's description string
918 Description
= (CHAR16
*) VariablePtr
;
921 // Get the option's description string size
923 VariablePtr
+= StrSize ((CHAR16
*) VariablePtr
);
926 // Get the option's device path
928 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) VariablePtr
;
929 VariablePtr
+= FilePathSize
;
931 OptionalDataSize
= (UINT32
) (VariableSize
- ((UINTN
) VariablePtr
- (UINTN
) Variable
));
932 if (OptionalDataSize
== 0) {
935 OptionalData
= VariablePtr
;
938 Status
= EfiBootManagerInitializeLoadOption (
948 ASSERT_EFI_ERROR (Status
);
950 CopyGuid (&Option
->VendorGuid
, VendorGuid
);
957 Build the Boot#### or Driver#### option from the VariableName.
959 @param VariableName EFI Variable name indicate if it is Boot#### or Driver####
960 @param Option Return the Boot#### or Driver#### option.
962 @retval EFI_SUCCESS Get the option just been created
963 @retval EFI_NOT_FOUND Failed to get the new option
967 EfiBootManagerVariableToLoadOption (
968 IN CHAR16
*VariableName
,
969 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
972 return EfiBootManagerVariableToLoadOptionEx (VariableName
, &gEfiGlobalVariableGuid
, Option
);
976 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
978 EFI_BOOT_MANAGER_LOAD_OPTION
*Options
;
980 } BM_COLLECT_LOAD_OPTIONS_PARAM
;
983 Visitor function to collect the Platform Recovery load options or OS Recovery
984 load options from NV storage.
986 @param Name Variable name.
987 @param Guid Variable GUID.
988 @param Context The same context passed to BmForEachVariable.
991 BmCollectLoadOptions (
998 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
1000 EFI_BOOT_MANAGER_LOAD_OPTION Option
;
1002 BM_COLLECT_LOAD_OPTIONS_PARAM
*Param
;
1004 Param
= (BM_COLLECT_LOAD_OPTIONS_PARAM
*) Context
;
1006 if (CompareGuid (Guid
, Param
->Guid
) && (
1007 Param
->OptionType
== LoadOptionTypePlatformRecovery
&&
1008 EfiBootManagerIsValidLoadOptionVariableName (Name
, &OptionType
, &OptionNumber
) &&
1009 OptionType
== LoadOptionTypePlatformRecovery
1011 Status
= EfiBootManagerVariableToLoadOptionEx (Name
, Guid
, &Option
);
1012 if (!EFI_ERROR (Status
)) {
1013 for (Index
= 0; Index
< Param
->OptionCount
; Index
++) {
1014 if (Param
->Options
[Index
].OptionNumber
> Option
.OptionNumber
) {
1018 Param
->Options
= ReallocatePool (
1019 Param
->OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
1020 (Param
->OptionCount
+ 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
1023 ASSERT (Param
->Options
!= NULL
);
1024 CopyMem (&Param
->Options
[Index
+ 1], &Param
->Options
[Index
], (Param
->OptionCount
- Index
) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
1025 CopyMem (&Param
->Options
[Index
], &Option
, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
1026 Param
->OptionCount
++;
1032 Returns an array of load options based on the EFI variable
1033 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
1034 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
1036 @param LoadOptionCount Returns number of entries in the array.
1037 @param LoadOptionType The type of the load option.
1039 @retval NULL No load options exist.
1040 @retval !NULL Array of load option entries.
1043 EFI_BOOT_MANAGER_LOAD_OPTION
*
1045 EfiBootManagerGetLoadOptions (
1046 OUT UINTN
*OptionCount
,
1047 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
1051 UINT16
*OptionOrder
;
1052 UINTN OptionOrderSize
;
1055 EFI_BOOT_MANAGER_LOAD_OPTION
*Options
;
1056 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
1057 UINT16 OptionNumber
;
1058 BM_COLLECT_LOAD_OPTIONS_PARAM Param
;
1063 if (LoadOptionType
== LoadOptionTypeDriver
|| LoadOptionType
== LoadOptionTypeSysPrep
|| LoadOptionType
== LoadOptionTypeBoot
) {
1065 // Read the BootOrder, or DriverOrder variable.
1067 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
1068 if (OptionOrder
== NULL
) {
1072 *OptionCount
= OptionOrderSize
/ sizeof (UINT16
);
1074 Options
= AllocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
1075 ASSERT (Options
!= NULL
);
1078 for (Index
= 0; Index
< *OptionCount
; Index
++) {
1079 OptionNumber
= OptionOrder
[Index
];
1080 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[LoadOptionType
], OptionNumber
);
1082 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &Options
[OptionIndex
]);
1083 if (EFI_ERROR (Status
)) {
1084 DEBUG ((EFI_D_INFO
, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName
));
1085 EfiBootManagerDeleteLoadOptionVariable (OptionNumber
, LoadOptionType
);
1087 ASSERT (Options
[OptionIndex
].OptionNumber
== OptionNumber
);
1092 if (OptionOrder
!= NULL
) {
1093 FreePool (OptionOrder
);
1096 if (OptionIndex
< *OptionCount
) {
1097 Options
= ReallocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), OptionIndex
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), Options
);
1098 ASSERT (Options
!= NULL
);
1099 *OptionCount
= OptionIndex
;
1102 } else if (LoadOptionType
== LoadOptionTypePlatformRecovery
) {
1103 Param
.OptionType
= LoadOptionTypePlatformRecovery
;
1104 Param
.Options
= NULL
;
1105 Param
.OptionCount
= 0;
1106 Param
.Guid
= &gEfiGlobalVariableGuid
;
1108 BmForEachVariable (BmCollectLoadOptions
, (VOID
*) &Param
);
1110 *OptionCount
= Param
.OptionCount
;
1111 Options
= Param
.Options
;
1118 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1120 @param LoadOption Pointer to boot option to Free.
1122 @return EFI_SUCCESS BootOption was freed
1123 @return EFI_NOT_FOUND BootOption == NULL
1128 EfiBootManagerFreeLoadOption (
1129 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1132 if (LoadOption
== NULL
) {
1133 return EFI_NOT_FOUND
;
1136 if (LoadOption
->Description
!= NULL
) {
1137 FreePool (LoadOption
->Description
);
1139 if (LoadOption
->FilePath
!= NULL
) {
1140 FreePool (LoadOption
->FilePath
);
1142 if (LoadOption
->OptionalData
!= NULL
) {
1143 FreePool (LoadOption
->OptionalData
);
1150 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1151 EfiBootManagerGetLoadOptions().
1153 @param Option Pointer to boot option array to free.
1154 @param OptionCount Number of array entries in BootOption
1156 @return EFI_SUCCESS BootOption was freed
1157 @return EFI_NOT_FOUND BootOption == NULL
1162 EfiBootManagerFreeLoadOptions (
1163 IN EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
1164 IN UINTN OptionCount
1169 if (Option
== NULL
) {
1170 return EFI_NOT_FOUND
;
1173 for (Index
= 0;Index
< OptionCount
; Index
++) {
1174 EfiBootManagerFreeLoadOption (&Option
[Index
]);
1183 Return whether the PE header of the load option is valid or not.
1185 @param[in] Type The load option type.
1186 It's used to check whether the load option is valid.
1187 When it's LoadOptionTypeMax, the routine only guarantees
1188 the load option is a valid PE image but doesn't guarantee
1189 the PE's subsystem type is valid.
1190 @param[in] FileBuffer The PE file buffer of the load option.
1191 @param[in] FileSize The size of the load option file.
1193 @retval TRUE The PE header of the load option is valid.
1194 @retval FALSE The PE header of the load option is not valid.
1197 BmIsLoadOptionPeHeaderValid (
1198 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type
,
1199 IN VOID
*FileBuffer
,
1203 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1204 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHeader
;
1205 EFI_IMAGE_OPTIONAL_HEADER32
*OptionalHeader
;
1208 if (FileBuffer
== NULL
|| FileSize
== 0) {
1215 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) FileBuffer
;
1216 if (FileSize
>= sizeof (EFI_IMAGE_DOS_HEADER
) &&
1217 FileSize
> DosHeader
->e_lfanew
&& DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
1220 // Read and check PE signature
1222 PeHeader
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) FileBuffer
+ DosHeader
->e_lfanew
);
1223 if (FileSize
>= DosHeader
->e_lfanew
+ sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
) &&
1224 PeHeader
->Pe32
.Signature
== EFI_IMAGE_NT_SIGNATURE
1227 // Check PE32 or PE32+ magic, and machine type
1229 OptionalHeader
= (EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHeader
->Pe32
.OptionalHeader
;
1230 if ((OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
||
1231 OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) &&
1232 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader
->Pe32
.FileHeader
.Machine
)
1235 // Check the Subsystem:
1236 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1237 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1239 Subsystem
= OptionalHeader
->Subsystem
;
1240 if ((Type
== LoadOptionTypeMax
) ||
1241 (Type
== LoadOptionTypeDriver
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
1242 (Type
== LoadOptionTypeDriver
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) ||
1243 (Type
== LoadOptionTypeSysPrep
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) ||
1244 (Type
== LoadOptionTypeBoot
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) ||
1245 (Type
== LoadOptionTypePlatformRecovery
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)
1257 Return the next matched load option buffer.
1258 The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
1259 load option is read.
1261 @param Type The load option type.
1262 It's used to check whether the load option is valid.
1263 When it's LoadOptionTypeMax, the routine only guarantees
1264 the load option is a valid PE image but doesn't guarantee
1265 the PE's subsystem type is valid.
1266 @param FilePath The device path pointing to a load option.
1267 It could be a short-form device path.
1268 @param FullPath Return the next full device path of the load option after
1269 short-form device path expanding.
1270 Caller is responsible to free it.
1271 NULL to return the first matched full device path.
1272 @param FileSize Return the load option size.
1274 @return The load option buffer. Caller is responsible to free the memory.
1277 BmGetNextLoadOptionBuffer (
1278 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type
,
1279 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1280 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1285 EFI_DEVICE_PATH_PROTOCOL
*PreFullPath
;
1286 EFI_DEVICE_PATH_PROTOCOL
*CurFullPath
;
1287 UINTN LocalFileSize
;
1288 UINT32 AuthenticationStatus
;
1289 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1293 CurFullPath
= *FullPath
;
1295 PreFullPath
= CurFullPath
;
1296 CurFullPath
= BmGetNextLoadOptionDevicePath (FilePath
, CurFullPath
);
1298 // Only free the full path created *inside* this routine
1300 if ((PreFullPath
!= NULL
) && (PreFullPath
!= *FullPath
)) {
1301 FreePool (PreFullPath
);
1303 if (CurFullPath
== NULL
) {
1306 FileBuffer
= GetFileBufferByFilePath (TRUE
, CurFullPath
, &LocalFileSize
, &AuthenticationStatus
);
1307 if ((FileBuffer
!= NULL
) && !BmIsLoadOptionPeHeaderValid (Type
, FileBuffer
, LocalFileSize
)) {
1309 // Free the RAM disk file system if the load option is invalid.
1311 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1312 if (RamDiskDevicePath
!= NULL
) {
1313 BmDestroyRamDisk (RamDiskDevicePath
);
1314 FreePool (RamDiskDevicePath
);
1318 // Free the invalid load option buffer.
1320 FreePool (FileBuffer
);
1323 } while (FileBuffer
== NULL
);
1325 if (FileBuffer
== NULL
) {
1330 DEBUG ((DEBUG_INFO
, "[Bds] Expand "));
1331 BmPrintDp (FilePath
);
1332 DEBUG ((DEBUG_INFO
, " -> "));
1333 BmPrintDp (CurFullPath
);
1334 DEBUG ((DEBUG_INFO
, "\n"));
1336 *FullPath
= CurFullPath
;
1337 *FileSize
= LocalFileSize
;
1342 Process (load and execute) the load option.
1344 @param LoadOption Pointer to the load option.
1346 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1347 or the load option file path doesn't point to a valid file.
1348 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1349 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1353 EfiBootManagerProcessLoadOption (
1354 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1358 EFI_DEVICE_PATH_PROTOCOL
*PreFullPath
;
1359 EFI_DEVICE_PATH_PROTOCOL
*CurFullPath
;
1360 EFI_HANDLE ImageHandle
;
1361 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1365 if ((UINT32
) LoadOption
->OptionType
>= LoadOptionTypeMax
) {
1366 return EFI_INVALID_PARAMETER
;
1369 if (LoadOption
->OptionType
== LoadOptionTypeBoot
) {
1370 return EFI_UNSUPPORTED
;
1374 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1375 // the boot manager will not automatically load the option.
1377 if ((LoadOption
->Attributes
& LOAD_OPTION_ACTIVE
) == 0) {
1382 // Load and start the load option.
1385 DEBUG_INFO
| DEBUG_LOAD
, "Process %s%04x (%s) ...\n",
1386 mBmLoadOptionName
[LoadOption
->OptionType
], LoadOption
->OptionNumber
,
1387 LoadOption
->Description
1391 EfiBootManagerConnectDevicePath (LoadOption
->FilePath
, NULL
);
1394 // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
1397 Status
= EFI_INVALID_PARAMETER
;
1398 PreFullPath
= CurFullPath
;
1399 FileBuffer
= BmGetNextLoadOptionBuffer (LoadOption
->OptionType
, LoadOption
->FilePath
, &CurFullPath
, &FileSize
);
1400 if (PreFullPath
!= NULL
) {
1401 FreePool (PreFullPath
);
1403 if (FileBuffer
== NULL
) {
1406 Status
= gBS
->LoadImage (
1414 FreePool (FileBuffer
);
1416 if (!EFI_ERROR (Status
)) {
1417 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&ImageInfo
);
1418 ASSERT_EFI_ERROR (Status
);
1420 ImageInfo
->LoadOptionsSize
= LoadOption
->OptionalDataSize
;
1421 ImageInfo
->LoadOptions
= LoadOption
->OptionalData
;
1423 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1425 gBS
->SetWatchdogTimer (5 * 60, 0, 0, NULL
);
1427 LoadOption
->Status
= gBS
->StartImage (ImageHandle
, &LoadOption
->ExitDataSize
, &LoadOption
->ExitData
);
1429 DEBUG_INFO
| DEBUG_LOAD
, "%s%04x Return Status = %r\n",
1430 mBmLoadOptionName
[LoadOption
->OptionType
], LoadOption
->OptionNumber
, LoadOption
->Status
1434 // Clear the Watchdog Timer after the image returns
1436 gBS
->SetWatchdogTimer (0, 0, 0, NULL
);
1438 if ((LoadOption
->OptionType
!= LoadOptionTypePlatformRecovery
) || (LoadOption
->Status
== EFI_SUCCESS
)) {
1444 if (CurFullPath
!= NULL
) {
1445 FreePool (CurFullPath
);