]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg: SmmReportStatusCodeLib: ReportStatusCodeLib in StandaloneMm
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
index 6a23477eb8730dfa94faa4e6447b792d514cd901..aff620ad52eec6e51bffad40ba982bd9885b0a85 100644 (file)
@@ -1,15 +1,10 @@
 /** @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
@@ -1069,6 +1064,9 @@ BmExpandMediaDevicePath (
   //\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
@@ -1389,6 +1387,37 @@ BmExpandLoadFile (
   //\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
@@ -1667,6 +1696,51 @@ BmIsBootManagerMenuFilePath (
   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
@@ -1820,13 +1894,14 @@ EfiBootManagerBoot (
 \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
@@ -1834,6 +1909,11 @@ EfiBootManagerBoot (
         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
@@ -1902,16 +1982,6 @@ EfiBootManagerBoot (
   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
@@ -1921,6 +1991,15 @@ EfiBootManagerBoot (
     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
@@ -1979,37 +2058,33 @@ BmMatchPartitionDevicePathNode (
   }\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
@@ -2217,12 +2292,15 @@ EfiBootManagerRefreshAllBootOption (
   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
@@ -2232,7 +2310,6 @@ EfiBootManagerRefreshAllBootOption (
   }\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
@@ -2242,6 +2319,30 @@ EfiBootManagerRefreshAllBootOption (
     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
@@ -2461,3 +2562,26 @@ EfiBootManagerGetBootManagerMenu (
   }\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