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*
BdsExtractFilePathFromDevicePath(IN CONST CHAR16 * StrDevicePath,IN UINTN NumberDevicePathNode)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
BdsIsRemovableUsb(IN EFI_DEVICE_PATH * DevicePath)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
BdsGetDeviceUsb(IN EFI_DEVICE_PATH * RemovableDevicePath,OUT EFI_HANDLE * DeviceHandle,OUT EFI_DEVICE_PATH ** NewDevicePath)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
BdsIsRemovableHd(IN EFI_DEVICE_PATH * DevicePath)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
BdsGetDeviceHd(IN EFI_DEVICE_PATH * RemovableDevicePath,OUT EFI_HANDLE * DeviceHandle,OUT EFI_DEVICE_PATH ** NewDevicePath)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
IsRemovableDevice(IN EFI_DEVICE_PATH * DevicePath)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
TryRemovableDevice(IN EFI_DEVICE_PATH * DevicePath,OUT EFI_HANDLE * DeviceHandle,OUT EFI_DEVICE_PATH ** NewDevicePath)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
BdsConnectAndUpdateDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,OUT EFI_HANDLE * Handle,OUT EFI_DEVICE_PATH_PROTOCOL ** RemainingDevicePath)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
BdsConnectDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT EFI_HANDLE * Handle,OUT EFI_DEVICE_PATH_PROTOCOL ** RemainingDevicePath)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
BdsFileSystemSupport(IN EFI_DEVICE_PATH * DevicePath,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH * RemainingDevicePath)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
BdsFileSystemLoadImage(IN OUT 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)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
BdsMemoryMapSupport(IN EFI_DEVICE_PATH * DevicePath,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH * RemainingDevicePath)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
BdsMemoryMapLoadImage(IN OUT 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)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
BdsFirmwareVolumeSupport(IN EFI_DEVICE_PATH * DevicePath,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH * RemainingDevicePath)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
BdsFirmwareVolumeLoadImage(IN OUT 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)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
BdsPxeSupport(IN EFI_DEVICE_PATH * DevicePath,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH * RemainingDevicePath)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
BdsPxeLoadImage(IN OUT 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)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
BdsTftpSupport(IN EFI_DEVICE_PATH * DevicePath,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH * RemainingDevicePath)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
Mtftp4GetFileSize(IN EFI_MTFTP4_PROTOCOL * Mtftp4,IN CHAR8 * FilePath,OUT UINT64 * FileSize)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
Mtftp4CheckPacket(IN EFI_MTFTP4_PROTOCOL * This,IN EFI_MTFTP4_TOKEN * Token,IN UINT16 PacketLen,IN EFI_MTFTP4_PACKET * Packet)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
BdsTftpLoadImage(IN OUT EFI_DEVICE_PATH ** DevicePath,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH * RemainingDevicePath,IN EFI_ALLOCATE_TYPE Type,IN OUT EFI_PHYSICAL_ADDRESS * Image,OUT UINTN * ImageSize)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
LoadAndroidBootImg(IN UINTN BufferSize,IN VOID * Buffer,IN BDS_LOAD_OPTION * BdsLoadOption,OUT EFI_PHYSICAL_ADDRESS * Image,OUT UINTN * ImageSize)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
BdsAndroidKernelSupport(IN EFI_DEVICE_PATH * DevicePath,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH * RemainingDevicePath)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
CompareDevicePath(IN EFI_DEVICE_PATH * DevicePath1,IN EFI_DEVICE_PATH * DevicePath2)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
BdsLocateBootOption(IN EFI_DEVICE_PATH * DevicePath,OUT BDS_LOAD_OPTION ** BdsLoadOption)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
BdsAndroidKernelLoadImage(IN OUT 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)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
BdsLoadImageAndUpdateDevicePath(IN OUT EFI_DEVICE_PATH ** DevicePath,IN EFI_ALLOCATE_TYPE Type,IN OUT EFI_PHYSICAL_ADDRESS * Image,OUT UINTN * FileSize)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
BdsLoadImage(IN EFI_DEVICE_PATH * DevicePath,IN EFI_ALLOCATE_TYPE Type,IN OUT EFI_PHYSICAL_ADDRESS * Image,OUT UINTN * FileSize)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
BdsStartEfiApplication(IN EFI_HANDLE ParentImageHandle,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINTN LoadOptionsSize,IN VOID * LoadOptions)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