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