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