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