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
);
103 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
106 if (LoadOptionType
== LoadOptionTypeBoot
) {
107 GetEfiGlobalVariable2 (L
"BootNext", (VOID
**) &BootNext
, NULL
);
110 for (OptionNumber
= 0;
111 OptionNumber
< OptionOrderSize
/ sizeof (UINT16
)
112 + ((BootNext
!= NULL
) ? 1 : 0);
116 // Search in OptionOrder whether the OptionNumber exists
118 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
119 if (OptionNumber
== OptionOrder
[Index
]) {
125 // We didn't find it in the ****Order array and it doesn't equal to BootNext
126 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
128 if ((Index
== OptionOrderSize
/ sizeof (UINT16
)) &&
129 ((BootNext
== NULL
) || (OptionNumber
!= *BootNext
))
134 if (OptionOrder
!= NULL
) {
135 FreePool (OptionOrder
);
138 if (BootNext
!= NULL
) {
143 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
144 // OptionNumber equals to 0x10000 which is not valid.
146 ASSERT (OptionNumber
<= 0x10000);
147 if (OptionNumber
== 0x10000) {
148 return EFI_OUT_OF_RESOURCES
;
150 *FreeOptionNumber
= (UINT16
) OptionNumber
;
156 Create the Boot####, Driver####, SysPrep####, variable from the load option.
158 @param LoadOption Pointer to the load option.
160 @retval EFI_SUCCESS The variable was created.
161 @retval Others Error status returned by RT->SetVariable.
165 EfiBootManagerLoadOptionToVariable (
166 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Option
172 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
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
;
236 return gRT
->SetVariable (
238 &gEfiGlobalVariableGuid
,
246 Update order variable .
248 @param OptionOrderName Order variable name which need to be updated.
249 @param OptionNumber Option number for the new option.
250 @param Position Position of the new load option to put in the ****Order variable.
252 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
253 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
254 @retval EFI_STATUS Return the status of gRT->SetVariable ().
258 BmAddOptionNumberToOrderVariable (
259 IN CHAR16
*OptionOrderName
,
260 IN UINT16 OptionNumber
,
267 UINT16
*NewOptionOrder
;
268 UINTN OptionOrderSize
;
270 // Update the option order variable
272 GetEfiGlobalVariable2 (OptionOrderName
, (VOID
**) &OptionOrder
, &OptionOrderSize
);
273 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
275 Status
= EFI_SUCCESS
;
276 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
277 if (OptionOrder
[Index
] == OptionNumber
) {
278 Status
= EFI_ALREADY_STARTED
;
283 if (!EFI_ERROR (Status
)) {
284 Position
= MIN (Position
, OptionOrderSize
/ sizeof (UINT16
));
286 NewOptionOrder
= AllocatePool (OptionOrderSize
+ sizeof (UINT16
));
287 ASSERT (NewOptionOrder
!= NULL
);
288 if (OptionOrderSize
!= 0) {
289 CopyMem (NewOptionOrder
, OptionOrder
, Position
* sizeof (UINT16
));
290 CopyMem (&NewOptionOrder
[Position
+ 1], &OptionOrder
[Position
], OptionOrderSize
- Position
* sizeof (UINT16
));
292 NewOptionOrder
[Position
] = OptionNumber
;
294 Status
= gRT
->SetVariable (
296 &gEfiGlobalVariableGuid
,
297 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
298 OptionOrderSize
+ sizeof (UINT16
),
301 FreePool (NewOptionOrder
);
304 if (OptionOrder
!= NULL
) {
305 FreePool (OptionOrder
);
312 This function will register the new Boot####, Driver#### or SysPrep#### option.
313 After the *#### is updated, the *Order will also be updated.
315 @param Option Pointer to load option to add.
316 @param Position Position of the new load option to put in the ****Order variable.
318 @retval EFI_SUCCESS The *#### have been successfully registered.
319 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
320 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
321 Note: this API only adds new load option, no replacement support.
322 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
323 option number specified in the Option is LoadOptionNumberUnassigned.
324 @retval EFI_STATUS Return the status of gRT->SetVariable ().
329 EfiBootManagerAddLoadOptionVariable (
330 IN EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
337 if (Option
== NULL
) {
338 return EFI_INVALID_PARAMETER
;
341 if (Option
->OptionType
!= LoadOptionTypeDriver
&&
342 Option
->OptionType
!= LoadOptionTypeSysPrep
&&
343 Option
->OptionType
!= LoadOptionTypeBoot
345 return EFI_INVALID_PARAMETER
;
349 // Get the free option number if the option number is unassigned
351 if (Option
->OptionNumber
== LoadOptionNumberUnassigned
) {
352 Status
= BmGetFreeOptionNumber (Option
->OptionType
, &OptionNumber
);
353 if (EFI_ERROR (Status
)) {
356 Option
->OptionNumber
= OptionNumber
;
359 if (Option
->OptionNumber
>= LoadOptionNumberMax
) {
360 return EFI_INVALID_PARAMETER
;
363 Status
= BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName
[Option
->OptionType
], (UINT16
) Option
->OptionNumber
, Position
);
364 if (!EFI_ERROR (Status
)) {
366 // Save the Boot#### or Driver#### variable
368 Status
= EfiBootManagerLoadOptionToVariable (Option
);
369 if (EFI_ERROR (Status
)) {
371 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
373 EfiBootManagerDeleteLoadOptionVariable (Option
->OptionNumber
, Option
->OptionType
);
381 Sort the load option. The DriverOrder or BootOrder will be re-created to
382 reflect the new order.
384 @param OptionType Load option type
385 @param CompareFunction The comparator
389 EfiBootManagerSortLoadOptionVariable (
390 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
391 SORT_COMPARE CompareFunction
395 EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
;
396 UINTN LoadOptionCount
;
400 LoadOption
= EfiBootManagerGetLoadOptions (&LoadOptionCount
, OptionType
);
403 // Insertion sort algorithm
408 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
),
413 // Create new ****Order variable
415 OptionOrder
= AllocatePool (LoadOptionCount
* sizeof (UINT16
));
416 ASSERT (OptionOrder
!= NULL
);
417 for (Index
= 0; Index
< LoadOptionCount
; Index
++) {
418 OptionOrder
[Index
] = (UINT16
) LoadOption
[Index
].OptionNumber
;
421 Status
= gRT
->SetVariable (
422 mBmLoadOptionOrderName
[OptionType
],
423 &gEfiGlobalVariableGuid
,
424 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
425 LoadOptionCount
* sizeof (UINT16
),
429 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
431 ASSERT_EFI_ERROR (Status
);
433 FreePool (OptionOrder
);
434 EfiBootManagerFreeLoadOptions (LoadOption
, LoadOptionCount
);
438 Initialize a load option.
440 @param Option Pointer to the load option to be initialized.
441 @param OptionNumber Option number of the load option.
442 @param OptionType Type of the load option.
443 @param Attributes Attributes of the load option.
444 @param Description Description of the load option.
445 @param FilePath Device path of the load option.
446 @param OptionalData Optional data of the load option.
447 @param OptionalDataSize Size of the optional data of the load option.
449 @retval EFI_SUCCESS The load option was initialized successfully.
450 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
454 EfiBootManagerInitializeLoadOption (
455 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
456 IN UINTN OptionNumber
,
457 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
,
458 IN UINT32 Attributes
,
459 IN CHAR16
*Description
,
460 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
461 IN UINT8
*OptionalData
, OPTIONAL
462 IN UINT32 OptionalDataSize
465 if ((Option
== NULL
) || (Description
== NULL
) || (FilePath
== NULL
)) {
466 return EFI_INVALID_PARAMETER
;
469 if (((OptionalData
!= NULL
) && (OptionalDataSize
== 0)) ||
470 ((OptionalData
== NULL
) && (OptionalDataSize
!= 0))) {
471 return EFI_INVALID_PARAMETER
;
474 if ((UINT32
) OptionType
>= LoadOptionTypeMax
) {
475 return EFI_INVALID_PARAMETER
;
478 ZeroMem (Option
, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
479 Option
->OptionNumber
= OptionNumber
;
480 Option
->OptionType
= OptionType
;
481 Option
->Attributes
= Attributes
;
482 Option
->Description
= AllocateCopyPool (StrSize (Description
), Description
);
483 Option
->FilePath
= DuplicateDevicePath (FilePath
);
484 if (OptionalData
!= NULL
) {
485 Option
->OptionalData
= AllocateCopyPool (OptionalDataSize
, OptionalData
);
486 Option
->OptionalDataSize
= OptionalDataSize
;
494 Return the index of the load option in the load option array.
496 The function consider two load options are equal when the
497 OptionType, Attributes, Description, FilePath and OptionalData are equal.
499 @param Key Pointer to the load option to be found.
500 @param Array Pointer to the array of load options to be found.
501 @param Count Number of entries in the Array.
503 @retval -1 Key wasn't found in the Array.
504 @retval 0 ~ Count-1 The index of the Key in the Array.
508 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
509 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
515 for (Index
= 0; Index
< Count
; Index
++) {
516 if ((Key
->OptionType
== Array
[Index
].OptionType
) &&
517 (Key
->Attributes
== Array
[Index
].Attributes
) &&
518 (StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
519 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
520 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
521 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0)) {
530 Delete the load option.
532 @param OptionNumber Indicate the option number of load option
533 @param OptionType Indicate the type of load option
535 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
536 @retval EFI_NOT_FOUND The load option cannot be found
537 @retval EFI_SUCCESS The load option was deleted
538 @retval others Status of RT->SetVariable()
542 EfiBootManagerDeleteLoadOptionVariable (
543 IN UINTN OptionNumber
,
544 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
548 UINTN OptionOrderSize
;
552 if (((UINT32
) OptionType
>= LoadOptionTypeMax
) || (OptionNumber
>= LoadOptionNumberMax
)) {
553 return EFI_INVALID_PARAMETER
;
556 Status
= EFI_NOT_FOUND
;
558 if (OptionType
== LoadOptionTypeDriver
|| OptionType
== LoadOptionTypeSysPrep
|| OptionType
== LoadOptionTypeBoot
) {
560 // If the associated *Order exists, just remove the reference in *Order.
562 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[OptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
563 ASSERT ((OptionOrder
!= NULL
&& OptionOrderSize
!= 0) || (OptionOrder
== NULL
&& OptionOrderSize
== 0));
565 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
566 if (OptionOrder
[Index
] == OptionNumber
) {
567 OptionOrderSize
-= sizeof (UINT16
);
568 CopyMem (&OptionOrder
[Index
], &OptionOrder
[Index
+ 1], OptionOrderSize
- Index
* sizeof (UINT16
));
569 Status
= gRT
->SetVariable (
570 mBmLoadOptionOrderName
[OptionType
],
571 &gEfiGlobalVariableGuid
,
572 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
579 if (OptionOrder
!= NULL
) {
580 FreePool (OptionOrder
);
588 Convert a single character to number.
589 It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
591 @param Char The input char which need to convert to int.
598 if ((Char
>= L
'0') && (Char
<= L
'9')) {
599 return (UINTN
) (Char
- L
'0');
602 if ((Char
>= L
'A') && (Char
<= L
'F')) {
603 return (UINTN
) (Char
- L
'A' + 0xA);
611 Returns the size of a device path in bytes.
613 This function returns the size, in bytes, of the device path data structure
614 specified by DevicePath including the end of device path node. If DevicePath
615 is NULL, then 0 is returned. If the length of the device path is bigger than
616 MaxSize, also return 0 to indicate this is an invalidate device path.
618 @param DevicePath A pointer to a device path data structure.
619 @param MaxSize Max valid device path size. If big than this size,
622 @retval 0 An invalid device path.
623 @retval Others The size of a device path in bytes.
627 BmGetDevicePathSizeEx (
628 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
635 if (DevicePath
== NULL
) {
640 // Search for the end of the device path structure
643 while (!IsDevicePathEnd (DevicePath
)) {
644 NodeSize
= DevicePathNodeLength (DevicePath
);
649 if (Size
> MaxSize
) {
652 DevicePath
= NextDevicePathNode (DevicePath
);
654 Size
+= DevicePathNodeLength (DevicePath
);
655 if (Size
> MaxSize
) {
663 Returns the length of a Null-terminated Unicode string. If the length is
664 bigger than MaxStringLen, return length 0 to indicate that this is an
667 This function returns the number of Unicode characters in the Null-terminated
668 Unicode string specified by String.
670 If String is NULL, then ASSERT().
671 If String is not aligned on a 16-bit boundary, then ASSERT().
673 @param String A pointer to a Null-terminated Unicode string.
674 @param MaxStringLen Max string len in this string.
676 @retval 0 An invalid string.
677 @retval Others The length of String.
682 IN CONST CHAR16
*String
,
683 IN UINTN MaxStringLen
688 ASSERT (String
!= NULL
&& MaxStringLen
!= 0);
689 ASSERT (((UINTN
) String
& BIT0
) == 0);
691 for (Length
= 0; *String
!= L
'\0' && MaxStringLen
!= Length
; String
++, Length
+=2);
693 if (*String
!= L
'\0' && MaxStringLen
== Length
) {
701 Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)
703 @param Variable The variable data.
704 @param VariableSize The variable size.
706 @retval TRUE The variable data is correct.
707 @retval FALSE The variable data is corrupted.
717 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
718 UINTN DescriptionSize
;
720 if (VariableSize
<= sizeof (UINT16
) + sizeof (UINT32
)) {
725 // Skip the option attribute
727 Variable
+= sizeof (UINT32
);
730 // Get the option's device path size
732 FilePathSize
= ReadUnaligned16 ((UINT16
*) Variable
);
733 Variable
+= sizeof (UINT16
);
736 // Get the option's description string size
738 DescriptionSize
= BmStrSizeEx ((CHAR16
*) Variable
, VariableSize
- sizeof (UINT16
) - sizeof (UINT32
));
739 Variable
+= DescriptionSize
;
742 // Get the option's device path
744 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Variable
;
747 // Validation boot option variable.
749 if ((FilePathSize
== 0) || (DescriptionSize
== 0)) {
753 if (sizeof (UINT32
) + sizeof (UINT16
) + DescriptionSize
+ FilePathSize
> VariableSize
) {
757 return (BOOLEAN
) (BmGetDevicePathSizeEx (DevicePath
, FilePathSize
) != 0);
761 Check whether the VariableName is a valid load option variable name
762 and return the load option type and option number.
764 @param VariableName The name of the load option variable.
765 @param OptionType Return the load option type.
766 @param OptionNumber Return the load option number.
768 @retval TRUE The variable name is valid; The load option type and
769 load option number is returned.
770 @retval FALSE The variable name is NOT valid.
773 BmIsValidLoadOptionVariableName (
774 IN CHAR16
*VariableName
,
775 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE
*OptionType
,
776 OUT UINT16
*OptionNumber
779 UINTN VariableNameLen
;
783 VariableNameLen
= StrLen (VariableName
);
785 if (VariableNameLen
<= 4) {
789 for (Index
= 0; Index
< sizeof (mBmLoadOptionName
) / sizeof (mBmLoadOptionName
[0]); Index
++) {
790 if ((VariableNameLen
- 4 == StrLen (mBmLoadOptionName
[Index
])) &&
791 (StrnCmp (VariableName
, mBmLoadOptionName
[Index
], VariableNameLen
- 4) == 0)
797 if (Index
== sizeof (mBmLoadOptionName
) / sizeof (mBmLoadOptionName
[0])) {
801 *OptionType
= (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE
) Index
;
803 for (Index
= VariableNameLen
- 4; Index
< VariableNameLen
; Index
++) {
804 Uint
= BmCharToUint (VariableName
[Index
]);
808 *OptionNumber
= (UINT16
) Uint
+ *OptionNumber
* 0x10;
812 return (BOOLEAN
) (Index
== VariableNameLen
);
816 Build the Boot#### or Driver#### option from the VariableName.
818 @param VariableName Variable name of the load option
819 @param VendorGuid Variable GUID of the load option
820 @param Option Return the load option.
822 @retval EFI_SUCCESS Get the option just been created
823 @retval EFI_NOT_FOUND Failed to get the new option
828 EfiBootManagerVariableToLoadOptionEx (
829 IN CHAR16
*VariableName
,
830 IN EFI_GUID
*VendorGuid
,
831 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
840 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
842 UINT32 OptionalDataSize
;
844 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
;
847 if ((VariableName
== NULL
) || (Option
== NULL
)) {
848 return EFI_INVALID_PARAMETER
;
851 if (!BmIsValidLoadOptionVariableName (VariableName
, &OptionType
, &OptionNumber
)) {
852 return EFI_INVALID_PARAMETER
;
858 GetVariable2 (VariableName
, VendorGuid
, (VOID
**) &Variable
, &VariableSize
);
859 if (Variable
== NULL
) {
860 return EFI_NOT_FOUND
;
864 // Validate *#### variable data.
866 if (!BmValidateOption(Variable
, VariableSize
)) {
868 return EFI_INVALID_PARAMETER
;
872 // Get the option attribute
874 VariablePtr
= Variable
;
875 Attribute
= ReadUnaligned32 ((UINT32
*) VariablePtr
);
876 VariablePtr
+= sizeof (UINT32
);
879 // Get the option's device path size
881 FilePathSize
= ReadUnaligned16 ((UINT16
*) VariablePtr
);
882 VariablePtr
+= sizeof (UINT16
);
885 // Get the option's description string
887 Description
= (CHAR16
*) VariablePtr
;
890 // Get the option's description string size
892 VariablePtr
+= StrSize ((CHAR16
*) VariablePtr
);
895 // Get the option's device path
897 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) VariablePtr
;
898 VariablePtr
+= FilePathSize
;
900 OptionalDataSize
= (UINT32
) (VariableSize
- (UINTN
) (VariablePtr
- Variable
));
901 if (OptionalDataSize
== 0) {
904 OptionalData
= VariablePtr
;
907 Status
= EfiBootManagerInitializeLoadOption (
917 ASSERT_EFI_ERROR (Status
);
919 CopyGuid (&Option
->VendorGuid
, VendorGuid
);
926 Build the Boot#### or Driver#### option from the VariableName.
928 @param VariableName EFI Variable name indicate if it is Boot#### or Driver####
929 @param Option Return the Boot#### or Driver#### option.
931 @retval EFI_SUCCESS Get the option just been created
932 @retval EFI_NOT_FOUND Failed to get the new option
936 EfiBootManagerVariableToLoadOption (
937 IN CHAR16
*VariableName
,
938 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*Option
941 return EfiBootManagerVariableToLoadOptionEx (VariableName
, &gEfiGlobalVariableGuid
, Option
);
945 Returns an array of load options based on the EFI variable
946 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
947 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
949 @param LoadOptionCount Returns number of entries in the array.
950 @param LoadOptionType The type of the load option.
952 @retval NULL No load options exist.
953 @retval !NULL Array of load option entries.
956 EFI_BOOT_MANAGER_LOAD_OPTION
*
958 EfiBootManagerGetLoadOptions (
959 OUT UINTN
*OptionCount
,
960 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
965 UINTN OptionOrderSize
;
968 EFI_BOOT_MANAGER_LOAD_OPTION
*Options
;
969 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
974 if (LoadOptionType
== LoadOptionTypeDriver
|| LoadOptionType
== LoadOptionTypeSysPrep
|| LoadOptionType
== LoadOptionTypeBoot
) {
976 // Read the BootOrder, or DriverOrder variable.
978 GetEfiGlobalVariable2 (mBmLoadOptionOrderName
[LoadOptionType
], (VOID
**) &OptionOrder
, &OptionOrderSize
);
979 if (OptionOrder
== NULL
) {
983 *OptionCount
= OptionOrderSize
/ sizeof (UINT16
);
985 Options
= AllocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
));
986 ASSERT (Options
!= NULL
);
989 for (Index
= 0; Index
< *OptionCount
; Index
++) {
990 OptionNumber
= OptionOrder
[Index
];
991 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"%s%04x", mBmLoadOptionName
[LoadOptionType
], OptionNumber
);
993 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &Options
[OptionIndex
]);
994 if (EFI_ERROR (Status
)) {
995 DEBUG ((EFI_D_INFO
, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName
));
996 EfiBootManagerDeleteLoadOptionVariable (OptionNumber
, LoadOptionType
);
998 ASSERT (Options
[OptionIndex
].OptionNumber
== OptionNumber
);
1003 if (OptionOrder
!= NULL
) {
1004 FreePool (OptionOrder
);
1007 if (OptionIndex
< *OptionCount
) {
1008 Options
= ReallocatePool (*OptionCount
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), OptionIndex
* sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
), Options
);
1009 ASSERT (Options
!= NULL
);
1010 *OptionCount
= OptionIndex
;
1021 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1023 @param LoadOption Pointer to boot option to Free.
1025 @return EFI_SUCCESS BootOption was freed
1026 @return EFI_NOT_FOUND BootOption == NULL
1031 EfiBootManagerFreeLoadOption (
1032 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1035 if (LoadOption
== NULL
) {
1036 return EFI_NOT_FOUND
;
1039 if (LoadOption
->Description
!= NULL
) {
1040 FreePool (LoadOption
->Description
);
1042 if (LoadOption
->FilePath
!= NULL
) {
1043 FreePool (LoadOption
->FilePath
);
1045 if (LoadOption
->OptionalData
!= NULL
) {
1046 FreePool (LoadOption
->OptionalData
);
1053 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1054 EfiBootManagerGetLoadOptions().
1056 @param Option Pointer to boot option array to free.
1057 @param OptionCount Number of array entries in BootOption
1059 @return EFI_SUCCESS BootOption was freed
1060 @return EFI_NOT_FOUND BootOption == NULL
1065 EfiBootManagerFreeLoadOptions (
1066 IN EFI_BOOT_MANAGER_LOAD_OPTION
*Option
,
1067 IN UINTN OptionCount
1072 if (Option
== NULL
) {
1073 return EFI_NOT_FOUND
;
1076 for (Index
= 0;Index
< OptionCount
; Index
++) {
1077 EfiBootManagerFreeLoadOption (&Option
[Index
]);
1086 Return whether the PE header of the load option is valid or not.
1088 @param[in] Type The load option type.
1089 @param[in] FileBuffer The PE file buffer of the load option.
1090 @param[in] FileSize The size of the load option file.
1092 @retval TRUE The PE header of the load option is valid.
1093 @retval FALSE The PE header of the load option is not valid.
1096 BmIsLoadOptionPeHeaderValid (
1097 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type
,
1098 IN VOID
*FileBuffer
,
1102 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1103 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHeader
;
1104 EFI_IMAGE_OPTIONAL_HEADER32
*OptionalHeader
;
1107 if (FileBuffer
== NULL
|| FileSize
== 0) {
1114 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) FileBuffer
;
1115 if (FileSize
>= sizeof (EFI_IMAGE_DOS_HEADER
) &&
1116 FileSize
> DosHeader
->e_lfanew
&& DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
1119 // Read and check PE signature
1121 PeHeader
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) FileBuffer
+ DosHeader
->e_lfanew
);
1122 if (FileSize
>= DosHeader
->e_lfanew
+ sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
) &&
1123 PeHeader
->Pe32
.Signature
== EFI_IMAGE_NT_SIGNATURE
1126 // Check PE32 or PE32+ magic, and machine type
1128 OptionalHeader
= (EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHeader
->Pe32
.OptionalHeader
;
1129 if ((OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
||
1130 OptionalHeader
->Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) &&
1131 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader
->Pe32
.FileHeader
.Machine
)
1134 // Check the Subsystem:
1135 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1136 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1138 Subsystem
= OptionalHeader
->Subsystem
;
1139 if ((Type
== LoadOptionTypeDriver
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
) ||
1140 (Type
== LoadOptionTypeDriver
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) ||
1141 (Type
== LoadOptionTypeSysPrep
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) ||
1142 (Type
== LoadOptionTypeBoot
&& Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)
1154 Process (load and execute) the load option.
1156 @param LoadOption Pointer to the load option.
1158 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1159 or the load option file path doesn't point to a valid file.
1160 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1161 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1165 EfiBootManagerProcessLoadOption (
1166 IN EFI_BOOT_MANAGER_LOAD_OPTION
*LoadOption
1170 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1171 EFI_HANDLE ImageHandle
;
1172 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1176 if ((UINT32
) LoadOption
->OptionType
>= LoadOptionTypeMax
) {
1177 return EFI_INVALID_PARAMETER
;
1180 if (LoadOption
->OptionType
== LoadOptionTypeBoot
) {
1181 return EFI_UNSUPPORTED
;
1185 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1186 // the boot manager will not automatically load the option.
1188 if ((LoadOption
->Attributes
& LOAD_OPTION_ACTIVE
) == 0) {
1192 Status
= EFI_INVALID_PARAMETER
;
1195 // Load and start the load option.
1198 DEBUG_INFO
| DEBUG_LOAD
, "Process Load Option (%s%04x) ...\n",
1199 mBmLoadOptionName
[LoadOption
->OptionType
], LoadOption
->OptionNumber
1202 FileBuffer
= BmGetLoadOptionBuffer (LoadOption
->FilePath
, &FilePath
, &FileSize
);
1204 if (FileBuffer
!= NULL
&& CompareMem (LoadOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1205 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1206 BmPrintDp (LoadOption
->FilePath
);
1207 DEBUG ((EFI_D_INFO
, " -> "));
1208 BmPrintDp (FilePath
);
1209 DEBUG ((EFI_D_INFO
, "\n"));
1212 if (BmIsLoadOptionPeHeaderValid (LoadOption
->OptionType
, FileBuffer
, FileSize
)) {
1213 Status
= gBS
->LoadImage (
1222 if (FilePath
!= NULL
) {
1223 FreePool (FilePath
);
1225 if (FileBuffer
!= NULL
) {
1226 FreePool (FileBuffer
);
1229 if (!EFI_ERROR (Status
)) {
1230 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1231 ASSERT_EFI_ERROR (Status
);
1233 ImageInfo
->LoadOptionsSize
= LoadOption
->OptionalDataSize
;
1234 ImageInfo
->LoadOptions
= LoadOption
->OptionalData
;
1236 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1238 gBS
->SetWatchdogTimer (5 * 60, 0, 0, NULL
);
1240 LoadOption
->Status
= gBS
->StartImage (ImageHandle
, &LoadOption
->ExitDataSize
, &LoadOption
->ExitData
);
1242 DEBUG_INFO
| DEBUG_LOAD
, "Load Option (%s%04x) Return Status = %r\n",
1243 mBmLoadOptionName
[LoadOption
->OptionType
], LoadOption
->OptionNumber
, LoadOption
->Status
1247 // Clear the Watchdog Timer after the image returns
1249 gBS
->SetWatchdogTimer (0, 0, 0, NULL
);