Add new GetFileBufferByFilePath API into DxeServicesLib.
[efi/edk2/.git] / edk2 / MdePkg / Library / DxeServicesLib / DxeServicesLib.c
index 1073515..fa54c7b 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   MDE DXE Services Library provides functions that simplify the development of DXE Drivers.  \r
-  These functions help access data from sections of FFS files.\r
+  These functions help access data from sections of FFS files or from file path.\r
 \r
-  Copyright (c) 2007 - 2008, Intel Corporation<BR>\r
+  Copyright (c) 2007 - 2009, Intel Corporation<BR>\r
   All rights reserved. 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
 #include <Library/DebugLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiLib.h>\r
 #include <Library/DxeServicesLib.h>\r
 #include <Protocol/FirmwareVolume2.h>\r
 #include <Protocol/LoadedImage.h>\r
-\r
+#include <Protocol/LoadFile2.h>\r
+#include <Protocol/LoadFile.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Guid/FileInfo.h>\r
 \r
 /**\r
   Identify the device handle from which the Image is loaded from. As this device handle is passed to\r
@@ -392,3 +397,332 @@ GetSectionFromFfs (
            );\r
 }\r
 \r
+\r
+/**\r
+  Get the image file buffer data and buffer size by its device path. \r
+  \r
+  Access the file either from a a firmware volume, from a file system interface, \r
+  or from the load file interface.\r
+  \r
+  Allocate memory to store the found image. The caller is responsible to free memory.\r
+\r
+  If File is NULL, then NULL is returned.\r
+  If FileSize is NULL, then NULL is returned.\r
+  If AuthenticationStatus is NULL, then NULL is returned.\r
+\r
+  @param[in]       BootPolicy \r
+                             Policy for Open Image File.If TRUE, indicates that the request \r
+                             originates from the boot manager, and that the boot manager is\r
+                             attempting to load FilePath as a boot selection. If FALSE, \r
+                             then FilePath must match an exact file to be loaded.\r
+  @param[in]       FilePath  Pointer to the device path of the file that is absracted to the file buffer.\r
+  @param[out]      FileSize  Pointer to the size of the abstracted file buffer.\r
+  @param[out]      AuthenticationStatus   \r
+                             Pointer to a caller-allocated UINT32 in which\r
+                             the authentication status is returned.\r
+\r
+  @retval NULL   File is NULL, or FileSize is NULL. Or the file can't be found.\r
+  @retval other  The abstracted file buffer. The caller is responsible to free memory.\r
+**/\r
+VOID *\r
+EFIAPI\r
+GetFileBufferByFilePath (\r
+  IN BOOLEAN                           BootPolicy,\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
+  OUT      UINTN                       *FileSize,\r
+  OUT UINT32                           *AuthenticationStatus\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL          *DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL          *OrigDevicePathNode;\r
+  EFI_HANDLE                        Handle;\r
+  EFI_GUID                          *FvNameGuid;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;\r
+  EFI_SECTION_TYPE                  SectionType;\r
+  UINT8                             *ImageBuffer;\r
+  UINTN                             ImageBufferSize;\r
+  EFI_FV_FILETYPE                   Type;\r
+  EFI_FV_FILE_ATTRIBUTES            Attrib;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Volume;\r
+  EFI_FILE_HANDLE                   FileHandle;\r
+  EFI_FILE_HANDLE                   LastHandle;\r
+  EFI_FILE_INFO                     *FileInfo;\r
+  UINTN                             FileInfoSize;\r
+  EFI_LOAD_FILE_PROTOCOL            *LoadFile;\r
+  EFI_LOAD_FILE2_PROTOCOL           *LoadFile2;\r
+  EFI_STATUS                        Status;\r
+\r
+  //\r
+  // Check input File device path.\r
+  //\r
+  if (FilePath == NULL || FileSize == NULL || AuthenticationStatus == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Init local variable\r
+  //\r
+  FvNameGuid          = NULL;\r
+  FileInfo            = NULL;\r
+  FileHandle          = NULL;\r
+  ImageBuffer         = NULL;\r
+  ImageBufferSize     = 0;\r
+  *AuthenticationStatus = 0;\r
+  \r
+  //\r
+  // Copy File Device Path\r
+  //\r
+  OrigDevicePathNode = DuplicateDevicePath (FilePath);\r
+  if (OrigDevicePathNode == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Check whether this device path support FV2 protocol.\r
+  // Is so, this device path may contain a Image.\r
+  //\r
+  DevicePathNode = OrigDevicePathNode;\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For FwVol File system there is only a single file name that is a GUID.\r
+    //\r
+    FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePathNode);\r
+    if (FvNameGuid == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+    } else {\r
+      //\r
+      // Read image from the firmware file\r
+      //\r
+      Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol);\r
+      if (!EFI_ERROR (Status)) {\r
+        SectionType = EFI_SECTION_PE32;\r
+        ImageBuffer = NULL;\r
+        Status = FwVol->ReadSection (\r
+                          FwVol,\r
+                          FvNameGuid,\r
+                          SectionType,\r
+                          0,\r
+                          (VOID **)&ImageBuffer,\r
+                          &ImageBufferSize,\r
+                          AuthenticationStatus\r
+                          );\r
+        if (EFI_ERROR (Status)) {\r
+          //\r
+          // Try a raw file, since a PE32 SECTION does not exist\r
+          //\r
+          if (ImageBuffer != NULL) {\r
+            FreePool (ImageBuffer);\r
+            *AuthenticationStatus = 0;\r
+          }\r
+          ImageBuffer = NULL;\r
+          Status = FwVol->ReadFile (\r
+                            FwVol,\r
+                            FvNameGuid,\r
+                            (VOID **)&ImageBuffer,\r
+                            &ImageBufferSize,\r
+                            &Type,\r
+                            &Attrib,\r
+                            AuthenticationStatus\r
+                            );\r
+        }\r
+      }\r
+    }\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // Attempt to access the file via a file system interface\r
+  //\r
+  DevicePathNode = OrigDevicePathNode;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Open the Volume to get the File System handle\r
+      //\r
+      Status = Volume->OpenVolume (Volume, &FileHandle);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the\r
+        // directory information and filename can be seperate. The goal is to inch\r
+        // our way down each device path node and close the previous node\r
+        //\r
+        while (!IsDevicePathEnd (DevicePathNode) && !EFI_ERROR (Status)) {\r
+          if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH ||\r
+              DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) {\r
+            Status = EFI_UNSUPPORTED;\r
+            break;\r
+          }\r
+  \r
+          LastHandle = FileHandle;\r
+          FileHandle = NULL;\r
+  \r
+          Status = LastHandle->Open (\r
+                                LastHandle,\r
+                                &FileHandle,\r
+                                ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName,\r
+                                EFI_FILE_MODE_READ,\r
+                                0\r
+                                );\r
+  \r
+          //\r
+          // Close the previous node\r
+          //\r
+          LastHandle->Close (LastHandle);\r
+  \r
+          DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+        }\r
+  \r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // We have found the file. Now we need to read it. Before we can read the file we need to\r
+          // figure out how big the file is.\r
+          //\r
+          FileInfo = NULL;\r
+          FileInfoSize = 0;\r
+          Status = FileHandle->GetInfo (\r
+                                FileHandle,\r
+                                &gEfiFileInfoGuid,\r
+                                &FileInfoSize,\r
+                                FileInfo\r
+                                );\r
+  \r
+          if (Status == EFI_BUFFER_TOO_SMALL) {\r
+            FileInfo = AllocatePool (FileInfoSize);\r
+            if (FileInfo == NULL) {\r
+              Status = EFI_OUT_OF_RESOURCES;\r
+            } else {\r
+              Status = FileHandle->GetInfo (\r
+                                    FileHandle,\r
+                                    &gEfiFileInfoGuid,\r
+                                    &FileInfoSize,\r
+                                    FileInfo\r
+                                    );\r
+            }\r
+          }\r
+          \r
+          if (!EFI_ERROR (Status)) {\r
+            //\r
+            // Allocate space for the file\r
+            //\r
+            ImageBuffer = AllocatePool ((UINTN)FileInfo->FileSize);\r
+            if (ImageBuffer == NULL) {\r
+              Status = EFI_OUT_OF_RESOURCES;\r
+            } else {\r
+              //\r
+              // Read the file into the buffer we allocated\r
+              //\r
+              ImageBufferSize = (UINTN)FileInfo->FileSize;\r
+              Status          = FileHandle->Read (FileHandle, &ImageBufferSize, ImageBuffer);\r
+            }\r
+          }\r
+        }\r
+        //\r
+        // Close the file and Free FileInfo since we are done\r
+        // \r
+        if (FileInfo != NULL) {\r
+          FreePool (FileInfo);\r
+        }\r
+        if (FileHandle != NULL) {\r
+          FileHandle->Close (FileHandle);\r
+        }\r
+      }\r
+    }\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // Attempt to access the file via LoadFile2 interface\r
+  //\r
+  if (!BootPolicy) {\r
+    DevicePathNode = OrigDevicePathNode;\r
+    Status = gBS->LocateDevicePath (&gEfiLoadFile2ProtocolGuid, &DevicePathNode, &Handle);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = gBS->HandleProtocol (Handle, &gEfiLoadFile2ProtocolGuid, (VOID**)&LoadFile2);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Call LoadFile2 with the correct buffer size\r
+        //\r
+        ImageBufferSize = 0;\r
+        ImageBuffer     = NULL;\r
+        Status = LoadFile2->LoadFile (\r
+                             LoadFile2,\r
+                             DevicePathNode,\r
+                             FALSE,\r
+                             &ImageBufferSize,\r
+                             ImageBuffer\r
+                             );\r
+        if (Status == EFI_BUFFER_TOO_SMALL) {\r
+          ImageBuffer = AllocatePool (ImageBufferSize);\r
+          if (ImageBuffer == NULL) {\r
+            Status = EFI_OUT_OF_RESOURCES;\r
+          } else {\r
+            Status = LoadFile2->LoadFile (\r
+                                 LoadFile2,\r
+                                 DevicePathNode,\r
+                                 BootPolicy,\r
+                                 &ImageBufferSize,\r
+                                 ImageBuffer\r
+                                 );\r
+          }\r
+        }\r
+      }\r
+      goto Finish;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Attempt to access the file via LoadFile interface\r
+  //\r
+  DevicePathNode = OrigDevicePathNode;\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &DevicePathNode, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID**)&LoadFile);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Call LoadFile with the correct buffer size\r
+      //\r
+      ImageBufferSize = 0;\r
+      ImageBuffer     = NULL;\r
+      Status = LoadFile->LoadFile (\r
+                           LoadFile,\r
+                           DevicePathNode,\r
+                           BootPolicy,\r
+                           &ImageBufferSize,\r
+                           ImageBuffer\r
+                           );\r
+      if (Status == EFI_BUFFER_TOO_SMALL) {\r
+        ImageBuffer = AllocatePool (ImageBufferSize);\r
+        if (ImageBuffer == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+        } else {\r
+          Status = LoadFile->LoadFile (\r
+                               LoadFile,\r
+                               DevicePathNode,\r
+                               BootPolicy,\r
+                               &ImageBufferSize,\r
+                               ImageBuffer\r
+                               );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+Finish:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (ImageBuffer != NULL) {\r
+      FreePool (ImageBuffer);\r
+      ImageBuffer = NULL;\r
+    }\r
+    *FileSize = 0;\r
+  } else {\r
+    *FileSize = ImageBufferSize;\r
+  }\r
+\r
+  FreePool (OrigDevicePathNode);\r
+\r
+  return ImageBuffer;\r
+}\r