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