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