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