]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg: Add new API HttpUrlGetPath() to HttpLib.h
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
index 028edc35d53963f9c309b7bd0bdfd291f7d09888..7297a1ddda2f7e7159b9a3ce29ddffaafdd05caf 100644 (file)
@@ -2,6 +2,7 @@
   Library functions which relates with booting.\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
@@ -51,6 +52,28 @@ EfiBootManagerRegisterLegacyBootSupport (
   mBmLegacyBoot              = LegacyBoot;\r
 }\r
 \r
+/**\r
+  Return TRUE when the boot option is auto-created instead of manually added.\r
+\r
+  @param BootOption Pointer to the boot option to check.\r
+\r
+  @retval TRUE  The boot option is auto-created.\r
+  @retval FALSE The boot option is manually added.\r
+**/\r
+BOOLEAN\r
+BmIsAutoCreateBootOption (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    *BootOption\r
+  )\r
+{\r
+  if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&\r
+      CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)\r
+      ) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
 /**\r
   For a bootable Device path, return its boot type.\r
 \r
@@ -69,6 +92,8 @@ EfiBootManagerRegisterLegacyBootSupport (
   @retval MessageNetworkBoot           If given device path contains MESSAGING_DEVICE_PATH type device path node\r
                                        and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,\r
                                        MSG_IPv4_DP or MSG_IPv6_DP.\r
+  @retval MessageHttpBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+                                       and its last device path node's subtype is MSG_URI_DP.\r
   @retval UnsupportedBoot              If tiven device path doesn't match the above condition, it's not supported.\r
 \r
 **/\r
@@ -113,7 +138,7 @@ BmDevicePathType (
         // If the device path not only point to driver device, it is not a messaging device path,\r
         //\r
         if (!IsDevicePathEndType (NextNode)) {\r
-          break;\r
+          continue;\r
         }\r
 \r
         switch (DevicePathSubType (Node)) {\r
@@ -139,6 +164,10 @@ BmDevicePathType (
         case MSG_IPv6_DP:\r
           return BmMessageNetworkBoot;\r
           break;\r
+\r
+        case MSG_URI_DP:\r
+          return BmMessageHttpBoot;\r
+          break;\r
         }\r
     }\r
   }\r
@@ -199,7 +228,7 @@ BmFindBootOptionInVariable (
   if (OptionNumber == LoadOptionNumberUnassigned) {\r
     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
 \r
-    Index = BmFindLoadOption (OptionToFind, BootOptions, BootOptionCount);\r
+    Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);\r
     if (Index != -1) {\r
       OptionNumber = BootOptions[Index].OptionNumber;\r
     }\r
@@ -686,6 +715,10 @@ BmGetMiscDescription (
     Description = L"Network";\r
     break;\r
 \r
+  case BmMessageHttpBoot:\r
+    Description = L"Http";\r
+    break;\r
+\r
   default:\r
     Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);\r
     if (!EFI_ERROR (Status)) {\r
@@ -946,7 +979,6 @@ BmFindUsbDevice (
   EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;\r
   EFI_USB_IO_PROTOCOL       *UsbIo;\r
   UINTN                     Index;\r
-  UINTN                     UsbIoDevicePathSize;\r
   BOOLEAN                   Matched;\r
 \r
   ASSERT (UsbIoHandleCount != NULL);  \r
@@ -978,7 +1010,6 @@ BmFindUsbDevice (
     UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);\r
     Matched         = FALSE;\r
     if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {\r
-      UsbIoDevicePathSize = GetDevicePathSize (UsbIoDevicePath) - END_DEVICE_PATH_LENGTH;\r
 \r
       //\r
       // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
@@ -1063,6 +1094,76 @@ BmExpandUsbDevicePath (
   return FileBuffer;\r
 }\r
 \r
+/**\r
+  Expand File-path device path node to be full device path in platform.\r
+\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 full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\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
+BmExpandFileDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,\r
+  OUT UINTN                       *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Index;\r
+  UINTN                           HandleCount;\r
+  EFI_HANDLE                      *Handles;\r
+  EFI_BLOCK_IO_PROTOCOL           *BlockIo;\r
+  UINTN                           MediaType;\r
+  EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;\r
+  VOID                            *FileBuffer;\r
+  UINT32                          AuthenticationStatus;\r
+  \r
+  EfiBootManagerConnectAll ();\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);\r
+  if (EFI_ERROR (Status)) {\r
+    HandleCount = 0;\r
+    Handles = NULL;\r
+  }\r
+\r
+  //\r
+  // Enumerate all removable media devices followed by all fixed media devices,\r
+  //   followed by media devices which don't layer on block io.\r
+  //\r
+  for (MediaType = 0; MediaType < 3; MediaType++) {\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);\r
+      if (EFI_ERROR (Status)) {\r
+        BlockIo = NULL;\r
+      }\r
+      if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||\r
+          (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||\r
+          (MediaType == 2 && BlockIo == NULL)\r
+          ) {\r
+        FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
+        FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);\r
+        if (FileBuffer != NULL) {\r
+          *FullPath = FullDevicePath;\r
+          FreePool (Handles);\r
+          return FileBuffer;\r
+        }\r
+        FreePool (FullDevicePath);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  *FullPath = NULL;\r
+  return NULL;\r
+}\r
+\r
 /**\r
   Save the partition DevicePath to the CachedDevicePath as the first instance.\r
 \r
@@ -1464,6 +1565,12 @@ BmGetLoadOptionBuffer (
     // Expand the Harddrive device path\r
     //\r
     return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\r
+  } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
+             (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {\r
+    //\r
+    // Expand the File-path device path\r
+    //\r
+    return BmExpandFileDevicePath (FilePath, FullPath, FileSize);\r
   } else {\r
     for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
       if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
@@ -1501,9 +1608,18 @@ BmGetLoadOptionBuffer (
   // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),\r
   //   or it directly points to a file in simple file system instance.\r
   //\r
+  Node   = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
   FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
   if (FileBuffer != NULL) {\r
-    *FullPath = DuplicateDevicePath (FilePath);\r
+    if (EFI_ERROR (Status)) {\r
+      *FullPath = DuplicateDevicePath (FilePath);\r
+    } else {\r
+      //\r
+      // LoadFile () may cause the device path of the Handle be updated.\r
+      //\r
+      *FullPath = AppendDevicePath (DevicePathFromHandle (Handle), Node);\r
+    }\r
   }\r
 \r
   return FileBuffer;\r
@@ -1671,11 +1787,9 @@ EfiBootManagerBoot (
   // 6. Adjust the different type memory page number just before booting\r
   //    and save the updated info into the variable for next boot to use\r
   //\r
-  if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) {\r
-    if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {\r
-      BmSetMemoryTypeInformationVariable ();\r
-    }\r
-  }\r
+  BmSetMemoryTypeInformationVariable (\r
+    (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
+    );\r
 \r
   DEBUG_CODE_BEGIN();\r
     if (BootOption->Description == NULL) {\r
@@ -1722,8 +1836,10 @@ EfiBootManagerBoot (
   Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  ImageInfo->LoadOptionsSize  = BootOption->OptionalDataSize;\r
-  ImageInfo->LoadOptions      = BootOption->OptionalData;\r
+  if (!BmIsAutoCreateBootOption (BootOption)) {\r
+    ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;\r
+    ImageInfo->LoadOptions     = BootOption->OptionalData;\r
+  }\r
 \r
   //\r
   // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
@@ -1849,6 +1965,66 @@ BmMatchPartitionDevicePathNode (
     );\r
 }\r
 \r
+/**\r
+  Enumerate all boot option descriptions and append " 2"/" 3"/... to make\r
+  unique description.\r
+\r
+  @param BootOptions            Array of boot options.\r
+  @param BootOptionCount        Count of boot options.\r
+**/\r
+VOID\r
+BmMakeBootOptionDescriptionUnique (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION         *BootOptions,\r
+  UINTN                                BootOptionCount\r
+  )\r
+{\r
+  UINTN                                Base;\r
+  UINTN                                Index;\r
+  UINTN                                DescriptionSize;\r
+  UINTN                                MaxSuffixSize;\r
+  BOOLEAN                              *Visited;\r
+  UINTN                                MatchCount;\r
+\r
+  if (BootOptionCount == 0) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Calculate the maximum buffer size for the number suffix.\r
+  // The initial sizeof (CHAR16) is for the blank space before the number.\r
+  //\r
+  MaxSuffixSize = sizeof (CHAR16);\r
+  for (Index = BootOptionCount; Index != 0; Index = Index / 10) {\r
+    MaxSuffixSize += sizeof (CHAR16);\r
+  }\r
+\r
+  Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);\r
+  ASSERT (Visited != NULL);\r
+\r
+  for (Base = 0; Base < BootOptionCount; Base++) {\r
+    if (!Visited[Base]) {\r
+      MatchCount      = 1;\r
+      Visited[Base]   = TRUE;\r
+      DescriptionSize = StrSize (BootOptions[Base].Description);\r
+      for (Index = Base + 1; Index < BootOptionCount; Index++) {\r
+        if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {\r
+          Visited[Index] = TRUE;\r
+          MatchCount++;\r
+          FreePool (BootOptions[Index].Description);\r
+          BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);\r
+          UnicodeSPrint (\r
+            BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,\r
+            L"%s %d",\r
+            BootOptions[Base].Description, MatchCount\r
+            );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  FreePool (Visited);\r
+}\r
+\r
 /**\r
   Emuerate all possible bootable medias in the following order:\r
   1. Removable BlockIo            - The boot option only points to the removable media\r
@@ -2035,6 +2211,7 @@ BmEnumerateBootOptions (
     FreePool (Handles);\r
   }\r
 \r
+  BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);\r
   return BootOptions;\r
 }\r
 \r
@@ -2078,15 +2255,13 @@ EfiBootManagerRefreshAllBootOption (
   for (Index = 0; Index < NvBootOptionCount; Index++) {\r
     if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || \r
          (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
-        ) &&\r
-        (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) &&\r
-        CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid)\r
+        ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])\r
        ) {\r
       //\r
       // Only check those added by BDS\r
       // so that the boot options added by end-user or OS installer won't be deleted\r
       //\r
-      if (BmFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {\r
+      if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {\r
         Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
         //\r
         // Deleting variable with current variable implementation shouldn't fail.\r
@@ -2100,7 +2275,7 @@ EfiBootManagerRefreshAllBootOption (
   // Add new EFI boot options to NV\r
   //\r
   for (Index = 0; Index < BootOptionCount; Index++) {\r
-    if (BmFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {\r
+    if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {\r
       EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
       //\r
       // Try best to add the boot options so continue upon failure.\r
@@ -2181,7 +2356,7 @@ BmRegisterBootManagerMenu (
     UINTN                           BootOptionCount;\r
 \r
     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
-    ASSERT (BmFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);\r
+    ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);\r
     EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
     );\r
 \r