]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPkg/BdsLib: Rework TFTP boot
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsFilePath.c
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/UsbIo.h>
21 #include <Protocol/DiskIo.h>
22 #include <Protocol/LoadedImage.h>
23 #include <Protocol/SimpleNetwork.h>
24 #include <Protocol/Dhcp4.h>
25 #include <Protocol/Mtftp4.h>
26
27 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
28
29 /*
30 Constant strings and define related to the message indicating the amount of
31 progress in the dowloading of a TFTP file.
32 */
33
34 // Frame for the progression slider
35 STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]";
36
37 // Number of steps in the progression slider
38 #define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
39
40 // Size in number of characters plus one (final zero) of the message to
41 // indicate the progress of a tftp download. The format is "[(progress slider:
42 // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
43 // are thus the number of characters in mTftpProgressFrame[] plus 11 characters
44 // (2 // spaces, "Kb" and seven characters for the number of KBytes).
45 #define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
46
47 // String to delete the tftp progress message to be able to update it :
48 // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
49 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";
50
51
52 // Extract the FilePath from the Device Path
53 CHAR16*
54 BdsExtractFilePathFromDevicePath (
55 IN CONST CHAR16 *StrDevicePath,
56 IN UINTN NumberDevicePathNode
57 )
58 {
59 UINTN Node;
60 CHAR16 *Str;
61
62 Str = (CHAR16*)StrDevicePath;
63 Node = 0;
64 while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
65 if ((*Str == L'/') || (*Str == L'\\')) {
66 Node++;
67 }
68 Str++;
69 }
70
71 if (*Str == L'\0') {
72 return NULL;
73 } else {
74 return Str;
75 }
76 }
77
78 BOOLEAN
79 BdsIsRemovableUsb (
80 IN EFI_DEVICE_PATH* DevicePath
81 )
82 {
83 return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
84 ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
85 (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));
86 }
87
88 EFI_STATUS
89 BdsGetDeviceUsb (
90 IN EFI_DEVICE_PATH* RemovableDevicePath,
91 OUT EFI_HANDLE* DeviceHandle,
92 OUT EFI_DEVICE_PATH** NewDevicePath
93 )
94 {
95 EFI_STATUS Status;
96 UINTN Index;
97 UINTN UsbIoHandleCount;
98 EFI_HANDLE *UsbIoBuffer;
99 EFI_DEVICE_PATH* UsbIoDevicePath;
100 EFI_DEVICE_PATH* TmpDevicePath;
101 USB_WWID_DEVICE_PATH* WwidDevicePath1;
102 USB_WWID_DEVICE_PATH* WwidDevicePath2;
103 USB_CLASS_DEVICE_PATH* UsbClassDevicePath1;
104 USB_CLASS_DEVICE_PATH* UsbClassDevicePath2;
105
106 // Get all the UsbIo handles
107 UsbIoHandleCount = 0;
108 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
109 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0)) {
110 return Status;
111 }
112
113 // Check if one of the handles matches the USB description
114 for (Index = 0; Index < UsbIoHandleCount; Index++) {
115 Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);
116 if (!EFI_ERROR (Status)) {
117 TmpDevicePath = UsbIoDevicePath;
118 while (!IsDevicePathEnd (TmpDevicePath)) {
119 // Check if the Device Path node is a USB Removable device Path node
120 if (BdsIsRemovableUsb (TmpDevicePath)) {
121 if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {
122 WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;
123 WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;
124 if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&
125 (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&
126 (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) == 0))
127 {
128 *DeviceHandle = UsbIoBuffer[Index];
129 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
130 *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));
131 return EFI_SUCCESS;
132 }
133 } else {
134 UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;
135 UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;
136 if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&
137 (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&
138 (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&
139 (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&
140 (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))
141 {
142 *DeviceHandle = UsbIoBuffer[Index];
143 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
144 *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));
145 return EFI_SUCCESS;
146 }
147 }
148 }
149 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
150 }
151
152 }
153 }
154
155 return EFI_NOT_FOUND;
156 }
157
158 BOOLEAN
159 BdsIsRemovableHd (
160 IN EFI_DEVICE_PATH* DevicePath
161 )
162 {
163 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);
164 }
165
166 EFI_STATUS
167 BdsGetDeviceHd (
168 IN EFI_DEVICE_PATH* RemovableDevicePath,
169 OUT EFI_HANDLE* DeviceHandle,
170 OUT EFI_DEVICE_PATH** NewDevicePath
171 )
172 {
173 EFI_STATUS Status;
174 UINTN Index;
175 UINTN PartitionHandleCount;
176 EFI_HANDLE *PartitionBuffer;
177 EFI_DEVICE_PATH* PartitionDevicePath;
178 EFI_DEVICE_PATH* TmpDevicePath;
179 HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1;
180 HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2;
181
182 // Get all the DiskIo handles
183 PartitionHandleCount = 0;
184 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);
185 if (EFI_ERROR (Status) || (PartitionHandleCount == 0)) {
186 return Status;
187 }
188
189 // Check if one of the handles matches the Hard Disk Description
190 for (Index = 0; Index < PartitionHandleCount; Index++) {
191 Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);
192 if (!EFI_ERROR (Status)) {
193 TmpDevicePath = PartitionDevicePath;
194 while (!IsDevicePathEnd (TmpDevicePath)) {
195 // Check if the Device Path node is a HD Removable device Path node
196 if (BdsIsRemovableHd (TmpDevicePath)) {
197 HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;
198 HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;
199 if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&
200 (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&
201 (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))
202 {
203 *DeviceHandle = PartitionBuffer[Index];
204 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
205 *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode (RemovableDevicePath));
206 return EFI_SUCCESS;
207 }
208 }
209 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
210 }
211
212 }
213 }
214
215 return EFI_NOT_FOUND;
216 }
217
218 /*BOOLEAN
219 BdsIsRemovableCdrom (
220 IN EFI_DEVICE_PATH* DevicePath
221 )
222 {
223 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
224 }
225
226 EFI_STATUS
227 BdsGetDeviceCdrom (
228 IN EFI_DEVICE_PATH* RemovableDevicePath,
229 OUT EFI_HANDLE* DeviceHandle,
230 OUT EFI_DEVICE_PATH** DevicePath
231 )
232 {
233 ASSERT(0);
234 return EFI_UNSUPPORTED;
235 }*/
236
237 typedef BOOLEAN
238 (*BDS_IS_REMOVABLE) (
239 IN EFI_DEVICE_PATH* DevicePath
240 );
241
242 typedef EFI_STATUS
243 (*BDS_GET_DEVICE) (
244 IN EFI_DEVICE_PATH* RemovableDevicePath,
245 OUT EFI_HANDLE* DeviceHandle,
246 OUT EFI_DEVICE_PATH** DevicePath
247 );
248
249 typedef struct {
250 BDS_IS_REMOVABLE IsRemovable;
251 BDS_GET_DEVICE GetDevice;
252 } BDS_REMOVABLE_DEVICE_SUPPORT;
253
254 BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = {
255 { BdsIsRemovableUsb, BdsGetDeviceUsb },
256 { BdsIsRemovableHd, BdsGetDeviceHd },
257 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
258 };
259
260 STATIC
261 BOOLEAN
262 IsRemovableDevice (
263 IN EFI_DEVICE_PATH* DevicePath
264 )
265 {
266 UINTN Index;
267 EFI_DEVICE_PATH* TmpDevicePath;
268
269 TmpDevicePath = DevicePath;
270 while (!IsDevicePathEnd (TmpDevicePath)) {
271 for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
272 if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) {
273 return TRUE;
274 }
275 }
276 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
277 }
278
279 return FALSE;
280 }
281
282 STATIC
283 EFI_STATUS
284 TryRemovableDevice (
285 IN EFI_DEVICE_PATH* DevicePath,
286 OUT EFI_HANDLE* DeviceHandle,
287 OUT EFI_DEVICE_PATH** NewDevicePath
288 )
289 {
290 EFI_STATUS Status;
291 UINTN Index;
292 EFI_DEVICE_PATH* TmpDevicePath;
293 BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;
294 EFI_DEVICE_PATH* RemovableDevicePath;
295 BOOLEAN RemovableFound;
296
297 RemovableDevice = NULL;
298 RemovableDevicePath = NULL;
299 RemovableFound = FALSE;
300 TmpDevicePath = DevicePath;
301
302 while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
303 for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
304 RemovableDevice = &RemovableDeviceSupport[Index];
305 if (RemovableDevice->IsRemovable (TmpDevicePath)) {
306 RemovableDevicePath = TmpDevicePath;
307 RemovableFound = TRUE;
308 break;
309 }
310 }
311 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
312 }
313
314 if (!RemovableFound) {
315 return EFI_NOT_FOUND;
316 }
317
318 // Search into the current started drivers
319 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
320 if (Status == EFI_NOT_FOUND) {
321 // Connect all the drivers
322 BdsConnectAllDrivers ();
323
324 // Search again into all the drivers
325 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
326 }
327
328 return Status;
329 }
330
331 STATIC
332 EFI_STATUS
333 BdsConnectAndUpdateDevicePath (
334 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
335 OUT EFI_HANDLE *Handle,
336 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
337 )
338 {
339 EFI_DEVICE_PATH* Remaining;
340 EFI_DEVICE_PATH* NewDevicePath;
341 EFI_STATUS Status;
342 EFI_HANDLE PreviousHandle;
343
344 if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {
345 return EFI_INVALID_PARAMETER;
346 }
347
348 PreviousHandle = NULL;
349 do {
350 Remaining = *DevicePath;
351
352 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
353 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
354 // to point to the remaining part of the device path
355 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
356
357 if (!EFI_ERROR (Status)) {
358 if (*Handle == PreviousHandle) {
359 //
360 // If no forward progress is made try invoking the Dispatcher.
361 // A new FV may have been added to the system and new drivers
362 // may now be found.
363 // Status == EFI_SUCCESS means a driver was dispatched
364 // Status == EFI_NOT_FOUND means no new drivers were dispatched
365 //
366 Status = gDS->Dispatch ();
367 }
368
369 if (!EFI_ERROR (Status)) {
370 PreviousHandle = *Handle;
371
372 // Recursive = FALSE: We do not want to start the whole device tree
373 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
374 }
375 }
376 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
377
378 if (!EFI_ERROR (Status)) {
379 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
380 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
381 Remaining = *DevicePath;
382 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
383 if (!EFI_ERROR (Status)) {
384 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
385 if (EFI_ERROR (Status)) {
386 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
387 if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
388 Status = EFI_SUCCESS;
389 }
390 }
391 }
392 } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
393
394 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
395 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
396 Status = EFI_SUCCESS;
397 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
398 Status = EFI_SUCCESS;
399 }*/
400
401 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
402 Status = EFI_SUCCESS;
403 } else {
404 Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath);
405 if (!EFI_ERROR (Status)) {
406 Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);
407 *DevicePath = NewDevicePath;
408 return Status;
409 }
410 }
411
412 if (RemainingDevicePath) {
413 *RemainingDevicePath = Remaining;
414 }
415
416 return Status;
417 }
418
419 /**
420 Connect a Device Path and return the handle of the driver that support this DevicePath
421
422 @param DevicePath Device Path of the File to connect
423 @param Handle Handle of the driver that support this DevicePath
424 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
425
426 @retval EFI_SUCCESS A driver that matches the Device Path has been found
427 @retval EFI_NOT_FOUND No handles match the search.
428 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
429
430 **/
431 EFI_STATUS
432 BdsConnectDevicePath (
433 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
434 OUT EFI_HANDLE *Handle,
435 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
436 )
437 {
438 return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);
439 }
440
441 BOOLEAN
442 BdsFileSystemSupport (
443 IN EFI_DEVICE_PATH *DevicePath,
444 IN EFI_HANDLE Handle,
445 IN EFI_DEVICE_PATH *RemainingDevicePath
446 )
447 {
448 EFI_STATUS Status;
449 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
450
451 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
452
453 return (!EFI_ERROR (Status) && IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));
454 }
455
456 EFI_STATUS
457 BdsFileSystemLoadImage (
458 IN EFI_DEVICE_PATH *DevicePath,
459 IN EFI_HANDLE Handle,
460 IN EFI_DEVICE_PATH *RemainingDevicePath,
461 IN EFI_ALLOCATE_TYPE Type,
462 IN OUT EFI_PHYSICAL_ADDRESS* Image,
463 OUT UINTN *ImageSize
464 )
465 {
466 FILEPATH_DEVICE_PATH* FilePathDevicePath;
467 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
468 EFI_FILE_PROTOCOL *Fs;
469 EFI_STATUS Status;
470 EFI_FILE_INFO *FileInfo;
471 EFI_FILE_PROTOCOL *File;
472 UINTN Size;
473
474 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));
475
476 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
477
478 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
479 if (EFI_ERROR (Status)) {
480 return Status;
481 }
482
483 // Try to Open the volume and get root directory
484 Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
485 if (EFI_ERROR (Status)) {
486 return Status;
487 }
488
489 File = NULL;
490 Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
491 if (EFI_ERROR (Status)) {
492 return Status;
493 }
494
495 Size = 0;
496 File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
497 FileInfo = AllocatePool (Size);
498 Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
499 if (EFI_ERROR (Status)) {
500 return Status;
501 }
502
503 // Get the file size
504 Size = FileInfo->FileSize;
505 if (ImageSize) {
506 *ImageSize = Size;
507 }
508 FreePool (FileInfo);
509
510 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
511 // Try to allocate in any pages if failed to allocate memory at the defined location
512 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
513 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
514 }
515 if (!EFI_ERROR (Status)) {
516 Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
517 }
518
519 return Status;
520 }
521
522 BOOLEAN
523 BdsMemoryMapSupport (
524 IN EFI_DEVICE_PATH *DevicePath,
525 IN EFI_HANDLE Handle,
526 IN EFI_DEVICE_PATH *RemainingDevicePath
527 )
528 {
529 return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||
530 IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);
531 }
532
533 EFI_STATUS
534 BdsMemoryMapLoadImage (
535 IN EFI_DEVICE_PATH *DevicePath,
536 IN EFI_HANDLE Handle,
537 IN EFI_DEVICE_PATH *RemainingDevicePath,
538 IN EFI_ALLOCATE_TYPE Type,
539 IN OUT EFI_PHYSICAL_ADDRESS* Image,
540 OUT UINTN *ImageSize
541 )
542 {
543 EFI_STATUS Status;
544 MEMMAP_DEVICE_PATH* MemMapPathDevicePath;
545 UINTN Size;
546
547 if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {
548 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
549 } else {
550 ASSERT (IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));
551 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;
552 }
553
554 Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
555 if (Size == 0) {
556 return EFI_INVALID_PARAMETER;
557 }
558
559 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
560 // Try to allocate in any pages if failed to allocate memory at the defined location
561 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
562 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
563 }
564 if (!EFI_ERROR (Status)) {
565 CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
566
567 if (ImageSize != NULL) {
568 *ImageSize = Size;
569 }
570 }
571
572 return Status;
573 }
574
575 BOOLEAN
576 BdsFirmwareVolumeSupport (
577 IN EFI_DEVICE_PATH *DevicePath,
578 IN EFI_HANDLE Handle,
579 IN EFI_DEVICE_PATH *RemainingDevicePath
580 )
581 {
582 return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
583 }
584
585 EFI_STATUS
586 BdsFirmwareVolumeLoadImage (
587 IN EFI_DEVICE_PATH *DevicePath,
588 IN EFI_HANDLE Handle,
589 IN EFI_DEVICE_PATH *RemainingDevicePath,
590 IN EFI_ALLOCATE_TYPE Type,
591 IN OUT EFI_PHYSICAL_ADDRESS* Image,
592 OUT UINTN *ImageSize
593 )
594 {
595 EFI_STATUS Status;
596 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
597 EFI_GUID *FvNameGuid;
598 EFI_SECTION_TYPE SectionType;
599 EFI_FV_FILETYPE FvType;
600 EFI_FV_FILE_ATTRIBUTES Attrib;
601 UINT32 AuthenticationStatus;
602 VOID* ImageBuffer;
603
604 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
605
606 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
607 if (EFI_ERROR (Status)) {
608 return Status;
609 }
610
611 FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
612 if (FvNameGuid == NULL) {
613 Status = EFI_INVALID_PARAMETER;
614 }
615
616 SectionType = EFI_SECTION_PE32;
617 AuthenticationStatus = 0;
618 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
619 ImageBuffer = NULL;
620 Status = FwVol->ReadSection (
621 FwVol,
622 FvNameGuid,
623 SectionType,
624 0,
625 &ImageBuffer,
626 ImageSize,
627 &AuthenticationStatus
628 );
629 if (!EFI_ERROR (Status)) {
630 #if 0
631 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
632 if (Type != AllocateAnyPages) {
633 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
634 if (!EFI_ERROR (Status)) {
635 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
636 FreePool (ImageBuffer);
637 }
638 }
639 #else
640 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
641 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
642 // Try to allocate in any pages if failed to allocate memory at the defined location
643 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
644 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
645 }
646 if (!EFI_ERROR (Status)) {
647 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
648 FreePool (ImageBuffer);
649 }
650 #endif
651 } else {
652 // Try a raw file, since a PE32 SECTION does not exist
653 Status = FwVol->ReadFile (
654 FwVol,
655 FvNameGuid,
656 NULL,
657 ImageSize,
658 &FvType,
659 &Attrib,
660 &AuthenticationStatus
661 );
662 if (!EFI_ERROR (Status)) {
663 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
664 // Try to allocate in any pages if failed to allocate memory at the defined location
665 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
666 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
667 }
668 if (!EFI_ERROR (Status)) {
669 Status = FwVol->ReadFile (
670 FwVol,
671 FvNameGuid,
672 (VOID*)(UINTN)(*Image),
673 ImageSize,
674 &FvType,
675 &Attrib,
676 &AuthenticationStatus
677 );
678 }
679 }
680 }
681 return Status;
682 }
683
684 BOOLEAN
685 BdsPxeSupport (
686 IN EFI_DEVICE_PATH* DevicePath,
687 IN EFI_HANDLE Handle,
688 IN EFI_DEVICE_PATH* RemainingDevicePath
689 )
690 {
691 EFI_STATUS Status;
692 EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
693
694 if (!IsDevicePathEnd (RemainingDevicePath)) {
695 return FALSE;
696 }
697
698 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
699 if (EFI_ERROR (Status)) {
700 return FALSE;
701 } else {
702 return TRUE;
703 }
704 }
705
706 EFI_STATUS
707 BdsPxeLoadImage (
708 IN EFI_DEVICE_PATH* DevicePath,
709 IN EFI_HANDLE Handle,
710 IN EFI_DEVICE_PATH* RemainingDevicePath,
711 IN EFI_ALLOCATE_TYPE Type,
712 IN OUT EFI_PHYSICAL_ADDRESS *Image,
713 OUT UINTN *ImageSize
714 )
715 {
716 EFI_STATUS Status;
717 EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;
718 UINTN BufferSize;
719 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
720
721 // Get Load File Protocol attached to the PXE protocol
722 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
723 if (EFI_ERROR (Status)) {
724 return Status;
725 }
726
727 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);
728 if (Status == EFI_BUFFER_TOO_SMALL) {
729 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
730 if (EFI_ERROR (Status)) {
731 return Status;
732 }
733
734 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
735 if (!EFI_ERROR (Status) && (ImageSize != NULL)) {
736 *ImageSize = BufferSize;
737 }
738 }
739
740 if (Status == EFI_ALREADY_STARTED) {
741 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
742 if (!EFI_ERROR(Status)) {
743 // If PXE is already started, we stop it
744 Pxe->Stop (Pxe);
745 // And we try again
746 return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);
747 }
748 }
749 return Status;
750 }
751
752 BOOLEAN
753 BdsTftpSupport (
754 IN EFI_DEVICE_PATH *DevicePath,
755 IN EFI_HANDLE Handle,
756 IN EFI_DEVICE_PATH *RemainingDevicePath
757 )
758 {
759 EFI_STATUS Status;
760 EFI_DEVICE_PATH *NextDevicePath;
761 VOID *Interface;
762
763 // Validate the Remaining Device Path
764 if (IsDevicePathEnd (RemainingDevicePath)) {
765 return FALSE;
766 }
767 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&
768 !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {
769 return FALSE;
770 }
771 NextDevicePath = NextDevicePathNode (RemainingDevicePath);
772 if (IsDevicePathEnd (NextDevicePath)) {
773 return FALSE;
774 }
775 if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {
776 return FALSE;
777 }
778
779 Status = gBS->HandleProtocol (
780 Handle, &gEfiDevicePathProtocolGuid,
781 &Interface
782 );
783 if (EFI_ERROR (Status)) {
784 return FALSE;
785 }
786
787 //
788 // Check that the controller (identified by its handle "Handle") supports the
789 // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
790 // EFI MTFTPv4 Protocol needed to download the image through TFTP.
791 //
792 Status = gBS->HandleProtocol (
793 Handle, &gEfiMtftp4ServiceBindingProtocolGuid,
794 &Interface
795 );
796 if (EFI_ERROR (Status)) {
797 return FALSE;
798 }
799
800 return TRUE;
801 }
802
803 /**
804 Worker function that get the size in numbers of bytes of a file from a TFTP
805 server before to download the file.
806
807 @param[in] Mtftp4 MTFTP4 protocol interface
808 @param[in] FilePath Path of the file, Ascii encoded
809 @param[out] FileSize Address where to store the file size in number of
810 bytes.
811
812 @retval EFI_SUCCESS The size of the file was returned.
813 @retval !EFI_SUCCESS The size of the file was not returned.
814
815 **/
816 STATIC
817 EFI_STATUS
818 Mtftp4GetFileSize (
819 IN EFI_MTFTP4_PROTOCOL *Mtftp4,
820 IN CHAR8 *FilePath,
821 OUT UINT64 *FileSize
822 )
823 {
824 EFI_STATUS Status;
825 EFI_MTFTP4_OPTION ReqOpt[1];
826 EFI_MTFTP4_PACKET *Packet;
827 UINT32 PktLen;
828 EFI_MTFTP4_OPTION *TableOfOptions;
829 EFI_MTFTP4_OPTION *Option;
830 UINT32 OptCnt;
831 UINT8 OptBuf[128];
832
833 ReqOpt[0].OptionStr = (UINT8*)"tsize";
834 OptBuf[0] = '0';
835 OptBuf[1] = 0;
836 ReqOpt[0].ValueStr = OptBuf;
837
838 Status = Mtftp4->GetInfo (
839 Mtftp4,
840 NULL,
841 (UINT8*)FilePath,
842 NULL,
843 1,
844 ReqOpt,
845 &PktLen,
846 &Packet
847 );
848
849 if (EFI_ERROR (Status)) {
850 goto Error;
851 }
852
853 Status = Mtftp4->ParseOptions (
854 Mtftp4,
855 PktLen,
856 Packet,
857 (UINT32 *) &OptCnt,
858 &TableOfOptions
859 );
860 if (EFI_ERROR (Status)) {
861 goto Error;
862 }
863
864 Option = TableOfOptions;
865 while (OptCnt != 0) {
866 if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
867 *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr);
868 break;
869 }
870 OptCnt--;
871 Option++;
872 }
873 FreePool (TableOfOptions);
874
875 if (OptCnt == 0) {
876 Status = EFI_UNSUPPORTED;
877 }
878
879 Error :
880
881 return Status;
882 }
883
884 /**
885 Update the progress of a file download
886 This procedure is called each time a new TFTP packet is received.
887
888 @param[in] This MTFTP4 protocol interface
889 @param[in] Token Parameters for the download of the file
890 @param[in] PacketLen Length of the packet
891 @param[in] Packet Address of the packet
892
893 @retval EFI_SUCCESS All packets are accepted.
894
895 **/
896 STATIC
897 EFI_STATUS
898 Mtftp4CheckPacket (
899 IN EFI_MTFTP4_PROTOCOL *This,
900 IN EFI_MTFTP4_TOKEN *Token,
901 IN UINT16 PacketLen,
902 IN EFI_MTFTP4_PACKET *Packet
903 )
904 {
905 BDS_TFTP_CONTEXT *Context;
906 CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];
907 UINT64 NbOfKb;
908 UINTN Index;
909 UINTN LastStep;
910 UINTN Step;
911 UINT64 LastNbOf50Kb;
912 UINT64 NbOf50Kb;
913
914 if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) {
915 Context = (BDS_TFTP_CONTEXT*)Token->Context;
916
917 if (Context->DownloadedNbOfBytes == 0) {
918 if (Context->FileSize > 0) {
919 Print (L"%s 0 Kb", mTftpProgressFrame);
920 } else {
921 Print (L" 0 Kb");
922 }
923 }
924
925 //
926 // The data is the packet are prepended with two UINT16 :
927 // . OpCode = EFI_MTFTP4_OPCODE_DATA
928 // . Block = the number of this block of data
929 //
930 Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
931 NbOfKb = Context->DownloadedNbOfBytes / 1024;
932
933 Progress[0] = L'\0';
934 if (Context->FileSize > 0) {
935 LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
936 Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
937 if (Step > LastStep) {
938 Print (mTftpProgressDelete);
939 StrCpy (Progress, mTftpProgressFrame);
940 for (Index = 1; Index < Step; Index++) {
941 Progress[Index] = L'=';
942 }
943 Progress[Step] = L'>';
944
945 UnicodeSPrint (
946 Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
947 sizeof (Progress) - sizeof (mTftpProgressFrame),
948 L" %7d Kb",
949 NbOfKb
950 );
951 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
952 }
953 } else {
954 //
955 // Case when we do not know the size of the final file.
956 // We print the updated size every 50KB of downloaded data
957 //
958 LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024);
959 NbOf50Kb = Context->DownloadedNbOfBytes / (50*1024);
960 if (NbOf50Kb > LastNbOf50Kb) {
961 Print (L"\b\b\b\b\b\b\b\b\b\b");
962 UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb);
963 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
964 }
965 }
966 if (Progress[0] != L'\0') {
967 Print (L"%s", Progress);
968 }
969 }
970
971 return EFI_SUCCESS;
972 }
973
974 /**
975 Download an image from a TFTP server
976
977 @param[in] DevicePath Device path of the TFTP boot option
978 @param[in] ControllerHandle Handle of the network controller
979 @param[in] RemainingDevicePath Device path of the TFTP boot option but
980 the first node that identifies the network controller
981 @param[in] Type Type to allocate memory pages
982 @param[out] Image Address of the bufer where the image is stored in
983 case of success
984 @param[out] ImageSize Size in number of bytes of the i;age in case of
985 success
986
987 @retval EFI_SUCCESS The image was returned.
988 @retval !EFI_SUCCESS Something went wrong.
989
990 **/
991 EFI_STATUS
992 BdsTftpLoadImage (
993 IN EFI_DEVICE_PATH* DevicePath,
994 IN EFI_HANDLE ControllerHandle,
995 IN EFI_DEVICE_PATH* RemainingDevicePath,
996 IN EFI_ALLOCATE_TYPE Type,
997 IN OUT EFI_PHYSICAL_ADDRESS *Image,
998 OUT UINTN *ImageSize
999 )
1000 {
1001 EFI_STATUS Status;
1002 EFI_HANDLE Dhcp4ChildHandle;
1003 EFI_DHCP4_PROTOCOL *Dhcp4;
1004 BOOLEAN Dhcp4ToStop;
1005 EFI_HANDLE Mtftp4ChildHandle;
1006 EFI_MTFTP4_PROTOCOL *Mtftp4;
1007 EFI_DHCP4_CONFIG_DATA Dhcp4CfgData;
1008 EFI_DHCP4_MODE_DATA Dhcp4Mode;
1009 EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData;
1010 IPv4_DEVICE_PATH *IPv4DevicePathNode;
1011 FILEPATH_DEVICE_PATH *FilePathDevicePathNode;
1012 CHAR8 *AsciiFilePath;
1013 EFI_MTFTP4_TOKEN Mtftp4Token;
1014 UINT64 FileSize;
1015 UINT64 TftpBufferSize;
1016 BDS_TFTP_CONTEXT *TftpContext;
1017
1018 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));
1019 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
1020
1021 Dhcp4ChildHandle = NULL;
1022 Dhcp4 = NULL;
1023 Dhcp4ToStop = FALSE;
1024 Mtftp4ChildHandle = NULL;
1025 Mtftp4 = NULL;
1026 AsciiFilePath = NULL;
1027 TftpContext = NULL;
1028
1029 if (!IPv4DevicePathNode->StaticIpAddress) {
1030 //
1031 // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
1032 // install the DHCP4 protocol on it. Then, open the DHCP protocol.
1033 //
1034 Status = NetLibCreateServiceChild (
1035 ControllerHandle,
1036 gImageHandle,
1037 &gEfiDhcp4ServiceBindingProtocolGuid,
1038 &Dhcp4ChildHandle
1039 );
1040 if (!EFI_ERROR (Status)) {
1041 Status = gBS->OpenProtocol (
1042 Dhcp4ChildHandle,
1043 &gEfiDhcp4ProtocolGuid,
1044 (VOID **) &Dhcp4,
1045 gImageHandle,
1046 ControllerHandle,
1047 EFI_OPEN_PROTOCOL_BY_DRIVER
1048 );
1049 }
1050 if (EFI_ERROR (Status)) {
1051 Print (L"Unable to open DHCP4 protocol\n");
1052 goto Error;
1053 }
1054 }
1055
1056 //
1057 // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
1058 // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
1059 //
1060 Status = NetLibCreateServiceChild (
1061 ControllerHandle,
1062 gImageHandle,
1063 &gEfiMtftp4ServiceBindingProtocolGuid,
1064 &Mtftp4ChildHandle
1065 );
1066 if (!EFI_ERROR (Status)) {
1067 Status = gBS->OpenProtocol (
1068 Mtftp4ChildHandle,
1069 &gEfiMtftp4ProtocolGuid,
1070 (VOID **) &Mtftp4,
1071 gImageHandle,
1072 ControllerHandle,
1073 EFI_OPEN_PROTOCOL_BY_DRIVER
1074 );
1075 }
1076 if (EFI_ERROR (Status)) {
1077 Print (L"Unable to open MTFTP4 protocol\n");
1078 goto Error;
1079 }
1080
1081 if (!IPv4DevicePathNode->StaticIpAddress) {
1082 //
1083 // Configure the DHCP4, all default settings. It is acceptable for the configuration to
1084 // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
1085 // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
1086 // process has been started but is not completed yet.
1087 //
1088 ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
1089 Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
1090 if (EFI_ERROR (Status)) {
1091 if (Status != EFI_ACCESS_DENIED) {
1092 Print (L"Error while configuring the DHCP4 protocol\n");
1093 goto Error;
1094 }
1095 }
1096
1097 //
1098 // Start the DHCP configuration. This may have already been done thus do not leave in error
1099 // if the return code is EFI_ALREADY_STARTED.
1100 //
1101 Status = Dhcp4->Start (Dhcp4, NULL);
1102 if (EFI_ERROR (Status)) {
1103 if (Status != EFI_ALREADY_STARTED) {
1104 Print (L"DHCP configuration failed\n");
1105 goto Error;
1106 }
1107 } else {
1108 Dhcp4ToStop = TRUE;
1109 }
1110
1111 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
1112 if (EFI_ERROR (Status)) {
1113 goto Error;
1114 }
1115
1116 if (Dhcp4Mode.State != Dhcp4Bound) {
1117 Status = EFI_TIMEOUT;
1118 Print (L"DHCP configuration failed\n");
1119 goto Error;
1120 }
1121 }
1122
1123 //
1124 // Configure the TFTP4 protocol
1125 //
1126
1127 ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA));
1128 Mtftp4CfgData.UseDefaultSetting = FALSE;
1129 Mtftp4CfgData.TimeoutValue = 4;
1130 Mtftp4CfgData.TryCount = 6;
1131
1132 if (IPv4DevicePathNode->StaticIpAddress) {
1133 CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
1134 CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1135 CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
1136 } else {
1137 CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1138 CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask , sizeof (EFI_IPv4_ADDRESS));
1139 CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1140 }
1141
1142 CopyMem (&Mtftp4CfgData.ServerIp , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
1143
1144 Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData);
1145 if (EFI_ERROR (Status)) {
1146 Print (L"Error while configuring the MTFTP4 protocol\n");
1147 goto Error;
1148 }
1149
1150 //
1151 // Convert the Unicode path of the file to Ascii
1152 //
1153
1154 FilePathDevicePathNode = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
1155 AsciiFilePath = AllocatePool ((StrLen (FilePathDevicePathNode->PathName) + 1) * sizeof (CHAR8));
1156 if (AsciiFilePath == NULL) {
1157 Status = EFI_OUT_OF_RESOURCES;
1158 goto Error;
1159 }
1160 UnicodeStrToAsciiStr (FilePathDevicePathNode->PathName, AsciiFilePath);
1161
1162 //
1163 // Try to get the size of the file in bytes from the server. If it fails,
1164 // start with a 8MB buffer to download the file.
1165 //
1166 FileSize = 0;
1167 if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) {
1168 TftpBufferSize = FileSize;
1169 } else {
1170 TftpBufferSize = SIZE_8MB;
1171 }
1172
1173 TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT));
1174 if (TftpContext == NULL) {
1175 Status = EFI_OUT_OF_RESOURCES;
1176 goto Error;
1177 }
1178 TftpContext->FileSize = FileSize;
1179
1180 for (; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize);
1181 TftpBufferSize = (TftpBufferSize + SIZE_8MB) & (~(SIZE_8MB-1))) {
1182 //
1183 // Allocate a buffer to hold the whole file.
1184 //
1185 Status = gBS->AllocatePages (
1186 Type,
1187 EfiBootServicesCode,
1188 EFI_SIZE_TO_PAGES (TftpBufferSize),
1189 Image
1190 );
1191 if (EFI_ERROR (Status)) {
1192 Print (L"Failed to allocate space for image\n");
1193 goto Error;
1194 }
1195
1196 TftpContext->DownloadedNbOfBytes = 0;
1197 TftpContext->LastReportedNbOfBytes = 0;
1198
1199 ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
1200 Mtftp4Token.Filename = (UINT8*)AsciiFilePath;
1201 Mtftp4Token.BufferSize = TftpBufferSize;
1202 Mtftp4Token.Buffer = (VOID *)(UINTN)*Image;
1203 Mtftp4Token.CheckPacket = Mtftp4CheckPacket;
1204 Mtftp4Token.Context = (VOID*)TftpContext;
1205
1206 Print (L"Downloading the file <%s> from the TFTP server\n", FilePathDevicePathNode->PathName);
1207 Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
1208 Print (L"\n");
1209 if (EFI_ERROR (Status)) {
1210 if (Status == EFI_BUFFER_TOO_SMALL) {
1211 Print (L"Downloading failed, file larger than expected.\n");
1212 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
1213 continue;
1214 } else {
1215 goto Error;
1216 }
1217 }
1218
1219 *ImageSize = Mtftp4Token.BufferSize;
1220 break;
1221 }
1222
1223 Error:
1224 if (Dhcp4ChildHandle != NULL) {
1225 if (Dhcp4 != NULL) {
1226 if (Dhcp4ToStop) {
1227 Dhcp4->Stop (Dhcp4);
1228 }
1229 gBS->CloseProtocol (
1230 Dhcp4ChildHandle,
1231 &gEfiDhcp4ProtocolGuid,
1232 gImageHandle,
1233 ControllerHandle
1234 );
1235 }
1236 NetLibDestroyServiceChild (
1237 ControllerHandle,
1238 gImageHandle,
1239 &gEfiDhcp4ServiceBindingProtocolGuid,
1240 Dhcp4ChildHandle
1241 );
1242 }
1243
1244 if (Mtftp4ChildHandle != NULL) {
1245 if (Mtftp4 != NULL) {
1246 if (AsciiFilePath != NULL) {
1247 FreePool (AsciiFilePath);
1248 }
1249 if (TftpContext != NULL) {
1250 FreePool (TftpContext);
1251 }
1252 gBS->CloseProtocol (
1253 Mtftp4ChildHandle,
1254 &gEfiMtftp4ProtocolGuid,
1255 gImageHandle,
1256 ControllerHandle
1257 );
1258 }
1259 NetLibDestroyServiceChild (
1260 ControllerHandle,
1261 gImageHandle,
1262 &gEfiMtftp4ServiceBindingProtocolGuid,
1263 Mtftp4ChildHandle
1264 );
1265 }
1266
1267 if (EFI_ERROR (Status)) {
1268 Print (L"Failed to download the file - Error=%r\n", Status);
1269 }
1270
1271 return Status;
1272 }
1273
1274 BDS_FILE_LOADER FileLoaders[] = {
1275 { BdsFileSystemSupport, BdsFileSystemLoadImage },
1276 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
1277 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
1278 { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
1279 { BdsPxeSupport, BdsPxeLoadImage },
1280 { BdsTftpSupport, BdsTftpLoadImage },
1281 { NULL, NULL }
1282 };
1283
1284 EFI_STATUS
1285 BdsLoadImageAndUpdateDevicePath (
1286 IN OUT EFI_DEVICE_PATH **DevicePath,
1287 IN EFI_ALLOCATE_TYPE Type,
1288 IN OUT EFI_PHYSICAL_ADDRESS* Image,
1289 OUT UINTN *FileSize
1290 )
1291 {
1292 EFI_STATUS Status;
1293 EFI_HANDLE Handle;
1294 EFI_DEVICE_PATH *RemainingDevicePath;
1295 BDS_FILE_LOADER* FileLoader;
1296
1297 Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);
1298 if (EFI_ERROR (Status)) {
1299 return Status;
1300 }
1301
1302 FileLoader = FileLoaders;
1303 while (FileLoader->Support != NULL) {
1304 if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {
1305 return FileLoader->LoadImage (*DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
1306 }
1307 FileLoader++;
1308 }
1309
1310 return EFI_UNSUPPORTED;
1311 }
1312
1313 EFI_STATUS
1314 BdsLoadImage (
1315 IN EFI_DEVICE_PATH *DevicePath,
1316 IN EFI_ALLOCATE_TYPE Type,
1317 IN OUT EFI_PHYSICAL_ADDRESS* Image,
1318 OUT UINTN *FileSize
1319 )
1320 {
1321 return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
1322 }
1323
1324 /**
1325 Start an EFI Application from a Device Path
1326
1327 @param ParentImageHandle Handle of the calling image
1328 @param DevicePath Location of the EFI Application
1329
1330 @retval EFI_SUCCESS All drivers have been connected
1331 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
1332 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
1333
1334 **/
1335 EFI_STATUS
1336 BdsStartEfiApplication (
1337 IN EFI_HANDLE ParentImageHandle,
1338 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1339 IN UINTN LoadOptionsSize,
1340 IN VOID* LoadOptions
1341 )
1342 {
1343 EFI_STATUS Status;
1344 EFI_HANDLE ImageHandle;
1345 EFI_PHYSICAL_ADDRESS BinaryBuffer;
1346 UINTN BinarySize;
1347 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
1348
1349 // Find the nearest supported file loader
1350 Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);
1351 if (EFI_ERROR (Status)) {
1352 return Status;
1353 }
1354
1355 // Load the image from the Buffer with Boot Services function
1356 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
1357 if (EFI_ERROR (Status)) {
1358 return Status;
1359 }
1360
1361 // Passed LoadOptions to the EFI Application
1362 if (LoadOptionsSize != 0) {
1363 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
1364 if (EFI_ERROR (Status)) {
1365 return Status;
1366 }
1367
1368 LoadedImage->LoadOptionsSize = LoadOptionsSize;
1369 LoadedImage->LoadOptions = LoadOptions;
1370 }
1371
1372 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
1373 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
1374 // Start the image
1375 Status = gBS->StartImage (ImageHandle, NULL, NULL);
1376 // Clear the Watchdog Timer after the image returns
1377 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
1378
1379 return Status;
1380 }