]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/BdsLib/BdsFilePath.c
ARM Packages: Corrected non-DOS line endings
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsFilePath.c
index 2f8788ad1f56daeca66db165c27451baba30abb1..f754b8899bdc7d397b3c313a67839486d296aa5f 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 *\r
-*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+*  Copyright (c) 2011-2014, 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
@@ -17,6 +17,7 @@
 #include <Protocol/UsbIo.h>\r
 #include <Protocol/DiskIo.h>\r
 #include <Protocol/LoadedImage.h>\r
+#include <Protocol/SimpleNetwork.h>\r
 \r
 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))\r
 \r
@@ -299,35 +300,24 @@ 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
 \r
-  if ((DevicePath == NULL) || (Handle == NULL)) {\r
+  if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   do {\r
-    Remaining = DevicePath;\r
+    Remaining = *DevicePath;\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
@@ -347,7 +337,7 @@ BdsConnectDevicePath (
   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
@@ -370,9 +360,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
@@ -383,6 +375,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
@@ -661,6 +675,7 @@ BdsPxeLoadImage (
   EFI_STATUS              Status;\r
   EFI_LOAD_FILE_PROTOCOL  *LoadFileProtocol;\r
   UINTN                   BufferSize;\r
+  EFI_PXE_BASE_CODE_PROTOCOL *Pxe;\r
 \r
   // Get Load File Protocol attached to the PXE protocol\r
   Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);\r
@@ -681,6 +696,15 @@ BdsPxeLoadImage (
     }\r
   }\r
 \r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
+    if (!EFI_ERROR(Status)) {\r
+      // If PXE is already started, we stop it\r
+      Pxe->Stop (Pxe);\r
+      // And we try again\r
+      return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);\r
+    }\r
+  }\r
   return Status;\r
 }\r
 \r
@@ -732,11 +756,13 @@ 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
   EFI_IP_ADDRESS              LocalIp;\r
+  CHAR8*                      AsciiPathName;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
 \r
   ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));\r
 \r
@@ -753,18 +779,46 @@ BdsTftpLoadImage (
     return Status;\r
   }\r
 \r
-  if (!IPv4DevicePathNode->StaticIpAddress) {\r
-    Status = Pxe->Dhcp(Pxe, TRUE);\r
-  } else {\r
-    CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
-    Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);\r
-  }\r
-  if (EFI_ERROR (Status)) {\r
+  do {\r
+    if (!IPv4DevicePathNode->StaticIpAddress) {\r
+      Status = Pxe->Dhcp (Pxe, TRUE);\r
+    } else {\r
+      CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
+      Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);\r
+    }\r
+\r
+    // If an IP Address has already been set and a different static IP address is requested then restart\r
+    // the Network service.\r
+    if (Status == EFI_ALREADY_STARTED) {\r
+      Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&Snp);\r
+      if (!EFI_ERROR (Status) && IPv4DevicePathNode->StaticIpAddress &&\r
+          (CompareMem (&Snp->Mode->CurrentAddress, &IPv4DevicePathNode->LocalIpAddress, sizeof(EFI_MAC_ADDRESS)) != 0))\r
+      {\r
+        Pxe->Stop (Pxe);\r
+        Status = Pxe->Start (Pxe, FALSE);\r
+        if (EFI_ERROR(Status)) {\r
+          break;\r
+        }\r
+        // After restarting the PXE protocol, we want to try again with our new IP Address\r
+        Status = EFI_ALREADY_STARTED;\r
+      }\r
+    }\r
+  } while (Status == EFI_ALREADY_STARTED);\r
+\r
+  if (EFI_ERROR(Status)) {\r
     return Status;\r
   }\r
 \r
   CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
 \r
+  // Convert the Unicode PathName to Ascii\r
+  AsciiPathName = AllocatePool ((StrLen (FilePathDevicePath->PathName) + 1) * sizeof (CHAR8));\r
+  if (AsciiPathName == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\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
@@ -773,38 +827,91 @@ BdsTftpLoadImage (
                   &TftpBufferSize,\r
                   NULL,\r
                   &ServerIp,\r
-                  (UINT8 *)FilePathDevicePath->PathName,\r
+                  (UINT8*)AsciiPathName,\r
                   NULL,\r
-                  TRUE\r
+                  FALSE\r
                   );\r
-  if (EFI_ERROR (Status)) {\r
-    return 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
-    return EFI_OUT_OF_RESOURCES;\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 *)FilePathDevicePath->PathName,\r
-                  NULL,\r
-                  FALSE\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (TftpBuffer);\r
-  } else if (ImageSize != NULL) {\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
+  FreePool (AsciiPathName);\r
   return Status;\r
 }\r
 \r
@@ -819,8 +926,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
@@ -831,15 +938,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
@@ -847,6 +954,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
@@ -873,7 +991,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