-/** @file
-*
-* Copyright (c) 2011, ARM Limited. All rights reserved.
-*
-* This program and the accompanying materials
-* are licensed and made available under the terms and conditions of the BSD License
-* which accompanies this distribution. The full text of the license may be found at
-* http://opensource.org/licenses/bsd-license.php
-*
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-*
-**/
-
-#include "BdsInternal.h"
-
-#include <Protocol/UsbIo.h>
-#include <Protocol/DiskIo.h>
-
-#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
-
-// Extract the FilePath from the Device Path
-CHAR16*
-BdsExtractFilePathFromDevicePath (
- IN CONST CHAR16 *StrDevicePath,
- IN UINTN NumberDevicePathNode
- )
-{
- UINTN Node;
- CHAR16 *Str;
-
- Str = (CHAR16*)StrDevicePath;
- Node = 0;
- while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
- if ((*Str == L'/') || (*Str == L'\\')) {
- Node++;
- }
- Str++;
- }
-
- if (*Str == L'\0') {
- return NULL;
- } else {
- return Str;
- }
-}
-
-BOOLEAN
-BdsIsRemovableUsb (
- IN EFI_DEVICE_PATH* DevicePath
- )
-{
- return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
- (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));
-}
-
-EFI_STATUS
-BdsGetDeviceUsb (
- IN EFI_DEVICE_PATH* RemovableDevicePath,
- OUT EFI_HANDLE* DeviceHandle,
- OUT EFI_DEVICE_PATH** NewDevicePath
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINTN UsbIoHandleCount;
- EFI_HANDLE *UsbIoBuffer;
- EFI_DEVICE_PATH* UsbIoDevicePath;
- EFI_DEVICE_PATH* TmpDevicePath;
- USB_WWID_DEVICE_PATH* WwidDevicePath1;
- USB_WWID_DEVICE_PATH* WwidDevicePath2;
- USB_CLASS_DEVICE_PATH* UsbClassDevicePath1;
- USB_CLASS_DEVICE_PATH* UsbClassDevicePath2;
-
- // Get all the UsbIo handles
- UsbIoHandleCount = 0;
- Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
- if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) {
- return Status;
- }
-
- // Check if one of the handles matches the USB description
- for (Index = 0; Index < UsbIoHandleCount; Index++) {
- Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &UsbIoDevicePath);
- if (!EFI_ERROR(Status)) {
- TmpDevicePath = UsbIoDevicePath;
- while (!IsDevicePathEnd (TmpDevicePath)) {
- // Check if the Device Path node is a USB Removable device Path node
- if (BdsIsRemovableUsb (TmpDevicePath)) {
- if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {
- WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;
- WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;
- if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&
- (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&
- (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0))
- {
- *DeviceHandle = UsbIoBuffer[Index];
- // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
- *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));
- return EFI_SUCCESS;
- }
- } else {
- UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;
- UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;
- if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&
- (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&
- (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&
- (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&
- (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))
- {
- *DeviceHandle = UsbIoBuffer[Index];
- // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
- *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));
- return EFI_SUCCESS;
- }
- }
- }
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-BOOLEAN
-BdsIsRemovableHd (
- IN EFI_DEVICE_PATH* DevicePath
- )
-{
- return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);
-}
-
-EFI_STATUS
-BdsGetDeviceHd (
- IN EFI_DEVICE_PATH* RemovableDevicePath,
- OUT EFI_HANDLE* DeviceHandle,
- OUT EFI_DEVICE_PATH** NewDevicePath
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINTN PartitionHandleCount;
- EFI_HANDLE *PartitionBuffer;
- EFI_DEVICE_PATH* PartitionDevicePath;
- EFI_DEVICE_PATH* TmpDevicePath;
- HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1;
- HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2;
-
- // Get all the DiskIo handles
- PartitionHandleCount = 0;
- Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);
- if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) {
- return Status;
- }
-
- // Check if one of the handles matches the Hard Disk Description
- for (Index = 0; Index < PartitionHandleCount; Index++) {
- Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &PartitionDevicePath);
- if (!EFI_ERROR(Status)) {
- TmpDevicePath = PartitionDevicePath;
- while (!IsDevicePathEnd (TmpDevicePath)) {
- // Check if the Device Path node is a HD Removable device Path node
- if (BdsIsRemovableHd (TmpDevicePath)) {
- HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;
- HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;
- if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&
- (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&
- (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))
- {
- *DeviceHandle = PartitionBuffer[Index];
- // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
- *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath));
- return EFI_SUCCESS;
- }
- }
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/*BOOLEAN
-BdsIsRemovableCdrom (
- IN EFI_DEVICE_PATH* DevicePath
- )
-{
- return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
-}
-
-EFI_STATUS
-BdsGetDeviceCdrom (
- IN EFI_DEVICE_PATH* RemovableDevicePath,
- OUT EFI_HANDLE* DeviceHandle,
- OUT EFI_DEVICE_PATH** DevicePath
- )
-{
- ASSERT(0);
- return EFI_UNSUPPORTED;
-}*/
-
-typedef BOOLEAN
-(*BDS_IS_REMOVABLE) (
- IN EFI_DEVICE_PATH* DevicePath
- );
-
-typedef EFI_STATUS
-(*BDS_GET_DEVICE) (
- IN EFI_DEVICE_PATH* RemovableDevicePath,
- OUT EFI_HANDLE* DeviceHandle,
- OUT EFI_DEVICE_PATH** DevicePath
- );
-
-typedef struct {
- BDS_IS_REMOVABLE IsRemovable;
- BDS_GET_DEVICE GetDevice;
-} BDS_REMOVABLE_DEVICE_SUPPORT;
-
-BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = {
- { BdsIsRemovableUsb, BdsGetDeviceUsb },
- { BdsIsRemovableHd, BdsGetDeviceHd },
- //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
-};
-
-STATIC
-BOOLEAN
-IsRemovableDevice (
- IN EFI_DEVICE_PATH* DevicePath
- )
-{
- UINTN Index;
- EFI_DEVICE_PATH* TmpDevicePath;
-
- TmpDevicePath = DevicePath;
- while (!IsDevicePathEnd (TmpDevicePath)) {
- for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
- if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) {
- return TRUE;
- }
- }
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- return FALSE;
-}
-
-STATIC
-EFI_STATUS
-TryRemovableDevice (
- IN EFI_DEVICE_PATH* DevicePath,
- OUT EFI_HANDLE* DeviceHandle,
- OUT EFI_DEVICE_PATH** NewDevicePath
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- EFI_DEVICE_PATH* TmpDevicePath;
- BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;
- EFI_DEVICE_PATH* RemovableDevicePath;
- BOOLEAN RemovableFound;
-
- RemovableDevice = NULL;
- RemovableDevicePath = NULL;
- RemovableFound = FALSE;
- TmpDevicePath = DevicePath;
-
- while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
- for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
- RemovableDevice = &RemovableDeviceSupport[Index];
- if (RemovableDevice->IsRemovable(TmpDevicePath)) {
- RemovableDevicePath = TmpDevicePath;
- RemovableFound = TRUE;
- break;
- }
- }
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- if (!RemovableFound) {
- return EFI_NOT_FOUND;
- }
-
- // Search into the current started drivers
- Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
- if (Status == EFI_NOT_FOUND) {
- // Connect all the drivers
- BdsConnectAllDrivers ();
-
- // Search again into all the drivers
- Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
- }
-
- return Status;
-}
-
-/**
- Connect a Device Path and return the handle of the driver that support this DevicePath
-
- @param DevicePath Device Path of the File to connect
- @param Handle Handle of the driver that support this DevicePath
- @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
-
- @retval EFI_SUCCESS A driver that matches the Device Path has been found
- @retval EFI_NOT_FOUND No handles match the search.
- @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
-
-**/
-EFI_STATUS
-BdsConnectDevicePath (
- IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
- OUT EFI_HANDLE *Handle,
- OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
- )
-{
- EFI_DEVICE_PATH* Remaining;
- EFI_DEVICE_PATH* NewDevicePath;
- EFI_STATUS Status;
-
- if ((DevicePath == NULL) || (Handle == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- do {
- Remaining = DevicePath;
- // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
- // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
- // to point to the remaining part of the device path
- Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
- if (!EFI_ERROR (Status)) {
- // Recursive = FALSE: We do not want to start all the device tree
- Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
- }
-
- /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling
- // NextDevicePathNode() will return an undetermined Device Path Node
- if (!IsDevicePathEnd (RemainingDevicePath)) {
- RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
- }*/
- } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
-
- if (!EFI_ERROR (Status)) {
- // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
- // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
- Remaining = DevicePath;
- Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle);
- if (!EFI_ERROR (Status)) {
- Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
- if (EFI_ERROR (Status)) {
- // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
- if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
- Status = EFI_SUCCESS;
- }
- }
- }
- } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
-
- /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
- if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
- Status = EFI_SUCCESS;
- } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
- Status = EFI_SUCCESS;
- }*/
-
- //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
- Status = EFI_SUCCESS;
- } else {
- Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath);
- if (!EFI_ERROR (Status)) {
- return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);
- }
- }
-
- if (RemainingDevicePath) {
- *RemainingDevicePath = Remaining;
- }
-
- return Status;
-}
-
-BOOLEAN
-BdsFileSystemSupport (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH *RemainingDevicePath
- )
-{
- EFI_STATUS Status;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
-
- Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
-
- return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
-}
-
-EFI_STATUS
-BdsFileSystemLoadImage (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH *RemainingDevicePath,
- IN EFI_ALLOCATE_TYPE Type,
- IN OUT EFI_PHYSICAL_ADDRESS* Image,
- OUT UINTN *ImageSize
- )
-{
- FILEPATH_DEVICE_PATH* FilePathDevicePath;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
- EFI_FILE_PROTOCOL *Fs;
- EFI_STATUS Status;
- EFI_FILE_INFO *FileInfo;
- EFI_FILE_PROTOCOL *File;
- UINTN Size;
-
- ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
-
- FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
-
- Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Try to Open the volume and get root directory
- Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- File = NULL;
- Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- Size = 0;
- File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL);
- FileInfo = AllocatePool (Size);
- Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Get the file size
- Size = FileInfo->FileSize;
- if (ImageSize) {
- *ImageSize = Size;
- }
- FreePool(FileInfo);
-
- Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
- // Try to allocate in any pages if failed to allocate memory at the defined location
- if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
- Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
- }
- if (!EFI_ERROR(Status)) {
- Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
- }
-
- return Status;
-}
-
-BOOLEAN
-BdsMemoryMapSupport (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH *RemainingDevicePath
- )
-{
- return IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
-}
-
-EFI_STATUS
-BdsMemoryMapLoadImage (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH *RemainingDevicePath,
- IN EFI_ALLOCATE_TYPE Type,
- IN OUT EFI_PHYSICAL_ADDRESS* Image,
- OUT UINTN *ImageSize
- )
-{
- EFI_STATUS Status;
- MEMMAP_DEVICE_PATH* MemMapPathDevicePath;
- UINTN Size;
-
- ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP));
-
- MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
-
- Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
- if (Size == 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
- // Try to allocate in any pages if failed to allocate memory at the defined location
- if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
- Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
- }
- if (!EFI_ERROR(Status)) {
- CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
-
- if (ImageSize != NULL) {
- *ImageSize = Size;
- }
- }
-
- return Status;
-}
-
-BOOLEAN
-BdsFirmwareVolumeSupport (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH *RemainingDevicePath
- )
-{
- return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
-}
-
-EFI_STATUS
-BdsFirmwareVolumeLoadImage (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH *RemainingDevicePath,
- IN EFI_ALLOCATE_TYPE Type,
- IN OUT EFI_PHYSICAL_ADDRESS* Image,
- OUT UINTN *ImageSize
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
- EFI_GUID *FvNameGuid;
- EFI_SECTION_TYPE SectionType;
- EFI_FV_FILETYPE FvType;
- EFI_FV_FILE_ATTRIBUTES Attrib;
- UINT32 AuthenticationStatus;
- VOID* ImageBuffer;
-
- ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
-
- Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
- if (FvNameGuid == NULL) {
- Status = EFI_INVALID_PARAMETER;
- }
-
- SectionType = EFI_SECTION_PE32;
- AuthenticationStatus = 0;
- //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
- ImageBuffer = NULL;
- Status = FwVol->ReadSection (
- FwVol,
- FvNameGuid,
- SectionType,
- 0,
- &ImageBuffer,
- ImageSize,
- &AuthenticationStatus
- );
- if (!EFI_ERROR (Status)) {
-#if 0
- // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
- if (Type != AllocateAnyPages) {
- Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
- if (!EFI_ERROR(Status)) {
- CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
- FreePool (ImageBuffer);
- }
- }
-#else
- // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
- Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
- // Try to allocate in any pages if failed to allocate memory at the defined location
- if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
- Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
- }
- if (!EFI_ERROR(Status)) {
- CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
- FreePool (ImageBuffer);
- }
-#endif
- } else {
- // Try a raw file, since a PE32 SECTION does not exist
- Status = FwVol->ReadFile (
- FwVol,
- FvNameGuid,
- NULL,
- ImageSize,
- &FvType,
- &Attrib,
- &AuthenticationStatus
- );
- if (!EFI_ERROR(Status)) {
- Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
- // Try to allocate in any pages if failed to allocate memory at the defined location
- if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
- Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
- }
- if (!EFI_ERROR(Status)) {
- Status = FwVol->ReadFile (
- FwVol,
- FvNameGuid,
- (VOID*)(UINTN)(*Image),
- ImageSize,
- &FvType,
- &Attrib,
- &AuthenticationStatus
- );
- }
- }
- }
- return Status;
-}
-
-BOOLEAN
-BdsPxeSupport (
- IN EFI_DEVICE_PATH* DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH* RemainingDevicePath
- )
-{
- EFI_STATUS Status;
- EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
-
- if (!IsDevicePathEnd(RemainingDevicePath)) {
- return FALSE;
- }
-
- Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
- if (EFI_ERROR (Status)) {
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-EFI_STATUS
-BdsPxeLoadImage (
- IN EFI_DEVICE_PATH* DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH* RemainingDevicePath,
- IN EFI_ALLOCATE_TYPE Type,
- IN OUT EFI_PHYSICAL_ADDRESS *Image,
- OUT UINTN *ImageSize
- )
-{
- EFI_STATUS Status;
- EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;
- UINTN BufferSize;
-
- // Get Load File Protocol attached to the PXE protocol
- Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
- if (!EFI_ERROR(Status) && (ImageSize != NULL)) {
- *ImageSize = BufferSize;
- }
- }
-
- return Status;
-}
-
-BOOLEAN
-BdsTftpSupport (
- IN EFI_DEVICE_PATH* DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH* RemainingDevicePath
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH *NextDevicePath;
- EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
-
- // Validate the Remaining Device Path
- if (IsDevicePathEnd(RemainingDevicePath)) {
- return FALSE;
- }
- if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
- !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
- return FALSE;
- }
- NextDevicePath = NextDevicePathNode (RemainingDevicePath);
- if (IsDevicePathEnd(NextDevicePath)) {
- return FALSE;
- }
- if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
- return FALSE;
- }
-
- Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
- if (EFI_ERROR (Status)) {
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-EFI_STATUS
-BdsTftpLoadImage (
- IN EFI_DEVICE_PATH* DevicePath,
- IN EFI_HANDLE Handle,
- IN EFI_DEVICE_PATH* RemainingDevicePath,
- IN EFI_ALLOCATE_TYPE Type,
- IN OUT EFI_PHYSICAL_ADDRESS *Image,
- OUT UINTN *ImageSize
- )
-{
- EFI_STATUS Status;
- EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
- UINT64 TftpBufferSize;
- VOID* TftpBuffer;
- EFI_IP_ADDRESS ServerIp;
- IPv4_DEVICE_PATH* IPv4DevicePathNode;
- FILEPATH_DEVICE_PATH* FilePathDevicePath;
- EFI_IP_ADDRESS LocalIp;
-
- ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP));
-
- IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
- FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
-
- Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- Status = Pxe->Start (Pxe, FALSE);
- if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
- return Status;
- }
-
- if (!IPv4DevicePathNode->StaticIpAddress) {
- Status = Pxe->Dhcp(Pxe, TRUE);
- } else {
- CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
- Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);
- }
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
-
- Status = Pxe->Mtftp (
- Pxe,
- EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
- NULL,
- FALSE,
- &TftpBufferSize,
- NULL,
- &ServerIp,
- (UINT8 *)FilePathDevicePath->PathName,
- NULL,
- TRUE
- );
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Allocate a buffer to hold the whole file.
- TftpBuffer = AllocatePool(TftpBufferSize);
- if (TftpBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = Pxe->Mtftp (
- Pxe,
- EFI_PXE_BASE_CODE_TFTP_READ_FILE,
- TftpBuffer,
- FALSE,
- &TftpBufferSize,
- NULL,
- &ServerIp,
- (UINT8 *)FilePathDevicePath->PathName,
- NULL,
- FALSE
- );
- if (EFI_ERROR(Status)) {
- FreePool(TftpBuffer);
- } else if (ImageSize != NULL) {
- *ImageSize = (UINTN)TftpBufferSize;
- }
-
- return Status;
-}
-
-BDS_FILE_LOADER FileLoaders[] = {
- { BdsFileSystemSupport, BdsFileSystemLoadImage },
- { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
- //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
- { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
- { BdsPxeSupport, BdsPxeLoadImage },
- { BdsTftpSupport, BdsTftpLoadImage },
- { NULL, NULL }
-};
-
-EFI_STATUS
-BdsLoadImage (
- IN EFI_DEVICE_PATH *DevicePath,
- IN EFI_ALLOCATE_TYPE Type,
- IN OUT EFI_PHYSICAL_ADDRESS* Image,
- OUT UINTN *FileSize
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE Handle;
- EFI_DEVICE_PATH *RemainingDevicePath;
- BDS_FILE_LOADER* FileLoader;
-
- Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- FileLoader = FileLoaders;
- while (FileLoader->Support != NULL) {
- if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) {
- return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
- }
- FileLoader++;
- }
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- Start an EFI Application from a Device Path
-
- @param ParentImageHandle Handle of the calling image
- @param DevicePath Location of the EFI Application
-
- @retval EFI_SUCCESS All drivers have been connected
- @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
- @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
-
-**/
-EFI_STATUS
-BdsStartEfiApplication (
- IN EFI_HANDLE ParentImageHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE ImageHandle;
- EFI_PHYSICAL_ADDRESS BinaryBuffer;
- UINTN BinarySize;
-
- // Find the nearest supported file loader
- Status = BdsLoadImage (DevicePath, AllocateAnyPages,&BinaryBuffer,&BinarySize);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Load the image from the Buffer with Boot Services function
- Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- // Before calling the image, enable the Watchdog Timer for the 5 Minute period
- gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
- // Start the image
- Status = gBS->StartImage (ImageHandle, NULL, NULL);
- // Clear the Watchdog Timer after the image returns
- gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
-
- return Status;
-}
+/** @file\r
+*\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
+* 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
+#include "BdsInternal.h"\r
+\r
+#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
+// Extract the FilePath from the Device Path\r
+CHAR16*\r
+BdsExtractFilePathFromDevicePath (\r
+ IN CONST CHAR16 *StrDevicePath,\r
+ IN UINTN NumberDevicePathNode\r
+ )\r
+{\r
+ UINTN Node;\r
+ CHAR16 *Str;\r
+\r
+ Str = (CHAR16*)StrDevicePath;\r
+ Node = 0;\r
+ while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {\r
+ if ((*Str == L'/') || (*Str == L'\\')) {\r
+ Node++;\r
+ }\r
+ Str++;\r
+ }\r
+\r
+ if (*Str == L'\0') {\r
+ return NULL;\r
+ } else {\r
+ return Str;\r
+ }\r
+}\r
+\r
+BOOLEAN\r
+BdsIsRemovableUsb (\r
+ IN EFI_DEVICE_PATH* DevicePath\r
+ )\r
+{\r
+ return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||\r
+ (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));\r
+}\r
+\r
+EFI_STATUS\r
+BdsGetDeviceUsb (\r
+ IN EFI_DEVICE_PATH* RemovableDevicePath,\r
+ OUT EFI_HANDLE* DeviceHandle,\r
+ OUT EFI_DEVICE_PATH** NewDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN UsbIoHandleCount;\r
+ EFI_HANDLE *UsbIoBuffer;\r
+ EFI_DEVICE_PATH* UsbIoDevicePath;\r
+ EFI_DEVICE_PATH* TmpDevicePath;\r
+ USB_WWID_DEVICE_PATH* WwidDevicePath1;\r
+ USB_WWID_DEVICE_PATH* WwidDevicePath2;\r
+ USB_CLASS_DEVICE_PATH* UsbClassDevicePath1;\r
+ USB_CLASS_DEVICE_PATH* UsbClassDevicePath2;\r
+\r
+ // Get all the UsbIo handles\r
+ UsbIoHandleCount = 0;\r
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);\r
+ if (EFI_ERROR (Status) || (UsbIoHandleCount == 0)) {\r
+ return Status;\r
+ }\r
+\r
+ // Check if one of the handles matches the USB description\r
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);\r
+ if (!EFI_ERROR (Status)) {\r
+ TmpDevicePath = UsbIoDevicePath;\r
+ while (!IsDevicePathEnd (TmpDevicePath)) {\r
+ // Check if the Device Path node is a USB Removable device Path node\r
+ if (BdsIsRemovableUsb (TmpDevicePath)) {\r
+ if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {\r
+ WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;\r
+ WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;\r
+ if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&\r
+ (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&\r
+ (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) == 0))\r
+ {\r
+ *DeviceHandle = UsbIoBuffer[Index];\r
+ // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
+ *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));\r
+ return EFI_SUCCESS;\r
+ }\r
+ } else {\r
+ UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;\r
+ UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;\r
+ if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&\r
+ (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&\r
+ (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&\r
+ (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&\r
+ (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))\r
+ {\r
+ *DeviceHandle = UsbIoBuffer[Index];\r
+ // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
+ *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+BOOLEAN\r
+BdsIsRemovableHd (\r
+ IN EFI_DEVICE_PATH* DevicePath\r
+ )\r
+{\r
+ return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsGetDeviceHd (\r
+ IN EFI_DEVICE_PATH* RemovableDevicePath,\r
+ OUT EFI_HANDLE* DeviceHandle,\r
+ OUT EFI_DEVICE_PATH** NewDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN PartitionHandleCount;\r
+ EFI_HANDLE *PartitionBuffer;\r
+ EFI_DEVICE_PATH* PartitionDevicePath;\r
+ EFI_DEVICE_PATH* TmpDevicePath;\r
+ HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1;\r
+ HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2;\r
+\r
+ // Get all the DiskIo handles\r
+ PartitionHandleCount = 0;\r
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);\r
+ if (EFI_ERROR (Status) || (PartitionHandleCount == 0)) {\r
+ return Status;\r
+ }\r
+\r
+ // Check if one of the handles matches the Hard Disk Description\r
+ for (Index = 0; Index < PartitionHandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);\r
+ if (!EFI_ERROR (Status)) {\r
+ TmpDevicePath = PartitionDevicePath;\r
+ while (!IsDevicePathEnd (TmpDevicePath)) {\r
+ // Check if the Device Path node is a HD Removable device Path node\r
+ if (BdsIsRemovableHd (TmpDevicePath)) {\r
+ HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;\r
+ HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;\r
+ if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&\r
+ (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&\r
+ (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))\r
+ {\r
+ *DeviceHandle = PartitionBuffer[Index];\r
+ // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
+ *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode (RemovableDevicePath));\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/*BOOLEAN\r
+BdsIsRemovableCdrom (\r
+ IN EFI_DEVICE_PATH* DevicePath\r
+ )\r
+{\r
+ return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsGetDeviceCdrom (\r
+ IN EFI_DEVICE_PATH* RemovableDevicePath,\r
+ OUT EFI_HANDLE* DeviceHandle,\r
+ OUT EFI_DEVICE_PATH** DevicePath\r
+ )\r
+{\r
+ ASSERT(0);\r
+ return EFI_UNSUPPORTED;\r
+}*/\r
+\r
+typedef BOOLEAN\r
+(*BDS_IS_REMOVABLE) (\r
+ IN EFI_DEVICE_PATH* DevicePath\r
+ );\r
+\r
+typedef EFI_STATUS\r
+(*BDS_GET_DEVICE) (\r
+ IN EFI_DEVICE_PATH* RemovableDevicePath,\r
+ OUT EFI_HANDLE* DeviceHandle,\r
+ OUT EFI_DEVICE_PATH** DevicePath\r
+ );\r
+\r
+typedef struct {\r
+ BDS_IS_REMOVABLE IsRemovable;\r
+ BDS_GET_DEVICE GetDevice;\r
+} BDS_REMOVABLE_DEVICE_SUPPORT;\r
+\r
+BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = {\r
+ { BdsIsRemovableUsb, BdsGetDeviceUsb },\r
+ { BdsIsRemovableHd, BdsGetDeviceHd },\r
+ //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }\r
+};\r
+\r
+STATIC\r
+BOOLEAN\r
+IsRemovableDevice (\r
+ IN EFI_DEVICE_PATH* DevicePath\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH* TmpDevicePath;\r
+\r
+ TmpDevicePath = DevicePath;\r
+ while (!IsDevicePathEnd (TmpDevicePath)) {\r
+ for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {\r
+ if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+TryRemovableDevice (\r
+ IN EFI_DEVICE_PATH* DevicePath,\r
+ OUT EFI_HANDLE* DeviceHandle,\r
+ OUT EFI_DEVICE_PATH** NewDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH* TmpDevicePath;\r
+ BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;\r
+ EFI_DEVICE_PATH* RemovableDevicePath;\r
+ BOOLEAN RemovableFound;\r
+\r
+ RemovableDevice = NULL;\r
+ RemovableDevicePath = NULL;\r
+ RemovableFound = FALSE;\r
+ TmpDevicePath = DevicePath;\r
+\r
+ while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {\r
+ for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {\r
+ RemovableDevice = &RemovableDeviceSupport[Index];\r
+ if (RemovableDevice->IsRemovable (TmpDevicePath)) {\r
+ RemovableDevicePath = TmpDevicePath;\r
+ RemovableFound = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+ }\r
+\r
+ if (!RemovableFound) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ // Search into the current started drivers\r
+ Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ // Connect all the drivers\r
+ BdsConnectAllDrivers ();\r
+\r
+ // Search again into all the drivers\r
+ Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\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) || (*DevicePath == NULL) || (Handle == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PreviousHandle = NULL;\r
+ do {\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
+ 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
+ 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
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ // If the last node is a Memory Map Device Path just return EFI_SUCCESS.\r
+ if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {\r
+\r
+ /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly\r
+ if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {\r
+ Status = EFI_SUCCESS;\r
+ } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
+ Status = EFI_SUCCESS;\r
+ }*/\r
+\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
+ if (!EFI_ERROR (Status)) {\r
+ Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);\r
+ *DevicePath = NewDevicePath;\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (RemainingDevicePath) {\r
+ *RemainingDevicePath = Remaining;\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
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
+\r
+ return (!EFI_ERROR (Status) && IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));\r
+}\r
+\r
+EFI_STATUS\r
+BdsFileSystemLoadImage (\r
+ IN EFI_DEVICE_PATH *DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH *RemainingDevicePath,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+ OUT UINTN *ImageSize\r
+ )\r
+{\r
+ FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;\r
+ EFI_FILE_PROTOCOL *Fs;\r
+ EFI_STATUS Status;\r
+ EFI_FILE_INFO *FileInfo;\r
+ EFI_FILE_PROTOCOL *File;\r
+ UINTN Size;\r
+\r
+ ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));\r
+\r
+ FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Try to Open the volume and get root directory\r
+ Status = FsProtocol->OpenVolume (FsProtocol, &Fs);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ File = NULL;\r
+ Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Size = 0;\r
+ File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);\r
+ FileInfo = AllocatePool (Size);\r
+ Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Get the file size\r
+ Size = FileInfo->FileSize;\r
+ if (ImageSize) {\r
+ *ImageSize = Size;\r
+ }\r
+ FreePool (FileInfo);\r
+\r
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+ // Try to allocate in any pages if failed to allocate memory at the defined location\r
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsMemoryMapSupport (\r
+ IN EFI_DEVICE_PATH *DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH *RemainingDevicePath\r
+ )\r
+{\r
+ return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||\r
+ IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsMemoryMapLoadImage (\r
+ IN EFI_DEVICE_PATH *DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH *RemainingDevicePath,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+ OUT UINTN *ImageSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MEMMAP_DEVICE_PATH* MemMapPathDevicePath;\r
+ UINTN Size;\r
+\r
+ if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {\r
+ MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;\r
+ } else {\r
+ ASSERT (IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));\r
+ MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;\r
+ }\r
+\r
+ Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;\r
+ if (Size == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+ // Try to allocate in any pages if failed to allocate memory at the defined location\r
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);\r
+\r
+ if (ImageSize != NULL) {\r
+ *ImageSize = Size;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsFirmwareVolumeSupport (\r
+ IN EFI_DEVICE_PATH *DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH *RemainingDevicePath\r
+ )\r
+{\r
+ return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsFirmwareVolumeLoadImage (\r
+ IN EFI_DEVICE_PATH *DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH *RemainingDevicePath,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+ OUT UINTN *ImageSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;\r
+ EFI_GUID *FvNameGuid;\r
+ EFI_SECTION_TYPE SectionType;\r
+ EFI_FV_FILETYPE FvType;\r
+ EFI_FV_FILE_ATTRIBUTES Attrib;\r
+ UINT32 AuthenticationStatus;\r
+ VOID* ImageBuffer;\r
+\r
+ ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);\r
+ if (FvNameGuid == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SectionType = EFI_SECTION_PE32;\r
+ AuthenticationStatus = 0;\r
+ //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.\r
+ ImageBuffer = NULL;\r
+ Status = FwVol->ReadSection (\r
+ FwVol,\r
+ FvNameGuid,\r
+ SectionType,\r
+ 0,\r
+ &ImageBuffer,\r
+ ImageSize,\r
+ &AuthenticationStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+#if 0\r
+ // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements\r
+ if (Type != AllocateAnyPages) {\r
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
+ FreePool (ImageBuffer);\r
+ }\r
+ }\r
+#else\r
+ // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation\r
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+ // Try to allocate in any pages if failed to allocate memory at the defined location\r
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
+ FreePool (ImageBuffer);\r
+ }\r
+#endif\r
+ } else {\r
+ // Try a raw file, since a PE32 SECTION does not exist\r
+ Status = FwVol->ReadFile (\r
+ FwVol,\r
+ FvNameGuid,\r
+ NULL,\r
+ ImageSize,\r
+ &FvType,\r
+ &Attrib,\r
+ &AuthenticationStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+ // Try to allocate in any pages if failed to allocate memory at the defined location\r
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FwVol->ReadFile (\r
+ FwVol,\r
+ FvNameGuid,\r
+ (VOID*)(UINTN)(*Image),\r
+ ImageSize,\r
+ &FvType,\r
+ &Attrib,\r
+ &AuthenticationStatus\r
+ );\r
+ }\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsPxeSupport (\r
+ IN EFI_DEVICE_PATH* DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH* RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;\r
+\r
+ if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+BdsPxeLoadImage (\r
+ IN EFI_DEVICE_PATH* DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH* RemainingDevicePath,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *Image,\r
+ OUT UINTN *ImageSize\r
+ )\r
+{\r
+ 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
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));\r
+ if (!EFI_ERROR (Status) && (ImageSize != NULL)) {\r
+ *ImageSize = BufferSize;\r
+ }\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
+BOOLEAN\r
+BdsTftpSupport (\r
+ IN EFI_DEVICE_PATH* DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH* RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH *NextDevicePath;\r
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
+\r
+ // Validate the Remaining Device Path\r
+ if (IsDevicePathEnd (RemainingDevicePath)) {\r
+ return FALSE;\r
+ }\r
+ if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&\r
+ !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {\r
+ return FALSE;\r
+ }\r
+ NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
+ if (IsDevicePathEnd (NextDevicePath)) {\r
+ return FALSE;\r
+ }\r
+ if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+BdsTftpLoadImage (\r
+ IN EFI_DEVICE_PATH* DevicePath,\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DEVICE_PATH* RemainingDevicePath,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *Image,\r
+ OUT UINTN *ImageSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PXE_BASE_CODE_PROTOCOL *Pxe;\r
+ UINT64 TftpBufferSize;\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
+ IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;\r
+ FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
+\r
+ Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = Pxe->Start (Pxe, FALSE);\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ return Status;\r
+ }\r
+\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
+ NULL,\r
+ FALSE,\r
+ &TftpBufferSize,\r
+ NULL,\r
+ &ServerIp,\r
+ (UINT8*)AsciiPathName,\r
+ NULL,\r
+ FALSE\r
+ );\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
+ //\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
+ 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
+BDS_FILE_LOADER FileLoaders[] = {\r
+ { BdsFileSystemSupport, BdsFileSystemLoadImage },\r
+ { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },\r
+ //{ BdsLoadFileSupport, BdsLoadFileLoadImage },\r
+ { BdsMemoryMapSupport, BdsMemoryMapLoadImage },\r
+ { BdsPxeSupport, BdsPxeLoadImage },\r
+ { BdsTftpSupport, BdsTftpLoadImage },\r
+ { NULL, NULL }\r
+};\r
+\r
+EFI_STATUS\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
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ EFI_DEVICE_PATH *RemainingDevicePath;\r
+ BDS_FILE_LOADER* FileLoader;\r
+\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
+ }\r
+ FileLoader++;\r
+ }\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
+ @param ParentImageHandle Handle of the calling image\r
+ @param DevicePath Location of the EFI Application\r
+\r
+ @retval EFI_SUCCESS All drivers have been connected\r
+ @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsStartEfiApplication (\r
+ IN EFI_HANDLE ParentImageHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN UINTN LoadOptionsSize,\r
+ IN VOID* LoadOptions\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE ImageHandle;\r
+ EFI_PHYSICAL_ADDRESS BinaryBuffer;\r
+ UINTN BinarySize;\r
+ EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;\r
+\r
+ // Find the nearest supported file loader\r
+ Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Load the image from the Buffer with Boot Services function\r
+ Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Passed LoadOptions to the EFI Application\r
+ if (LoadOptionsSize != 0) {\r
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ LoadedImage->LoadOptionsSize = LoadOptionsSize;\r
+ LoadedImage->LoadOptions = LoadOptions;\r
+ }\r
+\r
+ // Before calling the image, enable the Watchdog Timer for the 5 Minute period\r
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
+ // Start the image\r
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
+ // Clear the Watchdog Timer after the image returns\r
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+\r
+ return Status;\r
+}\r