mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 07:10:07 +00:00 
			
		
		
		
	Trailing spaces create issue/warning when generating/applying patches. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <ronald.cron@arm.com> Reviewed-By: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15833 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1025 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1025 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
*
 | 
						|
*  Copyright (c) 2011-2014, 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>
 | 
						|
#include <Protocol/LoadedImage.h>
 | 
						|
#include <Protocol/SimpleNetwork.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;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
BdsConnectAndUpdateDevicePath (
 | 
						|
  IN OUT 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) || (*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)) {
 | 
						|
      Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);
 | 
						|
      *DevicePath = NewDevicePath;
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (RemainingDevicePath) {
 | 
						|
    *RemainingDevicePath = Remaining;
 | 
						|
  }
 | 
						|
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);
 | 
						|
}
 | 
						|
 | 
						|
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 (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||
 | 
						|
         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;
 | 
						|
 | 
						|
  if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {
 | 
						|
    MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
 | 
						|
  } else {
 | 
						|
    ASSERT (IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));
 | 
						|
    MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
  EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
 | 
						|
 | 
						|
  // 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;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
 | 
						|
    if (!EFI_ERROR(Status)) {
 | 
						|
      // If PXE is already started, we stop it
 | 
						|
      Pxe->Stop (Pxe);
 | 
						|
      // And we try again
 | 
						|
      return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  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;
 | 
						|
  UINT64                      TftpTransferSize;
 | 
						|
  EFI_IP_ADDRESS              ServerIp;
 | 
						|
  IPv4_DEVICE_PATH*           IPv4DevicePathNode;
 | 
						|
  FILEPATH_DEVICE_PATH*       FilePathDevicePath;
 | 
						|
  EFI_IP_ADDRESS              LocalIp;
 | 
						|
  CHAR8*                      AsciiPathName;
 | 
						|
  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
 | 
						|
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    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 an IP Address has already been set and a different static IP address is requested then restart
 | 
						|
    // the Network service.
 | 
						|
    if (Status == EFI_ALREADY_STARTED) {
 | 
						|
      Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&Snp);
 | 
						|
      if (!EFI_ERROR (Status) && IPv4DevicePathNode->StaticIpAddress &&
 | 
						|
          (CompareMem (&Snp->Mode->CurrentAddress, &IPv4DevicePathNode->LocalIpAddress, sizeof(EFI_MAC_ADDRESS)) != 0))
 | 
						|
      {
 | 
						|
        Pxe->Stop (Pxe);
 | 
						|
        Status = Pxe->Start (Pxe, FALSE);
 | 
						|
        if (EFI_ERROR(Status)) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        // After restarting the PXE protocol, we want to try again with our new IP Address
 | 
						|
        Status = EFI_ALREADY_STARTED;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } while (Status == EFI_ALREADY_STARTED);
 | 
						|
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  // Convert the Unicode PathName to Ascii
 | 
						|
  AsciiPathName = AllocatePool ((StrLen (FilePathDevicePath->PathName) + 1) * sizeof (CHAR8));
 | 
						|
  if (AsciiPathName == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  UnicodeStrToAsciiStr (FilePathDevicePath->PathName, AsciiPathName);
 | 
						|
 | 
						|
  // Try to get the size (required the TFTP server to have "tsize" extension)
 | 
						|
  Status = Pxe->Mtftp (
 | 
						|
                  Pxe,
 | 
						|
                  EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
 | 
						|
                  NULL,
 | 
						|
                  FALSE,
 | 
						|
                  &TftpBufferSize,
 | 
						|
                  NULL,
 | 
						|
                  &ServerIp,
 | 
						|
                  (UINT8*)AsciiPathName,
 | 
						|
                  NULL,
 | 
						|
                  FALSE
 | 
						|
                  );
 | 
						|
  // Pxe.Mtftp replies EFI_PROTOCOL_ERROR if tsize is not supported by the TFTP server
 | 
						|
  if (EFI_ERROR (Status) && (Status != EFI_PROTOCOL_ERROR)) {
 | 
						|
    if (Status == EFI_TFTP_ERROR) {
 | 
						|
      DEBUG((EFI_D_ERROR, "TFTP Error: Fail to get the size of the file\n"));
 | 
						|
    }
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Two cases:
 | 
						|
  //   1) the file size is unknown (tsize extension not supported)
 | 
						|
  //   2) tsize returned the file size
 | 
						|
  //
 | 
						|
  if (Status == EFI_PROTOCOL_ERROR) {
 | 
						|
    for (TftpBufferSize = SIZE_8MB; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize); TftpBufferSize += SIZE_8MB) {
 | 
						|
      // Allocate a buffer to hold the whole file.
 | 
						|
      Status = gBS->AllocatePages (
 | 
						|
                      Type,
 | 
						|
                      EfiBootServicesCode,
 | 
						|
                      EFI_SIZE_TO_PAGES (TftpBufferSize),
 | 
						|
                      Image
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        DEBUG ((EFI_D_ERROR, "Failed to allocate space for image: %r\n", Status));
 | 
						|
        goto EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      TftpTransferSize = TftpBufferSize;
 | 
						|
      Status = Pxe->Mtftp (
 | 
						|
                      Pxe,
 | 
						|
                      EFI_PXE_BASE_CODE_TFTP_READ_FILE,
 | 
						|
                      (VOID *)(UINTN)*Image,
 | 
						|
                      FALSE,
 | 
						|
                      &TftpTransferSize,
 | 
						|
                      NULL,
 | 
						|
                      &ServerIp,
 | 
						|
                      (UINT8*)AsciiPathName,
 | 
						|
                      NULL,
 | 
						|
                      FALSE
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
 | 
						|
      } else {
 | 
						|
        *ImageSize = (UINTN)TftpBufferSize;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    // Allocate a buffer to hold the whole file.
 | 
						|
    Status = gBS->AllocatePages (
 | 
						|
                    Type,
 | 
						|
                    EfiBootServicesCode,
 | 
						|
                    EFI_SIZE_TO_PAGES (TftpBufferSize),
 | 
						|
                    Image
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Failed to allocate space for kernel image: %r\n", Status));
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = Pxe->Mtftp (
 | 
						|
                    Pxe,
 | 
						|
                    EFI_PXE_BASE_CODE_TFTP_READ_FILE,
 | 
						|
                    (VOID *)(UINTN)*Image,
 | 
						|
                    FALSE,
 | 
						|
                    &TftpBufferSize,
 | 
						|
                    NULL,
 | 
						|
                    &ServerIp,
 | 
						|
                    (UINT8*)AsciiPathName,
 | 
						|
                    NULL,
 | 
						|
                    FALSE
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
 | 
						|
    } else {
 | 
						|
      *ImageSize = (UINTN)TftpBufferSize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
EXIT:
 | 
						|
  FreePool (AsciiPathName);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
BDS_FILE_LOADER FileLoaders[] = {
 | 
						|
    { BdsFileSystemSupport, BdsFileSystemLoadImage },
 | 
						|
    { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
 | 
						|
    //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
 | 
						|
    { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
 | 
						|
    { BdsPxeSupport, BdsPxeLoadImage },
 | 
						|
    { BdsTftpSupport, BdsTftpLoadImage },
 | 
						|
    { NULL, NULL }
 | 
						|
};
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsLoadImageAndUpdateDevicePath (
 | 
						|
  IN OUT 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 = BdsConnectAndUpdateDevicePath (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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsLoadImage (
 | 
						|
  IN     EFI_DEVICE_PATH       *DevicePath,
 | 
						|
  IN     EFI_ALLOCATE_TYPE     Type,
 | 
						|
  IN OUT EFI_PHYSICAL_ADDRESS* Image,
 | 
						|
  OUT    UINTN                 *FileSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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,
 | 
						|
  IN UINTN                       LoadOptionsSize,
 | 
						|
  IN VOID*                       LoadOptions
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  EFI_HANDLE                   ImageHandle;
 | 
						|
  EFI_PHYSICAL_ADDRESS         BinaryBuffer;
 | 
						|
  UINTN                        BinarySize;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL*   LoadedImage;
 | 
						|
 | 
						|
  // Find the nearest supported file loader
 | 
						|
  Status = BdsLoadImageAndUpdateDevicePath (&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;
 | 
						|
  }
 | 
						|
 | 
						|
  // Passed LoadOptions to the EFI Application
 | 
						|
  if (LoadOptionsSize != 0) {
 | 
						|
    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    LoadedImage->LoadOptionsSize  = LoadOptionsSize;
 | 
						|
    LoadedImage->LoadOptions      = LoadOptions;
 | 
						|
  }
 | 
						|
 | 
						|
  // 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;
 | 
						|
}
 |