]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPkg/TimerDxe: Register the virt and hyp timer interrupts at init time.
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsFilePath.c
index 25f92725f538d62651b4ea071b844f29fd51c982..f26ba39ddba8bc1c9122085727336911ea18ee85 100644 (file)
@@ -1,14 +1,14 @@
 /** @file\r
 *\r
-*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
-*  \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
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\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
+*  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
 *\r
 **/\r
 \r
@@ -300,55 +300,57 @@ TryRemovableDevice (
   return Status;\r
 }\r
 \r
-/**\r
-  Connect a Device Path and return the handle of the driver that support this DevicePath\r
-\r
-  @param  DevicePath            Device Path of the File to connect\r
-  @param  Handle                Handle of the driver that support this DevicePath\r
-  @param  RemainingDevicePath   Remaining DevicePath nodes that do not match the driver DevicePath\r
-\r
-  @retval EFI_SUCCESS           A driver that matches the Device Path has been found\r
-  @retval EFI_NOT_FOUND         No handles match the search.\r
-  @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL\r
-\r
-**/\r
+STATIC\r
 EFI_STATUS\r
-BdsConnectDevicePath (\r
-  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
-  OUT EFI_HANDLE                *Handle,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath\r
+BdsConnectAndUpdateDevicePath (\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath,\r
+  OUT    EFI_HANDLE                *Handle,\r
+  OUT    EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath\r
   )\r
 {\r
   EFI_DEVICE_PATH*            Remaining;\r
   EFI_DEVICE_PATH*            NewDevicePath;\r
   EFI_STATUS                  Status;\r
+  EFI_HANDLE                  PreviousHandle;\r
 \r
-  if ((DevicePath == NULL) || (Handle == NULL)) {\r
+  if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  PreviousHandle = NULL;\r
   do {\r
-    Remaining = DevicePath;\r
+    Remaining = *DevicePath;\r
+\r
     // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns\r
     // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified\r
     // to point to the remaining part of the device path\r
     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
+\r
     if (!EFI_ERROR (Status)) {\r
-      // Recursive = FALSE: We do not want to start all the device tree\r
-      Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
-    }\r
+      if (*Handle == PreviousHandle) {\r
+        //\r
+        // If no forward progress is made try invoking the Dispatcher.\r
+        // A new FV may have been added to the system and new drivers\r
+        // may now be found.\r
+        // Status == EFI_SUCCESS means a driver was dispatched\r
+        // Status == EFI_NOT_FOUND means no new drivers were dispatched\r
+        //\r
+        Status = gDS->Dispatch ();\r
+      }\r
 \r
-    /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling\r
-    // NextDevicePathNode () will return an undetermined Device Path Node\r
-    if (!IsDevicePathEnd (RemainingDevicePath)) {\r
-      RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);\r
-    }*/\r
+      if (!EFI_ERROR (Status)) {\r
+        PreviousHandle = *Handle;\r
+\r
+        // Recursive = FALSE: We do not want to start the whole device tree\r
+        Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
+      }\r
+    }\r
   } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));\r
 \r
   if (!EFI_ERROR (Status)) {\r
     // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver\r
     // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)\r
-    Remaining = DevicePath;\r
+    Remaining = *DevicePath;\r
     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
     if (!EFI_ERROR (Status)) {\r
       Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
@@ -371,9 +373,11 @@ BdsConnectDevicePath (
     //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath\r
     Status = EFI_SUCCESS;\r
   } else {\r
-    Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath);\r
+    Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath);\r
     if (!EFI_ERROR (Status)) {\r
-      return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);\r
+      Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);\r
+      *DevicePath = NewDevicePath;\r
+      return Status;\r
     }\r
   }\r
 \r
@@ -384,6 +388,28 @@ BdsConnectDevicePath (
   return Status;\r
 }\r
 \r
+/**\r
+  Connect a Device Path and return the handle of the driver that support this DevicePath\r
+\r
+  @param  DevicePath            Device Path of the File to connect\r
+  @param  Handle                Handle of the driver that support this DevicePath\r
+  @param  RemainingDevicePath   Remaining DevicePath nodes that do not match the driver DevicePath\r
+\r
+  @retval EFI_SUCCESS           A driver that matches the Device Path has been found\r
+  @retval EFI_NOT_FOUND         No handles match the search.\r
+  @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+BdsConnectDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  OUT EFI_HANDLE                *Handle,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath\r
+  )\r
+{\r
+  return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);\r
+}\r
+\r
 BOOLEAN\r
 BdsFileSystemSupport (\r
   IN EFI_DEVICE_PATH *DevicePath,\r
@@ -743,7 +769,7 @@ BdsTftpLoadImage (
   EFI_STATUS                  Status;\r
   EFI_PXE_BASE_CODE_PROTOCOL  *Pxe;\r
   UINT64                      TftpBufferSize;\r
-  VOID*                       TftpBuffer;\r
+  UINT64                      TftpTransferSize;\r
   EFI_IP_ADDRESS              ServerIp;\r
   IPv4_DEVICE_PATH*           IPv4DevicePathNode;\r
   FILEPATH_DEVICE_PATH*       FilePathDevicePath;\r
@@ -805,6 +831,7 @@ BdsTftpLoadImage (
   }\r
   UnicodeStrToAsciiStr (FilePathDevicePath->PathName, AsciiPathName);\r
 \r
+  // Try to get the size (required the TFTP server to have "tsize" extension)\r
   Status = Pxe->Mtftp (\r
                   Pxe,\r
                   EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
@@ -817,37 +844,83 @@ BdsTftpLoadImage (
                   NULL,\r
                   FALSE\r
                   );\r
-  if (EFI_ERROR(Status)) {\r
+  // Pxe.Mtftp replies EFI_PROTOCOL_ERROR if tsize is not supported by the TFTP server\r
+  if (EFI_ERROR (Status) && (Status != EFI_PROTOCOL_ERROR)) {\r
     if (Status == EFI_TFTP_ERROR) {\r
       DEBUG((EFI_D_ERROR, "TFTP Error: Fail to get the size of the file\n"));\r
     }\r
     goto EXIT;\r
   }\r
 \r
-  // Allocate a buffer to hold the whole file.\r
-  TftpBuffer = AllocatePool (TftpBufferSize);\r
-  if (TftpBuffer == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto EXIT;\r
-  }\r
+  //\r
+  // Two cases:\r
+  //   1) the file size is unknown (tsize extension not supported)\r
+  //   2) tsize returned the file size\r
+  //\r
+  if (Status == EFI_PROTOCOL_ERROR) {\r
+    for (TftpBufferSize = SIZE_8MB; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize); TftpBufferSize += SIZE_8MB) {\r
+      // Allocate a buffer to hold the whole file.\r
+      Status = gBS->AllocatePages (\r
+                      Type,\r
+                      EfiBootServicesCode,\r
+                      EFI_SIZE_TO_PAGES (TftpBufferSize),\r
+                      Image\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Failed to allocate space for image: %r\n", Status));\r
+        goto EXIT;\r
+      }\r
 \r
-  Status = Pxe->Mtftp (\r
-                  Pxe,\r
-                  EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
-                  TftpBuffer,\r
-                  FALSE,\r
-                  &TftpBufferSize,\r
-                  NULL,\r
-                  &ServerIp,\r
-                  (UINT8*)AsciiPathName,\r
-                  NULL,\r
-                  FALSE\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (TftpBuffer);\r
-  } else if (ImageSize != NULL) {\r
-    *Image = (UINTN)TftpBuffer;\r
-    *ImageSize = (UINTN)TftpBufferSize;\r
+      TftpTransferSize = TftpBufferSize;\r
+      Status = Pxe->Mtftp (\r
+                      Pxe,\r
+                      EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
+                      (VOID *)(UINTN)*Image,\r
+                      FALSE,\r
+                      &TftpTransferSize,\r
+                      NULL,\r
+                      &ServerIp,\r
+                      (UINT8*)AsciiPathName,\r
+                      NULL,\r
+                      FALSE\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));\r
+      } else {\r
+        *ImageSize = (UINTN)TftpBufferSize;\r
+        break;\r
+      }\r
+    }\r
+  } else {\r
+    // Allocate a buffer to hold the whole file.\r
+    Status = gBS->AllocatePages (\r
+                    Type,\r
+                    EfiBootServicesCode,\r
+                    EFI_SIZE_TO_PAGES (TftpBufferSize),\r
+                    Image\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Failed to allocate space for kernel image: %r\n", Status));\r
+      goto EXIT;\r
+    }\r
+\r
+    Status = Pxe->Mtftp (\r
+                    Pxe,\r
+                    EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
+                    (VOID *)(UINTN)*Image,\r
+                    FALSE,\r
+                    &TftpBufferSize,\r
+                    NULL,\r
+                    &ServerIp,\r
+                    (UINT8*)AsciiPathName,\r
+                    NULL,\r
+                    FALSE\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));\r
+    } else {\r
+      *ImageSize = (UINTN)TftpBufferSize;\r
+    }\r
   }\r
 \r
 EXIT:\r
@@ -866,8 +939,8 @@ BDS_FILE_LOADER FileLoaders[] = {
 };\r
 \r
 EFI_STATUS\r
-BdsLoadImage (\r
-  IN     EFI_DEVICE_PATH       *DevicePath,\r
+BdsLoadImageAndUpdateDevicePath (\r
+  IN OUT EFI_DEVICE_PATH       **DevicePath,\r
   IN     EFI_ALLOCATE_TYPE     Type,\r
   IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
   OUT    UINTN                 *FileSize\r
@@ -878,15 +951,15 @@ BdsLoadImage (
   EFI_DEVICE_PATH *RemainingDevicePath;\r
   BDS_FILE_LOADER*  FileLoader;\r
 \r
-  Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
+  Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   FileLoader = FileLoaders;\r
   while (FileLoader->Support != NULL) {\r
-    if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) {\r
-      return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);\r
+    if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {\r
+      return FileLoader->LoadImage (*DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);\r
     }\r
     FileLoader++;\r
   }\r
@@ -894,6 +967,17 @@ BdsLoadImage (
   return EFI_UNSUPPORTED;\r
 }\r
 \r
+EFI_STATUS\r
+BdsLoadImage (\r
+  IN     EFI_DEVICE_PATH       *DevicePath,\r
+  IN     EFI_ALLOCATE_TYPE     Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+  OUT    UINTN                 *FileSize\r
+  )\r
+{\r
+  return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);\r
+}\r
+\r
 /**\r
   Start an EFI Application from a Device Path\r
 \r
@@ -920,7 +1004,7 @@ BdsStartEfiApplication (
   EFI_LOADED_IMAGE_PROTOCOL*   LoadedImage;\r
 \r
   // Find the nearest supported file loader\r
-  Status = BdsLoadImage (DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);\r
+  Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r