/** @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
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
//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
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
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
}\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
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
};\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
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
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
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