Home | History | Annotate | Download | only in BdsLib
      1 /** @file
      2 *
      3 *  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
      4 *
      5 *  This program and the accompanying materials
      6 *  are licensed and made available under the terms and conditions of the BSD License
      7 *  which accompanies this distribution.  The full text of the license may be found at
      8 *  http://opensource.org/licenses/bsd-license.php
      9 *
     10 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 *
     13 **/
     14 
     15 #include "BdsInternal.h"
     16 
     17 #include <Library/NetLib.h>
     18 
     19 #include <Protocol/Bds.h>
     20 #include <Protocol/BlockIo.h>
     21 #include <Protocol/UsbIo.h>
     22 #include <Protocol/DiskIo.h>
     23 #include <Protocol/LoadedImage.h>
     24 #include <Protocol/SimpleNetwork.h>
     25 #include <Protocol/Dhcp4.h>
     26 #include <Protocol/Mtftp4.h>
     27 
     28 #include <Guid/Fdt.h>
     29 
     30 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
     31 
     32 /* Type and defines to set up the DHCP4 options */
     33 
     34 typedef struct {
     35   EFI_DHCP4_PACKET_OPTION Head;
     36   UINT8                   Route;
     37 } DHCP4_OPTION;
     38 
     39 #define DHCP_TAG_PARA_LIST  55
     40 #define DHCP_TAG_NETMASK     1
     41 #define DHCP_TAG_ROUTER      3
     42 
     43 STATIC VOID *gArgs;
     44 
     45 /*
     46    Constant strings and define related to the message indicating the amount of
     47    progress in the dowloading of a TFTP file.
     48 */
     49 
     50 // Frame for the progression slider
     51 STATIC CONST CHAR16 mTftpProgressFrame[] = L"[                                        ]";
     52 
     53 // Number of steps in the progression slider
     54 #define TFTP_PROGRESS_SLIDER_STEPS  ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
     55 
     56 // Size in number of characters plus one (final zero) of the message to
     57 // indicate the progress of a tftp download. The format is "[(progress slider:
     58 // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
     59 // are thus the number of characters in mTftpProgressFrame[] plus 11 characters
     60 // (2 // spaces, "Kb" and seven characters for the number of KBytes).
     61 #define TFTP_PROGRESS_MESSAGE_SIZE  ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
     62 
     63 // String to delete the tftp progress message to be able to update it :
     64 // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
     65 STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
     66 
     67 
     68 // Extract the FilePath from the Device Path
     69 CHAR16*
     70 BdsExtractFilePathFromDevicePath (
     71   IN  CONST CHAR16    *StrDevicePath,
     72   IN  UINTN           NumberDevicePathNode
     73   )
     74 {
     75   UINTN       Node;
     76   CHAR16      *Str;
     77 
     78   Str = (CHAR16*)StrDevicePath;
     79   Node = 0;
     80   while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
     81     if ((*Str == L'/') || (*Str == L'\\')) {
     82         Node++;
     83     }
     84     Str++;
     85   }
     86 
     87   if (*Str == L'\0') {
     88     return NULL;
     89   } else {
     90     return Str;
     91   }
     92 }
     93 
     94 BOOLEAN
     95 BdsIsRemovableUsb (
     96   IN  EFI_DEVICE_PATH*  DevicePath
     97   )
     98 {
     99   return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
    100           ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
    101            (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));
    102 }
    103 
    104 EFI_STATUS
    105 BdsGetDeviceUsb (
    106   IN  EFI_DEVICE_PATH*  RemovableDevicePath,
    107   OUT EFI_HANDLE*       DeviceHandle,
    108   OUT EFI_DEVICE_PATH** NewDevicePath
    109   )
    110 {
    111   EFI_STATUS                    Status;
    112   UINTN                         Index;
    113   UINTN                         UsbIoHandleCount;
    114   EFI_HANDLE                    *UsbIoBuffer;
    115   EFI_DEVICE_PATH*              UsbIoDevicePath;
    116   EFI_DEVICE_PATH*              TmpDevicePath;
    117   USB_WWID_DEVICE_PATH*         WwidDevicePath1;
    118   USB_WWID_DEVICE_PATH*         WwidDevicePath2;
    119   USB_CLASS_DEVICE_PATH*        UsbClassDevicePath1;
    120   USB_CLASS_DEVICE_PATH*        UsbClassDevicePath2;
    121 
    122   // Get all the UsbIo handles
    123   UsbIoHandleCount = 0;
    124   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
    125   if (EFI_ERROR (Status) || (UsbIoHandleCount == 0)) {
    126     return Status;
    127   }
    128 
    129   // Check if one of the handles matches the USB description
    130   for (Index = 0; Index < UsbIoHandleCount; Index++) {
    131     Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);
    132     if (!EFI_ERROR (Status)) {
    133       TmpDevicePath = UsbIoDevicePath;
    134       while (!IsDevicePathEnd (TmpDevicePath)) {
    135         // Check if the Device Path node is a USB Removable device Path node
    136         if (BdsIsRemovableUsb (TmpDevicePath)) {
    137           if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {
    138             WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;
    139             WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;
    140             if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&
    141                 (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&
    142                 (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) == 0))
    143             {
    144               *DeviceHandle = UsbIoBuffer[Index];
    145               // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
    146               *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));
    147               return EFI_SUCCESS;
    148             }
    149           } else {
    150             UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;
    151             UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;
    152             if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&
    153                 (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&
    154                 (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&
    155                 (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&
    156                 (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))
    157             {
    158               *DeviceHandle = UsbIoBuffer[Index];
    159               // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
    160               *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));
    161               return EFI_SUCCESS;
    162             }
    163           }
    164         }
    165         TmpDevicePath = NextDevicePathNode (TmpDevicePath);
    166       }
    167 
    168     }
    169   }
    170 
    171   return EFI_NOT_FOUND;
    172 }
    173 
    174 BOOLEAN
    175 BdsIsRemovableHd (
    176   IN  EFI_DEVICE_PATH*  DevicePath
    177   )
    178 {
    179   return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);
    180 }
    181 
    182 EFI_STATUS
    183 BdsGetDeviceHd (
    184   IN  EFI_DEVICE_PATH*  RemovableDevicePath,
    185   OUT EFI_HANDLE*       DeviceHandle,
    186   OUT EFI_DEVICE_PATH** NewDevicePath
    187   )
    188 {
    189   EFI_STATUS                    Status;
    190   UINTN                         Index;
    191   UINTN                         PartitionHandleCount;
    192   EFI_HANDLE                    *PartitionBuffer;
    193   EFI_DEVICE_PATH*              PartitionDevicePath;
    194   EFI_DEVICE_PATH*              TmpDevicePath;
    195   HARDDRIVE_DEVICE_PATH*        HardDriveDevicePath1;
    196   HARDDRIVE_DEVICE_PATH*        HardDriveDevicePath2;
    197 
    198   // Get all the DiskIo handles
    199   PartitionHandleCount = 0;
    200   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);
    201   if (EFI_ERROR (Status) || (PartitionHandleCount == 0)) {
    202     return Status;
    203   }
    204 
    205   // Check if one of the handles matches the Hard Disk Description
    206   for (Index = 0; Index < PartitionHandleCount; Index++) {
    207     Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);
    208     if (!EFI_ERROR (Status)) {
    209       TmpDevicePath = PartitionDevicePath;
    210       while (!IsDevicePathEnd (TmpDevicePath)) {
    211         // Check if the Device Path node is a HD Removable device Path node
    212         if (BdsIsRemovableHd (TmpDevicePath)) {
    213           HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;
    214           HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;
    215           if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&
    216               (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&
    217               (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))
    218           {
    219             *DeviceHandle = PartitionBuffer[Index];
    220             // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
    221             *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode (RemovableDevicePath));
    222             return EFI_SUCCESS;
    223           }
    224         }
    225         TmpDevicePath = NextDevicePathNode (TmpDevicePath);
    226       }
    227 
    228     }
    229   }
    230 
    231   return EFI_NOT_FOUND;
    232 }
    233 
    234 /*BOOLEAN
    235 BdsIsRemovableCdrom (
    236   IN  EFI_DEVICE_PATH*  DevicePath
    237   )
    238 {
    239   return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
    240 }
    241 
    242 EFI_STATUS
    243 BdsGetDeviceCdrom (
    244   IN  EFI_DEVICE_PATH*  RemovableDevicePath,
    245   OUT EFI_HANDLE*       DeviceHandle,
    246   OUT EFI_DEVICE_PATH** DevicePath
    247   )
    248 {
    249   ASSERT(0);
    250   return EFI_UNSUPPORTED;
    251 }*/
    252 
    253 typedef BOOLEAN
    254 (*BDS_IS_REMOVABLE) (
    255   IN  EFI_DEVICE_PATH*  DevicePath
    256   );
    257 
    258 typedef EFI_STATUS
    259 (*BDS_GET_DEVICE) (
    260   IN  EFI_DEVICE_PATH*  RemovableDevicePath,
    261   OUT EFI_HANDLE*       DeviceHandle,
    262   OUT EFI_DEVICE_PATH** DevicePath
    263   );
    264 
    265 typedef struct {
    266   BDS_IS_REMOVABLE    IsRemovable;
    267   BDS_GET_DEVICE      GetDevice;
    268 } BDS_REMOVABLE_DEVICE_SUPPORT;
    269 
    270 BDS_REMOVABLE_DEVICE_SUPPORT  RemovableDeviceSupport[] = {
    271   { BdsIsRemovableUsb, BdsGetDeviceUsb },
    272   { BdsIsRemovableHd, BdsGetDeviceHd },
    273   //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
    274 };
    275 
    276 STATIC
    277 BOOLEAN
    278 IsRemovableDevice (
    279   IN  EFI_DEVICE_PATH*  DevicePath
    280   )
    281 {
    282   UINTN             Index;
    283   EFI_DEVICE_PATH*  TmpDevicePath;
    284 
    285   TmpDevicePath = DevicePath;
    286   while (!IsDevicePathEnd (TmpDevicePath)) {
    287     for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
    288       if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) {
    289         return TRUE;
    290       }
    291     }
    292     TmpDevicePath = NextDevicePathNode (TmpDevicePath);
    293   }
    294 
    295   return FALSE;
    296 }
    297 
    298 STATIC
    299 EFI_STATUS
    300 TryRemovableDevice (
    301   IN  EFI_DEVICE_PATH*  DevicePath,
    302   OUT EFI_HANDLE*       DeviceHandle,
    303   OUT EFI_DEVICE_PATH** NewDevicePath
    304   )
    305 {
    306   EFI_STATUS        Status;
    307   UINTN             Index;
    308   EFI_DEVICE_PATH*  TmpDevicePath;
    309   BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;
    310   EFI_DEVICE_PATH* RemovableDevicePath;
    311   BOOLEAN         RemovableFound;
    312 
    313   RemovableDevice     = NULL;
    314   RemovableDevicePath = NULL;
    315   RemovableFound      = FALSE;
    316   TmpDevicePath       = DevicePath;
    317 
    318   while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
    319     for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
    320       RemovableDevice = &RemovableDeviceSupport[Index];
    321       if (RemovableDevice->IsRemovable (TmpDevicePath)) {
    322         RemovableDevicePath = TmpDevicePath;
    323         RemovableFound = TRUE;
    324         break;
    325       }
    326     }
    327     TmpDevicePath = NextDevicePathNode (TmpDevicePath);
    328   }
    329 
    330   if (!RemovableFound) {
    331     return EFI_NOT_FOUND;
    332   }
    333 
    334   // Search into the current started drivers
    335   Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
    336   if (Status == EFI_NOT_FOUND) {
    337     // Connect all the drivers
    338     BdsConnectAllDrivers ();
    339 
    340     // Search again into all the drivers
    341     Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
    342   }
    343 
    344   return Status;
    345 }
    346 
    347 STATIC
    348 EFI_STATUS
    349 BdsConnectAndUpdateDevicePath (
    350   IN OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath,
    351   OUT    EFI_HANDLE                *Handle,
    352   OUT    EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath
    353   )
    354 {
    355   EFI_DEVICE_PATH*            Remaining;
    356   EFI_DEVICE_PATH*            NewDevicePath;
    357   EFI_STATUS                  Status;
    358   EFI_HANDLE                  PreviousHandle;
    359 
    360   if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {
    361     return EFI_INVALID_PARAMETER;
    362   }
    363 
    364   PreviousHandle = NULL;
    365   do {
    366     Remaining = *DevicePath;
    367 
    368     // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
    369     // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
    370     // to point to the remaining part of the device path
    371     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
    372 
    373     if (!EFI_ERROR (Status)) {
    374       if (*Handle == PreviousHandle) {
    375         //
    376         // If no forward progress is made try invoking the Dispatcher.
    377         // A new FV may have been added to the system and new drivers
    378         // may now be found.
    379         // Status == EFI_SUCCESS means a driver was dispatched
    380         // Status == EFI_NOT_FOUND means no new drivers were dispatched
    381         //
    382         Status = gDS->Dispatch ();
    383       }
    384 
    385       if (!EFI_ERROR (Status)) {
    386         PreviousHandle = *Handle;
    387 
    388         // Recursive = FALSE: We do not want to start the whole device tree
    389         Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
    390       }
    391     }
    392   } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
    393 
    394   if (!EFI_ERROR (Status)) {
    395     // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
    396     // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
    397     Remaining = *DevicePath;
    398     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
    399     if (!EFI_ERROR (Status)) {
    400       Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
    401       if (EFI_ERROR (Status)) {
    402         // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
    403         if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
    404             Status = EFI_SUCCESS;
    405         }
    406       }
    407     }
    408   } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
    409 
    410     /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
    411     if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
    412       Status = EFI_SUCCESS;
    413     } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
    414       Status = EFI_SUCCESS;
    415     }*/
    416 
    417     //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
    418     Status = EFI_SUCCESS;
    419   } else {
    420     Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath);
    421     if (!EFI_ERROR (Status)) {
    422       Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);
    423       *DevicePath = NewDevicePath;
    424       return Status;
    425     }
    426   }
    427 
    428   if (RemainingDevicePath) {
    429     *RemainingDevicePath = Remaining;
    430   }
    431 
    432   return Status;
    433 }
    434 
    435 /**
    436   Connect a Device Path and return the handle of the driver that support this DevicePath
    437 
    438   @param  DevicePath            Device Path of the File to connect
    439   @param  Handle                Handle of the driver that support this DevicePath
    440   @param  RemainingDevicePath   Remaining DevicePath nodes that do not match the driver DevicePath
    441 
    442   @retval EFI_SUCCESS           A driver that matches the Device Path has been found
    443   @retval EFI_NOT_FOUND         No handles match the search.
    444   @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
    445 
    446 **/
    447 EFI_STATUS
    448 BdsConnectDevicePath (
    449   IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,
    450   OUT EFI_HANDLE                *Handle,
    451   OUT EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath
    452   )
    453 {
    454   return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);
    455 }
    456 
    457 BOOLEAN
    458 BdsFileSystemSupport (
    459   IN EFI_DEVICE_PATH *DevicePath,
    460   IN EFI_HANDLE Handle,
    461   IN EFI_DEVICE_PATH *RemainingDevicePath
    462   )
    463 {
    464   EFI_STATUS  Status;
    465   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *FsProtocol;
    466 
    467   if (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {
    468     Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
    469     return (!EFI_ERROR (Status));
    470   }
    471   return FALSE;
    472 }
    473 
    474 EFI_STATUS
    475 BdsFileSystemLoadImage (
    476   IN OUT EFI_DEVICE_PATH       **DevicePath,
    477   IN     EFI_HANDLE            Handle,
    478   IN     EFI_DEVICE_PATH       *RemainingDevicePath,
    479   IN     EFI_ALLOCATE_TYPE     Type,
    480   IN OUT EFI_PHYSICAL_ADDRESS  *Image,
    481   OUT    UINTN                 *ImageSize
    482   )
    483 {
    484   EFI_STATUS                       Status;
    485   FILEPATH_DEVICE_PATH             *FilePathDevicePath;
    486   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FsProtocol;
    487   EFI_FILE_PROTOCOL                *Fs;
    488   EFI_FILE_INFO                    *FileInfo;
    489   EFI_FILE_PROTOCOL                *File;
    490   UINTN                            Size;
    491 
    492   ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));
    493 
    494   FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
    495 
    496   Status = gBS->OpenProtocol (
    497                   Handle,
    498                   &gEfiSimpleFileSystemProtocolGuid,
    499                   (VOID**)&FsProtocol,
    500                   gImageHandle,
    501                   Handle,
    502                   EFI_OPEN_PROTOCOL_BY_DRIVER
    503                   );
    504   if (EFI_ERROR (Status)) {
    505     return Status;
    506   }
    507 
    508   // Try to Open the volume and get root directory
    509   Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
    510   if (EFI_ERROR (Status)) {
    511     goto CLOSE_PROTOCOL;
    512   }
    513 
    514   Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
    515   if (EFI_ERROR (Status)) {
    516     goto CLOSE_PROTOCOL;
    517   }
    518 
    519   Size = 0;
    520   File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
    521   FileInfo = AllocatePool (Size);
    522   Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
    523   if (EFI_ERROR (Status)) {
    524     goto CLOSE_FILE;
    525   }
    526 
    527   // Get the file size
    528   Size = FileInfo->FileSize;
    529   if (ImageSize) {
    530     *ImageSize = Size;
    531   }
    532   FreePool (FileInfo);
    533 
    534   Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
    535   // Try to allocate in any pages if failed to allocate memory at the defined location
    536   if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
    537     Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
    538   }
    539   if (!EFI_ERROR (Status)) {
    540     Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
    541   }
    542 
    543 CLOSE_FILE:
    544   File->Close (File);
    545 
    546 CLOSE_PROTOCOL:
    547   gBS->CloseProtocol (
    548          Handle,
    549          &gEfiSimpleFileSystemProtocolGuid,
    550          gImageHandle,
    551          Handle);
    552 
    553   return Status;
    554 }
    555 
    556 BOOLEAN
    557 BdsMemoryMapSupport (
    558   IN EFI_DEVICE_PATH *DevicePath,
    559   IN EFI_HANDLE Handle,
    560   IN EFI_DEVICE_PATH *RemainingDevicePath
    561   )
    562 {
    563   return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||
    564          IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);
    565 }
    566 
    567 EFI_STATUS
    568 BdsMemoryMapLoadImage (
    569   IN OUT EFI_DEVICE_PATH       **DevicePath,
    570   IN     EFI_HANDLE            Handle,
    571   IN     EFI_DEVICE_PATH       *RemainingDevicePath,
    572   IN     EFI_ALLOCATE_TYPE     Type,
    573   IN OUT EFI_PHYSICAL_ADDRESS* Image,
    574   OUT    UINTN                 *ImageSize
    575   )
    576 {
    577   EFI_STATUS            Status;
    578   MEMMAP_DEVICE_PATH*   MemMapPathDevicePath;
    579   UINTN                 Size;
    580 
    581   if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {
    582     MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
    583   } else {
    584     ASSERT (IS_DEVICE_PATH_NODE (*DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));
    585     MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)*DevicePath;
    586   }
    587 
    588   Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
    589   if (Size == 0) {
    590       return EFI_INVALID_PARAMETER;
    591   }
    592 
    593   Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
    594   // Try to allocate in any pages if failed to allocate memory at the defined location
    595   if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
    596     Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
    597   }
    598   if (!EFI_ERROR (Status)) {
    599     CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
    600 
    601     if (ImageSize != NULL) {
    602         *ImageSize = Size;
    603     }
    604   }
    605 
    606   return Status;
    607 }
    608 
    609 BOOLEAN
    610 BdsFirmwareVolumeSupport (
    611   IN EFI_DEVICE_PATH *DevicePath,
    612   IN EFI_HANDLE Handle,
    613   IN EFI_DEVICE_PATH *RemainingDevicePath
    614   )
    615 {
    616   return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
    617 }
    618 
    619 EFI_STATUS
    620 BdsFirmwareVolumeLoadImage (
    621   IN OUT EFI_DEVICE_PATH       **DevicePath,
    622   IN     EFI_HANDLE            Handle,
    623   IN     EFI_DEVICE_PATH       *RemainingDevicePath,
    624   IN     EFI_ALLOCATE_TYPE     Type,
    625   IN OUT EFI_PHYSICAL_ADDRESS* Image,
    626   OUT    UINTN                 *ImageSize
    627   )
    628 {
    629   EFI_STATUS            Status;
    630   EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;
    631   EFI_GUID                          *FvNameGuid;
    632   EFI_SECTION_TYPE                  SectionType;
    633   EFI_FV_FILETYPE                   FvType;
    634   EFI_FV_FILE_ATTRIBUTES            Attrib;
    635   UINT32                            AuthenticationStatus;
    636   VOID* ImageBuffer;
    637   UINTN                           NoHandles, HandleIndex;
    638   EFI_HANDLE                      *Handles;
    639   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwDevicePath;
    640 
    641   ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
    642 
    643   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles);
    644   if (EFI_ERROR (Status) || (NoHandles == 0)) {
    645     DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n"));
    646     return Status;
    647   }
    648   // Search in all Firmware Volume for the EFI Application
    649   for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) {
    650     Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
    651     if (EFI_ERROR (Status))
    652       continue;
    653 
    654     FwDevicePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath;
    655     FvNameGuid = &(FwDevicePath->FvFileName);
    656     if (FvNameGuid == NULL) {
    657       Status = EFI_INVALID_PARAMETER;
    658       continue;
    659     }
    660 
    661     SectionType = EFI_SECTION_PE32;
    662     AuthenticationStatus = 0;
    663     //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
    664     ImageBuffer = NULL;
    665     Status = FwVol->ReadSection (
    666                       FwVol,
    667                       FvNameGuid,
    668                       SectionType,
    669                       0,
    670                       &ImageBuffer,
    671                       ImageSize,
    672                       &AuthenticationStatus
    673                       );
    674     if (!EFI_ERROR (Status)) {
    675 #if 0
    676       // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
    677       if (Type != AllocateAnyPages) {
    678         Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
    679         if (!EFI_ERROR (Status)) {
    680           CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
    681           FreePool (ImageBuffer);
    682         }
    683       }
    684 #else
    685       // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
    686       Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
    687       // Try to allocate in any pages if failed to allocate memory at the defined location
    688       if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
    689         Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
    690       }
    691       if (!EFI_ERROR (Status)) {
    692         CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
    693         FreePool (ImageBuffer);
    694 	return Status;
    695       }
    696 #endif
    697     } else {
    698       // Try a raw file, since a PE32 SECTION does not exist
    699       Status = FwVol->ReadFile (
    700                           FwVol,
    701                           FvNameGuid,
    702                           NULL,
    703                           ImageSize,
    704                           &FvType,
    705                           &Attrib,
    706                           &AuthenticationStatus
    707                           );
    708       if (!EFI_ERROR (Status)) {
    709         Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
    710         // Try to allocate in any pages if failed to allocate memory at the defined location
    711         if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
    712           Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
    713         }
    714         if (!EFI_ERROR (Status)) {
    715           Status = FwVol->ReadFile (
    716                                   FwVol,
    717                                   FvNameGuid,
    718                                   (VOID*)(UINTN)(*Image),
    719                                   ImageSize,
    720                                   &FvType,
    721                                   &Attrib,
    722                                   &AuthenticationStatus
    723                                   );
    724 	  if (!EFI_ERROR (Status))
    725 	    return Status;
    726         }
    727       }
    728     }
    729   }
    730   return Status;
    731 }
    732 
    733 BOOLEAN
    734 BdsPxeSupport (
    735   IN EFI_DEVICE_PATH*           DevicePath,
    736   IN EFI_HANDLE                 Handle,
    737   IN EFI_DEVICE_PATH*           RemainingDevicePath
    738   )
    739 {
    740   EFI_STATUS                  Status;
    741   EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
    742 
    743   if (!IsDevicePathEnd (RemainingDevicePath)) {
    744     return FALSE;
    745   }
    746 
    747   Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
    748   if (EFI_ERROR (Status)) {
    749     return FALSE;
    750   } else {
    751     return TRUE;
    752   }
    753 }
    754 
    755 EFI_STATUS
    756 BdsPxeLoadImage (
    757   IN OUT EFI_DEVICE_PATH       **DevicePath,
    758   IN     EFI_HANDLE            Handle,
    759   IN     EFI_DEVICE_PATH       *RemainingDevicePath,
    760   IN     EFI_ALLOCATE_TYPE     Type,
    761   IN OUT EFI_PHYSICAL_ADDRESS* Image,
    762   OUT    UINTN                 *ImageSize
    763   )
    764 {
    765   EFI_STATUS              Status;
    766   EFI_LOAD_FILE_PROTOCOL  *LoadFileProtocol;
    767   UINTN                   BufferSize;
    768   EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
    769 
    770   // Get Load File Protocol attached to the PXE protocol
    771   Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
    772   if (EFI_ERROR (Status)) {
    773     return Status;
    774   }
    775 
    776   Status = LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevicePath, TRUE, &BufferSize, NULL);
    777   if (Status == EFI_BUFFER_TOO_SMALL) {
    778     Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
    779     if (EFI_ERROR (Status)) {
    780       return Status;
    781     }
    782 
    783     Status = LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
    784     if (!EFI_ERROR (Status) && (ImageSize != NULL)) {
    785       *ImageSize = BufferSize;
    786     }
    787   }
    788 
    789   if (Status == EFI_ALREADY_STARTED) {
    790     Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
    791     if (!EFI_ERROR(Status)) {
    792       // If PXE is already started, we stop it
    793       Pxe->Stop (Pxe);
    794       // And we try again
    795       return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);
    796     }
    797   }
    798   return Status;
    799 }
    800 
    801 BOOLEAN
    802 BdsTftpSupport (
    803   IN EFI_DEVICE_PATH  *DevicePath,
    804   IN EFI_HANDLE       Handle,
    805   IN EFI_DEVICE_PATH  *RemainingDevicePath
    806   )
    807 {
    808   EFI_STATUS       Status;
    809   EFI_DEVICE_PATH  *NextDevicePath;
    810   VOID             *Interface;
    811 
    812   // Validate the Remaining Device Path
    813   if (IsDevicePathEnd (RemainingDevicePath)) {
    814     return FALSE;
    815   }
    816   if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&
    817       !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {
    818     return FALSE;
    819   }
    820   NextDevicePath = NextDevicePathNode (RemainingDevicePath);
    821   if (IsDevicePathEnd (NextDevicePath)) {
    822     return FALSE;
    823   }
    824   if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {
    825     return FALSE;
    826   }
    827 
    828   Status = gBS->HandleProtocol (
    829                   Handle, &gEfiDevicePathProtocolGuid,
    830                   &Interface
    831                   );
    832   if (EFI_ERROR (Status)) {
    833     return FALSE;
    834   }
    835 
    836   //
    837   // Check that the controller (identified by its handle "Handle") supports the
    838   // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
    839   // EFI MTFTPv4 Protocol needed to download the image through TFTP.
    840   //
    841   Status = gBS->HandleProtocol (
    842                   Handle, &gEfiMtftp4ServiceBindingProtocolGuid,
    843                   &Interface
    844                   );
    845   if (EFI_ERROR (Status)) {
    846     return FALSE;
    847   }
    848 
    849   return TRUE;
    850 }
    851 
    852 /**
    853   Worker function that get the size in numbers of bytes of a file from a TFTP
    854   server before to download the file.
    855 
    856   @param[in]   Mtftp4    MTFTP4 protocol interface
    857   @param[in]   FilePath  Path of the file, Ascii encoded
    858   @param[out]  FileSize  Address where to store the file size in number of
    859                          bytes.
    860 
    861   @retval  EFI_SUCCESS   The size of the file was returned.
    862   @retval  !EFI_SUCCESS  The size of the file was not returned.
    863 
    864 **/
    865 STATIC
    866 EFI_STATUS
    867 Mtftp4GetFileSize (
    868   IN  EFI_MTFTP4_PROTOCOL  *Mtftp4,
    869   IN  CHAR8                *FilePath,
    870   OUT UINT64               *FileSize
    871   )
    872 {
    873   EFI_STATUS         Status;
    874   EFI_MTFTP4_OPTION  ReqOpt[1];
    875   EFI_MTFTP4_PACKET  *Packet;
    876   UINT32             PktLen;
    877   EFI_MTFTP4_OPTION  *TableOfOptions;
    878   EFI_MTFTP4_OPTION  *Option;
    879   UINT32             OptCnt;
    880   UINT8              OptBuf[128];
    881 
    882   ReqOpt[0].OptionStr = (UINT8*)"tsize";
    883   OptBuf[0] = '0';
    884   OptBuf[1] = 0;
    885   ReqOpt[0].ValueStr = OptBuf;
    886 
    887   Status = Mtftp4->GetInfo (
    888              Mtftp4,
    889              NULL,
    890              (UINT8*)FilePath,
    891              NULL,
    892              1,
    893              ReqOpt,
    894              &PktLen,
    895              &Packet
    896              );
    897 
    898   if (EFI_ERROR (Status)) {
    899     goto Error;
    900   }
    901 
    902   Status = Mtftp4->ParseOptions (
    903                      Mtftp4,
    904                      PktLen,
    905                      Packet,
    906                      (UINT32 *) &OptCnt,
    907                      &TableOfOptions
    908                      );
    909   if (EFI_ERROR (Status)) {
    910     goto Error;
    911   }
    912 
    913   Option = TableOfOptions;
    914   while (OptCnt != 0) {
    915     if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
    916       *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr);
    917       break;
    918     }
    919     OptCnt--;
    920     Option++;
    921   }
    922   FreePool (TableOfOptions);
    923 
    924   if (OptCnt == 0) {
    925     Status = EFI_UNSUPPORTED;
    926   }
    927 
    928 Error :
    929 
    930   return Status;
    931 }
    932 
    933 /**
    934   Update the progress of a file download
    935   This procedure is called each time a new TFTP packet is received.
    936 
    937   @param[in]  This       MTFTP4 protocol interface
    938   @param[in]  Token      Parameters for the download of the file
    939   @param[in]  PacketLen  Length of the packet
    940   @param[in]  Packet     Address of the packet
    941 
    942   @retval  EFI_SUCCESS  All packets are accepted.
    943 
    944 **/
    945 STATIC
    946 EFI_STATUS
    947 Mtftp4CheckPacket (
    948   IN EFI_MTFTP4_PROTOCOL  *This,
    949   IN EFI_MTFTP4_TOKEN     *Token,
    950   IN UINT16               PacketLen,
    951   IN EFI_MTFTP4_PACKET    *Packet
    952   )
    953 {
    954   BDS_TFTP_CONTEXT  *Context;
    955   CHAR16            Progress[TFTP_PROGRESS_MESSAGE_SIZE];
    956   UINT64            NbOfKb;
    957   UINTN             Index;
    958   UINTN             LastStep;
    959   UINTN             Step;
    960   UINT64            LastNbOf50Kb;
    961   UINT64            NbOf50Kb;
    962 
    963   if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) {
    964     Context = (BDS_TFTP_CONTEXT*)Token->Context;
    965 
    966     if (Context->DownloadedNbOfBytes == 0) {
    967       if (Context->FileSize > 0) {
    968         Print (L"%s       0 Kb", mTftpProgressFrame);
    969       } else {
    970         Print (L"    0 Kb");
    971       }
    972     }
    973 
    974     //
    975     // The data is the packet are prepended with two UINT16 :
    976     // . OpCode = EFI_MTFTP4_OPCODE_DATA
    977     // . Block  = the number of this block of data
    978     //
    979     Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
    980     NbOfKb = Context->DownloadedNbOfBytes / 1024;
    981 
    982     Progress[0] = L'\0';
    983     if (Context->FileSize > 0) {
    984       LastStep  = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
    985       Step      = (Context->DownloadedNbOfBytes   * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
    986       if (Step > LastStep) {
    987         Print (mTftpProgressDelete);
    988         StrCpy (Progress, mTftpProgressFrame);
    989         for (Index = 1; Index < Step; Index++) {
    990           Progress[Index] = L'=';
    991         }
    992         Progress[Step] = L'>';
    993 
    994         UnicodeSPrint (
    995           Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
    996           sizeof (Progress) - sizeof (mTftpProgressFrame),
    997           L" %7d Kb",
    998           NbOfKb
    999           );
   1000         Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
   1001       }
   1002     } else {
   1003       //
   1004       // Case when we do not know the size of the final file.
   1005       // We print the updated size every 50KB of downloaded data
   1006       //
   1007       LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024);
   1008       NbOf50Kb     = Context->DownloadedNbOfBytes   / (50*1024);
   1009       if (NbOf50Kb > LastNbOf50Kb) {
   1010         Print (L"\b\b\b\b\b\b\b\b\b\b");
   1011         UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb);
   1012         Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
   1013       }
   1014     }
   1015     if (Progress[0] != L'\0') {
   1016       Print (L"%s", Progress);
   1017     }
   1018   }
   1019 
   1020   return EFI_SUCCESS;
   1021 }
   1022 
   1023 /**
   1024   Download an image from a TFTP server
   1025 
   1026   @param[in]   DevicePath           Device path of the TFTP boot option
   1027   @param[in]   ControllerHandle     Handle of the network controller
   1028   @param[in]   RemainingDevicePath  Device path of the TFTP boot option but
   1029                                     the first node that identifies the network controller
   1030   @param[in]   Type                 Type to allocate memory pages
   1031   @param[out]  Image                Address of the bufer where the image is stored in
   1032                                     case of success
   1033   @param[out]  ImageSize            Size in number of bytes of the i;age in case of
   1034                                     success
   1035 
   1036   @retval  EFI_SUCCESS   The image was returned.
   1037   @retval  !EFI_SUCCESS  Something went wrong.
   1038 
   1039 **/
   1040 EFI_STATUS
   1041 BdsTftpLoadImage (
   1042   IN OUT EFI_DEVICE_PATH       **DevicePath,
   1043   IN     EFI_HANDLE            ControllerHandle,
   1044   IN     EFI_DEVICE_PATH       *RemainingDevicePath,
   1045   IN     EFI_ALLOCATE_TYPE     Type,
   1046   IN OUT EFI_PHYSICAL_ADDRESS  *Image,
   1047   OUT    UINTN                 *ImageSize
   1048   )
   1049 {
   1050   EFI_STATUS               Status;
   1051   EFI_HANDLE               Dhcp4ChildHandle;
   1052   EFI_DHCP4_PROTOCOL       *Dhcp4;
   1053   BOOLEAN                  Dhcp4ToStop;
   1054   EFI_HANDLE               Mtftp4ChildHandle;
   1055   EFI_MTFTP4_PROTOCOL      *Mtftp4;
   1056   DHCP4_OPTION             ParaList;
   1057   EFI_DHCP4_PACKET_OPTION  *OptionList[2];
   1058   EFI_DHCP4_CONFIG_DATA    Dhcp4CfgData;
   1059   EFI_DHCP4_MODE_DATA      Dhcp4Mode;
   1060   EFI_MTFTP4_CONFIG_DATA   Mtftp4CfgData;
   1061   IPv4_DEVICE_PATH         *IPv4DevicePathNode;
   1062   CHAR16                   *PathName;
   1063   CHAR8                    *AsciiFilePath;
   1064   EFI_MTFTP4_TOKEN         Mtftp4Token;
   1065   UINT64                   FileSize;
   1066   UINT64                   TftpBufferSize;
   1067   BDS_TFTP_CONTEXT         *TftpContext;
   1068 
   1069   ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));
   1070   IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
   1071 
   1072   Dhcp4ChildHandle  = NULL;
   1073   Dhcp4             = NULL;
   1074   Dhcp4ToStop       = FALSE;
   1075   Mtftp4ChildHandle = NULL;
   1076   Mtftp4            = NULL;
   1077   AsciiFilePath     = NULL;
   1078   TftpContext       = NULL;
   1079 
   1080   if (!IPv4DevicePathNode->StaticIpAddress) {
   1081     //
   1082     // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
   1083     // install the DHCP4 protocol on it. Then, open the DHCP protocol.
   1084     //
   1085     Status = NetLibCreateServiceChild (
   1086                ControllerHandle,
   1087                gImageHandle,
   1088                &gEfiDhcp4ServiceBindingProtocolGuid,
   1089                &Dhcp4ChildHandle
   1090                );
   1091     if (!EFI_ERROR (Status)) {
   1092       Status = gBS->OpenProtocol (
   1093                       Dhcp4ChildHandle,
   1094                       &gEfiDhcp4ProtocolGuid,
   1095                       (VOID **) &Dhcp4,
   1096                       gImageHandle,
   1097                       ControllerHandle,
   1098                       EFI_OPEN_PROTOCOL_BY_DRIVER
   1099                       );
   1100     }
   1101     if (EFI_ERROR (Status)) {
   1102       Print (L"Unable to open DHCP4 protocol\n");
   1103       goto Error;
   1104     }
   1105   }
   1106 
   1107   //
   1108   // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
   1109   // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
   1110   //
   1111   Status = NetLibCreateServiceChild (
   1112              ControllerHandle,
   1113              gImageHandle,
   1114              &gEfiMtftp4ServiceBindingProtocolGuid,
   1115              &Mtftp4ChildHandle
   1116              );
   1117   if (!EFI_ERROR (Status)) {
   1118     Status = gBS->OpenProtocol (
   1119                     Mtftp4ChildHandle,
   1120                     &gEfiMtftp4ProtocolGuid,
   1121                     (VOID **) &Mtftp4,
   1122                     gImageHandle,
   1123                     ControllerHandle,
   1124                     EFI_OPEN_PROTOCOL_BY_DRIVER
   1125                     );
   1126   }
   1127   if (EFI_ERROR (Status)) {
   1128     Print (L"Unable to open MTFTP4 protocol\n");
   1129     goto Error;
   1130   }
   1131 
   1132   if (!IPv4DevicePathNode->StaticIpAddress) {
   1133     //
   1134     // Configure the DHCP4, all default settings. It is acceptable for the configuration to
   1135     // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
   1136     // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
   1137     // process has been started but is not completed yet.
   1138     //
   1139     ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
   1140     ParaList.Head.OpCode     = DHCP_TAG_PARA_LIST;
   1141     ParaList.Head.Length     = 2;
   1142     ParaList.Head.Data[0]    = DHCP_TAG_NETMASK;
   1143     ParaList.Route           = DHCP_TAG_ROUTER;
   1144     OptionList[0]            = &ParaList.Head;
   1145     Dhcp4CfgData.OptionCount = 1;
   1146     Dhcp4CfgData.OptionList  = OptionList;
   1147 
   1148     Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
   1149     if (EFI_ERROR (Status)) {
   1150       if (Status != EFI_ACCESS_DENIED) {
   1151         Print (L"Error while configuring the DHCP4 protocol\n");
   1152         goto Error;
   1153       }
   1154     }
   1155 
   1156     //
   1157     // Start the DHCP configuration. This may have already been done thus do not leave in error
   1158     // if the return code is EFI_ALREADY_STARTED.
   1159     //
   1160     Status = Dhcp4->Start (Dhcp4, NULL);
   1161     if (EFI_ERROR (Status)) {
   1162       if (Status != EFI_ALREADY_STARTED) {
   1163         Print (L"DHCP configuration failed\n");
   1164         goto Error;
   1165       }
   1166     } else {
   1167       Dhcp4ToStop = TRUE;
   1168     }
   1169 
   1170     Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
   1171     if (EFI_ERROR (Status)) {
   1172       goto Error;
   1173     }
   1174 
   1175     if (Dhcp4Mode.State != Dhcp4Bound) {
   1176       Status = EFI_TIMEOUT;
   1177       Print (L"DHCP configuration failed\n");
   1178       goto Error;
   1179     }
   1180   }
   1181 
   1182   //
   1183   // Configure the TFTP4 protocol
   1184   //
   1185 
   1186   ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA));
   1187   Mtftp4CfgData.UseDefaultSetting = FALSE;
   1188   Mtftp4CfgData.TimeoutValue      = 4;
   1189   Mtftp4CfgData.TryCount          = 6;
   1190 
   1191   if (IPv4DevicePathNode->StaticIpAddress) {
   1192     CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1193     CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
   1194     CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1195   } else {
   1196     CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
   1197     CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask   , sizeof (EFI_IPv4_ADDRESS));
   1198     CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
   1199   }
   1200 
   1201   CopyMem (&Mtftp4CfgData.ServerIp  , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1202 
   1203   Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData);
   1204   if (EFI_ERROR (Status)) {
   1205     Print (L"Error while configuring the MTFTP4 protocol\n");
   1206     goto Error;
   1207   }
   1208 
   1209   // The Device Path might contain multiple FilePath nodes
   1210   PathName      = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*)(IPv4DevicePathNode + 1), FALSE, FALSE);
   1211   AsciiFilePath = AllocatePool (StrLen (PathName) + 1);
   1212   UnicodeStrToAsciiStr (PathName, AsciiFilePath);
   1213 
   1214   //
   1215   // Try to get the size of the file in bytes from the server. If it fails,
   1216   // start with a 8MB buffer to download the file.
   1217   //
   1218   FileSize = 0;
   1219   if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) {
   1220     TftpBufferSize = FileSize;
   1221   } else {
   1222     TftpBufferSize = SIZE_16MB;
   1223   }
   1224 
   1225   TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT));
   1226   if (TftpContext == NULL) {
   1227     Status = EFI_OUT_OF_RESOURCES;
   1228     goto Error;
   1229   }
   1230   TftpContext->FileSize = FileSize;
   1231 
   1232   for (; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize);
   1233          TftpBufferSize = (TftpBufferSize + SIZE_16MB) & (~(SIZE_16MB-1))) {
   1234     //
   1235     // Allocate a buffer to hold the whole file.
   1236     //
   1237     Status = gBS->AllocatePages (
   1238                     Type,
   1239                     EfiBootServicesCode,
   1240                     EFI_SIZE_TO_PAGES (TftpBufferSize),
   1241                     Image
   1242                     );
   1243     if (EFI_ERROR (Status)) {
   1244       Print (L"Failed to allocate space for image\n");
   1245       goto Error;
   1246     }
   1247 
   1248     TftpContext->DownloadedNbOfBytes   = 0;
   1249     TftpContext->LastReportedNbOfBytes = 0;
   1250 
   1251     ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
   1252     Mtftp4Token.Filename    = (UINT8*)AsciiFilePath;
   1253     Mtftp4Token.BufferSize  = TftpBufferSize;
   1254     Mtftp4Token.Buffer      = (VOID *)(UINTN)*Image;
   1255     Mtftp4Token.CheckPacket = Mtftp4CheckPacket;
   1256     Mtftp4Token.Context     = (VOID*)TftpContext;
   1257 
   1258     Print (L"Downloading the file <%a> from the TFTP server\n", AsciiFilePath);
   1259     Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
   1260     Print (L"\n");
   1261     if (EFI_ERROR (Status)) {
   1262       gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
   1263       if (Status == EFI_BUFFER_TOO_SMALL) {
   1264         Print (L"Downloading failed, file larger than expected.\n");
   1265         continue;
   1266       } else {
   1267         goto Error;
   1268       }
   1269     }
   1270 
   1271     *ImageSize = Mtftp4Token.BufferSize;
   1272     break;
   1273   }
   1274 
   1275 Error:
   1276   if (Dhcp4ChildHandle != NULL) {
   1277     if (Dhcp4 != NULL) {
   1278       if (Dhcp4ToStop) {
   1279         Dhcp4->Stop (Dhcp4);
   1280       }
   1281       gBS->CloseProtocol (
   1282              Dhcp4ChildHandle,
   1283              &gEfiDhcp4ProtocolGuid,
   1284              gImageHandle,
   1285              ControllerHandle
   1286             );
   1287     }
   1288     NetLibDestroyServiceChild (
   1289       ControllerHandle,
   1290       gImageHandle,
   1291       &gEfiDhcp4ServiceBindingProtocolGuid,
   1292       Dhcp4ChildHandle
   1293       );
   1294   }
   1295 
   1296   if (Mtftp4ChildHandle != NULL) {
   1297     if (Mtftp4 != NULL) {
   1298       if (AsciiFilePath != NULL) {
   1299         FreePool (AsciiFilePath);
   1300       }
   1301       if (TftpContext != NULL) {
   1302         FreePool (TftpContext);
   1303       }
   1304       gBS->CloseProtocol (
   1305              Mtftp4ChildHandle,
   1306              &gEfiMtftp4ProtocolGuid,
   1307              gImageHandle,
   1308              ControllerHandle
   1309             );
   1310     }
   1311     NetLibDestroyServiceChild (
   1312       ControllerHandle,
   1313       gImageHandle,
   1314       &gEfiMtftp4ServiceBindingProtocolGuid,
   1315       Mtftp4ChildHandle
   1316       );
   1317   }
   1318 
   1319   if (EFI_ERROR (Status)) {
   1320     *Image = 0;
   1321     Print (L"Failed to download the file - Error=%r\n", Status);
   1322   }
   1323 
   1324   return Status;
   1325 }
   1326 
   1327 #define BOOT_MAGIC        "ANDROID!"
   1328 #define BOOT_MAGIC_LENGTH sizeof (BOOT_MAGIC) - 1
   1329 #define BOOTIMG_KERNEL_ARGS_SIZE 512
   1330 
   1331 
   1332 // Check Val (unsigned) is a power of 2 (has only one bit set)
   1333 #define IS_POWER_OF_2(Val) (Val != 0 && ((Val & (Val - 1)) == 0))
   1334 
   1335 /* It's the hack value of arm64 efi stub kernel */
   1336 #define KERNEL_IMAGE_STEXT_OFFSET     0x12C
   1337 #define KERNEL_IMAGE_RAW_SIZE_OFFSET  0x130
   1338 
   1339 typedef struct {
   1340   CHAR8   BootMagic[BOOT_MAGIC_LENGTH];
   1341   UINT32  KernelSize;
   1342   UINT32  KernelAddress;
   1343   UINT32  RamdiskSize;
   1344   UINT32  RamdiskAddress;
   1345   UINT32  SecondStageBootloaderSize;
   1346   UINT32  SecondStageBootloaderAddress;
   1347   UINT32  KernelTaggsAddress;
   1348   UINT32  PageSize;
   1349   UINT32  Reserved[2];
   1350   CHAR8   ProductName[16];
   1351   CHAR8   KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE];
   1352   UINT32  Id[32];
   1353 } ANDROID_BOOTIMG_HEADER;
   1354 
   1355 EFI_STATUS
   1356 STATIC LoadAndroidBootImg (
   1357   IN UINTN                    BufferSize,
   1358   IN VOID                    *Buffer,
   1359   IN BDS_LOAD_OPTION         *BdsLoadOption,
   1360   OUT EFI_PHYSICAL_ADDRESS   *Image,
   1361   OUT UINTN                  *ImageSize
   1362   )
   1363 {
   1364   EFI_STATUS                  Status;
   1365   EFI_PHYSICAL_ADDRESS        KernelBase, RamdiskBase, FdtBase;
   1366   UINTN                       KernelSize;
   1367   ANDROID_BOOTIMG_HEADER     *Header;
   1368   CHAR16                      KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE];
   1369   CHAR16                      InitrdArgs[64];
   1370   UINTN                       VariableSize;
   1371   CHAR16                      SerialNoArgs[40], DataUnicode[17];
   1372 
   1373   Header = (ANDROID_BOOTIMG_HEADER *) Buffer;
   1374 
   1375   if (AsciiStrnCmp (Header->BootMagic, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) {
   1376     return EFI_INVALID_PARAMETER;
   1377   }
   1378 
   1379   if (Header->KernelSize == 0) {
   1380     return EFI_NOT_FOUND;
   1381   }
   1382 
   1383   ASSERT (IS_POWER_OF_2 (Header->PageSize));
   1384 
   1385   KernelBase = Header->KernelAddress;
   1386   Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode,
   1387                                EFI_SIZE_TO_PAGES (Header->KernelSize), (VOID *)&KernelBase);
   1388   ASSERT_EFI_ERROR (Status);
   1389   CopyMem ((VOID *)KernelBase,
   1390            (CONST VOID *)((UINTN)Buffer + Header->PageSize),
   1391 	   Header->KernelSize);
   1392 
   1393   RamdiskBase = Header->RamdiskAddress;
   1394   if (Header->RamdiskSize != 0) {
   1395     Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode,
   1396                                  EFI_SIZE_TO_PAGES (Header->RamdiskSize), (VOID *)&RamdiskBase);
   1397     ASSERT_EFI_ERROR (Status);
   1398     CopyMem ((VOID *)RamdiskBase,
   1399              (VOID *)((UINTN)Buffer + Header->PageSize + ALIGN_VALUE (Header->KernelSize, Header->PageSize)),
   1400 	     Header->RamdiskSize
   1401 	    );
   1402     if (RamdiskBase != Header->RamdiskAddress)
   1403       Header->RamdiskAddress = RamdiskBase;
   1404   }
   1405   /* Install Fdt */
   1406   KernelSize = *(UINT32 *)(KernelBase + KERNEL_IMAGE_STEXT_OFFSET) +
   1407                *(UINT32 *)(KernelBase + KERNEL_IMAGE_RAW_SIZE_OFFSET);
   1408   ASSERT (KernelSize < Header->KernelSize);
   1409 
   1410   /* FDT is at the end of kernel image */
   1411   FdtBase = KernelBase + KernelSize;
   1412   Status = gBS->InstallConfigurationTable (
   1413 		  &gFdtTableGuid,
   1414 		  (VOID *)FdtBase
   1415 		  );
   1416   ASSERT_EFI_ERROR (Status);
   1417 
   1418   /* update kernel args */
   1419   AsciiStrToUnicodeStr (Header->KernelArgs, KernelArgs);
   1420   if (StrnCmp (KernelArgs, BdsLoadOption->OptionalData,
   1421                BOOTIMG_KERNEL_ARGS_SIZE) != 0) {
   1422     ASSERT (BdsLoadOption->OptionalData != NULL);
   1423     ASSERT (StrSize (KernelArgs) <= BOOTIMG_KERNEL_ARGS_SIZE);
   1424 
   1425     UnicodeSPrint (InitrdArgs, 64 * sizeof(CHAR16), L" initrd=0x%x,0x%x",
   1426 		   Header->RamdiskAddress, Header->RamdiskSize);
   1427     StrCat (KernelArgs, InitrdArgs);
   1428     VariableSize = 17 * sizeof (CHAR16);
   1429     Status = gRT->GetVariable (
   1430 		    (CHAR16 *)L"SerialNo",
   1431 		    &gHiKeyVariableGuid,
   1432 		    NULL,
   1433 		    &VariableSize,
   1434 		    &DataUnicode
   1435 		    );
   1436     if (EFI_ERROR (Status)) {
   1437       goto out;
   1438     }
   1439     DataUnicode[(VariableSize / sizeof(CHAR16)) - 1] = '\0';
   1440     ZeroMem (SerialNoArgs, 40 * sizeof (CHAR16));
   1441     UnicodeSPrint (SerialNoArgs, 40 * sizeof(CHAR16), L" androidboot.serialno=%s", DataUnicode);
   1442     StrCat (KernelArgs, SerialNoArgs);
   1443     ASSERT (StrSize (KernelArgs) <= BOOTIMG_KERNEL_ARGS_SIZE);
   1444     if (gArgs != NULL) {
   1445       CopyMem ((VOID *)gArgs,
   1446                (VOID *)KernelArgs,
   1447 	       StrSize (KernelArgs)
   1448 	      );
   1449     }
   1450   }
   1451 
   1452   *Image = KernelBase;
   1453   *ImageSize = Header->KernelSize;
   1454   return EFI_SUCCESS;
   1455 out:
   1456   return Status;
   1457 }
   1458 
   1459 BOOLEAN
   1460 BdsAndroidKernelSupport (
   1461   IN EFI_DEVICE_PATH  *DevicePath,
   1462   IN EFI_HANDLE       Handle,
   1463   IN EFI_DEVICE_PATH  *RemainingDevicePath
   1464   )
   1465 {
   1466   // Validate the Remaining Device Path
   1467   if (IsDevicePathEnd (RemainingDevicePath)) {
   1468     return FALSE;
   1469   }
   1470   if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH,
   1471 			    MEDIA_RELATIVE_OFFSET_RANGE_DP)) {
   1472     return FALSE;
   1473   }
   1474   return TRUE;
   1475 }
   1476 
   1477 STATIC
   1478 BOOLEAN
   1479 CompareDevicePath (
   1480   IN EFI_DEVICE_PATH    *DevicePath1,
   1481   IN EFI_DEVICE_PATH    *DevicePath2
   1482   )
   1483 {
   1484   UINTN     Size1, Size2;
   1485 
   1486   Size1 = GetDevicePathSize (DevicePath1);
   1487   Size2 = GetDevicePathSize (DevicePath2);
   1488   if (Size1 != Size2)
   1489     return FALSE;
   1490   if (Size1 == 0)
   1491     return FALSE;
   1492   if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
   1493     return FALSE;
   1494   }
   1495 
   1496   return TRUE;
   1497 }
   1498 
   1499 STATIC
   1500 EFI_STATUS
   1501 BdsLocateBootOption (
   1502   IN EFI_DEVICE_PATH    *DevicePath,
   1503   OUT BDS_LOAD_OPTION  **BdsLoadOption
   1504   )
   1505 {
   1506   UINTN             Index;
   1507   EFI_STATUS        Status;
   1508   BDS_LOAD_OPTION  *LoadOption;
   1509 
   1510   for (Index = 0; ; Index++) {
   1511     Status = BootOptionFromLoadOptionIndex (Index, &LoadOption);
   1512     if (EFI_ERROR (Status))
   1513       return Status;
   1514     if (CompareDevicePath (DevicePath, LoadOption->FilePathList) == FALSE)
   1515       continue;
   1516     *BdsLoadOption = LoadOption;
   1517     return EFI_SUCCESS;
   1518   }
   1519   return Status;
   1520 }
   1521 
   1522 EFI_STATUS
   1523 BdsAndroidKernelLoadImage (
   1524   IN OUT EFI_DEVICE_PATH       **DevicePath,
   1525   IN     EFI_HANDLE            Handle,
   1526   IN     EFI_DEVICE_PATH       *RemainingDevicePath,
   1527   IN     EFI_ALLOCATE_TYPE     Type,
   1528   IN OUT EFI_PHYSICAL_ADDRESS  *Image,
   1529   OUT    UINTN                 *ImageSize
   1530   )
   1531 {
   1532   EFI_STATUS   Status;
   1533   EFI_BLOCK_IO_PROTOCOL   *BlockIo;
   1534   EFI_DEVICE_PATH_PROTOCOL           *Node, *NextNode;
   1535   HARDDRIVE_DEVICE_PATH        *PartitionPath;
   1536   UINT32                        MediaId;
   1537   UINTN                         BlockSize;
   1538   VOID                         *Buffer;
   1539   BDS_LOAD_OPTION              *BdsLoadOption = NULL;
   1540 
   1541   /* Find DevicePath node of Partition */
   1542   NextNode = *DevicePath;
   1543   do {
   1544     Node = NextNode;
   1545     NextNode = NextDevicePathNode (Node);
   1546   } while (!IS_DEVICE_PATH_NODE (NextNode, MEDIA_DEVICE_PATH,
   1547 			         MEDIA_RELATIVE_OFFSET_RANGE_DP));
   1548   PartitionPath = (HARDDRIVE_DEVICE_PATH *)Node;
   1549 
   1550   Status = BdsLocateBootOption (*DevicePath, &BdsLoadOption);
   1551   if (EFI_ERROR (Status))
   1552     return Status;
   1553 
   1554   Status = gBS->OpenProtocol (
   1555 		  Handle,
   1556 		  &gEfiBlockIoProtocolGuid,
   1557 		  (VOID **) &BlockIo,
   1558 		  gImageHandle,
   1559 		  NULL,
   1560 		  EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1561 		  );
   1562   if (EFI_ERROR (Status)) {
   1563     DEBUG ((EFI_D_ERROR, "Can't open BlockIo protocol, Status:%r\n", Status));
   1564     return Status;
   1565   }
   1566   MediaId = BlockIo->Media->MediaId;
   1567   BlockSize = BlockIo->Media->BlockSize;
   1568   /* Both PartitionStart and PartitionSize are counted as block size. */
   1569   Buffer = AllocatePages (EFI_SIZE_TO_PAGES(PartitionPath->PartitionSize * BlockSize));
   1570   if (Buffer == NULL)
   1571     return EFI_BUFFER_TOO_SMALL;
   1572 
   1573   /* Load header of boot.img */
   1574   Status = BlockIo->ReadBlocks (BlockIo, MediaId, 0, PartitionPath->PartitionSize * BlockSize, Buffer);
   1575   if (EFI_ERROR (Status)) {
   1576     DEBUG ((EFI_D_ERROR, "Failed to read blocks: %r\n", Status));
   1577     return Status;
   1578   }
   1579   Status = LoadAndroidBootImg (PartitionPath->PartitionSize, Buffer, BdsLoadOption, Image, ImageSize);
   1580 
   1581   return EFI_SUCCESS;
   1582 }
   1583 
   1584 BDS_FILE_LOADER FileLoaders[] = {
   1585     { BdsFileSystemSupport, BdsFileSystemLoadImage },
   1586     { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
   1587     //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
   1588     { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
   1589     { BdsPxeSupport, BdsPxeLoadImage },
   1590     { BdsTftpSupport, BdsTftpLoadImage },
   1591     { BdsAndroidKernelSupport, BdsAndroidKernelLoadImage },
   1592     { NULL, NULL }
   1593 };
   1594 
   1595 EFI_STATUS
   1596 BdsLoadImageAndUpdateDevicePath (
   1597   IN OUT EFI_DEVICE_PATH       **DevicePath,
   1598   IN     EFI_ALLOCATE_TYPE     Type,
   1599   IN OUT EFI_PHYSICAL_ADDRESS* Image,
   1600   OUT    UINTN                 *FileSize
   1601   )
   1602 {
   1603   EFI_STATUS      Status;
   1604   EFI_HANDLE      Handle;
   1605   EFI_DEVICE_PATH *RemainingDevicePath;
   1606   BDS_FILE_LOADER*  FileLoader;
   1607 
   1608   Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);
   1609   if (EFI_ERROR (Status)) {
   1610     return Status;
   1611   }
   1612 
   1613   FileLoader = FileLoaders;
   1614   while (FileLoader->Support != NULL) {
   1615     if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {
   1616       return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
   1617     }
   1618     FileLoader++;
   1619   }
   1620 
   1621   return EFI_UNSUPPORTED;
   1622 }
   1623 
   1624 EFI_STATUS
   1625 BdsLoadImage (
   1626   IN     EFI_DEVICE_PATH       *DevicePath,
   1627   IN     EFI_ALLOCATE_TYPE     Type,
   1628   IN OUT EFI_PHYSICAL_ADDRESS* Image,
   1629   OUT    UINTN                 *FileSize
   1630   )
   1631 {
   1632   return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
   1633 }
   1634 
   1635 /**
   1636   Start an EFI Application from a Device Path
   1637 
   1638   @param  ParentImageHandle     Handle of the calling image
   1639   @param  DevicePath            Location of the EFI Application
   1640 
   1641   @retval EFI_SUCCESS           All drivers have been connected
   1642   @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found
   1643   @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.
   1644 
   1645 **/
   1646 EFI_STATUS
   1647 BdsStartEfiApplication (
   1648   IN EFI_HANDLE                  ParentImageHandle,
   1649   IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
   1650   IN UINTN                       LoadOptionsSize,
   1651   IN VOID*                       LoadOptions
   1652   )
   1653 {
   1654   EFI_STATUS                   Status;
   1655   EFI_HANDLE                   ImageHandle;
   1656   EFI_PHYSICAL_ADDRESS         BinaryBuffer;
   1657   UINTN                        BinarySize;
   1658   EFI_LOADED_IMAGE_PROTOCOL*   LoadedImage;
   1659 
   1660   // Hack for android kernel args
   1661   gArgs = LoadOptions;
   1662   // Find the nearest supported file loader
   1663   Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);
   1664   if (EFI_ERROR (Status)) {
   1665     return Status;
   1666   }
   1667 
   1668   // Load the image from the Buffer with Boot Services function
   1669   Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
   1670   if (EFI_ERROR (Status)) {
   1671     return Status;
   1672   }
   1673 
   1674   // Passed LoadOptions to the EFI Application
   1675   if (LoadOptionsSize != 0) {
   1676     Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
   1677     if (EFI_ERROR (Status)) {
   1678       return Status;
   1679     }
   1680 
   1681     LoadedImage->LoadOptionsSize  = LoadOptionsSize;
   1682     LoadedImage->LoadOptions      = LoadOptions;
   1683   }
   1684 
   1685   // Before calling the image, enable the Watchdog Timer for  the 5 Minute period
   1686   gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
   1687   // Start the image
   1688   Status = gBS->StartImage (ImageHandle, NULL, NULL);
   1689   // Clear the Watchdog Timer after the image returns
   1690   gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
   1691 
   1692   return Status;
   1693 }
   1694