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