/** @file\r
Load option library functions which relate with creating and processing load options.\r
\r
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
CHAR16 *mBmLoadOptionName[] = {\r
L"Driver",\r
L"SysPrep",\r
- L"Boot"\r
+ L"Boot",\r
+ L"PlatformRecovery"\r
};\r
\r
GLOBAL_REMOVE_IF_UNREFERENCED\r
CHAR16 *mBmLoadOptionOrderName[] = {\r
EFI_DRIVER_ORDER_VARIABLE_NAME,\r
EFI_SYS_PREP_ORDER_VARIABLE_NAME,\r
- EFI_BOOT_ORDER_VARIABLE_NAME\r
+ EFI_BOOT_ORDER_VARIABLE_NAME,\r
+ NULL // PlatformRecovery#### doesn't have associated *Order variable\r
};\r
\r
/**\r
OUT UINT16 *FreeOptionNumber\r
)\r
{\r
- \r
+\r
UINTN OptionNumber;\r
UINTN Index;\r
UINT16 *OptionOrder;\r
UINT16 *BootNext;\r
\r
ASSERT (FreeOptionNumber != NULL);\r
- ASSERT (LoadOptionType == LoadOptionTypeDriver || \r
+ ASSERT (LoadOptionType == LoadOptionTypeDriver ||\r
LoadOptionType == LoadOptionTypeBoot ||\r
LoadOptionType == LoadOptionTypeSysPrep);\r
\r
GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);\r
}\r
\r
- for (OptionNumber = 0; \r
+ for (OptionNumber = 0;\r
OptionNumber < OptionOrderSize / sizeof (UINT16)\r
- + ((BootNext != NULL) ? 1 : 0); \r
+ + ((BootNext != NULL) ? 1 : 0);\r
OptionNumber++\r
) {\r
//\r
}\r
\r
//\r
- // We didn't find it in the ****Order array and it doesn't equal to BootNext \r
+ // We didn't find it in the ****Order array and it doesn't equal to BootNext\r
// Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1\r
//\r
- if ((Index == OptionOrderSize / sizeof (UINT16)) && \r
+ if ((Index == OptionOrderSize / sizeof (UINT16)) &&\r
((BootNext == NULL) || (OptionNumber != *BootNext))\r
) {\r
break;\r
}\r
\r
/**\r
- Create the Boot####, Driver####, SysPrep####, variable from the load option.\r
- \r
+ Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable\r
+ from the load option.\r
+\r
@param LoadOption Pointer to the load option.\r
\r
@retval EFI_SUCCESS The variable was created.\r
IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
)\r
{\r
+ EFI_STATUS Status;\r
UINTN VariableSize;\r
UINT8 *Variable;\r
UINT8 *Ptr;\r
CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
CHAR16 *Description;\r
CHAR16 NullChar;\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
UINT32 VariableAttributes;\r
\r
if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||\r
EFI_DEVICE_PATH_PROTOCOL FilePathList[];\r
UINT8 OptionalData[];\r
TODO: FilePathList[] IS:\r
-A packed array of UEFI device paths. The first element of the \r
-array is a device path that describes the device and location of the \r
-Image for this load option. The FilePathList[0] is specific \r
-to the device type. Other device paths may optionally exist in the \r
-FilePathList, but their usage is OSV specific. Each element \r
-in the array is variable length, and ends at the device path end \r
+A packed array of UEFI device paths. The first element of the\r
+array is a device path that describes the device and location of the\r
+Image for this load option. The FilePathList[0] is specific\r
+to the device type. Other device paths may optionally exist in the\r
+FilePathList, but their usage is OSV specific. Each element\r
+in the array is variable length, and ends at the device path end\r
structure.\r
*/\r
VariableSize = sizeof (Option->Attributes)\r
UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);\r
\r
VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;\r
+ if (Option->OptionType == LoadOptionTypePlatformRecovery) {\r
+ //\r
+ // Lock the PlatformRecovery####\r
+ //\r
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
+ }\r
\r
- return gRT->SetVariable (\r
- OptionName,\r
- &gEfiGlobalVariableGuid,\r
- VariableAttributes,\r
- VariableSize,\r
- Variable\r
- );\r
+ Status = gRT->SetVariable (\r
+ OptionName,\r
+ &gEfiGlobalVariableGuid,\r
+ VariableAttributes,\r
+ VariableSize,\r
+ Variable\r
+ );\r
+ FreePool (Variable);\r
+\r
+ return Status;\r
}\r
\r
/**\r
This function will register the new Boot####, Driver#### or SysPrep#### option.\r
After the *#### is updated, the *Order will also be updated.\r
\r
- @param Option Pointer to load option to add.\r
+ @param Option Pointer to load option to add. If on input\r
+ Option->OptionNumber is LoadOptionNumberUnassigned,\r
+ then on output Option->OptionNumber is updated to\r
+ the number of the new Boot####,\r
+ Driver#### or SysPrep#### option.\r
@param Position Position of the new load option to put in the ****Order variable.\r
\r
@retval EFI_SUCCESS The *#### have been successfully registered.\r
Note: this API only adds new load option, no replacement support.\r
@retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the\r
option number specified in the Option is LoadOptionNumberUnassigned.\r
- @retval EFI_STATUS Return the status of gRT->SetVariable ().\r
+ @return Status codes of gRT->SetVariable ().\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
EfiBootManagerAddLoadOptionVariable (\r
- IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
- IN UINTN Position\r
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
+ IN UINTN Position\r
)\r
{\r
EFI_STATUS Status;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (Option->OptionType != LoadOptionTypeDriver && \r
+ if (Option->OptionType != LoadOptionTypeDriver &&\r
Option->OptionType != LoadOptionTypeSysPrep &&\r
Option->OptionType != LoadOptionTypeBoot\r
) {\r
}\r
\r
/**\r
- Sort the load option. The DriverOrder or BootOrder will be re-created to \r
+ Sort the load option. The DriverOrder or BootOrder will be re-created to\r
reflect the new order.\r
\r
@param OptionType Load option type\r
/**\r
Return the index of the load option in the load option array.\r
\r
- The function consider two load options are equal when the \r
+ The function consider two load options are equal when the\r
OptionType, Attributes, Description, FilePath and OptionalData are equal.\r
\r
@param Key Pointer to the load option to be found.\r
{\r
UINT16 *OptionOrder;\r
UINTN OptionOrderSize;\r
- EFI_STATUS Status;\r
UINTN Index;\r
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
\r
if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Status = EFI_NOT_FOUND;\r
-\r
if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {\r
//\r
- // If the associated *Order exists, just remove the reference in *Order.\r
+ // If the associated *Order exists, firstly remove the reference in *Order for\r
+ // Driver####, SysPrep#### and Boot####.\r
//\r
GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
if (OptionOrder[Index] == OptionNumber) {\r
OptionOrderSize -= sizeof (UINT16);\r
CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));\r
- Status = gRT->SetVariable (\r
- mBmLoadOptionOrderName[OptionType],\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- OptionOrderSize,\r
- OptionOrder\r
- );\r
+ gRT->SetVariable (\r
+ mBmLoadOptionOrderName[OptionType],\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ OptionOrderSize,\r
+ OptionOrder\r
+ );\r
break;\r
}\r
}\r
}\r
}\r
\r
- return Status;\r
+ //\r
+ // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.\r
+ //\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);\r
+ return gRT->SetVariable (\r
+ OptionName,\r
+ &gEfiGlobalVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
}\r
\r
/**\r
Returns the size of a device path in bytes.\r
\r
- This function returns the size, in bytes, of the device path data structure \r
- specified by DevicePath including the end of device path node. If DevicePath \r
+ This function returns the size, in bytes, of the device path data structure\r
+ specified by DevicePath including the end of device path node. If DevicePath\r
is NULL, then 0 is returned. If the length of the device path is bigger than\r
MaxSize, also return 0 to indicate this is an invalidate device path.\r
\r
@param DevicePath A pointer to a device path data structure.\r
- @param MaxSize Max valid device path size. If big than this size, \r
+ @param MaxSize Max valid device path size. If big than this size,\r
return error.\r
- \r
+\r
@retval 0 An invalid device path.\r
@retval Others The size of a device path in bytes.\r
\r
}\r
\r
/**\r
- Returns the length of a Null-terminated Unicode string. If the length is \r
- bigger than MaxStringLen, return length 0 to indicate that this is an \r
+ Returns the length of a Null-terminated Unicode string. If the length is\r
+ bigger than MaxStringLen, return length 0 to indicate that this is an\r
invalidate string.\r
\r
This function returns the number of Unicode characters in the Null-terminated\r
- Unicode string specified by String. \r
+ Unicode string specified by String.\r
\r
If String is NULL, then ASSERT().\r
If String is not aligned on a 16-bit boundary, then ASSERT().\r
}\r
\r
/**\r
- Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)\r
+ Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####\r
+ variable (VendorGuid/Name)\r
\r
@param Variable The variable data.\r
@param VariableSize The variable size.\r
@retval FALSE The variable data is corrupted.\r
\r
**/\r
-BOOLEAN \r
+BOOLEAN\r
BmValidateOption (\r
UINT8 *Variable,\r
UINTN VariableSize\r
@retval FALSE The variable name is NOT valid.\r
**/\r
BOOLEAN\r
-BmIsValidLoadOptionVariableName (\r
+EFIAPI\r
+EfiBootManagerIsValidLoadOptionVariableName (\r
IN CHAR16 *VariableName,\r
- OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,\r
- OUT UINT16 *OptionNumber\r
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType OPTIONAL,\r
+ OUT UINT16 *OptionNumber OPTIONAL\r
)\r
{\r
UINTN VariableNameLen;\r
UINTN Index;\r
UINTN Uint;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType;\r
+ UINT16 LocalOptionNumber;\r
+\r
+ if (VariableName == NULL) {\r
+ return FALSE;\r
+ }\r
\r
VariableNameLen = StrLen (VariableName);\r
\r
+ //\r
+ // Return FALSE when the variable name length is too small.\r
+ //\r
if (VariableNameLen <= 4) {\r
return FALSE;\r
}\r
\r
- for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {\r
- if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&\r
- (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)\r
+ //\r
+ // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery.\r
+ //\r
+ for (LocalOptionType = 0; LocalOptionType < ARRAY_SIZE (mBmLoadOptionName); LocalOptionType++) {\r
+ if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[LocalOptionType])) &&\r
+ (StrnCmp (VariableName, mBmLoadOptionName[LocalOptionType], VariableNameLen - 4) == 0)\r
) {\r
break;\r
}\r
}\r
-\r
- if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {\r
+ if (LocalOptionType == ARRAY_SIZE (mBmLoadOptionName)) {\r
return FALSE;\r
}\r
\r
- *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;\r
- *OptionNumber = 0;\r
+ //\r
+ // Return FALSE when the last four characters are not hex digits.\r
+ //\r
+ LocalOptionNumber = 0;\r
for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {\r
Uint = BmCharToUint (VariableName[Index]);\r
if (Uint == -1) {\r
break;\r
} else {\r
- *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
+ LocalOptionNumber = (UINT16) Uint + LocalOptionNumber * 0x10;\r
}\r
}\r
+ if (Index != VariableNameLen) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (OptionType != NULL) {\r
+ *OptionType = LocalOptionType;\r
+ }\r
+\r
+ if (OptionNumber != NULL) {\r
+ *OptionNumber = LocalOptionNumber;\r
+ }\r
\r
- return (BOOLEAN) (Index == VariableNameLen);\r
+ return TRUE;\r
}\r
\r
/**\r
EfiBootManagerVariableToLoadOptionEx (\r
IN CHAR16 *VariableName,\r
IN EFI_GUID *VendorGuid,\r
- IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option \r
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
)\r
{\r
EFI_STATUS Status;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
+ if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;\r
VariablePtr += FilePathSize;\r
\r
- OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));\r
+ OptionalDataSize = (UINT32) (VariableSize - ((UINTN) VariablePtr - (UINTN) Variable));\r
if (OptionalDataSize == 0) {\r
OptionalData = NULL;\r
} else {\r
return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);\r
}\r
\r
+typedef struct {\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
+ EFI_GUID *Guid;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *Options;\r
+ UINTN OptionCount;\r
+} BM_COLLECT_LOAD_OPTIONS_PARAM;\r
+\r
+/**\r
+ Visitor function to collect the Platform Recovery load options or OS Recovery\r
+ load options from NV storage.\r
+\r
+ @param Name Variable name.\r
+ @param Guid Variable GUID.\r
+ @param Context The same context passed to BmForEachVariable.\r
+**/\r
+VOID\r
+BmCollectLoadOptions (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *Guid,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
+ UINT16 OptionNumber;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION Option;\r
+ UINTN Index;\r
+ BM_COLLECT_LOAD_OPTIONS_PARAM *Param;\r
+\r
+ Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;\r
+\r
+ if (CompareGuid (Guid, Param->Guid) && (\r
+ Param->OptionType == LoadOptionTypePlatformRecovery &&\r
+ EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&\r
+ OptionType == LoadOptionTypePlatformRecovery\r
+ )) {\r
+ Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);\r
+ if (!EFI_ERROR (Status)) {\r
+ for (Index = 0; Index < Param->OptionCount; Index++) {\r
+ if (Param->Options[Index].OptionNumber > Option.OptionNumber) {\r
+ break;\r
+ }\r
+ }\r
+ Param->Options = ReallocatePool (\r
+ Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
+ (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
+ Param->Options\r
+ );\r
+ ASSERT (Param->Options != NULL);\r
+ CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+ CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+ Param->OptionCount++;\r
+ }\r
+ }\r
+}\r
+\r
/**\r
Returns an array of load options based on the EFI variable\r
L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.\r
- #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. \r
+ #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.\r
\r
@param LoadOptionCount Returns number of entries in the array.\r
@param LoadOptionType The type of the load option.\r
IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT16 *OptionOrder;\r
- UINTN OptionOrderSize;\r
- UINTN Index;\r
- UINTN OptionIndex;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *Options;\r
- CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
- UINT16 OptionNumber;\r
+ EFI_STATUS Status;\r
+ UINT16 *OptionOrder;\r
+ UINTN OptionOrderSize;\r
+ UINTN Index;\r
+ UINTN OptionIndex;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *Options;\r
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
+ UINT16 OptionNumber;\r
+ BM_COLLECT_LOAD_OPTIONS_PARAM Param;\r
\r
*OptionCount = 0;\r
+ Options = NULL;\r
\r
if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {\r
//\r
*OptionCount = OptionIndex;\r
}\r
\r
- } else {\r
- return NULL;\r
+ } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {\r
+ Param.OptionType = LoadOptionTypePlatformRecovery;\r
+ Param.Options = NULL;\r
+ Param.OptionCount = 0;\r
+ Param.Guid = &gEfiGlobalVariableGuid;\r
+\r
+ BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);\r
+\r
+ *OptionCount = Param.OptionCount;\r
+ Options = Param.Options;\r
}\r
\r
return Options;\r
\r
@param LoadOption Pointer to boot option to Free.\r
\r
- @return EFI_SUCCESS BootOption was freed \r
- @return EFI_NOT_FOUND BootOption == NULL \r
+ @return EFI_SUCCESS BootOption was freed\r
+ @return EFI_NOT_FOUND BootOption == NULL\r
\r
**/\r
EFI_STATUS\r
}\r
\r
/**\r
- Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by \r
+ Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by\r
EfiBootManagerGetLoadOptions().\r
\r
@param Option Pointer to boot option array to free.\r
@param OptionCount Number of array entries in BootOption\r
\r
- @return EFI_SUCCESS BootOption was freed \r
- @return EFI_NOT_FOUND BootOption == NULL \r
+ @return EFI_SUCCESS BootOption was freed\r
+ @return EFI_NOT_FOUND BootOption == NULL\r
\r
**/\r
EFI_STATUS\r
Return whether the PE header of the load option is valid or not.\r
\r
@param[in] Type The load option type.\r
+ It's used to check whether the load option is valid.\r
+ When it's LoadOptionTypeMax, the routine only guarantees\r
+ the load option is a valid PE image but doesn't guarantee\r
+ the PE's subsystem type is valid.\r
@param[in] FileBuffer The PE file buffer of the load option.\r
@param[in] FileSize The size of the load option file.\r
\r
// Check PE32 or PE32+ magic, and machine type\r
//\r
OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;\r
- if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || \r
+ if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||\r
OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&\r
EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)\r
) {\r
// SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application\r
//\r
Subsystem = OptionalHeader->Subsystem;\r
- if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
+ if ((Type == LoadOptionTypeMax) ||\r
+ (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
(Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||\r
(Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
- (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)\r
+ (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
+ (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)\r
) {\r
return TRUE;\r
}\r
return FALSE;\r
}\r
\r
+/**\r
+ Return the next matched load option buffer.\r
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid\r
+ load option is read.\r
+\r
+ @param Type The load option type.\r
+ It's used to check whether the load option is valid.\r
+ When it's LoadOptionTypeMax, the routine only guarantees\r
+ the load option is a valid PE image but doesn't guarantee\r
+ the PE's subsystem type is valid.\r
+ @param FilePath The device path pointing to a load option.\r
+ It could be a short-form device path.\r
+ @param FullPath Return the next full device path of the load option after\r
+ short-form device path expanding.\r
+ Caller is responsible to free it.\r
+ NULL to return the first matched full device path.\r
+ @param FileSize Return the load option size.\r
+\r
+ @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmGetNextLoadOptionBuffer (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
+ OUT UINTN *FileSize\r
+ )\r
+{\r
+ VOID *FileBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
+ UINTN LocalFileSize;\r
+ UINT32 AuthenticationStatus;\r
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;\r
+\r
+ LocalFileSize = 0;\r
+ FileBuffer = NULL;\r
+ CurFullPath = *FullPath;\r
+ do {\r
+ PreFullPath = CurFullPath;\r
+ CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);\r
+ //\r
+ // Only free the full path created *inside* this routine\r
+ //\r
+ if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {\r
+ FreePool (PreFullPath);\r
+ }\r
+ if (CurFullPath == NULL) {\r
+ break;\r
+ }\r
+ FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);\r
+ if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {\r
+ //\r
+ // Free the RAM disk file system if the load option is invalid.\r
+ //\r
+ RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
+ if (RamDiskDevicePath != NULL) {\r
+ BmDestroyRamDisk (RamDiskDevicePath);\r
+ FreePool (RamDiskDevicePath);\r
+ }\r
+\r
+ //\r
+ // Free the invalid load option buffer.\r
+ //\r
+ FreePool (FileBuffer);\r
+ FileBuffer = NULL;\r
+ }\r
+ } while (FileBuffer == NULL);\r
+\r
+ if (FileBuffer == NULL) {\r
+ CurFullPath = NULL;\r
+ LocalFileSize = 0;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "[Bds] Expand "));\r
+ BmPrintDp (FilePath);\r
+ DEBUG ((DEBUG_INFO, " -> "));\r
+ BmPrintDp (CurFullPath);\r
+ DEBUG ((DEBUG_INFO, "\n"));\r
+\r
+ *FullPath = CurFullPath;\r
+ *FileSize = LocalFileSize;\r
+ return FileBuffer;\r
+}\r
+\r
/**\r
Process (load and execute) the load option.\r
\r
@param LoadOption Pointer to the load option.\r
\r
- @retval EFI_INVALID_PARAMETER The load option type is invalid, \r
+ @retval EFI_INVALID_PARAMETER The load option type is invalid,\r
or the load option file path doesn't point to a valid file.\r
@retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.\r
@retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
EFI_HANDLE ImageHandle;\r
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
VOID *FileBuffer;\r
return EFI_SUCCESS;\r
}\r
\r
- Status = EFI_INVALID_PARAMETER;\r
-\r
//\r
// Load and start the load option.\r
//\r
DEBUG ((\r
- DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",\r
- mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber\r
+ DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",\r
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,\r
+ LoadOption->Description\r
));\r
ImageHandle = NULL;\r
- FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);\r
- DEBUG_CODE (\r
- if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
- DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
- BmPrintDp (LoadOption->FilePath);\r
- DEBUG ((EFI_D_INFO, " -> "));\r
- BmPrintDp (FilePath);\r
- DEBUG ((EFI_D_INFO, "\n"));\r
+ CurFullPath = NULL;\r
+ EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);\r
+\r
+ //\r
+ // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.\r
+ //\r
+ while (TRUE) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ PreFullPath = CurFullPath;\r
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);\r
+ if (PreFullPath != NULL) {\r
+ FreePool (PreFullPath);\r
+ }\r
+ if (FileBuffer == NULL) {\r
+ break;\r
}\r
- );\r
- if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {\r
Status = gBS->LoadImage (\r
FALSE,\r
gImageHandle,\r
- FilePath,\r
+ CurFullPath,\r
FileBuffer,\r
FileSize,\r
&ImageHandle\r
);\r
- }\r
- if (FilePath != NULL) {\r
- FreePool (FilePath);\r
- }\r
- if (FileBuffer != NULL) {\r
FreePool (FileBuffer);\r
- }\r
\r
- if (!EFI_ERROR (Status)) {\r
- Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
- ASSERT_EFI_ERROR (Status);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
- ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;\r
- ImageInfo->LoadOptions = LoadOption->OptionalData;\r
- //\r
- // Before calling the image, enable the Watchdog Timer for the 5-minute period\r
- //\r
- gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);\r
+ ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;\r
+ ImageInfo->LoadOptions = LoadOption->OptionalData;\r
+ //\r
+ // Before calling the image, enable the Watchdog Timer for the 5-minute period\r
+ //\r
+ gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);\r
\r
- LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);\r
- DEBUG ((\r
- DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",\r
- mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status\r
+ LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);\r
+ DEBUG ((\r
+ DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",\r
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status\r
));\r
\r
- //\r
- // Clear the Watchdog Timer after the image returns\r
- //\r
- gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
+ //\r
+ // Clear the Watchdog Timer after the image returns\r
+ //\r
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
+\r
+ if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (CurFullPath != NULL) {\r
+ FreePool (CurFullPath);\r
}\r
\r
return Status;\r