]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPlatformPkg/Bds: Test if OptionalData is NULL before using it
[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
17#include <Protocol/UsbIo.h>\r
18#include <Protocol/DiskIo.h>\r
19#include <Protocol/LoadedImage.h>\r
2edb5ad3 20#include <Protocol/SimpleNetwork.h>\r
1e57a462 21\r
22#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))\r
23\r
24// Extract the FilePath from the Device Path\r
25CHAR16*\r
26BdsExtractFilePathFromDevicePath (\r
27 IN CONST CHAR16 *StrDevicePath,\r
28 IN UINTN NumberDevicePathNode\r
29 )\r
30{\r
31 UINTN Node;\r
32 CHAR16 *Str;\r
33\r
34 Str = (CHAR16*)StrDevicePath;\r
35 Node = 0;\r
36 while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {\r
37 if ((*Str == L'/') || (*Str == L'\\')) {\r
38 Node++;\r
39 }\r
40 Str++;\r
41 }\r
42\r
43 if (*Str == L'\0') {\r
44 return NULL;\r
45 } else {\r
46 return Str;\r
47 }\r
48}\r
49\r
50BOOLEAN\r
51BdsIsRemovableUsb (\r
52 IN EFI_DEVICE_PATH* DevicePath\r
53 )\r
54{\r
55 return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
56 ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||\r
57 (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));\r
58}\r
59\r
60EFI_STATUS\r
61BdsGetDeviceUsb (\r
62 IN EFI_DEVICE_PATH* RemovableDevicePath,\r
63 OUT EFI_HANDLE* DeviceHandle,\r
64 OUT EFI_DEVICE_PATH** NewDevicePath\r
65 )\r
66{\r
67 EFI_STATUS Status;\r
68 UINTN Index;\r
69 UINTN UsbIoHandleCount;\r
70 EFI_HANDLE *UsbIoBuffer;\r
71 EFI_DEVICE_PATH* UsbIoDevicePath;\r
72 EFI_DEVICE_PATH* TmpDevicePath;\r
73 USB_WWID_DEVICE_PATH* WwidDevicePath1;\r
74 USB_WWID_DEVICE_PATH* WwidDevicePath2;\r
75 USB_CLASS_DEVICE_PATH* UsbClassDevicePath1;\r
76 USB_CLASS_DEVICE_PATH* UsbClassDevicePath2;\r
77\r
78 // Get all the UsbIo handles\r
79 UsbIoHandleCount = 0;\r
80 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);\r
6f711615 81 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0)) {\r
1e57a462 82 return Status;\r
83 }\r
84\r
85 // Check if one of the handles matches the USB description\r
86 for (Index = 0; Index < UsbIoHandleCount; Index++) {\r
87 Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);\r
6f711615 88 if (!EFI_ERROR (Status)) {\r
1e57a462 89 TmpDevicePath = UsbIoDevicePath;\r
90 while (!IsDevicePathEnd (TmpDevicePath)) {\r
91 // Check if the Device Path node is a USB Removable device Path node\r
92 if (BdsIsRemovableUsb (TmpDevicePath)) {\r
93 if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {\r
94 WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;\r
95 WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;\r
96 if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&\r
97 (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&\r
6f711615 98 (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) == 0))\r
1e57a462 99 {\r
100 *DeviceHandle = UsbIoBuffer[Index];\r
101 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
6f711615 102 *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));\r
1e57a462 103 return EFI_SUCCESS;\r
104 }\r
105 } else {\r
106 UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;\r
107 UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;\r
108 if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&\r
109 (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&\r
110 (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&\r
111 (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&\r
112 (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))\r
113 {\r
114 *DeviceHandle = UsbIoBuffer[Index];\r
115 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
6f711615 116 *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));\r
1e57a462 117 return EFI_SUCCESS;\r
118 }\r
119 }\r
120 }\r
121 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
122 }\r
123\r
124 }\r
125 }\r
126\r
127 return EFI_NOT_FOUND;\r
128}\r
129\r
130BOOLEAN\r
131BdsIsRemovableHd (\r
132 IN EFI_DEVICE_PATH* DevicePath\r
133 )\r
134{\r
6f711615 135 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);\r
1e57a462 136}\r
137\r
138EFI_STATUS\r
139BdsGetDeviceHd (\r
140 IN EFI_DEVICE_PATH* RemovableDevicePath,\r
141 OUT EFI_HANDLE* DeviceHandle,\r
142 OUT EFI_DEVICE_PATH** NewDevicePath\r
143 )\r
144{\r
145 EFI_STATUS Status;\r
146 UINTN Index;\r
147 UINTN PartitionHandleCount;\r
148 EFI_HANDLE *PartitionBuffer;\r
149 EFI_DEVICE_PATH* PartitionDevicePath;\r
150 EFI_DEVICE_PATH* TmpDevicePath;\r
151 HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1;\r
152 HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2;\r
153\r
154 // Get all the DiskIo handles\r
155 PartitionHandleCount = 0;\r
156 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);\r
6f711615 157 if (EFI_ERROR (Status) || (PartitionHandleCount == 0)) {\r
1e57a462 158 return Status;\r
159 }\r
160\r
161 // Check if one of the handles matches the Hard Disk Description\r
162 for (Index = 0; Index < PartitionHandleCount; Index++) {\r
163 Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);\r
6f711615 164 if (!EFI_ERROR (Status)) {\r
1e57a462 165 TmpDevicePath = PartitionDevicePath;\r
166 while (!IsDevicePathEnd (TmpDevicePath)) {\r
167 // Check if the Device Path node is a HD Removable device Path node\r
168 if (BdsIsRemovableHd (TmpDevicePath)) {\r
169 HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;\r
170 HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;\r
171 if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&\r
6f711615 172 (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&\r
1e57a462 173 (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))\r
174 {\r
175 *DeviceHandle = PartitionBuffer[Index];\r
176 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
6f711615 177 *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode (RemovableDevicePath));\r
1e57a462 178 return EFI_SUCCESS;\r
179 }\r
180 }\r
181 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
182 }\r
183\r
184 }\r
185 }\r
186\r
187 return EFI_NOT_FOUND;\r
188}\r
189\r
190/*BOOLEAN\r
191BdsIsRemovableCdrom (\r
192 IN EFI_DEVICE_PATH* DevicePath\r
193 )\r
194{\r
6f711615 195 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);\r
1e57a462 196}\r
197\r
198EFI_STATUS\r
199BdsGetDeviceCdrom (\r
200 IN EFI_DEVICE_PATH* RemovableDevicePath,\r
201 OUT EFI_HANDLE* DeviceHandle,\r
202 OUT EFI_DEVICE_PATH** DevicePath\r
203 )\r
204{\r
205 ASSERT(0);\r
206 return EFI_UNSUPPORTED;\r
207}*/\r
208\r
209typedef BOOLEAN\r
210(*BDS_IS_REMOVABLE) (\r
211 IN EFI_DEVICE_PATH* DevicePath\r
212 );\r
213\r
214typedef EFI_STATUS\r
215(*BDS_GET_DEVICE) (\r
216 IN EFI_DEVICE_PATH* RemovableDevicePath,\r
217 OUT EFI_HANDLE* DeviceHandle,\r
218 OUT EFI_DEVICE_PATH** DevicePath\r
219 );\r
220\r
221typedef struct {\r
222 BDS_IS_REMOVABLE IsRemovable;\r
223 BDS_GET_DEVICE GetDevice;\r
224} BDS_REMOVABLE_DEVICE_SUPPORT;\r
225\r
226BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = {\r
227 { BdsIsRemovableUsb, BdsGetDeviceUsb },\r
228 { BdsIsRemovableHd, BdsGetDeviceHd },\r
229 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }\r
230};\r
231\r
232STATIC\r
233BOOLEAN\r
234IsRemovableDevice (\r
235 IN EFI_DEVICE_PATH* DevicePath\r
236 )\r
237{\r
238 UINTN Index;\r
239 EFI_DEVICE_PATH* TmpDevicePath;\r
240\r
241 TmpDevicePath = DevicePath;\r
242 while (!IsDevicePathEnd (TmpDevicePath)) {\r
6f711615 243 for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {\r
244 if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) {\r
1e57a462 245 return TRUE;\r
246 }\r
247 }\r
248 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
249 }\r
250\r
251 return FALSE;\r
252}\r
253\r
254STATIC\r
255EFI_STATUS\r
256TryRemovableDevice (\r
257 IN EFI_DEVICE_PATH* DevicePath,\r
258 OUT EFI_HANDLE* DeviceHandle,\r
259 OUT EFI_DEVICE_PATH** NewDevicePath\r
260 )\r
261{\r
262 EFI_STATUS Status;\r
263 UINTN Index;\r
264 EFI_DEVICE_PATH* TmpDevicePath;\r
265 BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;\r
266 EFI_DEVICE_PATH* RemovableDevicePath;\r
267 BOOLEAN RemovableFound;\r
268\r
269 RemovableDevice = NULL;\r
270 RemovableDevicePath = NULL;\r
271 RemovableFound = FALSE;\r
272 TmpDevicePath = DevicePath;\r
273\r
274 while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {\r
6f711615 275 for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {\r
1e57a462 276 RemovableDevice = &RemovableDeviceSupport[Index];\r
6f711615 277 if (RemovableDevice->IsRemovable (TmpDevicePath)) {\r
1e57a462 278 RemovableDevicePath = TmpDevicePath;\r
279 RemovableFound = TRUE;\r
280 break;\r
281 }\r
282 }\r
283 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
284 }\r
285\r
286 if (!RemovableFound) {\r
287 return EFI_NOT_FOUND;\r
288 }\r
289\r
290 // Search into the current started drivers\r
291 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);\r
292 if (Status == EFI_NOT_FOUND) {\r
293 // Connect all the drivers\r
294 BdsConnectAllDrivers ();\r
295\r
296 // Search again into all the drivers\r
297 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);\r
298 }\r
299\r
300 return Status;\r
301}\r
302\r
62d441fb 303STATIC\r
1e57a462 304EFI_STATUS\r
62d441fb
RC
305BdsConnectAndUpdateDevicePath (\r
306 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,\r
307 OUT EFI_HANDLE *Handle,\r
308 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath\r
1e57a462 309 )\r
310{\r
311 EFI_DEVICE_PATH* Remaining;\r
312 EFI_DEVICE_PATH* NewDevicePath;\r
313 EFI_STATUS Status;\r
04ad241e 314 EFI_HANDLE PreviousHandle;\r
1e57a462 315\r
62d441fb 316 if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {\r
1e57a462 317 return EFI_INVALID_PARAMETER;\r
318 }\r
319\r
04ad241e 320 PreviousHandle = NULL;\r
1e57a462 321 do {\r
62d441fb 322 Remaining = *DevicePath;\r
04ad241e 323\r
1e57a462 324 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns\r
325 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified\r
326 // to point to the remaining part of the device path\r
327 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
04ad241e 328\r
1e57a462 329 if (!EFI_ERROR (Status)) {\r
04ad241e
OM
330 if (*Handle == PreviousHandle) {\r
331 //\r
332 // If no forward progress is made try invoking the Dispatcher.\r
333 // A new FV may have been added to the system and new drivers\r
334 // may now be found.\r
335 // Status == EFI_SUCCESS means a driver was dispatched\r
336 // Status == EFI_NOT_FOUND means no new drivers were dispatched\r
337 //\r
338 Status = gDS->Dispatch ();\r
339 }\r
1e57a462 340\r
04ad241e
OM
341 if (!EFI_ERROR (Status)) {\r
342 PreviousHandle = *Handle;\r
343\r
344 // Recursive = FALSE: We do not want to start the whole device tree\r
345 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
346 }\r
347 }\r
1e57a462 348 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));\r
349\r
350 if (!EFI_ERROR (Status)) {\r
351 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver\r
352 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)\r
62d441fb 353 Remaining = *DevicePath;\r
6f711615 354 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
1e57a462 355 if (!EFI_ERROR (Status)) {\r
356 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
357 if (EFI_ERROR (Status)) {\r
358 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.\r
359 if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
360 Status = EFI_SUCCESS;\r
361 }\r
362 }\r
363 }\r
364 } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {\r
365\r
366 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly\r
367 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {\r
368 Status = EFI_SUCCESS;\r
369 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
370 Status = EFI_SUCCESS;\r
371 }*/\r
372\r
373 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath\r
374 Status = EFI_SUCCESS;\r
375 } else {\r
62d441fb 376 Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath);\r
1e57a462 377 if (!EFI_ERROR (Status)) {\r
62d441fb
RC
378 Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);\r
379 *DevicePath = NewDevicePath;\r
380 return Status;\r
1e57a462 381 }\r
382 }\r
383\r
384 if (RemainingDevicePath) {\r
385 *RemainingDevicePath = Remaining;\r
386 }\r
387\r
388 return Status;\r
389}\r
390\r
62d441fb
RC
391/**\r
392 Connect a Device Path and return the handle of the driver that support this DevicePath\r
393\r
394 @param DevicePath Device Path of the File to connect\r
395 @param Handle Handle of the driver that support this DevicePath\r
396 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath\r
397\r
398 @retval EFI_SUCCESS A driver that matches the Device Path has been found\r
399 @retval EFI_NOT_FOUND No handles match the search.\r
400 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL\r
401\r
10ddca8d 402**/\r
62d441fb
RC
403EFI_STATUS\r
404BdsConnectDevicePath (\r
405 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
406 OUT EFI_HANDLE *Handle,\r
407 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath\r
408 )\r
409{\r
410 return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);\r
411}\r
412\r
1e57a462 413BOOLEAN\r
414BdsFileSystemSupport (\r
415 IN EFI_DEVICE_PATH *DevicePath,\r
416 IN EFI_HANDLE Handle,\r
417 IN EFI_DEVICE_PATH *RemainingDevicePath\r
418 )\r
419{\r
420 EFI_STATUS Status;\r
421 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;\r
422\r
6f711615 423 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
1e57a462 424\r
6f711615 425 return (!EFI_ERROR (Status) && IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));\r
1e57a462 426}\r
427\r
428EFI_STATUS\r
429BdsFileSystemLoadImage (\r
430 IN EFI_DEVICE_PATH *DevicePath,\r
431 IN EFI_HANDLE Handle,\r
432 IN EFI_DEVICE_PATH *RemainingDevicePath,\r
433 IN EFI_ALLOCATE_TYPE Type,\r
434 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
435 OUT UINTN *ImageSize\r
436 )\r
437{\r
438 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
439 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;\r
440 EFI_FILE_PROTOCOL *Fs;\r
441 EFI_STATUS Status;\r
442 EFI_FILE_INFO *FileInfo;\r
443 EFI_FILE_PROTOCOL *File;\r
444 UINTN Size;\r
445\r
6f711615 446 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));\r
1e57a462 447\r
448 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;\r
449\r
6f711615 450 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
451 if (EFI_ERROR (Status)) {\r
1e57a462 452 return Status;\r
453 }\r
454\r
455 // Try to Open the volume and get root directory\r
456 Status = FsProtocol->OpenVolume (FsProtocol, &Fs);\r
6f711615 457 if (EFI_ERROR (Status)) {\r
1e57a462 458 return Status;\r
459 }\r
460\r
461 File = NULL;\r
6f711615 462 Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);\r
463 if (EFI_ERROR (Status)) {\r
1e57a462 464 return Status;\r
465 }\r
466\r
467 Size = 0;\r
6f711615 468 File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);\r
1e57a462 469 FileInfo = AllocatePool (Size);\r
6f711615 470 Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);\r
471 if (EFI_ERROR (Status)) {\r
1e57a462 472 return Status;\r
473 }\r
474\r
475 // Get the file size\r
476 Size = FileInfo->FileSize;\r
477 if (ImageSize) {\r
478 *ImageSize = Size;\r
479 }\r
6f711615 480 FreePool (FileInfo);\r
1e57a462 481\r
482 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
483 // Try to allocate in any pages if failed to allocate memory at the defined location\r
484 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
485 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
486 }\r
6f711615 487 if (!EFI_ERROR (Status)) {\r
1e57a462 488 Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));\r
489 }\r
490\r
491 return Status;\r
492}\r
493\r
494BOOLEAN\r
495BdsMemoryMapSupport (\r
496 IN EFI_DEVICE_PATH *DevicePath,\r
497 IN EFI_HANDLE Handle,\r
498 IN EFI_DEVICE_PATH *RemainingDevicePath\r
499 )\r
500{\r
6f711615 501 return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||\r
502 IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);\r
1e57a462 503}\r
504\r
505EFI_STATUS\r
506BdsMemoryMapLoadImage (\r
507 IN EFI_DEVICE_PATH *DevicePath,\r
508 IN EFI_HANDLE Handle,\r
509 IN EFI_DEVICE_PATH *RemainingDevicePath,\r
510 IN EFI_ALLOCATE_TYPE Type,\r
511 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
512 OUT UINTN *ImageSize\r
513 )\r
514{\r
515 EFI_STATUS Status;\r
516 MEMMAP_DEVICE_PATH* MemMapPathDevicePath;\r
517 UINTN Size;\r
518\r
6f711615 519 if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {\r
1e57a462 520 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;\r
521 } else {\r
6f711615 522 ASSERT (IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));\r
1e57a462 523 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;\r
524 }\r
525\r
526 Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;\r
527 if (Size == 0) {\r
528 return EFI_INVALID_PARAMETER;\r
529 }\r
530\r
531 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
532 // Try to allocate in any pages if failed to allocate memory at the defined location\r
533 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
534 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
535 }\r
6f711615 536 if (!EFI_ERROR (Status)) {\r
1e57a462 537 CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);\r
538\r
539 if (ImageSize != NULL) {\r
540 *ImageSize = Size;\r
541 }\r
542 }\r
543\r
544 return Status;\r
545}\r
546\r
547BOOLEAN\r
548BdsFirmwareVolumeSupport (\r
549 IN EFI_DEVICE_PATH *DevicePath,\r
550 IN EFI_HANDLE Handle,\r
551 IN EFI_DEVICE_PATH *RemainingDevicePath\r
552 )\r
553{\r
6f711615 554 return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);\r
1e57a462 555}\r
556\r
557EFI_STATUS\r
558BdsFirmwareVolumeLoadImage (\r
559 IN EFI_DEVICE_PATH *DevicePath,\r
560 IN EFI_HANDLE Handle,\r
561 IN EFI_DEVICE_PATH *RemainingDevicePath,\r
562 IN EFI_ALLOCATE_TYPE Type,\r
563 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
564 OUT UINTN *ImageSize\r
565 )\r
566{\r
567 EFI_STATUS Status;\r
568 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;\r
569 EFI_GUID *FvNameGuid;\r
570 EFI_SECTION_TYPE SectionType;\r
571 EFI_FV_FILETYPE FvType;\r
572 EFI_FV_FILE_ATTRIBUTES Attrib;\r
573 UINT32 AuthenticationStatus;\r
574 VOID* ImageBuffer;\r
575\r
6f711615 576 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));\r
1e57a462 577\r
6f711615 578 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);\r
579 if (EFI_ERROR (Status)) {\r
1e57a462 580 return Status;\r
581 }\r
582\r
583 FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);\r
584 if (FvNameGuid == NULL) {\r
585 Status = EFI_INVALID_PARAMETER;\r
586 }\r
587\r
588 SectionType = EFI_SECTION_PE32;\r
589 AuthenticationStatus = 0;\r
590 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.\r
591 ImageBuffer = NULL;\r
592 Status = FwVol->ReadSection (\r
593 FwVol,\r
594 FvNameGuid,\r
595 SectionType,\r
596 0,\r
597 &ImageBuffer,\r
598 ImageSize,\r
599 &AuthenticationStatus\r
600 );\r
601 if (!EFI_ERROR (Status)) {\r
602#if 0\r
603 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements\r
604 if (Type != AllocateAnyPages) {\r
605 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);\r
6f711615 606 if (!EFI_ERROR (Status)) {\r
1e57a462 607 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
608 FreePool (ImageBuffer);\r
609 }\r
610 }\r
611#else\r
612 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation\r
613 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
614 // Try to allocate in any pages if failed to allocate memory at the defined location\r
615 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
616 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
617 }\r
6f711615 618 if (!EFI_ERROR (Status)) {\r
1e57a462 619 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
620 FreePool (ImageBuffer);\r
621 }\r
622#endif\r
623 } else {\r
624 // Try a raw file, since a PE32 SECTION does not exist\r
625 Status = FwVol->ReadFile (\r
626 FwVol,\r
627 FvNameGuid,\r
628 NULL,\r
629 ImageSize,\r
630 &FvType,\r
631 &Attrib,\r
632 &AuthenticationStatus\r
633 );\r
6f711615 634 if (!EFI_ERROR (Status)) {\r
1e57a462 635 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
636 // Try to allocate in any pages if failed to allocate memory at the defined location\r
637 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
638 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
639 }\r
6f711615 640 if (!EFI_ERROR (Status)) {\r
1e57a462 641 Status = FwVol->ReadFile (\r
642 FwVol,\r
643 FvNameGuid,\r
644 (VOID*)(UINTN)(*Image),\r
645 ImageSize,\r
646 &FvType,\r
647 &Attrib,\r
648 &AuthenticationStatus\r
649 );\r
650 }\r
651 }\r
652 }\r
653 return Status;\r
654}\r
655\r
656BOOLEAN\r
657BdsPxeSupport (\r
658 IN EFI_DEVICE_PATH* DevicePath,\r
659 IN EFI_HANDLE Handle,\r
660 IN EFI_DEVICE_PATH* RemainingDevicePath\r
661 )\r
662{\r
663 EFI_STATUS Status;\r
664 EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;\r
665\r
6f711615 666 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1e57a462 667 return FALSE;\r
668 }\r
669\r
670 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
671 if (EFI_ERROR (Status)) {\r
672 return FALSE;\r
673 } else {\r
674 return TRUE;\r
675 }\r
676}\r
677\r
678EFI_STATUS\r
679BdsPxeLoadImage (\r
680 IN EFI_DEVICE_PATH* DevicePath,\r
681 IN EFI_HANDLE Handle,\r
682 IN EFI_DEVICE_PATH* RemainingDevicePath,\r
683 IN EFI_ALLOCATE_TYPE Type,\r
684 IN OUT EFI_PHYSICAL_ADDRESS *Image,\r
685 OUT UINTN *ImageSize\r
686 )\r
687{\r
688 EFI_STATUS Status;\r
689 EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;\r
690 UINTN BufferSize;\r
2edb5ad3 691 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;\r
1e57a462 692\r
693 // Get Load File Protocol attached to the PXE protocol\r
694 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);\r
695 if (EFI_ERROR (Status)) {\r
696 return Status;\r
697 }\r
698\r
699 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);\r
700 if (Status == EFI_BUFFER_TOO_SMALL) {\r
701 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);\r
6f711615 702 if (EFI_ERROR (Status)) {\r
1e57a462 703 return Status;\r
704 }\r
705\r
706 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));\r
6f711615 707 if (!EFI_ERROR (Status) && (ImageSize != NULL)) {\r
1e57a462 708 *ImageSize = BufferSize;\r
709 }\r
710 }\r
711\r
2edb5ad3 712 if (Status == EFI_ALREADY_STARTED) {\r
713 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
714 if (!EFI_ERROR(Status)) {\r
715 // If PXE is already started, we stop it\r
716 Pxe->Stop (Pxe);\r
717 // And we try again\r
718 return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);\r
719 }\r
720 }\r
1e57a462 721 return Status;\r
722}\r
723\r
724BOOLEAN\r
725BdsTftpSupport (\r
726 IN EFI_DEVICE_PATH* DevicePath,\r
727 IN EFI_HANDLE Handle,\r
728 IN EFI_DEVICE_PATH* RemainingDevicePath\r
729 )\r
730{\r
731 EFI_STATUS Status;\r
732 EFI_DEVICE_PATH *NextDevicePath;\r
733 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
734\r
735 // Validate the Remaining Device Path\r
6f711615 736 if (IsDevicePathEnd (RemainingDevicePath)) {\r
1e57a462 737 return FALSE;\r
738 }\r
6f711615 739 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&\r
740 !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {\r
1e57a462 741 return FALSE;\r
742 }\r
743 NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
6f711615 744 if (IsDevicePathEnd (NextDevicePath)) {\r
1e57a462 745 return FALSE;\r
746 }\r
6f711615 747 if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {\r
1e57a462 748 return FALSE;\r
749 }\r
750\r
751 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
752 if (EFI_ERROR (Status)) {\r
753 return FALSE;\r
754 } else {\r
755 return TRUE;\r
756 }\r
757}\r
758\r
759EFI_STATUS\r
760BdsTftpLoadImage (\r
761 IN EFI_DEVICE_PATH* DevicePath,\r
762 IN EFI_HANDLE Handle,\r
763 IN EFI_DEVICE_PATH* RemainingDevicePath,\r
764 IN EFI_ALLOCATE_TYPE Type,\r
765 IN OUT EFI_PHYSICAL_ADDRESS *Image,\r
766 OUT UINTN *ImageSize\r
767 )\r
768{\r
769 EFI_STATUS Status;\r
770 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;\r
771 UINT64 TftpBufferSize;\r
edc93a31 772 UINT64 TftpTransferSize;\r
1e57a462 773 EFI_IP_ADDRESS ServerIp;\r
774 IPv4_DEVICE_PATH* IPv4DevicePathNode;\r
775 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
776 EFI_IP_ADDRESS LocalIp;\r
2edb5ad3 777 CHAR8* AsciiPathName;\r
778 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1e57a462 779\r
6f711615 780 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));\r
1e57a462 781\r
782 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;\r
783 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
784\r
785 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
6f711615 786 if (EFI_ERROR (Status)) {\r
1e57a462 787 return Status;\r
788 }\r
789\r
790 Status = Pxe->Start (Pxe, FALSE);\r
6f711615 791 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
1e57a462 792 return Status;\r
793 }\r
794\r
2edb5ad3 795 do {\r
796 if (!IPv4DevicePathNode->StaticIpAddress) {\r
797 Status = Pxe->Dhcp (Pxe, TRUE);\r
798 } else {\r
799 CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
800 Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);\r
801 }\r
802\r
803 // If an IP Address has already been set and a different static IP address is requested then restart\r
804 // the Network service.\r
805 if (Status == EFI_ALREADY_STARTED) {\r
806 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&Snp);\r
807 if (!EFI_ERROR (Status) && IPv4DevicePathNode->StaticIpAddress &&\r
808 (CompareMem (&Snp->Mode->CurrentAddress, &IPv4DevicePathNode->LocalIpAddress, sizeof(EFI_MAC_ADDRESS)) != 0))\r
809 {\r
810 Pxe->Stop (Pxe);\r
811 Status = Pxe->Start (Pxe, FALSE);\r
812 if (EFI_ERROR(Status)) {\r
813 break;\r
814 }\r
815 // After restarting the PXE protocol, we want to try again with our new IP Address\r
816 Status = EFI_ALREADY_STARTED;\r
817 }\r
818 }\r
819 } while (Status == EFI_ALREADY_STARTED);\r
820\r
821 if (EFI_ERROR(Status)) {\r
1e57a462 822 return Status;\r
823 }\r
824\r
825 CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
826\r
2edb5ad3 827 // Convert the Unicode PathName to Ascii\r
828 AsciiPathName = AllocatePool ((StrLen (FilePathDevicePath->PathName) + 1) * sizeof (CHAR8));\r
829 if (AsciiPathName == NULL) {\r
830 return EFI_OUT_OF_RESOURCES;\r
831 }\r
832 UnicodeStrToAsciiStr (FilePathDevicePath->PathName, AsciiPathName);\r
833\r
d8f36fb5 834 // Try to get the size (required the TFTP server to have "tsize" extension)\r
1e57a462 835 Status = Pxe->Mtftp (\r
836 Pxe,\r
837 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
838 NULL,\r
839 FALSE,\r
840 &TftpBufferSize,\r
841 NULL,\r
842 &ServerIp,\r
2edb5ad3 843 (UINT8*)AsciiPathName,\r
1e57a462 844 NULL,\r
2edb5ad3 845 FALSE\r
1e57a462 846 );\r
d8f36fb5
OM
847 // Pxe.Mtftp replies EFI_PROTOCOL_ERROR if tsize is not supported by the TFTP server\r
848 if (EFI_ERROR (Status) && (Status != EFI_PROTOCOL_ERROR)) {\r
2edb5ad3 849 if (Status == EFI_TFTP_ERROR) {\r
850 DEBUG((EFI_D_ERROR, "TFTP Error: Fail to get the size of the file\n"));\r
851 }\r
852 goto EXIT;\r
1e57a462 853 }\r
854\r
d8f36fb5
OM
855 //\r
856 // Two cases:\r
857 // 1) the file size is unknown (tsize extension not supported)\r
858 // 2) tsize returned the file size\r
859 //\r
860 if (Status == EFI_PROTOCOL_ERROR) {\r
861 for (TftpBufferSize = SIZE_8MB; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize); TftpBufferSize += SIZE_8MB) {\r
862 // Allocate a buffer to hold the whole file.\r
863 Status = gBS->AllocatePages (\r
864 Type,\r
865 EfiBootServicesCode,\r
866 EFI_SIZE_TO_PAGES (TftpBufferSize),\r
867 Image\r
868 );\r
869 if (EFI_ERROR (Status)) {\r
870 DEBUG ((EFI_D_ERROR, "Failed to allocate space for image: %r\n", Status));\r
871 goto EXIT;\r
872 }\r
1e57a462 873\r
edc93a31 874 TftpTransferSize = TftpBufferSize;\r
d8f36fb5
OM
875 Status = Pxe->Mtftp (\r
876 Pxe,\r
877 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
878 (VOID *)(UINTN)*Image,\r
879 FALSE,\r
edc93a31 880 &TftpTransferSize,\r
d8f36fb5
OM
881 NULL,\r
882 &ServerIp,\r
883 (UINT8*)AsciiPathName,\r
884 NULL,\r
885 FALSE\r
886 );\r
887 if (EFI_ERROR (Status)) {\r
888 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));\r
889 } else {\r
890 *ImageSize = (UINTN)TftpBufferSize;\r
891 break;\r
892 }\r
893 }\r
1aaa6f61 894 } else {\r
d8f36fb5
OM
895 // Allocate a buffer to hold the whole file.\r
896 Status = gBS->AllocatePages (\r
897 Type,\r
898 EfiBootServicesCode,\r
899 EFI_SIZE_TO_PAGES (TftpBufferSize),\r
900 Image\r
901 );\r
902 if (EFI_ERROR (Status)) {\r
903 DEBUG ((EFI_D_ERROR, "Failed to allocate space for kernel image: %r\n", Status));\r
904 goto EXIT;\r
905 }\r
906\r
907 Status = Pxe->Mtftp (\r
908 Pxe,\r
909 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
910 (VOID *)(UINTN)*Image,\r
911 FALSE,\r
912 &TftpBufferSize,\r
913 NULL,\r
914 &ServerIp,\r
915 (UINT8*)AsciiPathName,\r
916 NULL,\r
917 FALSE\r
918 );\r
919 if (EFI_ERROR (Status)) {\r
920 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));\r
921 } else {\r
922 *ImageSize = (UINTN)TftpBufferSize;\r
923 }\r
1e57a462 924 }\r
925\r
2edb5ad3 926EXIT:\r
927 FreePool (AsciiPathName);\r
1e57a462 928 return Status;\r
929}\r
930\r
931BDS_FILE_LOADER FileLoaders[] = {\r
932 { BdsFileSystemSupport, BdsFileSystemLoadImage },\r
933 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },\r
934 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },\r
935 { BdsMemoryMapSupport, BdsMemoryMapLoadImage },\r
936 { BdsPxeSupport, BdsPxeLoadImage },\r
937 { BdsTftpSupport, BdsTftpLoadImage },\r
938 { NULL, NULL }\r
939};\r
940\r
941EFI_STATUS\r
62d441fb
RC
942BdsLoadImageAndUpdateDevicePath (\r
943 IN OUT EFI_DEVICE_PATH **DevicePath,\r
1e57a462 944 IN EFI_ALLOCATE_TYPE Type,\r
945 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
946 OUT UINTN *FileSize\r
947 )\r
948{\r
949 EFI_STATUS Status;\r
950 EFI_HANDLE Handle;\r
951 EFI_DEVICE_PATH *RemainingDevicePath;\r
952 BDS_FILE_LOADER* FileLoader;\r
953\r
62d441fb 954 Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
1e57a462 955 if (EFI_ERROR (Status)) {\r
956 return Status;\r
957 }\r
958\r
959 FileLoader = FileLoaders;\r
960 while (FileLoader->Support != NULL) {\r
62d441fb
RC
961 if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {\r
962 return FileLoader->LoadImage (*DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);\r
1e57a462 963 }\r
964 FileLoader++;\r
965 }\r
966\r
967 return EFI_UNSUPPORTED;\r
968}\r
969\r
10ddca8d 970EFI_STATUS\r
62d441fb
RC
971BdsLoadImage (\r
972 IN EFI_DEVICE_PATH *DevicePath,\r
973 IN EFI_ALLOCATE_TYPE Type,\r
974 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
975 OUT UINTN *FileSize\r
976 )\r
977{\r
978 return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);\r
979}\r
980\r
1e57a462 981/**\r
982 Start an EFI Application from a Device Path\r
983\r
984 @param ParentImageHandle Handle of the calling image\r
985 @param DevicePath Location of the EFI Application\r
986\r
987 @retval EFI_SUCCESS All drivers have been connected\r
988 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found\r
989 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.\r
990\r
991**/\r
992EFI_STATUS\r
993BdsStartEfiApplication (\r
994 IN EFI_HANDLE ParentImageHandle,\r
995 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
996 IN UINTN LoadOptionsSize,\r
997 IN VOID* LoadOptions\r
998 )\r
999{\r
1000 EFI_STATUS Status;\r
1001 EFI_HANDLE ImageHandle;\r
1002 EFI_PHYSICAL_ADDRESS BinaryBuffer;\r
1003 UINTN BinarySize;\r
1004 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;\r
1005\r
1006 // Find the nearest supported file loader\r
62d441fb 1007 Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);\r
6f711615 1008 if (EFI_ERROR (Status)) {\r
1e57a462 1009 return Status;\r
1010 }\r
1011\r
1012 // Load the image from the Buffer with Boot Services function\r
1013 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);\r
6f711615 1014 if (EFI_ERROR (Status)) {\r
1e57a462 1015 return Status;\r
1016 }\r
1017\r
1018 // Passed LoadOptions to the EFI Application\r
1019 if (LoadOptionsSize != 0) {\r
1020 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);\r
6f711615 1021 if (EFI_ERROR (Status)) {\r
1e57a462 1022 return Status;\r
1023 }\r
1024\r
1025 LoadedImage->LoadOptionsSize = LoadOptionsSize;\r
1026 LoadedImage->LoadOptions = LoadOptions;\r
1027 }\r
1028\r
1029 // Before calling the image, enable the Watchdog Timer for the 5 Minute period\r
1030 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
1031 // Start the image\r
1032 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
1033 // Clear the Watchdog Timer after the image returns\r
1034 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
1035\r
1036 return Status;\r
1037}\r