]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/Bds: Wide match HTTP boot option.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
index a6826f61ae041b79807dc1f412ff1fa4a69b19de..35234bac19c11a748e9a7c26baabbddfcc3f9ac7 100644 (file)
@@ -1527,6 +1527,136 @@ BmExpandMediaDevicePath (
   return FileBuffer;\r
 }\r
 \r
+/**\r
+  Check whether Left and Right are the same without matching the specific\r
+  device path data in IP device path and URI device path node.\r
+\r
+  @retval TRUE  Left and Right are the same.\r
+  @retval FALSE Left and Right are the different.\r
+**/\r
+BOOLEAN\r
+BmMatchHttpBootDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *Left,\r
+  IN EFI_DEVICE_PATH_PROTOCOL *Right\r
+  )\r
+{\r
+  for (;  !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)\r
+       ;  Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)\r
+       ) {\r
+    if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {\r
+      if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {\r
+        return FALSE;\r
+      }\r
+\r
+      if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&\r
+          ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&\r
+          ((DevicePathSubType (Left) != MSG_URI_DP)  || (DevicePathSubType (Right) != MSG_URI_DP))\r
+          ) {\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+  return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));\r
+}\r
+\r
+/**\r
+  Get the file buffer from Load File instance.\r
+\r
+  @param FilePath    The media device path pointing to a LoadFile instance.\r
+  @param FullPath    Return the full device path pointing to the load option.\r
+  @param FileSize    Return the size of the load option.\r
+\r
+  @return  The load option buffer.\r
+**/\r
+VOID *\r
+BmGetFileBufferFromLoadFile (\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
+  EFI_HANDLE                      Handle;\r
+  VOID                            *FileBuffer;\r
+  EFI_HANDLE                      *Handles;\r
+  UINTN                           HandleCount;\r
+  UINTN                           Index;\r
+  EFI_DEVICE_PATH_PROTOCOL        *Node;\r
+  EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
+  UINTN                           BufferSize;\r
+\r
+  //\r
+  // Get file buffer from load file instance.\r
+  //\r
+  Node = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
+    //\r
+    // When wide match happens, pass full device path to LoadFile (),\r
+    // otherwise, pass remaining device path to LoadFile ().\r
+    //\r
+    FilePath = Node;\r
+  } else {\r
+    Handle = NULL;\r
+    //\r
+    // Use wide match algorithm to find one when\r
+    //  cannot find a LoadFile instance to exactly match the FilePath\r
+    //\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiLoadFileProtocolGuid,\r
+                    NULL,\r
+                    &HandleCount,\r
+                    &Handles\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Handles = NULL;\r
+      HandleCount = 0;\r
+    }\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {\r
+        Handle = Handles[Index];\r
+        break;\r
+      }\r
+    }\r
+    if (Handles != NULL) {\r
+      FreePool (Handles);\r
+    }\r
+  }\r
+\r
+  if (Handle == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  BufferSize = 0;\r
+  FileBuffer = NULL;\r
+  Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FileBuffer = AllocatePool (BufferSize);\r
+    if (FileBuffer != NULL) {\r
+      Status = EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // LoadFile () may cause the device path of the Handle be updated.\r
+    //\r
+    *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handle));\r
+    *FileSize = BufferSize;\r
+    return FileBuffer;\r
+  } else {\r
+    return NULL;\r
+  }\r
+}\r
+\r
 /**\r
   Get the load option by its device path.\r
 \r
@@ -1622,24 +1752,19 @@ BmGetLoadOptionBuffer (
   }\r
 \r
   //\r
-  // 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
+  // Get file buffer from simple file system.\r
   //\r
   Node   = FilePath;\r
-  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
-  FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
-  if (FileBuffer != NULL) {\r
-    if (EFI_ERROR (Status)) {\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
+    if (FileBuffer != NULL) {\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
+    return FileBuffer;\r
   }\r
 \r
-  return FileBuffer;\r
+  return BmGetFileBufferFromLoadFile (FilePath, FullPath, FileSize);\r
 }\r
 \r
 /**\r