]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/BdsLib/BdsFilePath.c
ARM Packages: Corrected non-DOS line endings
[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
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
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
314\r
62d441fb 315 if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {\r
1e57a462 316 return EFI_INVALID_PARAMETER;\r
317 }\r
318\r
319 do {\r
62d441fb 320 Remaining = *DevicePath;\r
1e57a462 321 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns\r
322 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified\r
323 // to point to the remaining part of the device path\r
324 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
325 if (!EFI_ERROR (Status)) {\r
326 // Recursive = FALSE: We do not want to start all the device tree\r
327 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
328 }\r
329\r
330 /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling\r
6f711615 331 // NextDevicePathNode () will return an undetermined Device Path Node\r
1e57a462 332 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
333 RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);\r
334 }*/\r
335 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));\r
336\r
337 if (!EFI_ERROR (Status)) {\r
338 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver\r
339 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)\r
62d441fb 340 Remaining = *DevicePath;\r
6f711615 341 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
1e57a462 342 if (!EFI_ERROR (Status)) {\r
343 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
344 if (EFI_ERROR (Status)) {\r
345 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.\r
346 if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
347 Status = EFI_SUCCESS;\r
348 }\r
349 }\r
350 }\r
351 } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {\r
352\r
353 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly\r
354 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {\r
355 Status = EFI_SUCCESS;\r
356 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
357 Status = EFI_SUCCESS;\r
358 }*/\r
359\r
360 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath\r
361 Status = EFI_SUCCESS;\r
362 } else {\r
62d441fb 363 Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath);\r
1e57a462 364 if (!EFI_ERROR (Status)) {\r
62d441fb
RC
365 Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);\r
366 *DevicePath = NewDevicePath;\r
367 return Status;\r
1e57a462 368 }\r
369 }\r
370\r
371 if (RemainingDevicePath) {\r
372 *RemainingDevicePath = Remaining;\r
373 }\r
374\r
375 return Status;\r
376}\r
377\r
62d441fb
RC
378/**\r
379 Connect a Device Path and return the handle of the driver that support this DevicePath\r
380\r
381 @param DevicePath Device Path of the File to connect\r
382 @param Handle Handle of the driver that support this DevicePath\r
383 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath\r
384\r
385 @retval EFI_SUCCESS A driver that matches the Device Path has been found\r
386 @retval EFI_NOT_FOUND No handles match the search.\r
387 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL\r
388\r
10ddca8d 389**/\r
62d441fb
RC
390EFI_STATUS\r
391BdsConnectDevicePath (\r
392 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
393 OUT EFI_HANDLE *Handle,\r
394 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath\r
395 )\r
396{\r
397 return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);\r
398}\r
399\r
1e57a462 400BOOLEAN\r
401BdsFileSystemSupport (\r
402 IN EFI_DEVICE_PATH *DevicePath,\r
403 IN EFI_HANDLE Handle,\r
404 IN EFI_DEVICE_PATH *RemainingDevicePath\r
405 )\r
406{\r
407 EFI_STATUS Status;\r
408 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;\r
409\r
6f711615 410 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
1e57a462 411\r
6f711615 412 return (!EFI_ERROR (Status) && IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));\r
1e57a462 413}\r
414\r
415EFI_STATUS\r
416BdsFileSystemLoadImage (\r
417 IN EFI_DEVICE_PATH *DevicePath,\r
418 IN EFI_HANDLE Handle,\r
419 IN EFI_DEVICE_PATH *RemainingDevicePath,\r
420 IN EFI_ALLOCATE_TYPE Type,\r
421 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
422 OUT UINTN *ImageSize\r
423 )\r
424{\r
425 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
426 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;\r
427 EFI_FILE_PROTOCOL *Fs;\r
428 EFI_STATUS Status;\r
429 EFI_FILE_INFO *FileInfo;\r
430 EFI_FILE_PROTOCOL *File;\r
431 UINTN Size;\r
432\r
6f711615 433 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));\r
1e57a462 434\r
435 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;\r
436\r
6f711615 437 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
438 if (EFI_ERROR (Status)) {\r
1e57a462 439 return Status;\r
440 }\r
441\r
442 // Try to Open the volume and get root directory\r
443 Status = FsProtocol->OpenVolume (FsProtocol, &Fs);\r
6f711615 444 if (EFI_ERROR (Status)) {\r
1e57a462 445 return Status;\r
446 }\r
447\r
448 File = NULL;\r
6f711615 449 Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);\r
450 if (EFI_ERROR (Status)) {\r
1e57a462 451 return Status;\r
452 }\r
453\r
454 Size = 0;\r
6f711615 455 File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);\r
1e57a462 456 FileInfo = AllocatePool (Size);\r
6f711615 457 Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);\r
458 if (EFI_ERROR (Status)) {\r
1e57a462 459 return Status;\r
460 }\r
461\r
462 // Get the file size\r
463 Size = FileInfo->FileSize;\r
464 if (ImageSize) {\r
465 *ImageSize = Size;\r
466 }\r
6f711615 467 FreePool (FileInfo);\r
1e57a462 468\r
469 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
470 // Try to allocate in any pages if failed to allocate memory at the defined location\r
471 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
472 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
473 }\r
6f711615 474 if (!EFI_ERROR (Status)) {\r
1e57a462 475 Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));\r
476 }\r
477\r
478 return Status;\r
479}\r
480\r
481BOOLEAN\r
482BdsMemoryMapSupport (\r
483 IN EFI_DEVICE_PATH *DevicePath,\r
484 IN EFI_HANDLE Handle,\r
485 IN EFI_DEVICE_PATH *RemainingDevicePath\r
486 )\r
487{\r
6f711615 488 return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||\r
489 IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);\r
1e57a462 490}\r
491\r
492EFI_STATUS\r
493BdsMemoryMapLoadImage (\r
494 IN EFI_DEVICE_PATH *DevicePath,\r
495 IN EFI_HANDLE Handle,\r
496 IN EFI_DEVICE_PATH *RemainingDevicePath,\r
497 IN EFI_ALLOCATE_TYPE Type,\r
498 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
499 OUT UINTN *ImageSize\r
500 )\r
501{\r
502 EFI_STATUS Status;\r
503 MEMMAP_DEVICE_PATH* MemMapPathDevicePath;\r
504 UINTN Size;\r
505\r
6f711615 506 if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {\r
1e57a462 507 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;\r
508 } else {\r
6f711615 509 ASSERT (IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));\r
1e57a462 510 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;\r
511 }\r
512\r
513 Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;\r
514 if (Size == 0) {\r
515 return EFI_INVALID_PARAMETER;\r
516 }\r
517\r
518 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
519 // Try to allocate in any pages if failed to allocate memory at the defined location\r
520 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
521 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
522 }\r
6f711615 523 if (!EFI_ERROR (Status)) {\r
1e57a462 524 CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);\r
525\r
526 if (ImageSize != NULL) {\r
527 *ImageSize = Size;\r
528 }\r
529 }\r
530\r
531 return Status;\r
532}\r
533\r
534BOOLEAN\r
535BdsFirmwareVolumeSupport (\r
536 IN EFI_DEVICE_PATH *DevicePath,\r
537 IN EFI_HANDLE Handle,\r
538 IN EFI_DEVICE_PATH *RemainingDevicePath\r
539 )\r
540{\r
6f711615 541 return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);\r
1e57a462 542}\r
543\r
544EFI_STATUS\r
545BdsFirmwareVolumeLoadImage (\r
546 IN EFI_DEVICE_PATH *DevicePath,\r
547 IN EFI_HANDLE Handle,\r
548 IN EFI_DEVICE_PATH *RemainingDevicePath,\r
549 IN EFI_ALLOCATE_TYPE Type,\r
550 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
551 OUT UINTN *ImageSize\r
552 )\r
553{\r
554 EFI_STATUS Status;\r
555 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;\r
556 EFI_GUID *FvNameGuid;\r
557 EFI_SECTION_TYPE SectionType;\r
558 EFI_FV_FILETYPE FvType;\r
559 EFI_FV_FILE_ATTRIBUTES Attrib;\r
560 UINT32 AuthenticationStatus;\r
561 VOID* ImageBuffer;\r
562\r
6f711615 563 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));\r
1e57a462 564\r
6f711615 565 Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);\r
566 if (EFI_ERROR (Status)) {\r
1e57a462 567 return Status;\r
568 }\r
569\r
570 FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);\r
571 if (FvNameGuid == NULL) {\r
572 Status = EFI_INVALID_PARAMETER;\r
573 }\r
574\r
575 SectionType = EFI_SECTION_PE32;\r
576 AuthenticationStatus = 0;\r
577 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.\r
578 ImageBuffer = NULL;\r
579 Status = FwVol->ReadSection (\r
580 FwVol,\r
581 FvNameGuid,\r
582 SectionType,\r
583 0,\r
584 &ImageBuffer,\r
585 ImageSize,\r
586 &AuthenticationStatus\r
587 );\r
588 if (!EFI_ERROR (Status)) {\r
589#if 0\r
590 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements\r
591 if (Type != AllocateAnyPages) {\r
592 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);\r
6f711615 593 if (!EFI_ERROR (Status)) {\r
1e57a462 594 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
595 FreePool (ImageBuffer);\r
596 }\r
597 }\r
598#else\r
599 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation\r
600 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
601 // Try to allocate in any pages if failed to allocate memory at the defined location\r
602 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
603 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
604 }\r
6f711615 605 if (!EFI_ERROR (Status)) {\r
1e57a462 606 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
607 FreePool (ImageBuffer);\r
608 }\r
609#endif\r
610 } else {\r
611 // Try a raw file, since a PE32 SECTION does not exist\r
612 Status = FwVol->ReadFile (\r
613 FwVol,\r
614 FvNameGuid,\r
615 NULL,\r
616 ImageSize,\r
617 &FvType,\r
618 &Attrib,\r
619 &AuthenticationStatus\r
620 );\r
6f711615 621 if (!EFI_ERROR (Status)) {\r
1e57a462 622 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
623 // Try to allocate in any pages if failed to allocate memory at the defined location\r
624 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
625 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
626 }\r
6f711615 627 if (!EFI_ERROR (Status)) {\r
1e57a462 628 Status = FwVol->ReadFile (\r
629 FwVol,\r
630 FvNameGuid,\r
631 (VOID*)(UINTN)(*Image),\r
632 ImageSize,\r
633 &FvType,\r
634 &Attrib,\r
635 &AuthenticationStatus\r
636 );\r
637 }\r
638 }\r
639 }\r
640 return Status;\r
641}\r
642\r
643BOOLEAN\r
644BdsPxeSupport (\r
645 IN EFI_DEVICE_PATH* DevicePath,\r
646 IN EFI_HANDLE Handle,\r
647 IN EFI_DEVICE_PATH* RemainingDevicePath\r
648 )\r
649{\r
650 EFI_STATUS Status;\r
651 EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;\r
652\r
6f711615 653 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1e57a462 654 return FALSE;\r
655 }\r
656\r
657 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
658 if (EFI_ERROR (Status)) {\r
659 return FALSE;\r
660 } else {\r
661 return TRUE;\r
662 }\r
663}\r
664\r
665EFI_STATUS\r
666BdsPxeLoadImage (\r
667 IN EFI_DEVICE_PATH* DevicePath,\r
668 IN EFI_HANDLE Handle,\r
669 IN EFI_DEVICE_PATH* RemainingDevicePath,\r
670 IN EFI_ALLOCATE_TYPE Type,\r
671 IN OUT EFI_PHYSICAL_ADDRESS *Image,\r
672 OUT UINTN *ImageSize\r
673 )\r
674{\r
675 EFI_STATUS Status;\r
676 EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;\r
677 UINTN BufferSize;\r
2edb5ad3 678 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;\r
1e57a462 679\r
680 // Get Load File Protocol attached to the PXE protocol\r
681 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);\r
682 if (EFI_ERROR (Status)) {\r
683 return Status;\r
684 }\r
685\r
686 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);\r
687 if (Status == EFI_BUFFER_TOO_SMALL) {\r
688 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);\r
6f711615 689 if (EFI_ERROR (Status)) {\r
1e57a462 690 return Status;\r
691 }\r
692\r
693 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));\r
6f711615 694 if (!EFI_ERROR (Status) && (ImageSize != NULL)) {\r
1e57a462 695 *ImageSize = BufferSize;\r
696 }\r
697 }\r
698\r
2edb5ad3 699 if (Status == EFI_ALREADY_STARTED) {\r
700 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
701 if (!EFI_ERROR(Status)) {\r
702 // If PXE is already started, we stop it\r
703 Pxe->Stop (Pxe);\r
704 // And we try again\r
705 return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);\r
706 }\r
707 }\r
1e57a462 708 return Status;\r
709}\r
710\r
711BOOLEAN\r
712BdsTftpSupport (\r
713 IN EFI_DEVICE_PATH* DevicePath,\r
714 IN EFI_HANDLE Handle,\r
715 IN EFI_DEVICE_PATH* RemainingDevicePath\r
716 )\r
717{\r
718 EFI_STATUS Status;\r
719 EFI_DEVICE_PATH *NextDevicePath;\r
720 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
721\r
722 // Validate the Remaining Device Path\r
6f711615 723 if (IsDevicePathEnd (RemainingDevicePath)) {\r
1e57a462 724 return FALSE;\r
725 }\r
6f711615 726 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&\r
727 !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {\r
1e57a462 728 return FALSE;\r
729 }\r
730 NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
6f711615 731 if (IsDevicePathEnd (NextDevicePath)) {\r
1e57a462 732 return FALSE;\r
733 }\r
6f711615 734 if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {\r
1e57a462 735 return FALSE;\r
736 }\r
737\r
738 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
739 if (EFI_ERROR (Status)) {\r
740 return FALSE;\r
741 } else {\r
742 return TRUE;\r
743 }\r
744}\r
745\r
746EFI_STATUS\r
747BdsTftpLoadImage (\r
748 IN EFI_DEVICE_PATH* DevicePath,\r
749 IN EFI_HANDLE Handle,\r
750 IN EFI_DEVICE_PATH* RemainingDevicePath,\r
751 IN EFI_ALLOCATE_TYPE Type,\r
752 IN OUT EFI_PHYSICAL_ADDRESS *Image,\r
753 OUT UINTN *ImageSize\r
754 )\r
755{\r
756 EFI_STATUS Status;\r
757 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;\r
758 UINT64 TftpBufferSize;\r
edc93a31 759 UINT64 TftpTransferSize;\r
1e57a462 760 EFI_IP_ADDRESS ServerIp;\r
761 IPv4_DEVICE_PATH* IPv4DevicePathNode;\r
762 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
763 EFI_IP_ADDRESS LocalIp;\r
2edb5ad3 764 CHAR8* AsciiPathName;\r
765 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1e57a462 766\r
6f711615 767 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));\r
1e57a462 768\r
769 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;\r
770 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
771\r
772 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
6f711615 773 if (EFI_ERROR (Status)) {\r
1e57a462 774 return Status;\r
775 }\r
776\r
777 Status = Pxe->Start (Pxe, FALSE);\r
6f711615 778 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
1e57a462 779 return Status;\r
780 }\r
781\r
2edb5ad3 782 do {\r
783 if (!IPv4DevicePathNode->StaticIpAddress) {\r
784 Status = Pxe->Dhcp (Pxe, TRUE);\r
785 } else {\r
786 CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
787 Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);\r
788 }\r
789\r
790 // If an IP Address has already been set and a different static IP address is requested then restart\r
791 // the Network service.\r
792 if (Status == EFI_ALREADY_STARTED) {\r
793 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&Snp);\r
794 if (!EFI_ERROR (Status) && IPv4DevicePathNode->StaticIpAddress &&\r
795 (CompareMem (&Snp->Mode->CurrentAddress, &IPv4DevicePathNode->LocalIpAddress, sizeof(EFI_MAC_ADDRESS)) != 0))\r
796 {\r
797 Pxe->Stop (Pxe);\r
798 Status = Pxe->Start (Pxe, FALSE);\r
799 if (EFI_ERROR(Status)) {\r
800 break;\r
801 }\r
802 // After restarting the PXE protocol, we want to try again with our new IP Address\r
803 Status = EFI_ALREADY_STARTED;\r
804 }\r
805 }\r
806 } while (Status == EFI_ALREADY_STARTED);\r
807\r
808 if (EFI_ERROR(Status)) {\r
1e57a462 809 return Status;\r
810 }\r
811\r
812 CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
813\r
2edb5ad3 814 // Convert the Unicode PathName to Ascii\r
815 AsciiPathName = AllocatePool ((StrLen (FilePathDevicePath->PathName) + 1) * sizeof (CHAR8));\r
816 if (AsciiPathName == NULL) {\r
817 return EFI_OUT_OF_RESOURCES;\r
818 }\r
819 UnicodeStrToAsciiStr (FilePathDevicePath->PathName, AsciiPathName);\r
820\r
d8f36fb5 821 // Try to get the size (required the TFTP server to have "tsize" extension)\r
1e57a462 822 Status = Pxe->Mtftp (\r
823 Pxe,\r
824 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
825 NULL,\r
826 FALSE,\r
827 &TftpBufferSize,\r
828 NULL,\r
829 &ServerIp,\r
2edb5ad3 830 (UINT8*)AsciiPathName,\r
1e57a462 831 NULL,\r
2edb5ad3 832 FALSE\r
1e57a462 833 );\r
d8f36fb5
OM
834 // Pxe.Mtftp replies EFI_PROTOCOL_ERROR if tsize is not supported by the TFTP server\r
835 if (EFI_ERROR (Status) && (Status != EFI_PROTOCOL_ERROR)) {\r
2edb5ad3 836 if (Status == EFI_TFTP_ERROR) {\r
837 DEBUG((EFI_D_ERROR, "TFTP Error: Fail to get the size of the file\n"));\r
838 }\r
839 goto EXIT;\r
1e57a462 840 }\r
841\r
d8f36fb5
OM
842 //\r
843 // Two cases:\r
844 // 1) the file size is unknown (tsize extension not supported)\r
845 // 2) tsize returned the file size\r
846 //\r
847 if (Status == EFI_PROTOCOL_ERROR) {\r
848 for (TftpBufferSize = SIZE_8MB; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize); TftpBufferSize += SIZE_8MB) {\r
849 // Allocate a buffer to hold the whole file.\r
850 Status = gBS->AllocatePages (\r
851 Type,\r
852 EfiBootServicesCode,\r
853 EFI_SIZE_TO_PAGES (TftpBufferSize),\r
854 Image\r
855 );\r
856 if (EFI_ERROR (Status)) {\r
857 DEBUG ((EFI_D_ERROR, "Failed to allocate space for image: %r\n", Status));\r
858 goto EXIT;\r
859 }\r
1e57a462 860\r
edc93a31 861 TftpTransferSize = TftpBufferSize;\r
d8f36fb5
OM
862 Status = Pxe->Mtftp (\r
863 Pxe,\r
864 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
865 (VOID *)(UINTN)*Image,\r
866 FALSE,\r
edc93a31 867 &TftpTransferSize,\r
d8f36fb5
OM
868 NULL,\r
869 &ServerIp,\r
870 (UINT8*)AsciiPathName,\r
871 NULL,\r
872 FALSE\r
873 );\r
874 if (EFI_ERROR (Status)) {\r
875 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));\r
876 } else {\r
877 *ImageSize = (UINTN)TftpBufferSize;\r
878 break;\r
879 }\r
880 }\r
1aaa6f61 881 } else {\r
d8f36fb5
OM
882 // Allocate a buffer to hold the whole file.\r
883 Status = gBS->AllocatePages (\r
884 Type,\r
885 EfiBootServicesCode,\r
886 EFI_SIZE_TO_PAGES (TftpBufferSize),\r
887 Image\r
888 );\r
889 if (EFI_ERROR (Status)) {\r
890 DEBUG ((EFI_D_ERROR, "Failed to allocate space for kernel image: %r\n", Status));\r
891 goto EXIT;\r
892 }\r
893\r
894 Status = Pxe->Mtftp (\r
895 Pxe,\r
896 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
897 (VOID *)(UINTN)*Image,\r
898 FALSE,\r
899 &TftpBufferSize,\r
900 NULL,\r
901 &ServerIp,\r
902 (UINT8*)AsciiPathName,\r
903 NULL,\r
904 FALSE\r
905 );\r
906 if (EFI_ERROR (Status)) {\r
907 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));\r
908 } else {\r
909 *ImageSize = (UINTN)TftpBufferSize;\r
910 }\r
1e57a462 911 }\r
912\r
2edb5ad3 913EXIT:\r
914 FreePool (AsciiPathName);\r
1e57a462 915 return Status;\r
916}\r
917\r
918BDS_FILE_LOADER FileLoaders[] = {\r
919 { BdsFileSystemSupport, BdsFileSystemLoadImage },\r
920 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },\r
921 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },\r
922 { BdsMemoryMapSupport, BdsMemoryMapLoadImage },\r
923 { BdsPxeSupport, BdsPxeLoadImage },\r
924 { BdsTftpSupport, BdsTftpLoadImage },\r
925 { NULL, NULL }\r
926};\r
927\r
928EFI_STATUS\r
62d441fb
RC
929BdsLoadImageAndUpdateDevicePath (\r
930 IN OUT EFI_DEVICE_PATH **DevicePath,\r
1e57a462 931 IN EFI_ALLOCATE_TYPE Type,\r
932 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
933 OUT UINTN *FileSize\r
934 )\r
935{\r
936 EFI_STATUS Status;\r
937 EFI_HANDLE Handle;\r
938 EFI_DEVICE_PATH *RemainingDevicePath;\r
939 BDS_FILE_LOADER* FileLoader;\r
940\r
62d441fb 941 Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
1e57a462 942 if (EFI_ERROR (Status)) {\r
943 return Status;\r
944 }\r
945\r
946 FileLoader = FileLoaders;\r
947 while (FileLoader->Support != NULL) {\r
62d441fb
RC
948 if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {\r
949 return FileLoader->LoadImage (*DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);\r
1e57a462 950 }\r
951 FileLoader++;\r
952 }\r
953\r
954 return EFI_UNSUPPORTED;\r
955}\r
956\r
10ddca8d 957EFI_STATUS\r
62d441fb
RC
958BdsLoadImage (\r
959 IN EFI_DEVICE_PATH *DevicePath,\r
960 IN EFI_ALLOCATE_TYPE Type,\r
961 IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
962 OUT UINTN *FileSize\r
963 )\r
964{\r
965 return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);\r
966}\r
967\r
1e57a462 968/**\r
969 Start an EFI Application from a Device Path\r
970\r
971 @param ParentImageHandle Handle of the calling image\r
972 @param DevicePath Location of the EFI Application\r
973\r
974 @retval EFI_SUCCESS All drivers have been connected\r
975 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found\r
976 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.\r
977\r
978**/\r
979EFI_STATUS\r
980BdsStartEfiApplication (\r
981 IN EFI_HANDLE ParentImageHandle,\r
982 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
983 IN UINTN LoadOptionsSize,\r
984 IN VOID* LoadOptions\r
985 )\r
986{\r
987 EFI_STATUS Status;\r
988 EFI_HANDLE ImageHandle;\r
989 EFI_PHYSICAL_ADDRESS BinaryBuffer;\r
990 UINTN BinarySize;\r
991 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;\r
992\r
993 // Find the nearest supported file loader\r
62d441fb 994 Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);\r
6f711615 995 if (EFI_ERROR (Status)) {\r
1e57a462 996 return Status;\r
997 }\r
998\r
999 // Load the image from the Buffer with Boot Services function\r
1000 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);\r
6f711615 1001 if (EFI_ERROR (Status)) {\r
1e57a462 1002 return Status;\r
1003 }\r
1004\r
1005 // Passed LoadOptions to the EFI Application\r
1006 if (LoadOptionsSize != 0) {\r
1007 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);\r
6f711615 1008 if (EFI_ERROR (Status)) {\r
1e57a462 1009 return Status;\r
1010 }\r
1011\r
1012 LoadedImage->LoadOptionsSize = LoadOptionsSize;\r
1013 LoadedImage->LoadOptions = LoadOptions;\r
1014 }\r
1015\r
1016 // Before calling the image, enable the Watchdog Timer for the 5 Minute period\r
1017 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
1018 // Start the image\r
1019 Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
1020 // Clear the Watchdog Timer after the image returns\r
1021 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
1022\r
1023 return Status;\r
1024}\r