2 Load option library functions which relate with creating and processing load options.
4 Copyright (c) 2011 - 2019, 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 #include <Library/VariablePolicyHelperLib.h>
14 GLOBAL_REMOVE_IF_UNREFERENCED
15 CHAR16
*mBmLoadOptionName
[] = {
22 GLOBAL_REMOVE_IF_UNREFERENCED
23 CHAR16
*mBmLoadOptionOrderName
[] = {
24 EFI_DRIVER_ORDER_VARIABLE_NAME
,
25 EFI_SYS_PREP_ORDER_VARIABLE_NAME
,
26 EFI_BOOT_ORDER_VARIABLE_NAME
,
27 NULL
// PlatformRecovery#### doesn't have associated *Order variable
31 Call Visitor function for each variable in variable storage.
33 @param Visitor Visitor function.
34 @param Context The context passed to Visitor function.
38 BM_VARIABLE_VISITOR Visitor
,
48 NameSize
= sizeof (CHAR16
);
49 Name
= AllocateZeroPool (NameSize
);
50 ASSERT (Name
!= NULL
);
52 NewNameSize
= NameSize
;
53 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
54 if (Status
== EFI_BUFFER_TOO_SMALL
) {
55 Name
= ReallocatePool (NameSize
, NewNameSize
, Name
);
56 ASSERT (Name
!= NULL
);
57 Status
= gRT
->GetNextVariableName (&NewNameSize
, Name
, &Guid
);
58 NameSize
= NewNameSize
;
61 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
93 UINTN OptionOrderSize
;
96 ASSERT (FreeOptionNumber
!= NULL
);
98 LoadOptionType
== LoadOptionTypeDriver
||
99 LoadOptionType
== LoadOptionTypeBoot
||
100 LoadOptionType
== LoadOptionTypeSysPrep
103 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**)&OptionOrder
, &OptionOrderSize
);
104 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
107 if (LoadOptionType
== LoadOptionTypeBoot
) {
108 GetEfiGlobalVariable2 (L
"BootNext", (VOID
**)&BootNext
, NULL
);
111 for (OptionNumber
= 0;
112 OptionNumber
< OptionOrderSize
/ sizeof (UINT16
)
113 + ((BootNext
!= NULL
) ? 1 : 0);
118 // Search in OptionOrder whether the OptionNumber exists
120 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
121 if (OptionNumber
== OptionOrder
[Index
]) {
127 // We didn't find it in the ****Order array and it doesn't equal to BootNext
128 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
130 if ((Index
== OptionOrderSize
/ sizeof (UINT16
)) &&
131 ((BootNext
== NULL
) || (OptionNumber
!= *BootNext
))
138 if (OptionOrder
!= NULL
) {
139 FreePool (OptionOrder
);
142 if (BootNext
!= NULL
) {
147 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
148 // OptionNumber equals to 0x10000 which is not valid.
150 ASSERT (OptionNumber
<= 0x10000);
151 if (OptionNumber
== 0x10000) {
152 return EFI_OUT_OF_RESOURCES
;
154 *FreeOptionNumber
= (UINT16
)OptionNumber
;
160 Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable
161 from the load option.
163 @param LoadOption Pointer to the load option.
165 @retval EFI_SUCCESS The variable was created.
166 @retval Others Error status returned by RT->SetVariable.
170 EfiBootManagerLoadOptionToVariable (
171 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Option
178 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
181 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
;
182 UINT32 VariableAttributes
;
184 if ((Option
->OptionNumber
== LoadOptionNumberUnassigned
) ||
185 (Option
->FilePath
== NULL
) ||
186 ((UINT32
)Option
->OptionType
>= LoadOptionTypeMax
)
189 return EFI_INVALID_PARAMETER
;
193 // Convert NULL description to empty description
196 Description
= Option
->Description
;
197 if (Description
== NULL
) {
198 Description
= &NullChar
;
203 UINT16 FilePathListLength;
204 CHAR16 Description[];
205 EFI_DEVICE_PATH_PROTOCOL FilePathList[];
206 UINT8 OptionalData[];
207 TODO: FilePathList[] IS:
208 A packed array of UEFI device paths. The first element of the
209 array is a device path that describes the device and location of the
210 Image for this load option. The FilePathList[0] is specific
211 to the device type. Other device paths may optionally exist in the
212 FilePathList, but their usage is OSV specific. Each element
213 in the array is variable length, and ends at the device path end
216 VariableSize
= sizeof (Option
->Attributes
)
218 + StrSize (Description
)
219 + GetDevicePathSize (Option
->FilePath
)
220 + Option
->OptionalDataSize
;
222 Variable
= AllocatePool (VariableSize
);
223 ASSERT (Variable
!= NULL
);
226 WriteUnaligned32 ((UINT32
*)Ptr
, Option
->Attributes
);
227 Ptr
+= sizeof (Option
->Attributes
);
229 WriteUnaligned16 ((UINT16
*)Ptr
, (UINT16
)GetDevicePathSize (Option
->FilePath
));
230 Ptr
+= sizeof (UINT16
);
232 CopyMem (Ptr
, Description
, StrSize (Description
));
233 Ptr
+= StrSize (Description
);
235 CopyMem (Ptr
, Option
->FilePath
, GetDevicePathSize (Option
->FilePath
));
236 Ptr
+= GetDevicePathSize (Option
->FilePath
);
238 CopyMem (Ptr
, Option
->OptionalData
, Option
->OptionalDataSize
);
240 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[Option
->OptionType
], Option
->OptionNumber
);
242 VariableAttributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
;
243 if (Option
->OptionType
== LoadOptionTypePlatformRecovery
) {
245 // Lock the PlatformRecovery####
247 Status
= gBS
->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid
, NULL
, (VOID
**)&VariablePolicy
);
248 if (!EFI_ERROR (Status
)) {
249 Status
= RegisterBasicVariablePolicy (
251 &gEfiGlobalVariableGuid
,
253 VARIABLE_POLICY_NO_MIN_SIZE
,
254 VARIABLE_POLICY_NO_MAX_SIZE
,
255 VARIABLE_POLICY_NO_MUST_ATTR
,
256 VARIABLE_POLICY_NO_CANT_ATTR
,
257 VARIABLE_POLICY_TYPE_LOCK_NOW
259 ASSERT_EFI_ERROR (Status
);
262 VariableAttributes
= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
265 Status
= gRT
->SetVariable (
267 &gEfiGlobalVariableGuid
,
278 Update order variable .
280 @param OptionOrderName Order variable name which need to be updated.
281 @param OptionNumber Option number for the new option.
282 @param Position Position of the new load option to put in the ****Order variable.
284 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
285 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
286 @retval EFI_STATUS Return the status of gRT->SetVariable ().
290 BmAddOptionNumberToOrderVariable (
291 IN CHAR16
*OptionOrderName
,
292 IN UINT16 OptionNumber
,
299 UINT16
*NewOptionOrder
;
300 UINTN OptionOrderSize
;
303 // Update the option order variable
305 GetEfiGlobalVariable2 (OptionOrderName
, (VOID
**)&OptionOrder
, &OptionOrderSize
);
306 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
308 Status
= EFI_SUCCESS
;
309 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
310 if (OptionOrder
[Index
] == OptionNumber
) {
311 Status
= EFI_ALREADY_STARTED
;
316 if (!EFI_ERROR (Status
)) {
317 Position
= MIN (Position
, OptionOrderSize
/ sizeof (UINT16
));
319 NewOptionOrder
= AllocatePool (OptionOrderSize
+ sizeof (UINT16
));
320 ASSERT (NewOptionOrder
!= NULL
);
321 if (OptionOrderSize
!= 0) {
322 CopyMem (NewOptionOrder
, OptionOrder
, Position
* sizeof (UINT16
));
323 CopyMem (&NewOptionOrder
[Position
+ 1], &OptionOrder
[Position
], OptionOrderSize
- Position
* sizeof (UINT16
));
326 NewOptionOrder
[Position
] = OptionNumber
;
328 Status
= gRT
->SetVariable (
330 &gEfiGlobalVariableGuid
,
331 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
332 OptionOrderSize
+ sizeof (UINT16
),
335 FreePool (NewOptionOrder
);
338 if (OptionOrder
!= NULL
) {
339 FreePool (OptionOrder
);
346 This function will register the new Boot####, Driver#### or SysPrep#### option.
347 After the *#### is updated, the *Order will also be updated.
349 @param Option Pointer to load option to add. If on input
350 Option->OptionNumber is LoadOptionNumberUnassigned,
351 then on output Option->OptionNumber is updated to
352 the number of the new Boot####,
353 Driver#### or SysPrep#### option.
354 @param Position Position of the new load option to put in the ****Order variable.
356 @retval EFI_SUCCESS The *#### have been successfully registered.
357 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
358 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
359 Note: this API only adds new load option, no replacement support.
360 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
361 option number specified in the Option is LoadOptionNumberUnassigned.
362 @return Status codes of gRT->SetVariable ().
367 EfiBootManagerAddLoadOptionVariable (
368 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
375 if (Option
== NULL
) {
376 return EFI_INVALID_PARAMETER
;
379 if ((Option
->OptionType
!= LoadOptionTypeDriver
) &&
380 (Option
->OptionType
!= LoadOptionTypeSysPrep
) &&
381 (Option
->OptionType
!= LoadOptionTypeBoot
)
384 return EFI_INVALID_PARAMETER
;
388 // Get the free option number if the option number is unassigned
390 if (Option
->OptionNumber
== LoadOptionNumberUnassigned
) {
391 Status
= BmGetFreeOptionNumber (Option
->OptionType
, &OptionNumber
);
392 if (EFI_ERROR (Status
)) {
396 Option
->OptionNumber
= OptionNumber
;
399 if (Option
->OptionNumber
>= LoadOptionNumberMax
) {
400 return EFI_INVALID_PARAMETER
;
403 Status
= BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName
[Option
->OptionType
], (UINT16
)Option
->OptionNumber
, Position
);
404 if (!EFI_ERROR (Status
)) {
406 // Save the Boot#### or Driver#### variable
408 Status
= EfiBootManagerLoadOptionToVariable (Option
);
409 if (EFI_ERROR (Status
)) {
411 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
413 EfiBootManagerDeleteLoadOptionVariable (Option
->OptionNumber
, Option
->OptionType
);
421 Sort the load option. The DriverOrder or BootOrder will be re-created to
422 reflect the new order.
424 @param OptionType Load option type
425 @param CompareFunction The comparator
429 EfiBootManagerSortLoadOptionVariable (
430 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
431 SORT_COMPARE CompareFunction
435 EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
;
436 UINTN LoadOptionCount
;
440 LoadOption
= EfiBootManagerGetLoadOptions (&LoadOptionCount
, OptionType
);
443 // Insertion sort algorithm
448 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
453 // Create new ****Order variable
455 OptionOrder
= AllocatePool (LoadOptionCount
* sizeof (UINT16
));
456 ASSERT (OptionOrder
!= NULL
);
457 for (Index
= 0; Index
< LoadOptionCount
; Index
++) {
458 OptionOrder
[Index
] = (UINT16
)LoadOption
[Index
].OptionNumber
;
461 Status
= gRT
->SetVariable (
462 mBmLoadOptionOrderName
[OptionType
],
463 &gEfiGlobalVariableGuid
,
464 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
465 LoadOptionCount
* sizeof (UINT16
),
469 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
471 ASSERT_EFI_ERROR (Status
);
473 FreePool (OptionOrder
);
474 EfiBootManagerFreeLoadOptions (LoadOption
, LoadOptionCount
);
478 Initialize a load option.
480 @param Option Pointer to the load option to be initialized.
481 @param OptionNumber Option number of the load option.
482 @param OptionType Type of the load option.
483 @param Attributes Attributes of the load option.
484 @param Description Description of the load option.
485 @param FilePath Device path of the load option.
486 @param OptionalData Optional data of the load option.
487 @param OptionalDataSize Size of the optional data of the load option.
489 @retval EFI_SUCCESS The load option was initialized successfully.
490 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
494 EfiBootManagerInitializeLoadOption (
495 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
496 IN UINTN OptionNumber
,
497 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
498 IN UINT32 Attributes
,
499 IN CHAR16
*Description
,
500 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
501 IN UINT8
*OptionalData OPTIONAL
,
502 IN UINT32 OptionalDataSize
505 if ((Option
== NULL
) || (Description
== NULL
) || (FilePath
== NULL
)) {
506 return EFI_INVALID_PARAMETER
;
509 if (((OptionalData
!= NULL
) && (OptionalDataSize
== 0)) ||
510 ((OptionalData
== NULL
) && (OptionalDataSize
!= 0)))
512 return EFI_INVALID_PARAMETER
;
515 if ((UINT32
)OptionType
>= LoadOptionTypeMax
) {
516 return EFI_INVALID_PARAMETER
;
519 ZeroMem (Option
, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
520 Option
->OptionNumber
= OptionNumber
;
521 Option
->OptionType
= OptionType
;
522 Option
->Attributes
= Attributes
;
523 Option
->Description
= AllocateCopyPool (StrSize (Description
), Description
);
524 Option
->FilePath
= DuplicateDevicePath (FilePath
);
525 if (OptionalData
!= NULL
) {
526 Option
->OptionalData
= AllocateCopyPool (OptionalDataSize
, OptionalData
);
527 Option
->OptionalDataSize
= OptionalDataSize
;
534 Return the index of the load option in the load option array.
536 The function consider two load options are equal when the
537 OptionType, Attributes, Description, FilePath and OptionalData are equal.
539 @param Key Pointer to the load option to be found.
540 @param Array Pointer to the array of load options to be found.
541 @param Count Number of entries in the Array.
543 @retval -1 Key wasn't found in the Array.
544 @retval 0 ~ Count-1 The index of the Key in the Array.
548 EfiBootManagerFindLoadOption (
549 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
550 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
556 for (Index
= 0; Index
< Count
; Index
++) {
557 if ((Key
->OptionType
== Array
[Index
].OptionType
) &&
558 (Key
->Attributes
== Array
[Index
].Attributes
) &&
559 (StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
560 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
561 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
562 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0))
572 Delete the load option.
574 @param OptionNumber Indicate the option number of load option
575 @param OptionType Indicate the type of load option
577 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
578 @retval EFI_NOT_FOUND The load option cannot be found
579 @retval EFI_SUCCESS The load option was deleted
580 @retval others Status of RT->SetVariable()
584 EfiBootManagerDeleteLoadOptionVariable (
585 IN UINTN OptionNumber
,
586 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
590 UINTN OptionOrderSize
;
592 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
594 if (((UINT32
)OptionType
>= LoadOptionTypeMax
) || (OptionNumber
>= LoadOptionNumberMax
)) {
595 return EFI_INVALID_PARAMETER
;
598 if ((OptionType
== LoadOptionTypeDriver
) || (OptionType
== LoadOptionTypeSysPrep
) || (OptionType
== LoadOptionTypeBoot
)) {
600 // If the associated *Order exists, firstly remove the reference in *Order for
601 // Driver####, SysPrep#### and Boot####.
603 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[OptionType
], (VOID
**)&OptionOrder
, &OptionOrderSize
);
604 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
606 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
607 if (OptionOrder
[Index
] == OptionNumber
) {
608 OptionOrderSize
-= sizeof (UINT16
);
609 CopyMem (&OptionOrder
[Index
], &OptionOrder
[Index
+ 1], OptionOrderSize
- Index
* sizeof (UINT16
));
611 mBmLoadOptionOrderName
[OptionType
],
612 &gEfiGlobalVariableGuid
,
613 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
621 if (OptionOrder
!= NULL
) {
622 FreePool (OptionOrder
);
627 // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.
629 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[OptionType
], OptionNumber
);
630 return gRT
->SetVariable (
632 &gEfiGlobalVariableGuid
,
640 Returns the size of a device path in bytes.
642 This function returns the size, in bytes, of the device path data structure
643 specified by DevicePath including the end of device path node. If DevicePath
644 is NULL, then 0 is returned. If the length of the device path is bigger than
645 MaxSize, also return 0 to indicate this is an invalidate device path.
647 @param DevicePath A pointer to a device path data structure.
648 @param MaxSize Max valid device path size. If big than this size,
651 @retval 0 An invalid device path.
652 @retval Others The size of a device path in bytes.
656 BmGetDevicePathSizeEx (
657 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
664 if (DevicePath
== NULL
) {
669 // Search for the end of the device path structure
672 while (!IsDevicePathEnd (DevicePath
)) {
673 NodeSize
= DevicePathNodeLength (DevicePath
);
679 if (Size
> MaxSize
) {
683 DevicePath
= NextDevicePathNode (DevicePath
);
686 Size
+= DevicePathNodeLength (DevicePath
);
687 if (Size
> MaxSize
) {
695 Returns the length of a Null-terminated Unicode string. If the length is
696 bigger than MaxStringLen, return length 0 to indicate that this is an
699 This function returns the number of Unicode characters in the Null-terminated
700 Unicode string specified by String.
702 If String is NULL, then ASSERT().
703 If String is not aligned on a 16-bit boundary, then ASSERT().
705 @param String A pointer to a Null-terminated Unicode string.
706 @param MaxStringLen Max string len in this string.
708 @retval 0 An invalid string.
709 @retval Others The length of String.
714 IN CONST CHAR16
*String
,
715 IN UINTN MaxStringLen
720 ASSERT (String
!= NULL
&& MaxStringLen
!= 0);
721 ASSERT (((UINTN
)String
& BIT0
) == 0);
723 for (Length
= 0; *String
!= L
'\0' && MaxStringLen
!= Length
; String
++, Length
+= 2) {
726 if ((*String
!= L
'\0') && (MaxStringLen
== Length
)) {
734 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####
735 variable (VendorGuid/Name)
737 @param Variable The variable data.
738 @param VariableSize The variable size.
740 @retval TRUE The variable data is correct.
741 @retval FALSE The variable data is corrupted.
751 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
752 UINTN DescriptionSize
;
754 if (VariableSize
<= sizeof (UINT16
) + sizeof (UINT32
)) {
759 // Skip the option attribute
761 Variable
+= sizeof (UINT32
);
764 // Get the option's device path size
766 FilePathSize
= ReadUnaligned16 ((UINT16
*)Variable
);
767 Variable
+= sizeof (UINT16
);
770 // Get the option's description string size
772 DescriptionSize
= BmStrSizeEx ((CHAR16
*)Variable
, VariableSize
- sizeof (UINT16
) - sizeof (UINT32
));
773 Variable
+= DescriptionSize
;
776 // Get the option's device path
778 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)Variable
;
781 // Validation boot option variable.
783 if ((FilePathSize
== 0) || (DescriptionSize
== 0)) {
787 if (sizeof (UINT32
) + sizeof (UINT16
) + DescriptionSize
+ FilePathSize
> VariableSize
) {
791 return (BOOLEAN
)(BmGetDevicePathSizeEx (DevicePath
, FilePathSize
) != 0);
795 Check whether the VariableName is a valid load option variable name
796 and return the load option type and option number.
798 @param VariableName The name of the load option variable.
799 @param OptionType Return the load option type.
800 @param OptionNumber Return the load option number.
802 @retval TRUE The variable name is valid; The load option type and
803 load option number is returned.
804 @retval FALSE The variable name is NOT valid.
808 EfiBootManagerIsValidLoadOptionVariableName (
809 IN CHAR16
*VariableName
,
810 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE
*OptionType OPTIONAL
,
811 OUT UINT16
*OptionNumber OPTIONAL
814 UINTN VariableNameLen
;
817 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType
;
818 UINT16 LocalOptionNumber
;
820 if (VariableName
== NULL
) {
824 VariableNameLen
= StrLen (VariableName
);
827 // Return FALSE when the variable name length is too small.
829 if (VariableNameLen
<= 4) {
834 // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery.
836 for (LocalOptionType
= 0; LocalOptionType
< ARRAY_SIZE (mBmLoadOptionName
); LocalOptionType
++) {
837 if ((VariableNameLen
- 4 == StrLen (mBmLoadOptionName
[LocalOptionType
])) &&
838 (StrnCmp (VariableName
, mBmLoadOptionName
[LocalOptionType
], VariableNameLen
- 4) == 0)
845 if (LocalOptionType
== ARRAY_SIZE (mBmLoadOptionName
)) {
850 // Return FALSE when the last four characters are not hex digits.
852 LocalOptionNumber
= 0;
853 for (Index
= VariableNameLen
- 4; Index
< VariableNameLen
; Index
++) {
854 Uint
= BmCharToUint (VariableName
[Index
]);
858 LocalOptionNumber
= (UINT16
)Uint
+ LocalOptionNumber
* 0x10;
862 if (Index
!= VariableNameLen
) {
866 if (OptionType
!= NULL
) {
867 *OptionType
= LocalOptionType
;
870 if (OptionNumber
!= NULL
) {
871 *OptionNumber
= LocalOptionNumber
;
878 Build the Boot#### or Driver#### option from the VariableName.
880 @param VariableName Variable name of the load option
881 @param VendorGuid Variable GUID of the load option
882 @param Option Return the load option.
884 @retval EFI_SUCCESS Get the option just been created
885 @retval EFI_NOT_FOUND Failed to get the new option
890 EfiBootManagerVariableToLoadOptionEx (
891 IN CHAR16
*VariableName
,
892 IN EFI_GUID
*VendorGuid
,
893 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
902 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
904 UINT32 OptionalDataSize
;
906 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
909 if ((VariableName
== NULL
) || (Option
== NULL
)) {
910 return EFI_INVALID_PARAMETER
;
913 if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName
, &OptionType
, &OptionNumber
)) {
914 return EFI_INVALID_PARAMETER
;
920 GetVariable2 (VariableName
, VendorGuid
, (VOID
**)&Variable
, &VariableSize
);
921 if (Variable
== NULL
) {
922 return EFI_NOT_FOUND
;
926 // Validate *#### variable data.
928 if (!BmValidateOption (Variable
, VariableSize
)) {
930 return EFI_INVALID_PARAMETER
;
934 // Get the option attribute
936 VariablePtr
= Variable
;
937 Attribute
= ReadUnaligned32 ((UINT32
*)VariablePtr
);
938 VariablePtr
+= sizeof (UINT32
);
941 // Get the option's device path size
943 FilePathSize
= ReadUnaligned16 ((UINT16
*)VariablePtr
);
944 VariablePtr
+= sizeof (UINT16
);
947 // Get the option's description string
949 Description
= (CHAR16
*)VariablePtr
;
952 // Get the option's description string size
954 VariablePtr
+= StrSize ((CHAR16
*)VariablePtr
);
957 // Get the option's device path
959 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*)VariablePtr
;
960 VariablePtr
+= FilePathSize
;
962 OptionalDataSize
= (UINT32
)(VariableSize
- ((UINTN
)VariablePtr
- (UINTN
)Variable
));
963 if (OptionalDataSize
== 0) {
966 OptionalData
= VariablePtr
;
969 Status
= EfiBootManagerInitializeLoadOption (
979 ASSERT_EFI_ERROR (Status
);
981 CopyGuid (&Option
->VendorGuid
, VendorGuid
);
988 Build the Boot#### or Driver#### option from the VariableName.
990 @param VariableName EFI Variable name indicate if it is Boot#### or Driver####
991 @param Option Return the Boot#### or Driver#### option.
993 @retval EFI_SUCCESS Get the option just been created
994 @retval EFI_NOT_FOUND Failed to get the new option
998 EfiBootManagerVariableToLoadOption (
999 IN CHAR16
*VariableName
,
1000 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
1003 return EfiBootManagerVariableToLoadOptionEx (VariableName
, &gEfiGlobalVariableGuid
, Option
);
1007 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
1009 EFI_BOOT_MANAGER_LOAD_OPTION
*Options
;
1011 } BM_COLLECT_LOAD_OPTIONS_PARAM
;
1014 Visitor function to collect the Platform Recovery load options or OS Recovery
1015 load options from NV storage.
1017 @param Name Variable name.
1018 @param Guid Variable GUID.
1019 @param Context The same context passed to BmForEachVariable.
1022 BmCollectLoadOptions (
1029 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
1030 UINT16 OptionNumber
;
1031 EFI_BOOT_MANAGER_LOAD_OPTION Option
;
1033 BM_COLLECT_LOAD_OPTIONS_PARAM
*Param
;
1035 Param
= (BM_COLLECT_LOAD_OPTIONS_PARAM
*)Context
;
1037 if (CompareGuid (Guid
, Param
->Guid
) && (
1038 (Param
->OptionType
== LoadOptionTypePlatformRecovery
) &&
1039 EfiBootManagerIsValidLoadOptionVariableName (Name
, &OptionType
, &OptionNumber
) &&
1040 (OptionType
== LoadOptionTypePlatformRecovery
)
1043 Status
= EfiBootManagerVariableToLoadOptionEx (Name
, Guid
, &Option
);
1044 if (!EFI_ERROR (Status
)) {
1045 for (Index
= 0; Index
< Param
->OptionCount
; Index
++) {
1046 if (Param
->Options
[Index
].OptionNumber
> Option
.OptionNumber
) {
1051 Param
->Options
= ReallocatePool (
1052 Param
->OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
1053 (Param
->OptionCount
+ 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
1056 ASSERT (Param
->Options
!= NULL
);
1057 CopyMem (&Param
->Options
[Index
+ 1], &Param
->Options
[Index
], (Param
->OptionCount
- Index
) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
1058 CopyMem (&Param
->Options
[Index
], &Option
, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
1059 Param
->OptionCount
++;
1065 Returns an array of load options based on the EFI variable
1066 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
1067 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
1069 @param LoadOptionCount Returns number of entries in the array.
1070 @param LoadOptionType The type of the load option.
1072 @retval NULL No load options exist.
1073 @retval !NULL Array of load option entries.
1076 EFI_BOOT_MANAGER_LOAD_OPTION
*
1078 EfiBootManagerGetLoadOptions (
1079 OUT UINTN
*OptionCount
,
1080 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
1084 UINT16
*OptionOrder
;
1085 UINTN OptionOrderSize
;
1088 EFI_BOOT_MANAGER_LOAD_OPTION
*Options
;
1089 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
1090 UINT16 OptionNumber
;
1091 BM_COLLECT_LOAD_OPTIONS_PARAM Param
;
1096 if ((LoadOptionType
== LoadOptionTypeDriver
) || (LoadOptionType
== LoadOptionTypeSysPrep
) || (LoadOptionType
== LoadOptionTypeBoot
)) {
1098 // Read the BootOrder, or DriverOrder variable.
1100 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**)&OptionOrder
, &OptionOrderSize
);
1101 if (OptionOrder
== NULL
) {
1105 *OptionCount
= OptionOrderSize
/ sizeof (UINT16
);
1107 Options
= AllocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
1108 ASSERT (Options
!= NULL
);
1111 for (Index
= 0; Index
< *OptionCount
; Index
++) {
1112 OptionNumber
= OptionOrder
[Index
];
1113 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[LoadOptionType
], OptionNumber
);
1115 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &Options
[OptionIndex
]);
1116 if (EFI_ERROR (Status
)) {
1117 DEBUG ((DEBUG_INFO
, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName
));
1118 EfiBootManagerDeleteLoadOptionVariable (OptionNumber
, LoadOptionType
);
1120 ASSERT (Options
[OptionIndex
].OptionNumber
== OptionNumber
);
1125 if (OptionOrder
!= NULL
) {
1126 FreePool (OptionOrder
);
1129 if (OptionIndex
< *OptionCount
) {
1130 Options
= ReallocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), OptionIndex
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), Options
);
1131 ASSERT (Options
!= NULL
);
1132 *OptionCount
= OptionIndex
;
1134 } else if (LoadOptionType
== LoadOptionTypePlatformRecovery
) {
1135 Param
.OptionType
= LoadOptionTypePlatformRecovery
;
1136 Param
.Options
= NULL
;
1137 Param
.OptionCount
= 0;
1138 Param
.Guid
= &gEfiGlobalVariableGuid
;
1140 BmForEachVariable (BmCollectLoadOptions
, (VOID
*)&Param
);
1142 *OptionCount
= Param
.OptionCount
;
1143 Options
= Param
.Options
;
1150 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1152 @param LoadOption Pointer to boot option to Free.
1154 @return EFI_SUCCESS BootOption was freed
1155 @return EFI_NOT_FOUND BootOption == NULL
1160 EfiBootManagerFreeLoadOption (
1161 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1164 if (LoadOption
== NULL
) {
1165 return EFI_NOT_FOUND
;
1168 if (LoadOption
->Description
!= NULL
) {
1169 FreePool (LoadOption
->Description
);
1172 if (LoadOption
->FilePath
!= NULL
) {
1173 FreePool (LoadOption
->FilePath
);
1176 if (LoadOption
->OptionalData
!= NULL
) {
1177 FreePool (LoadOption
->OptionalData
);
1184 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1185 EfiBootManagerGetLoadOptions().
1187 @param Option Pointer to boot option array to free.
1188 @param OptionCount Number of array entries in BootOption
1190 @return EFI_SUCCESS BootOption was freed
1191 @return EFI_NOT_FOUND BootOption == NULL
1196 EfiBootManagerFreeLoadOptions (
1197 IN EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
1198 IN UINTN OptionCount
1203 if (Option
== NULL
) {
1204 return EFI_NOT_FOUND
;
1207 for (Index
= 0; Index
< OptionCount
; Index
++) {
1208 EfiBootManagerFreeLoadOption (&Option
[Index
]);
1217 Return whether the PE header of the load option is valid or not.
1219 @param[in] Type The load option type.
1220 It's used to check whether the load option is valid.
1221 When it's LoadOptionTypeMax, the routine only guarantees
1222 the load option is a valid PE image but doesn't guarantee
1223 the PE's subsystem type is valid.
1224 @param[in] FileBuffer The PE file buffer of the load option.
1225 @param[in] FileSize The size of the load option file.
1227 @retval TRUE The PE header of the load option is valid.
1228 @retval FALSE The PE header of the load option is not valid.
1231 BmIsLoadOptionPeHeaderValid (
1232 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type
,
1233 IN VOID
*FileBuffer
,
1237 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1238 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHeader
;
1239 EFI_IMAGE_OPTIONAL_HEADER32
*OptionalHeader
;
1242 if ((FileBuffer
== NULL
) || (FileSize
== 0)) {
1249 DosHeader
= (EFI_IMAGE_DOS_HEADER
*)FileBuffer
;
1250 if ((FileSize
>= sizeof (EFI_IMAGE_DOS_HEADER
)) &&
1251 (FileSize
> DosHeader
->e_lfanew
) && (DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
)
1255 // Read and check PE signature
1257 PeHeader
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINT8
*)FileBuffer
+ DosHeader
->e_lfanew
);
1258 if ((FileSize
>= DosHeader
->e_lfanew
+ sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
)) &&
1259 (PeHeader
->Pe32
.Signature
== EFI_IMAGE_NT_SIGNATURE
)
1263 // Check PE32 or PE32+ magic, and machine type
1265 OptionalHeader
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHeader
->Pe32
.OptionalHeader
;
1266 if ((OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) ||
1267 (OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
))
1270 // Check the Subsystem:
1271 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1272 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1274 Subsystem
= OptionalHeader
->Subsystem
;
1275 if ((Type
== LoadOptionTypeMax
) ||
1276 ((Type
== LoadOptionTypeDriver
) && (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
)) ||
1277 ((Type
== LoadOptionTypeDriver
) && (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
)) ||
1278 ((Type
== LoadOptionTypeSysPrep
) && (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)) ||
1279 ((Type
== LoadOptionTypeBoot
) && (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)) ||
1280 ((Type
== LoadOptionTypePlatformRecovery
) && (Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
))
1293 Return the next matched load option buffer.
1294 The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
1295 load option is read.
1297 @param Type The load option type.
1298 It's used to check whether the load option is valid.
1299 When it's LoadOptionTypeMax, the routine only guarantees
1300 the load option is a valid PE image but doesn't guarantee
1301 the PE's subsystem type is valid.
1302 @param FilePath The device path pointing to a load option.
1303 It could be a short-form device path.
1304 @param FullPath Return the next full device path of the load option after
1305 short-form device path expanding.
1306 Caller is responsible to free it.
1307 NULL to return the first matched full device path.
1308 @param FileSize Return the load option size.
1310 @return The load option buffer. Caller is responsible to free the memory.
1313 BmGetNextLoadOptionBuffer (
1314 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type
,
1315 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1316 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1321 EFI_DEVICE_PATH_PROTOCOL
*PreFullPath
;
1322 EFI_DEVICE_PATH_PROTOCOL
*CurFullPath
;
1323 UINTN LocalFileSize
;
1324 UINT32 AuthenticationStatus
;
1325 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1329 CurFullPath
= *FullPath
;
1331 PreFullPath
= CurFullPath
;
1332 CurFullPath
= BmGetNextLoadOptionDevicePath (FilePath
, CurFullPath
);
1334 // Only free the full path created *inside* this routine
1336 if ((PreFullPath
!= NULL
) && (PreFullPath
!= *FullPath
)) {
1337 FreePool (PreFullPath
);
1340 if (CurFullPath
== NULL
) {
1344 FileBuffer
= GetFileBufferByFilePath (TRUE
, CurFullPath
, &LocalFileSize
, &AuthenticationStatus
);
1345 if ((FileBuffer
!= NULL
) && !BmIsLoadOptionPeHeaderValid (Type
, FileBuffer
, LocalFileSize
)) {
1347 // Free the RAM disk file system if the load option is invalid.
1349 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1350 if (RamDiskDevicePath
!= NULL
) {
1351 BmDestroyRamDisk (RamDiskDevicePath
);
1352 FreePool (RamDiskDevicePath
);
1356 // Free the invalid load option buffer.
1358 FreePool (FileBuffer
);
1361 } while (FileBuffer
== NULL
);
1363 if (FileBuffer
== NULL
) {
1368 DEBUG ((DEBUG_INFO
, "[Bds] Expand "));
1369 BmPrintDp (FilePath
);
1370 DEBUG ((DEBUG_INFO
, " -> "));
1371 BmPrintDp (CurFullPath
);
1372 DEBUG ((DEBUG_INFO
, "\n"));
1374 *FullPath
= CurFullPath
;
1375 *FileSize
= LocalFileSize
;
1380 Process (load and execute) the load option.
1382 @param LoadOption Pointer to the load option.
1384 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1385 or the load option file path doesn't point to a valid file.
1386 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1387 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1391 EfiBootManagerProcessLoadOption (
1392 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1396 EFI_DEVICE_PATH_PROTOCOL
*PreFullPath
;
1397 EFI_DEVICE_PATH_PROTOCOL
*CurFullPath
;
1398 EFI_HANDLE ImageHandle
;
1399 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1403 if ((UINT32
)LoadOption
->OptionType
>= LoadOptionTypeMax
) {
1404 return EFI_INVALID_PARAMETER
;
1407 if (LoadOption
->OptionType
== LoadOptionTypeBoot
) {
1408 return EFI_UNSUPPORTED
;
1412 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1413 // the boot manager will not automatically load the option.
1415 if ((LoadOption
->Attributes
& LOAD_OPTION_ACTIVE
) == 0) {
1420 // Load and start the load option.
1423 DEBUG_INFO
| DEBUG_LOAD
,
1424 "Process %s%04x (%s) ...\n",
1425 mBmLoadOptionName
[LoadOption
->OptionType
],
1426 LoadOption
->OptionNumber
,
1427 LoadOption
->Description
1431 EfiBootManagerConnectDevicePath (LoadOption
->FilePath
, NULL
);
1434 // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
1437 Status
= EFI_INVALID_PARAMETER
;
1438 PreFullPath
= CurFullPath
;
1439 FileBuffer
= BmGetNextLoadOptionBuffer (LoadOption
->OptionType
, LoadOption
->FilePath
, &CurFullPath
, &FileSize
);
1440 if (PreFullPath
!= NULL
) {
1441 FreePool (PreFullPath
);
1444 if (FileBuffer
== NULL
) {
1448 Status
= gBS
->LoadImage (
1456 FreePool (FileBuffer
);
1458 if (EFI_ERROR (Status
)) {
1460 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1461 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1462 // If the caller doesn't have the option to defer the execution of an image, we should
1463 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1465 if (Status
== EFI_SECURITY_VIOLATION
) {
1466 gBS
->UnloadImage (ImageHandle
);
1469 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&ImageInfo
);
1470 ASSERT_EFI_ERROR (Status
);
1472 ImageInfo
->LoadOptionsSize
= LoadOption
->OptionalDataSize
;
1473 ImageInfo
->LoadOptions
= LoadOption
->OptionalData
;
1475 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1477 gBS
->SetWatchdogTimer (5 * 60, 0, 0, NULL
);
1479 LoadOption
->Status
= gBS
->StartImage (ImageHandle
, &LoadOption
->ExitDataSize
, &LoadOption
->ExitData
);
1481 DEBUG_INFO
| DEBUG_LOAD
,
1482 "%s%04x Return Status = %r\n",
1483 mBmLoadOptionName
[LoadOption
->OptionType
],
1484 LoadOption
->OptionNumber
,
1489 // Clear the Watchdog Timer after the image returns
1491 gBS
->SetWatchdogTimer (0, 0, 0, NULL
);
1493 if ((LoadOption
->OptionType
!= LoadOptionTypePlatformRecovery
) || (LoadOption
->Status
== EFI_SUCCESS
)) {
1499 if (CurFullPath
!= NULL
) {
1500 FreePool (CurFullPath
);