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