]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPkg/BdsLib: Fix DHCP4 configuration
[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 FILEPATH_DEVICE_PATH* FilePathDevicePath;
479 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
480 EFI_FILE_PROTOCOL *Fs;
481 EFI_STATUS Status;
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->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
491 if (EFI_ERROR (Status)) {
492 return Status;
493 }
494
495 // Try to Open the volume and get root directory
496 Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
497 if (EFI_ERROR (Status)) {
498 return Status;
499 }
500
501 File = NULL;
502 Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
503 if (EFI_ERROR (Status)) {
504 return Status;
505 }
506
507 Size = 0;
508 File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
509 FileInfo = AllocatePool (Size);
510 Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 // Get the file size
516 Size = FileInfo->FileSize;
517 if (ImageSize) {
518 *ImageSize = Size;
519 }
520 FreePool (FileInfo);
521
522 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
523 // Try to allocate in any pages if failed to allocate memory at the defined location
524 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
525 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
526 }
527 if (!EFI_ERROR (Status)) {
528 Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
529 }
530
531 return Status;
532 }
533
534 BOOLEAN
535 BdsMemoryMapSupport (
536 IN EFI_DEVICE_PATH *DevicePath,
537 IN EFI_HANDLE Handle,
538 IN EFI_DEVICE_PATH *RemainingDevicePath
539 )
540 {
541 return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||
542 IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);
543 }
544
545 EFI_STATUS
546 BdsMemoryMapLoadImage (
547 IN EFI_DEVICE_PATH *DevicePath,
548 IN EFI_HANDLE Handle,
549 IN EFI_DEVICE_PATH *RemainingDevicePath,
550 IN EFI_ALLOCATE_TYPE Type,
551 IN OUT EFI_PHYSICAL_ADDRESS* Image,
552 OUT UINTN *ImageSize
553 )
554 {
555 EFI_STATUS Status;
556 MEMMAP_DEVICE_PATH* MemMapPathDevicePath;
557 UINTN Size;
558
559 if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {
560 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
561 } else {
562 ASSERT (IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));
563 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;
564 }
565
566 Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
567 if (Size == 0) {
568 return EFI_INVALID_PARAMETER;
569 }
570
571 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
572 // Try to allocate in any pages if failed to allocate memory at the defined location
573 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
574 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
575 }
576 if (!EFI_ERROR (Status)) {
577 CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
578
579 if (ImageSize != NULL) {
580 *ImageSize = Size;
581 }
582 }
583
584 return Status;
585 }
586
587 BOOLEAN
588 BdsFirmwareVolumeSupport (
589 IN EFI_DEVICE_PATH *DevicePath,
590 IN EFI_HANDLE Handle,
591 IN EFI_DEVICE_PATH *RemainingDevicePath
592 )
593 {
594 return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
595 }
596
597 EFI_STATUS
598 BdsFirmwareVolumeLoadImage (
599 IN EFI_DEVICE_PATH *DevicePath,
600 IN EFI_HANDLE Handle,
601 IN EFI_DEVICE_PATH *RemainingDevicePath,
602 IN EFI_ALLOCATE_TYPE Type,
603 IN OUT EFI_PHYSICAL_ADDRESS* Image,
604 OUT UINTN *ImageSize
605 )
606 {
607 EFI_STATUS Status;
608 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
609 EFI_GUID *FvNameGuid;
610 EFI_SECTION_TYPE SectionType;
611 EFI_FV_FILETYPE FvType;
612 EFI_FV_FILE_ATTRIBUTES Attrib;
613 UINT32 AuthenticationStatus;
614 VOID* ImageBuffer;
615
616 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
617
618 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
619 if (EFI_ERROR (Status)) {
620 return Status;
621 }
622
623 FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
624 if (FvNameGuid == NULL) {
625 Status = EFI_INVALID_PARAMETER;
626 }
627
628 SectionType = EFI_SECTION_PE32;
629 AuthenticationStatus = 0;
630 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
631 ImageBuffer = NULL;
632 Status = FwVol->ReadSection (
633 FwVol,
634 FvNameGuid,
635 SectionType,
636 0,
637 &ImageBuffer,
638 ImageSize,
639 &AuthenticationStatus
640 );
641 if (!EFI_ERROR (Status)) {
642 #if 0
643 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
644 if (Type != AllocateAnyPages) {
645 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
646 if (!EFI_ERROR (Status)) {
647 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
648 FreePool (ImageBuffer);
649 }
650 }
651 #else
652 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
653 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
654 // Try to allocate in any pages if failed to allocate memory at the defined location
655 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
656 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
657 }
658 if (!EFI_ERROR (Status)) {
659 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
660 FreePool (ImageBuffer);
661 }
662 #endif
663 } else {
664 // Try a raw file, since a PE32 SECTION does not exist
665 Status = FwVol->ReadFile (
666 FwVol,
667 FvNameGuid,
668 NULL,
669 ImageSize,
670 &FvType,
671 &Attrib,
672 &AuthenticationStatus
673 );
674 if (!EFI_ERROR (Status)) {
675 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
676 // Try to allocate in any pages if failed to allocate memory at the defined location
677 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
678 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
679 }
680 if (!EFI_ERROR (Status)) {
681 Status = FwVol->ReadFile (
682 FwVol,
683 FvNameGuid,
684 (VOID*)(UINTN)(*Image),
685 ImageSize,
686 &FvType,
687 &Attrib,
688 &AuthenticationStatus
689 );
690 }
691 }
692 }
693 return Status;
694 }
695
696 BOOLEAN
697 BdsPxeSupport (
698 IN EFI_DEVICE_PATH* DevicePath,
699 IN EFI_HANDLE Handle,
700 IN EFI_DEVICE_PATH* RemainingDevicePath
701 )
702 {
703 EFI_STATUS Status;
704 EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
705
706 if (!IsDevicePathEnd (RemainingDevicePath)) {
707 return FALSE;
708 }
709
710 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
711 if (EFI_ERROR (Status)) {
712 return FALSE;
713 } else {
714 return TRUE;
715 }
716 }
717
718 EFI_STATUS
719 BdsPxeLoadImage (
720 IN EFI_DEVICE_PATH* DevicePath,
721 IN EFI_HANDLE Handle,
722 IN EFI_DEVICE_PATH* RemainingDevicePath,
723 IN EFI_ALLOCATE_TYPE Type,
724 IN OUT EFI_PHYSICAL_ADDRESS *Image,
725 OUT UINTN *ImageSize
726 )
727 {
728 EFI_STATUS Status;
729 EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;
730 UINTN BufferSize;
731 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
732
733 // Get Load File Protocol attached to the PXE protocol
734 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
735 if (EFI_ERROR (Status)) {
736 return Status;
737 }
738
739 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);
740 if (Status == EFI_BUFFER_TOO_SMALL) {
741 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
742 if (EFI_ERROR (Status)) {
743 return Status;
744 }
745
746 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
747 if (!EFI_ERROR (Status) && (ImageSize != NULL)) {
748 *ImageSize = BufferSize;
749 }
750 }
751
752 if (Status == EFI_ALREADY_STARTED) {
753 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
754 if (!EFI_ERROR(Status)) {
755 // If PXE is already started, we stop it
756 Pxe->Stop (Pxe);
757 // And we try again
758 return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);
759 }
760 }
761 return Status;
762 }
763
764 BOOLEAN
765 BdsTftpSupport (
766 IN EFI_DEVICE_PATH *DevicePath,
767 IN EFI_HANDLE Handle,
768 IN EFI_DEVICE_PATH *RemainingDevicePath
769 )
770 {
771 EFI_STATUS Status;
772 EFI_DEVICE_PATH *NextDevicePath;
773 VOID *Interface;
774
775 // Validate the Remaining Device Path
776 if (IsDevicePathEnd (RemainingDevicePath)) {
777 return FALSE;
778 }
779 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&
780 !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {
781 return FALSE;
782 }
783 NextDevicePath = NextDevicePathNode (RemainingDevicePath);
784 if (IsDevicePathEnd (NextDevicePath)) {
785 return FALSE;
786 }
787 if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {
788 return FALSE;
789 }
790
791 Status = gBS->HandleProtocol (
792 Handle, &gEfiDevicePathProtocolGuid,
793 &Interface
794 );
795 if (EFI_ERROR (Status)) {
796 return FALSE;
797 }
798
799 //
800 // Check that the controller (identified by its handle "Handle") supports the
801 // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
802 // EFI MTFTPv4 Protocol needed to download the image through TFTP.
803 //
804 Status = gBS->HandleProtocol (
805 Handle, &gEfiMtftp4ServiceBindingProtocolGuid,
806 &Interface
807 );
808 if (EFI_ERROR (Status)) {
809 return FALSE;
810 }
811
812 return TRUE;
813 }
814
815 /**
816 Worker function that get the size in numbers of bytes of a file from a TFTP
817 server before to download the file.
818
819 @param[in] Mtftp4 MTFTP4 protocol interface
820 @param[in] FilePath Path of the file, Ascii encoded
821 @param[out] FileSize Address where to store the file size in number of
822 bytes.
823
824 @retval EFI_SUCCESS The size of the file was returned.
825 @retval !EFI_SUCCESS The size of the file was not returned.
826
827 **/
828 STATIC
829 EFI_STATUS
830 Mtftp4GetFileSize (
831 IN EFI_MTFTP4_PROTOCOL *Mtftp4,
832 IN CHAR8 *FilePath,
833 OUT UINT64 *FileSize
834 )
835 {
836 EFI_STATUS Status;
837 EFI_MTFTP4_OPTION ReqOpt[1];
838 EFI_MTFTP4_PACKET *Packet;
839 UINT32 PktLen;
840 EFI_MTFTP4_OPTION *TableOfOptions;
841 EFI_MTFTP4_OPTION *Option;
842 UINT32 OptCnt;
843 UINT8 OptBuf[128];
844
845 ReqOpt[0].OptionStr = (UINT8*)"tsize";
846 OptBuf[0] = '0';
847 OptBuf[1] = 0;
848 ReqOpt[0].ValueStr = OptBuf;
849
850 Status = Mtftp4->GetInfo (
851 Mtftp4,
852 NULL,
853 (UINT8*)FilePath,
854 NULL,
855 1,
856 ReqOpt,
857 &PktLen,
858 &Packet
859 );
860
861 if (EFI_ERROR (Status)) {
862 goto Error;
863 }
864
865 Status = Mtftp4->ParseOptions (
866 Mtftp4,
867 PktLen,
868 Packet,
869 (UINT32 *) &OptCnt,
870 &TableOfOptions
871 );
872 if (EFI_ERROR (Status)) {
873 goto Error;
874 }
875
876 Option = TableOfOptions;
877 while (OptCnt != 0) {
878 if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
879 *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr);
880 break;
881 }
882 OptCnt--;
883 Option++;
884 }
885 FreePool (TableOfOptions);
886
887 if (OptCnt == 0) {
888 Status = EFI_UNSUPPORTED;
889 }
890
891 Error :
892
893 return Status;
894 }
895
896 /**
897 Update the progress of a file download
898 This procedure is called each time a new TFTP packet is received.
899
900 @param[in] This MTFTP4 protocol interface
901 @param[in] Token Parameters for the download of the file
902 @param[in] PacketLen Length of the packet
903 @param[in] Packet Address of the packet
904
905 @retval EFI_SUCCESS All packets are accepted.
906
907 **/
908 STATIC
909 EFI_STATUS
910 Mtftp4CheckPacket (
911 IN EFI_MTFTP4_PROTOCOL *This,
912 IN EFI_MTFTP4_TOKEN *Token,
913 IN UINT16 PacketLen,
914 IN EFI_MTFTP4_PACKET *Packet
915 )
916 {
917 BDS_TFTP_CONTEXT *Context;
918 CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];
919 UINT64 NbOfKb;
920 UINTN Index;
921 UINTN LastStep;
922 UINTN Step;
923 UINT64 LastNbOf50Kb;
924 UINT64 NbOf50Kb;
925
926 if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) {
927 Context = (BDS_TFTP_CONTEXT*)Token->Context;
928
929 if (Context->DownloadedNbOfBytes == 0) {
930 if (Context->FileSize > 0) {
931 Print (L"%s 0 Kb", mTftpProgressFrame);
932 } else {
933 Print (L" 0 Kb");
934 }
935 }
936
937 //
938 // The data is the packet are prepended with two UINT16 :
939 // . OpCode = EFI_MTFTP4_OPCODE_DATA
940 // . Block = the number of this block of data
941 //
942 Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
943 NbOfKb = Context->DownloadedNbOfBytes / 1024;
944
945 Progress[0] = L'\0';
946 if (Context->FileSize > 0) {
947 LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
948 Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
949 if (Step > LastStep) {
950 Print (mTftpProgressDelete);
951 StrCpy (Progress, mTftpProgressFrame);
952 for (Index = 1; Index < Step; Index++) {
953 Progress[Index] = L'=';
954 }
955 Progress[Step] = L'>';
956
957 UnicodeSPrint (
958 Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
959 sizeof (Progress) - sizeof (mTftpProgressFrame),
960 L" %7d Kb",
961 NbOfKb
962 );
963 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
964 }
965 } else {
966 //
967 // Case when we do not know the size of the final file.
968 // We print the updated size every 50KB of downloaded data
969 //
970 LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024);
971 NbOf50Kb = Context->DownloadedNbOfBytes / (50*1024);
972 if (NbOf50Kb > LastNbOf50Kb) {
973 Print (L"\b\b\b\b\b\b\b\b\b\b");
974 UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb);
975 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
976 }
977 }
978 if (Progress[0] != L'\0') {
979 Print (L"%s", Progress);
980 }
981 }
982
983 return EFI_SUCCESS;
984 }
985
986 /**
987 Download an image from a TFTP server
988
989 @param[in] DevicePath Device path of the TFTP boot option
990 @param[in] ControllerHandle Handle of the network controller
991 @param[in] RemainingDevicePath Device path of the TFTP boot option but
992 the first node that identifies the network controller
993 @param[in] Type Type to allocate memory pages
994 @param[out] Image Address of the bufer where the image is stored in
995 case of success
996 @param[out] ImageSize Size in number of bytes of the i;age in case of
997 success
998
999 @retval EFI_SUCCESS The image was returned.
1000 @retval !EFI_SUCCESS Something went wrong.
1001
1002 **/
1003 EFI_STATUS
1004 BdsTftpLoadImage (
1005 IN EFI_DEVICE_PATH* DevicePath,
1006 IN EFI_HANDLE ControllerHandle,
1007 IN EFI_DEVICE_PATH* RemainingDevicePath,
1008 IN EFI_ALLOCATE_TYPE Type,
1009 IN OUT EFI_PHYSICAL_ADDRESS *Image,
1010 OUT UINTN *ImageSize
1011 )
1012 {
1013 EFI_STATUS Status;
1014 EFI_HANDLE Dhcp4ChildHandle;
1015 EFI_DHCP4_PROTOCOL *Dhcp4;
1016 BOOLEAN Dhcp4ToStop;
1017 EFI_HANDLE Mtftp4ChildHandle;
1018 EFI_MTFTP4_PROTOCOL *Mtftp4;
1019 DHCP4_OPTION ParaList;
1020 EFI_DHCP4_PACKET_OPTION *OptionList[2];
1021 EFI_DHCP4_CONFIG_DATA Dhcp4CfgData;
1022 EFI_DHCP4_MODE_DATA Dhcp4Mode;
1023 EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData;
1024 IPv4_DEVICE_PATH *IPv4DevicePathNode;
1025 FILEPATH_DEVICE_PATH *FilePathDevicePathNode;
1026 CHAR8 *AsciiFilePath;
1027 EFI_MTFTP4_TOKEN Mtftp4Token;
1028 UINT64 FileSize;
1029 UINT64 TftpBufferSize;
1030 BDS_TFTP_CONTEXT *TftpContext;
1031
1032 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));
1033 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
1034
1035 Dhcp4ChildHandle = NULL;
1036 Dhcp4 = NULL;
1037 Dhcp4ToStop = FALSE;
1038 Mtftp4ChildHandle = NULL;
1039 Mtftp4 = NULL;
1040 AsciiFilePath = NULL;
1041 TftpContext = NULL;
1042
1043 if (!IPv4DevicePathNode->StaticIpAddress) {
1044 //
1045 // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
1046 // install the DHCP4 protocol on it. Then, open the DHCP protocol.
1047 //
1048 Status = NetLibCreateServiceChild (
1049 ControllerHandle,
1050 gImageHandle,
1051 &gEfiDhcp4ServiceBindingProtocolGuid,
1052 &Dhcp4ChildHandle
1053 );
1054 if (!EFI_ERROR (Status)) {
1055 Status = gBS->OpenProtocol (
1056 Dhcp4ChildHandle,
1057 &gEfiDhcp4ProtocolGuid,
1058 (VOID **) &Dhcp4,
1059 gImageHandle,
1060 ControllerHandle,
1061 EFI_OPEN_PROTOCOL_BY_DRIVER
1062 );
1063 }
1064 if (EFI_ERROR (Status)) {
1065 Print (L"Unable to open DHCP4 protocol\n");
1066 goto Error;
1067 }
1068 }
1069
1070 //
1071 // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
1072 // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
1073 //
1074 Status = NetLibCreateServiceChild (
1075 ControllerHandle,
1076 gImageHandle,
1077 &gEfiMtftp4ServiceBindingProtocolGuid,
1078 &Mtftp4ChildHandle
1079 );
1080 if (!EFI_ERROR (Status)) {
1081 Status = gBS->OpenProtocol (
1082 Mtftp4ChildHandle,
1083 &gEfiMtftp4ProtocolGuid,
1084 (VOID **) &Mtftp4,
1085 gImageHandle,
1086 ControllerHandle,
1087 EFI_OPEN_PROTOCOL_BY_DRIVER
1088 );
1089 }
1090 if (EFI_ERROR (Status)) {
1091 Print (L"Unable to open MTFTP4 protocol\n");
1092 goto Error;
1093 }
1094
1095 if (!IPv4DevicePathNode->StaticIpAddress) {
1096 //
1097 // Configure the DHCP4, all default settings. It is acceptable for the configuration to
1098 // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
1099 // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
1100 // process has been started but is not completed yet.
1101 //
1102 ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
1103 ParaList.Head.OpCode = DHCP_TAG_PARA_LIST;
1104 ParaList.Head.Length = 2;
1105 ParaList.Head.Data[0] = DHCP_TAG_NETMASK;
1106 ParaList.Route = DHCP_TAG_ROUTER;
1107 OptionList[0] = &ParaList.Head;
1108 Dhcp4CfgData.OptionCount = 1;
1109 Dhcp4CfgData.OptionList = OptionList;
1110
1111 Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
1112 if (EFI_ERROR (Status)) {
1113 if (Status != EFI_ACCESS_DENIED) {
1114 Print (L"Error while configuring the DHCP4 protocol\n");
1115 goto Error;
1116 }
1117 }
1118
1119 //
1120 // Start the DHCP configuration. This may have already been done thus do not leave in error
1121 // if the return code is EFI_ALREADY_STARTED.
1122 //
1123 Status = Dhcp4->Start (Dhcp4, NULL);
1124 if (EFI_ERROR (Status)) {
1125 if (Status != EFI_ALREADY_STARTED) {
1126 Print (L"DHCP configuration failed\n");
1127 goto Error;
1128 }
1129 } else {
1130 Dhcp4ToStop = TRUE;
1131 }
1132
1133 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
1134 if (EFI_ERROR (Status)) {
1135 goto Error;
1136 }
1137
1138 if (Dhcp4Mode.State != Dhcp4Bound) {
1139 Status = EFI_TIMEOUT;
1140 Print (L"DHCP configuration failed\n");
1141 goto Error;
1142 }
1143 }
1144
1145 //
1146 // Configure the TFTP4 protocol
1147 //
1148
1149 ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA));
1150 Mtftp4CfgData.UseDefaultSetting = FALSE;
1151 Mtftp4CfgData.TimeoutValue = 4;
1152 Mtftp4CfgData.TryCount = 6;
1153
1154 if (IPv4DevicePathNode->StaticIpAddress) {
1155 CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
1156 CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1157 CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
1158 } else {
1159 CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1160 CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask , sizeof (EFI_IPv4_ADDRESS));
1161 CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1162 }
1163
1164 CopyMem (&Mtftp4CfgData.ServerIp , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
1165
1166 Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData);
1167 if (EFI_ERROR (Status)) {
1168 Print (L"Error while configuring the MTFTP4 protocol\n");
1169 goto Error;
1170 }
1171
1172 //
1173 // Convert the Unicode path of the file to Ascii
1174 //
1175
1176 FilePathDevicePathNode = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
1177 AsciiFilePath = AllocatePool ((StrLen (FilePathDevicePathNode->PathName) + 1) * sizeof (CHAR8));
1178 if (AsciiFilePath == NULL) {
1179 Status = EFI_OUT_OF_RESOURCES;
1180 goto Error;
1181 }
1182 UnicodeStrToAsciiStr (FilePathDevicePathNode->PathName, AsciiFilePath);
1183
1184 //
1185 // Try to get the size of the file in bytes from the server. If it fails,
1186 // start with a 8MB buffer to download the file.
1187 //
1188 FileSize = 0;
1189 if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) {
1190 TftpBufferSize = FileSize;
1191 } else {
1192 TftpBufferSize = SIZE_8MB;
1193 }
1194
1195 TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT));
1196 if (TftpContext == NULL) {
1197 Status = EFI_OUT_OF_RESOURCES;
1198 goto Error;
1199 }
1200 TftpContext->FileSize = FileSize;
1201
1202 for (; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize);
1203 TftpBufferSize = (TftpBufferSize + SIZE_8MB) & (~(SIZE_8MB-1))) {
1204 //
1205 // Allocate a buffer to hold the whole file.
1206 //
1207 Status = gBS->AllocatePages (
1208 Type,
1209 EfiBootServicesCode,
1210 EFI_SIZE_TO_PAGES (TftpBufferSize),
1211 Image
1212 );
1213 if (EFI_ERROR (Status)) {
1214 Print (L"Failed to allocate space for image\n");
1215 goto Error;
1216 }
1217
1218 TftpContext->DownloadedNbOfBytes = 0;
1219 TftpContext->LastReportedNbOfBytes = 0;
1220
1221 ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
1222 Mtftp4Token.Filename = (UINT8*)AsciiFilePath;
1223 Mtftp4Token.BufferSize = TftpBufferSize;
1224 Mtftp4Token.Buffer = (VOID *)(UINTN)*Image;
1225 Mtftp4Token.CheckPacket = Mtftp4CheckPacket;
1226 Mtftp4Token.Context = (VOID*)TftpContext;
1227
1228 Print (L"Downloading the file <%s> from the TFTP server\n", FilePathDevicePathNode->PathName);
1229 Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
1230 Print (L"\n");
1231 if (EFI_ERROR (Status)) {
1232 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
1233 if (Status == EFI_BUFFER_TOO_SMALL) {
1234 Print (L"Downloading failed, file larger than expected.\n");
1235 continue;
1236 } else {
1237 goto Error;
1238 }
1239 }
1240
1241 *ImageSize = Mtftp4Token.BufferSize;
1242 break;
1243 }
1244
1245 Error:
1246 if (Dhcp4ChildHandle != NULL) {
1247 if (Dhcp4 != NULL) {
1248 if (Dhcp4ToStop) {
1249 Dhcp4->Stop (Dhcp4);
1250 }
1251 gBS->CloseProtocol (
1252 Dhcp4ChildHandle,
1253 &gEfiDhcp4ProtocolGuid,
1254 gImageHandle,
1255 ControllerHandle
1256 );
1257 }
1258 NetLibDestroyServiceChild (
1259 ControllerHandle,
1260 gImageHandle,
1261 &gEfiDhcp4ServiceBindingProtocolGuid,
1262 Dhcp4ChildHandle
1263 );
1264 }
1265
1266 if (Mtftp4ChildHandle != NULL) {
1267 if (Mtftp4 != NULL) {
1268 if (AsciiFilePath != NULL) {
1269 FreePool (AsciiFilePath);
1270 }
1271 if (TftpContext != NULL) {
1272 FreePool (TftpContext);
1273 }
1274 gBS->CloseProtocol (
1275 Mtftp4ChildHandle,
1276 &gEfiMtftp4ProtocolGuid,
1277 gImageHandle,
1278 ControllerHandle
1279 );
1280 }
1281 NetLibDestroyServiceChild (
1282 ControllerHandle,
1283 gImageHandle,
1284 &gEfiMtftp4ServiceBindingProtocolGuid,
1285 Mtftp4ChildHandle
1286 );
1287 }
1288
1289 if (EFI_ERROR (Status)) {
1290 Print (L"Failed to download the file - Error=%r\n", Status);
1291 }
1292
1293 return Status;
1294 }
1295
1296 BDS_FILE_LOADER FileLoaders[] = {
1297 { BdsFileSystemSupport, BdsFileSystemLoadImage },
1298 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
1299 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
1300 { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
1301 { BdsPxeSupport, BdsPxeLoadImage },
1302 { BdsTftpSupport, BdsTftpLoadImage },
1303 { NULL, NULL }
1304 };
1305
1306 EFI_STATUS
1307 BdsLoadImageAndUpdateDevicePath (
1308 IN OUT EFI_DEVICE_PATH **DevicePath,
1309 IN EFI_ALLOCATE_TYPE Type,
1310 IN OUT EFI_PHYSICAL_ADDRESS* Image,
1311 OUT UINTN *FileSize
1312 )
1313 {
1314 EFI_STATUS Status;
1315 EFI_HANDLE Handle;
1316 EFI_DEVICE_PATH *RemainingDevicePath;
1317 BDS_FILE_LOADER* FileLoader;
1318
1319 Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);
1320 if (EFI_ERROR (Status)) {
1321 return Status;
1322 }
1323
1324 FileLoader = FileLoaders;
1325 while (FileLoader->Support != NULL) {
1326 if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {
1327 return FileLoader->LoadImage (*DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
1328 }
1329 FileLoader++;
1330 }
1331
1332 return EFI_UNSUPPORTED;
1333 }
1334
1335 EFI_STATUS
1336 BdsLoadImage (
1337 IN EFI_DEVICE_PATH *DevicePath,
1338 IN EFI_ALLOCATE_TYPE Type,
1339 IN OUT EFI_PHYSICAL_ADDRESS* Image,
1340 OUT UINTN *FileSize
1341 )
1342 {
1343 return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
1344 }
1345
1346 /**
1347 Start an EFI Application from a Device Path
1348
1349 @param ParentImageHandle Handle of the calling image
1350 @param DevicePath Location of the EFI Application
1351
1352 @retval EFI_SUCCESS All drivers have been connected
1353 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
1354 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
1355
1356 **/
1357 EFI_STATUS
1358 BdsStartEfiApplication (
1359 IN EFI_HANDLE ParentImageHandle,
1360 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1361 IN UINTN LoadOptionsSize,
1362 IN VOID* LoadOptions
1363 )
1364 {
1365 EFI_STATUS Status;
1366 EFI_HANDLE ImageHandle;
1367 EFI_PHYSICAL_ADDRESS BinaryBuffer;
1368 UINTN BinarySize;
1369 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
1370
1371 // Find the nearest supported file loader
1372 Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);
1373 if (EFI_ERROR (Status)) {
1374 return Status;
1375 }
1376
1377 // Load the image from the Buffer with Boot Services function
1378 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
1379 if (EFI_ERROR (Status)) {
1380 return Status;
1381 }
1382
1383 // Passed LoadOptions to the EFI Application
1384 if (LoadOptionsSize != 0) {
1385 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
1386 if (EFI_ERROR (Status)) {
1387 return Status;
1388 }
1389
1390 LoadedImage->LoadOptionsSize = LoadOptionsSize;
1391 LoadedImage->LoadOptions = LoadOptions;
1392 }
1393
1394 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
1395 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
1396 // Start the image
1397 Status = gBS->StartImage (ImageHandle, NULL, NULL);
1398 // Clear the Watchdog Timer after the image returns
1399 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
1400
1401 return Status;
1402 }