]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPkg/BdsLib: Close file after reading an Image
[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 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 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 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*)(UINTN)(*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 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, DevicePath, 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, DevicePath, 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 StrCpy (Progress, 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 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 FILEPATH_DEVICE_PATH *FilePathDevicePathNode;
1042 CHAR8 *AsciiFilePath;
1043 EFI_MTFTP4_TOKEN Mtftp4Token;
1044 UINT64 FileSize;
1045 UINT64 TftpBufferSize;
1046 BDS_TFTP_CONTEXT *TftpContext;
1047
1048 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));
1049 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
1050
1051 Dhcp4ChildHandle = NULL;
1052 Dhcp4 = NULL;
1053 Dhcp4ToStop = FALSE;
1054 Mtftp4ChildHandle = NULL;
1055 Mtftp4 = NULL;
1056 AsciiFilePath = NULL;
1057 TftpContext = NULL;
1058
1059 if (!IPv4DevicePathNode->StaticIpAddress) {
1060 //
1061 // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
1062 // install the DHCP4 protocol on it. Then, open the DHCP protocol.
1063 //
1064 Status = NetLibCreateServiceChild (
1065 ControllerHandle,
1066 gImageHandle,
1067 &gEfiDhcp4ServiceBindingProtocolGuid,
1068 &Dhcp4ChildHandle
1069 );
1070 if (!EFI_ERROR (Status)) {
1071 Status = gBS->OpenProtocol (
1072 Dhcp4ChildHandle,
1073 &gEfiDhcp4ProtocolGuid,
1074 (VOID **) &Dhcp4,
1075 gImageHandle,
1076 ControllerHandle,
1077 EFI_OPEN_PROTOCOL_BY_DRIVER
1078 );
1079 }
1080 if (EFI_ERROR (Status)) {
1081 Print (L"Unable to open DHCP4 protocol\n");
1082 goto Error;
1083 }
1084 }
1085
1086 //
1087 // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
1088 // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
1089 //
1090 Status = NetLibCreateServiceChild (
1091 ControllerHandle,
1092 gImageHandle,
1093 &gEfiMtftp4ServiceBindingProtocolGuid,
1094 &Mtftp4ChildHandle
1095 );
1096 if (!EFI_ERROR (Status)) {
1097 Status = gBS->OpenProtocol (
1098 Mtftp4ChildHandle,
1099 &gEfiMtftp4ProtocolGuid,
1100 (VOID **) &Mtftp4,
1101 gImageHandle,
1102 ControllerHandle,
1103 EFI_OPEN_PROTOCOL_BY_DRIVER
1104 );
1105 }
1106 if (EFI_ERROR (Status)) {
1107 Print (L"Unable to open MTFTP4 protocol\n");
1108 goto Error;
1109 }
1110
1111 if (!IPv4DevicePathNode->StaticIpAddress) {
1112 //
1113 // Configure the DHCP4, all default settings. It is acceptable for the configuration to
1114 // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
1115 // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
1116 // process has been started but is not completed yet.
1117 //
1118 ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
1119 ParaList.Head.OpCode = DHCP_TAG_PARA_LIST;
1120 ParaList.Head.Length = 2;
1121 ParaList.Head.Data[0] = DHCP_TAG_NETMASK;
1122 ParaList.Route = DHCP_TAG_ROUTER;
1123 OptionList[0] = &ParaList.Head;
1124 Dhcp4CfgData.OptionCount = 1;
1125 Dhcp4CfgData.OptionList = OptionList;
1126
1127 Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
1128 if (EFI_ERROR (Status)) {
1129 if (Status != EFI_ACCESS_DENIED) {
1130 Print (L"Error while configuring the DHCP4 protocol\n");
1131 goto Error;
1132 }
1133 }
1134
1135 //
1136 // Start the DHCP configuration. This may have already been done thus do not leave in error
1137 // if the return code is EFI_ALREADY_STARTED.
1138 //
1139 Status = Dhcp4->Start (Dhcp4, NULL);
1140 if (EFI_ERROR (Status)) {
1141 if (Status != EFI_ALREADY_STARTED) {
1142 Print (L"DHCP configuration failed\n");
1143 goto Error;
1144 }
1145 } else {
1146 Dhcp4ToStop = TRUE;
1147 }
1148
1149 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
1150 if (EFI_ERROR (Status)) {
1151 goto Error;
1152 }
1153
1154 if (Dhcp4Mode.State != Dhcp4Bound) {
1155 Status = EFI_TIMEOUT;
1156 Print (L"DHCP configuration failed\n");
1157 goto Error;
1158 }
1159 }
1160
1161 //
1162 // Configure the TFTP4 protocol
1163 //
1164
1165 ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA));
1166 Mtftp4CfgData.UseDefaultSetting = FALSE;
1167 Mtftp4CfgData.TimeoutValue = 4;
1168 Mtftp4CfgData.TryCount = 6;
1169
1170 if (IPv4DevicePathNode->StaticIpAddress) {
1171 CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
1172 CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1173 CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
1174 } else {
1175 CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1176 CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask , sizeof (EFI_IPv4_ADDRESS));
1177 CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1178 }
1179
1180 CopyMem (&Mtftp4CfgData.ServerIp , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
1181
1182 Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData);
1183 if (EFI_ERROR (Status)) {
1184 Print (L"Error while configuring the MTFTP4 protocol\n");
1185 goto Error;
1186 }
1187
1188 //
1189 // Convert the Unicode path of the file to Ascii
1190 //
1191
1192 FilePathDevicePathNode = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
1193 AsciiFilePath = AllocatePool ((StrLen (FilePathDevicePathNode->PathName) + 1) * sizeof (CHAR8));
1194 if (AsciiFilePath == NULL) {
1195 Status = EFI_OUT_OF_RESOURCES;
1196 goto Error;
1197 }
1198 UnicodeStrToAsciiStr (FilePathDevicePathNode->PathName, AsciiFilePath);
1199
1200 //
1201 // Try to get the size of the file in bytes from the server. If it fails,
1202 // start with a 8MB buffer to download the file.
1203 //
1204 FileSize = 0;
1205 if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) {
1206 TftpBufferSize = FileSize;
1207 } else {
1208 TftpBufferSize = SIZE_8MB;
1209 }
1210
1211 TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT));
1212 if (TftpContext == NULL) {
1213 Status = EFI_OUT_OF_RESOURCES;
1214 goto Error;
1215 }
1216 TftpContext->FileSize = FileSize;
1217
1218 for (; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize);
1219 TftpBufferSize = (TftpBufferSize + SIZE_8MB) & (~(SIZE_8MB-1))) {
1220 //
1221 // Allocate a buffer to hold the whole file.
1222 //
1223 Status = gBS->AllocatePages (
1224 Type,
1225 EfiBootServicesCode,
1226 EFI_SIZE_TO_PAGES (TftpBufferSize),
1227 Image
1228 );
1229 if (EFI_ERROR (Status)) {
1230 Print (L"Failed to allocate space for image\n");
1231 goto Error;
1232 }
1233
1234 TftpContext->DownloadedNbOfBytes = 0;
1235 TftpContext->LastReportedNbOfBytes = 0;
1236
1237 ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
1238 Mtftp4Token.Filename = (UINT8*)AsciiFilePath;
1239 Mtftp4Token.BufferSize = TftpBufferSize;
1240 Mtftp4Token.Buffer = (VOID *)(UINTN)*Image;
1241 Mtftp4Token.CheckPacket = Mtftp4CheckPacket;
1242 Mtftp4Token.Context = (VOID*)TftpContext;
1243
1244 Print (L"Downloading the file <%s> from the TFTP server\n", FilePathDevicePathNode->PathName);
1245 Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
1246 Print (L"\n");
1247 if (EFI_ERROR (Status)) {
1248 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
1249 if (Status == EFI_BUFFER_TOO_SMALL) {
1250 Print (L"Downloading failed, file larger than expected.\n");
1251 continue;
1252 } else {
1253 goto Error;
1254 }
1255 }
1256
1257 *ImageSize = Mtftp4Token.BufferSize;
1258 break;
1259 }
1260
1261 Error:
1262 if (Dhcp4ChildHandle != NULL) {
1263 if (Dhcp4 != NULL) {
1264 if (Dhcp4ToStop) {
1265 Dhcp4->Stop (Dhcp4);
1266 }
1267 gBS->CloseProtocol (
1268 Dhcp4ChildHandle,
1269 &gEfiDhcp4ProtocolGuid,
1270 gImageHandle,
1271 ControllerHandle
1272 );
1273 }
1274 NetLibDestroyServiceChild (
1275 ControllerHandle,
1276 gImageHandle,
1277 &gEfiDhcp4ServiceBindingProtocolGuid,
1278 Dhcp4ChildHandle
1279 );
1280 }
1281
1282 if (Mtftp4ChildHandle != NULL) {
1283 if (Mtftp4 != NULL) {
1284 if (AsciiFilePath != NULL) {
1285 FreePool (AsciiFilePath);
1286 }
1287 if (TftpContext != NULL) {
1288 FreePool (TftpContext);
1289 }
1290 gBS->CloseProtocol (
1291 Mtftp4ChildHandle,
1292 &gEfiMtftp4ProtocolGuid,
1293 gImageHandle,
1294 ControllerHandle
1295 );
1296 }
1297 NetLibDestroyServiceChild (
1298 ControllerHandle,
1299 gImageHandle,
1300 &gEfiMtftp4ServiceBindingProtocolGuid,
1301 Mtftp4ChildHandle
1302 );
1303 }
1304
1305 if (EFI_ERROR (Status)) {
1306 Print (L"Failed to download the file - Error=%r\n", Status);
1307 }
1308
1309 return Status;
1310 }
1311
1312 BDS_FILE_LOADER FileLoaders[] = {
1313 { BdsFileSystemSupport, BdsFileSystemLoadImage },
1314 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
1315 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
1316 { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
1317 { BdsPxeSupport, BdsPxeLoadImage },
1318 { BdsTftpSupport, BdsTftpLoadImage },
1319 { NULL, NULL }
1320 };
1321
1322 EFI_STATUS
1323 BdsLoadImageAndUpdateDevicePath (
1324 IN OUT EFI_DEVICE_PATH **DevicePath,
1325 IN EFI_ALLOCATE_TYPE Type,
1326 IN OUT EFI_PHYSICAL_ADDRESS* Image,
1327 OUT UINTN *FileSize
1328 )
1329 {
1330 EFI_STATUS Status;
1331 EFI_HANDLE Handle;
1332 EFI_DEVICE_PATH *RemainingDevicePath;
1333 BDS_FILE_LOADER* FileLoader;
1334
1335 Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);
1336 if (EFI_ERROR (Status)) {
1337 return Status;
1338 }
1339
1340 FileLoader = FileLoaders;
1341 while (FileLoader->Support != NULL) {
1342 if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {
1343 return FileLoader->LoadImage (*DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
1344 }
1345 FileLoader++;
1346 }
1347
1348 return EFI_UNSUPPORTED;
1349 }
1350
1351 EFI_STATUS
1352 BdsLoadImage (
1353 IN EFI_DEVICE_PATH *DevicePath,
1354 IN EFI_ALLOCATE_TYPE Type,
1355 IN OUT EFI_PHYSICAL_ADDRESS* Image,
1356 OUT UINTN *FileSize
1357 )
1358 {
1359 return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
1360 }
1361
1362 /**
1363 Start an EFI Application from a Device Path
1364
1365 @param ParentImageHandle Handle of the calling image
1366 @param DevicePath Location of the EFI Application
1367
1368 @retval EFI_SUCCESS All drivers have been connected
1369 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
1370 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
1371
1372 **/
1373 EFI_STATUS
1374 BdsStartEfiApplication (
1375 IN EFI_HANDLE ParentImageHandle,
1376 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1377 IN UINTN LoadOptionsSize,
1378 IN VOID* LoadOptions
1379 )
1380 {
1381 EFI_STATUS Status;
1382 EFI_HANDLE ImageHandle;
1383 EFI_PHYSICAL_ADDRESS BinaryBuffer;
1384 UINTN BinarySize;
1385 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
1386
1387 // Find the nearest supported file loader
1388 Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);
1389 if (EFI_ERROR (Status)) {
1390 return Status;
1391 }
1392
1393 // Load the image from the Buffer with Boot Services function
1394 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
1395 if (EFI_ERROR (Status)) {
1396 return Status;
1397 }
1398
1399 // Passed LoadOptions to the EFI Application
1400 if (LoadOptionsSize != 0) {
1401 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
1402 if (EFI_ERROR (Status)) {
1403 return Status;
1404 }
1405
1406 LoadedImage->LoadOptionsSize = LoadOptionsSize;
1407 LoadedImage->LoadOptions = LoadOptions;
1408 }
1409
1410 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
1411 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
1412 // Start the image
1413 Status = gBS->StartImage (ImageHandle, NULL, NULL);
1414 // Clear the Watchdog Timer after the image returns
1415 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
1416
1417 return Status;
1418 }