/** @file\r
Library functions which relates with booting.\r
\r
-Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.\r
+Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015-2016 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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
//\r
Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
if (Buffer != NULL) {\r
BlockIo->ReadBlocks (\r
//\r
FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));\r
if (FileBuffer == NULL) {\r
+ DEBUG_CODE (\r
+ EFI_DEVICE_PATH *LoadFilePath;\r
+ CHAR16 *LoadFileText;\r
+ CHAR16 *FileText;\r
+\r
+ LoadFilePath = DevicePathFromHandle (LoadFileHandle);\r
+ if (LoadFilePath == NULL) {\r
+ LoadFileText = NULL;\r
+ } else {\r
+ LoadFileText = ConvertDevicePathToText (LoadFilePath, FALSE, FALSE);\r
+ }\r
+ FileText = ConvertDevicePathToText (FilePath, FALSE, FALSE);\r
+\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a:%a: failed to allocate reserved pages: "\r
+ "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",\r
+ gEfiCallerBaseName,\r
+ __FUNCTION__,\r
+ (UINT64)BufferSize,\r
+ LoadFileText,\r
+ FileText\r
+ ));\r
+\r
+ if (FileText != NULL) {\r
+ FreePool (FileText);\r
+ }\r
+ if (LoadFileText != NULL) {\r
+ FreePool (LoadFileText);\r
+ }\r
+ );\r
return NULL;\r
}\r
\r
return FALSE;\r
}\r
\r
+/**\r
+ Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or\r
+ StartImage() failure.\r
+\r
+ @param[in] ErrorCode An Error Code in the Software Class, DXE Boot\r
+ Service Driver Subclass. ErrorCode will be used to\r
+ compose the Value parameter for status code\r
+ reporting. Must be one of\r
+ EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and\r
+ EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.\r
+\r
+ @param[in] FailureStatus The failure status returned by the boot service\r
+ that should be reported.\r
+**/\r
+VOID\r
+BmReportLoadFailure (\r
+ IN UINT32 ErrorCode,\r
+ IN EFI_STATUS FailureStatus\r
+ )\r
+{\r
+ EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData;\r
+\r
+ if (!ReportErrorCodeEnabled ()) {\r
+ return;\r
+ }\r
+\r
+ ASSERT (\r
+ (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) ||\r
+ (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
+ );\r
+\r
+ ZeroMem (&ExtendedData, sizeof (ExtendedData));\r
+ ExtendedData.ReturnStatus = FailureStatus;\r
+\r
+ REPORT_STATUS_CODE_EX (\r
+ (EFI_ERROR_CODE | EFI_ERROR_MINOR),\r
+ (EFI_SOFTWARE_DXE_BS_DRIVER | ErrorCode),\r
+ 0,\r
+ NULL,\r
+ NULL,\r
+ &ExtendedData.DataHeader + 1,\r
+ sizeof (ExtendedData) - sizeof (ExtendedData.DataHeader)\r
+ );\r
+}\r
+\r
/**\r
Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
also signals the EFI ready to boot event. If the device path for the option\r
\r
if (EFI_ERROR (Status)) {\r
//\r
- // Report Status Code to indicate that the failure to load boot option\r
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created\r
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.\r
+ // If the caller doesn't have the option to defer the execution of an image, we should\r
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.\r
//\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
- );\r
- BootOption->Status = Status;\r
+ if (Status == EFI_SECURITY_VIOLATION) {\r
+ gBS->UnloadImage (ImageHandle);\r
+ }\r
//\r
// Destroy the RAM disk\r
//\r
BmDestroyRamDisk (RamDiskDevicePath);\r
FreePool (RamDiskDevicePath);\r
}\r
+ //\r
+ // Report Status Code with the failure status to indicate that the failure to load boot option\r
+ //\r
+ BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);\r
+ BootOption->Status = Status;\r
return;\r
}\r
}\r
Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);\r
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
BootOption->Status = Status;\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Report Status Code to indicate that boot failure\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
- );\r
- }\r
- PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
\r
//\r
// Destroy the RAM disk\r
FreePool (RamDiskDevicePath);\r
}\r
\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Report Status Code with the failure status to indicate that boot failure\r
+ //\r
+ BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);\r
+ }\r
+ PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+\r
+\r
//\r
// Clear the Watchdog Timer after the image returns\r
//\r
}\r
\r
//\r
- // find the partition device path node\r
+ // Match all the partition device path nodes including the nested partition nodes\r
//\r
while (!IsDevicePathEnd (BlockIoDevicePath)) {\r
if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&\r
(DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)\r
) {\r
- break;\r
+ //\r
+ // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
+ //\r
+ Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
+\r
+ //\r
+ // Match Signature and PartitionNumber.\r
+ // Unused bytes in Signature are initiaized with zeros.\r
+ //\r
+ if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
+ (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
+ (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
+ (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {\r
+ return TRUE;\r
+ }\r
}\r
\r
BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);\r
}\r
\r
- if (IsDevicePathEnd (BlockIoDevicePath)) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
- //\r
- Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
-\r
- //\r
- // Match Signature and PartitionNumber.\r
- // Unused bytes in Signature are initiaized with zeros.\r
- //\r
- return (BOOLEAN) (\r
- (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
- (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
- (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
- (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)\r
- );\r
+ return FALSE;\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;\r
- UINTN NvBootOptionCount;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
- UINTN BootOptionCount;\r
- UINTN Index;\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;\r
+ UINTN NvBootOptionCount;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINTN BootOptionCount;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *UpdatedBootOptions;\r
+ UINTN UpdatedBootOptionCount;\r
+ UINTN Index;\r
+ EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;\r
\r
//\r
// Optionally refresh the legacy boot option\r
}\r
\r
BootOptions = BmEnumerateBootOptions (&BootOptionCount);\r
- NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);\r
\r
//\r
// Mark the boot option as added by BDS by setting OptionalData to a special GUID\r
BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);\r
}\r
\r
+ //\r
+ // Locate Platform Boot Options Protocol\r
+ //\r
+ Status = gBS->LocateProtocol (&gEdkiiPlatformBootManagerProtocolGuid,\r
+ NULL,\r
+ (VOID **)&PlatformBootManager);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If found, call platform specific refresh to all auto enumerated and NV\r
+ // boot options.\r
+ //\r
+ Status = PlatformBootManager->RefreshAllBootOptions ((CONST EFI_BOOT_MANAGER_LOAD_OPTION *)BootOptions,\r
+ (CONST UINTN)BootOptionCount,\r
+ &UpdatedBootOptions,\r
+ &UpdatedBootOptionCount);\r
+ if (!EFI_ERROR (Status)) {\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+ BootOptions = UpdatedBootOptions;\r
+ BootOptionCount = UpdatedBootOptionCount;\r
+ }\r
+ }\r
+\r
+ NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);\r
+\r
//\r
// Remove invalid EFI boot options from NV\r
//\r
}\r
}\r
\r
+/**\r
+ Get the next possible full path pointing to the load option.\r
+ The routine doesn't guarantee the returned full path points to an existing\r
+ file, and it also doesn't guarantee the existing file is a valid load option.\r
+ BmGetNextLoadOptionBuffer() guarantees.\r
+\r
+ @param FilePath The device path pointing to a load option.\r
+ It could be a short-form device path.\r
+ @param FullPath The full path returned by the routine in last call.\r
+ Set to NULL in first call.\r
+\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+EfiBootManagerGetNextLoadOptionDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath\r
+ )\r
+{\r
+ return BmGetNextLoadOptionDevicePath(FilePath, FullPath);\r
+}\r