3 * Copyright (c) 2011, ARM Limited. All rights reserved.
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
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.
15 #include "BdsInternal.h"
17 #include <Protocol/UsbIo.h>
18 #include <Protocol/DiskIo.h>
19 #include <Protocol/LoadedImage.h>
21 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
23 // Extract the FilePath from the Device Path
25 BdsExtractFilePathFromDevicePath (
26 IN CONST CHAR16
*StrDevicePath
,
27 IN UINTN NumberDevicePathNode
33 Str
= (CHAR16
*)StrDevicePath
;
35 while ((Str
!= NULL
) && (*Str
!= L
'\0') && (Node
< NumberDevicePathNode
)) {
36 if ((*Str
== L
'/') || (*Str
== L
'\\')) {
51 IN EFI_DEVICE_PATH
* DevicePath
54 return ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
55 ((DevicePathSubType (DevicePath
) == MSG_USB_CLASS_DP
) ||
56 (DevicePathSubType (DevicePath
) == MSG_USB_WWID_DP
)));
61 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
62 OUT EFI_HANDLE
* DeviceHandle
,
63 OUT EFI_DEVICE_PATH
** NewDevicePath
68 UINTN UsbIoHandleCount
;
69 EFI_HANDLE
*UsbIoBuffer
;
70 EFI_DEVICE_PATH
* UsbIoDevicePath
;
71 EFI_DEVICE_PATH
* TmpDevicePath
;
72 USB_WWID_DEVICE_PATH
* WwidDevicePath1
;
73 USB_WWID_DEVICE_PATH
* WwidDevicePath2
;
74 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath1
;
75 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath2
;
77 // Get all the UsbIo handles
79 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiUsbIoProtocolGuid
, NULL
, &UsbIoHandleCount
, &UsbIoBuffer
);
80 if (EFI_ERROR(Status
) || (UsbIoHandleCount
== 0)) {
84 // Check if one of the handles matches the USB description
85 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
86 Status
= gBS
->HandleProtocol (UsbIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &UsbIoDevicePath
);
87 if (!EFI_ERROR(Status
)) {
88 TmpDevicePath
= UsbIoDevicePath
;
89 while (!IsDevicePathEnd (TmpDevicePath
)) {
90 // Check if the Device Path node is a USB Removable device Path node
91 if (BdsIsRemovableUsb (TmpDevicePath
)) {
92 if (TmpDevicePath
->SubType
== MSG_USB_WWID_DP
) {
93 WwidDevicePath1
= (USB_WWID_DEVICE_PATH
*)RemovableDevicePath
;
94 WwidDevicePath2
= (USB_WWID_DEVICE_PATH
*)TmpDevicePath
;
95 if ((WwidDevicePath1
->VendorId
== WwidDevicePath2
->VendorId
) &&
96 (WwidDevicePath1
->ProductId
== WwidDevicePath2
->ProductId
) &&
97 (CompareMem (WwidDevicePath1
+1, WwidDevicePath2
+1, DevicePathNodeLength(WwidDevicePath1
)-sizeof(USB_WWID_DEVICE_PATH
)) == 0))
99 *DeviceHandle
= UsbIoBuffer
[Index
];
100 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
101 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode(RemovableDevicePath
));
105 UsbClassDevicePath1
= (USB_CLASS_DEVICE_PATH
*)RemovableDevicePath
;
106 UsbClassDevicePath2
= (USB_CLASS_DEVICE_PATH
*)TmpDevicePath
;
107 if ((UsbClassDevicePath1
->VendorId
!= 0xFFFF) && (UsbClassDevicePath1
->VendorId
== UsbClassDevicePath2
->VendorId
) &&
108 (UsbClassDevicePath1
->ProductId
!= 0xFFFF) && (UsbClassDevicePath1
->ProductId
== UsbClassDevicePath2
->ProductId
) &&
109 (UsbClassDevicePath1
->DeviceClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceClass
== UsbClassDevicePath2
->DeviceClass
) &&
110 (UsbClassDevicePath1
->DeviceSubClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceSubClass
== UsbClassDevicePath2
->DeviceSubClass
) &&
111 (UsbClassDevicePath1
->DeviceProtocol
!= 0xFF) && (UsbClassDevicePath1
->DeviceProtocol
== UsbClassDevicePath2
->DeviceProtocol
))
113 *DeviceHandle
= UsbIoBuffer
[Index
];
114 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
115 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode(RemovableDevicePath
));
120 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
126 return EFI_NOT_FOUND
;
131 IN EFI_DEVICE_PATH
* DevicePath
134 return IS_DEVICE_PATH_NODE(DevicePath
, MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
);
139 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
140 OUT EFI_HANDLE
* DeviceHandle
,
141 OUT EFI_DEVICE_PATH
** NewDevicePath
146 UINTN PartitionHandleCount
;
147 EFI_HANDLE
*PartitionBuffer
;
148 EFI_DEVICE_PATH
* PartitionDevicePath
;
149 EFI_DEVICE_PATH
* TmpDevicePath
;
150 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath1
;
151 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath2
;
153 // Get all the DiskIo handles
154 PartitionHandleCount
= 0;
155 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDiskIoProtocolGuid
, NULL
, &PartitionHandleCount
, &PartitionBuffer
);
156 if (EFI_ERROR(Status
) || (PartitionHandleCount
== 0)) {
160 // Check if one of the handles matches the Hard Disk Description
161 for (Index
= 0; Index
< PartitionHandleCount
; Index
++) {
162 Status
= gBS
->HandleProtocol (PartitionBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &PartitionDevicePath
);
163 if (!EFI_ERROR(Status
)) {
164 TmpDevicePath
= PartitionDevicePath
;
165 while (!IsDevicePathEnd (TmpDevicePath
)) {
166 // Check if the Device Path node is a HD Removable device Path node
167 if (BdsIsRemovableHd (TmpDevicePath
)) {
168 HardDriveDevicePath1
= (HARDDRIVE_DEVICE_PATH
*)RemovableDevicePath
;
169 HardDriveDevicePath2
= (HARDDRIVE_DEVICE_PATH
*)TmpDevicePath
;
170 if ((HardDriveDevicePath1
->SignatureType
== HardDriveDevicePath2
->SignatureType
) &&
171 (CompareGuid ((EFI_GUID
*)HardDriveDevicePath1
->Signature
,(EFI_GUID
*)HardDriveDevicePath2
->Signature
) == TRUE
) &&
172 (HardDriveDevicePath1
->PartitionNumber
== HardDriveDevicePath2
->PartitionNumber
))
174 *DeviceHandle
= PartitionBuffer
[Index
];
175 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
176 *NewDevicePath
= AppendDevicePath (PartitionDevicePath
, NextDevicePathNode(RemovableDevicePath
));
180 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
186 return EFI_NOT_FOUND
;
190 BdsIsRemovableCdrom (
191 IN EFI_DEVICE_PATH* DevicePath
194 return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
199 IN EFI_DEVICE_PATH* RemovableDevicePath,
200 OUT EFI_HANDLE* DeviceHandle,
201 OUT EFI_DEVICE_PATH** DevicePath
205 return EFI_UNSUPPORTED;
209 (*BDS_IS_REMOVABLE
) (
210 IN EFI_DEVICE_PATH
* DevicePath
215 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
216 OUT EFI_HANDLE
* DeviceHandle
,
217 OUT EFI_DEVICE_PATH
** DevicePath
221 BDS_IS_REMOVABLE IsRemovable
;
222 BDS_GET_DEVICE GetDevice
;
223 } BDS_REMOVABLE_DEVICE_SUPPORT
;
225 BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport
[] = {
226 { BdsIsRemovableUsb
, BdsGetDeviceUsb
},
227 { BdsIsRemovableHd
, BdsGetDeviceHd
},
228 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
234 IN EFI_DEVICE_PATH
* DevicePath
238 EFI_DEVICE_PATH
* TmpDevicePath
;
240 TmpDevicePath
= DevicePath
;
241 while (!IsDevicePathEnd (TmpDevicePath
)) {
242 for (Index
= 0; Index
< sizeof(RemovableDeviceSupport
) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
243 if (RemovableDeviceSupport
[Index
].IsRemovable(TmpDevicePath
)) {
247 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
256 IN EFI_DEVICE_PATH
* DevicePath
,
257 OUT EFI_HANDLE
* DeviceHandle
,
258 OUT EFI_DEVICE_PATH
** NewDevicePath
263 EFI_DEVICE_PATH
* TmpDevicePath
;
264 BDS_REMOVABLE_DEVICE_SUPPORT
* RemovableDevice
;
265 EFI_DEVICE_PATH
* RemovableDevicePath
;
266 BOOLEAN RemovableFound
;
268 RemovableDevice
= NULL
;
269 RemovableDevicePath
= NULL
;
270 RemovableFound
= FALSE
;
271 TmpDevicePath
= DevicePath
;
273 while (!IsDevicePathEnd (TmpDevicePath
) && !RemovableFound
) {
274 for (Index
= 0; Index
< sizeof(RemovableDeviceSupport
) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
275 RemovableDevice
= &RemovableDeviceSupport
[Index
];
276 if (RemovableDevice
->IsRemovable(TmpDevicePath
)) {
277 RemovableDevicePath
= TmpDevicePath
;
278 RemovableFound
= TRUE
;
282 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
285 if (!RemovableFound
) {
286 return EFI_NOT_FOUND
;
289 // Search into the current started drivers
290 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
291 if (Status
== EFI_NOT_FOUND
) {
292 // Connect all the drivers
293 BdsConnectAllDrivers ();
295 // Search again into all the drivers
296 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
303 Connect a Device Path and return the handle of the driver that support this DevicePath
305 @param DevicePath Device Path of the File to connect
306 @param Handle Handle of the driver that support this DevicePath
307 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
309 @retval EFI_SUCCESS A driver that matches the Device Path has been found
310 @retval EFI_NOT_FOUND No handles match the search.
311 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
315 BdsConnectDevicePath (
316 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
317 OUT EFI_HANDLE
*Handle
,
318 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
321 EFI_DEVICE_PATH
* Remaining
;
322 EFI_DEVICE_PATH
* NewDevicePath
;
325 if ((DevicePath
== NULL
) || (Handle
== NULL
)) {
326 return EFI_INVALID_PARAMETER
;
330 Remaining
= DevicePath
;
331 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
332 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
333 // to point to the remaining part of the device path
334 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
335 if (!EFI_ERROR (Status
)) {
336 // Recursive = FALSE: We do not want to start all the device tree
337 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
340 /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling
341 // NextDevicePathNode() will return an undetermined Device Path Node
342 if (!IsDevicePathEnd (RemainingDevicePath)) {
343 RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
345 } while (!EFI_ERROR (Status
) && !IsDevicePathEnd (Remaining
));
347 if (!EFI_ERROR (Status
)) {
348 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
349 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
350 Remaining
= DevicePath
;
351 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
,&Remaining
,Handle
);
352 if (!EFI_ERROR (Status
)) {
353 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
354 if (EFI_ERROR (Status
)) {
355 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
356 if ((Remaining
->Type
== HARDWARE_DEVICE_PATH
) && (Remaining
->SubType
== HW_MEMMAP_DP
)) {
357 Status
= EFI_SUCCESS
;
361 } else if (!IsDevicePathEnd (Remaining
) && !IsRemovableDevice (Remaining
)) {
363 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
364 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
365 Status = EFI_SUCCESS;
366 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
367 Status = EFI_SUCCESS;
370 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
371 Status
= EFI_SUCCESS
;
373 Status
= TryRemovableDevice (DevicePath
, Handle
, &NewDevicePath
);
374 if (!EFI_ERROR (Status
)) {
375 return BdsConnectDevicePath (NewDevicePath
, Handle
, RemainingDevicePath
);
379 if (RemainingDevicePath
) {
380 *RemainingDevicePath
= Remaining
;
387 BdsFileSystemSupport (
388 IN EFI_DEVICE_PATH
*DevicePath
,
389 IN EFI_HANDLE Handle
,
390 IN EFI_DEVICE_PATH
*RemainingDevicePath
394 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
396 Status
= gBS
->HandleProtocol (Handle
,&gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
398 return (!EFI_ERROR(Status
) && IS_DEVICE_PATH_NODE(RemainingDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
));
402 BdsFileSystemLoadImage (
403 IN EFI_DEVICE_PATH
*DevicePath
,
404 IN EFI_HANDLE Handle
,
405 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
406 IN EFI_ALLOCATE_TYPE Type
,
407 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
411 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
412 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
413 EFI_FILE_PROTOCOL
*Fs
;
415 EFI_FILE_INFO
*FileInfo
;
416 EFI_FILE_PROTOCOL
*File
;
419 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
));
421 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)RemainingDevicePath
;
423 Status
= gBS
->HandleProtocol(Handle
,&gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
424 if (EFI_ERROR(Status
)) {
428 // Try to Open the volume and get root directory
429 Status
= FsProtocol
->OpenVolume (FsProtocol
, &Fs
);
430 if (EFI_ERROR(Status
)) {
435 Status
= Fs
->Open(Fs
, &File
, FilePathDevicePath
->PathName
, EFI_FILE_MODE_READ
, 0);
436 if (EFI_ERROR(Status
)) {
441 File
->GetInfo(File
, &gEfiFileInfoGuid
, &Size
, NULL
);
442 FileInfo
= AllocatePool (Size
);
443 Status
= File
->GetInfo(File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
444 if (EFI_ERROR(Status
)) {
449 Size
= FileInfo
->FileSize
;
455 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
456 // Try to allocate in any pages if failed to allocate memory at the defined location
457 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
458 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
460 if (!EFI_ERROR(Status
)) {
461 Status
= File
->Read (File
, &Size
, (VOID
*)(UINTN
)(*Image
));
468 BdsMemoryMapSupport (
469 IN EFI_DEVICE_PATH
*DevicePath
,
470 IN EFI_HANDLE Handle
,
471 IN EFI_DEVICE_PATH
*RemainingDevicePath
474 return IS_DEVICE_PATH_NODE(DevicePath
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
) ||
475 IS_DEVICE_PATH_NODE(RemainingDevicePath
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
);
479 BdsMemoryMapLoadImage (
480 IN EFI_DEVICE_PATH
*DevicePath
,
481 IN EFI_HANDLE Handle
,
482 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
483 IN EFI_ALLOCATE_TYPE Type
,
484 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
489 MEMMAP_DEVICE_PATH
* MemMapPathDevicePath
;
492 if (IS_DEVICE_PATH_NODE(RemainingDevicePath
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
)) {
493 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)RemainingDevicePath
;
495 ASSERT (IS_DEVICE_PATH_NODE(DevicePath
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
));
496 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)DevicePath
;
499 Size
= MemMapPathDevicePath
->EndingAddress
- MemMapPathDevicePath
->StartingAddress
;
501 return EFI_INVALID_PARAMETER
;
504 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
505 // Try to allocate in any pages if failed to allocate memory at the defined location
506 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
507 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
509 if (!EFI_ERROR(Status
)) {
510 CopyMem ((VOID
*)(UINTN
)(*Image
), (CONST VOID
*)(UINTN
)MemMapPathDevicePath
->StartingAddress
, Size
);
512 if (ImageSize
!= NULL
) {
521 BdsFirmwareVolumeSupport (
522 IN EFI_DEVICE_PATH
*DevicePath
,
523 IN EFI_HANDLE Handle
,
524 IN EFI_DEVICE_PATH
*RemainingDevicePath
527 return IS_DEVICE_PATH_NODE(RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
);
531 BdsFirmwareVolumeLoadImage (
532 IN EFI_DEVICE_PATH
*DevicePath
,
533 IN EFI_HANDLE Handle
,
534 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
535 IN EFI_ALLOCATE_TYPE Type
,
536 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
541 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVol
;
542 EFI_GUID
*FvNameGuid
;
543 EFI_SECTION_TYPE SectionType
;
544 EFI_FV_FILETYPE FvType
;
545 EFI_FV_FILE_ATTRIBUTES Attrib
;
546 UINT32 AuthenticationStatus
;
549 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
));
551 Status
= gBS
->HandleProtocol(Handle
,&gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&FwVol
);
552 if (EFI_ERROR(Status
)) {
556 FvNameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)RemainingDevicePath
);
557 if (FvNameGuid
== NULL
) {
558 Status
= EFI_INVALID_PARAMETER
;
561 SectionType
= EFI_SECTION_PE32
;
562 AuthenticationStatus
= 0;
563 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
565 Status
= FwVol
->ReadSection (
572 &AuthenticationStatus
574 if (!EFI_ERROR (Status
)) {
576 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
577 if (Type
!= AllocateAnyPages
) {
578 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
),Image
);
579 if (!EFI_ERROR(Status
)) {
580 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
581 FreePool (ImageBuffer
);
585 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
586 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
587 // Try to allocate in any pages if failed to allocate memory at the defined location
588 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
589 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
591 if (!EFI_ERROR(Status
)) {
592 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
593 FreePool (ImageBuffer
);
597 // Try a raw file, since a PE32 SECTION does not exist
598 Status
= FwVol
->ReadFile (
605 &AuthenticationStatus
607 if (!EFI_ERROR(Status
)) {
608 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
609 // Try to allocate in any pages if failed to allocate memory at the defined location
610 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
611 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
613 if (!EFI_ERROR(Status
)) {
614 Status
= FwVol
->ReadFile (
617 (VOID
*)(UINTN
)(*Image
),
621 &AuthenticationStatus
631 IN EFI_DEVICE_PATH
* DevicePath
,
632 IN EFI_HANDLE Handle
,
633 IN EFI_DEVICE_PATH
* RemainingDevicePath
637 EFI_PXE_BASE_CODE_PROTOCOL
* PxeBcProtocol
;
639 if (!IsDevicePathEnd(RemainingDevicePath
)) {
643 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
644 if (EFI_ERROR (Status
)) {
653 IN EFI_DEVICE_PATH
* DevicePath
,
654 IN EFI_HANDLE Handle
,
655 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
656 IN EFI_ALLOCATE_TYPE Type
,
657 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
662 EFI_LOAD_FILE_PROTOCOL
*LoadFileProtocol
;
665 // Get Load File Protocol attached to the PXE protocol
666 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFileProtocol
);
667 if (EFI_ERROR (Status
)) {
671 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, NULL
);
672 if (Status
== EFI_BUFFER_TOO_SMALL
) {
673 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(BufferSize
), Image
);
674 if (EFI_ERROR(Status
)) {
678 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, (VOID
*)(UINTN
)(*Image
));
679 if (!EFI_ERROR(Status
) && (ImageSize
!= NULL
)) {
680 *ImageSize
= BufferSize
;
689 IN EFI_DEVICE_PATH
* DevicePath
,
690 IN EFI_HANDLE Handle
,
691 IN EFI_DEVICE_PATH
* RemainingDevicePath
695 EFI_DEVICE_PATH
*NextDevicePath
;
696 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
698 // Validate the Remaining Device Path
699 if (IsDevicePathEnd(RemainingDevicePath
)) {
702 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
) &&
703 !IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv6_DP
)) {
706 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
707 if (IsDevicePathEnd(NextDevicePath
)) {
710 if (!IS_DEVICE_PATH_NODE(NextDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
)) {
714 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
715 if (EFI_ERROR (Status
)) {
724 IN EFI_DEVICE_PATH
* DevicePath
,
725 IN EFI_HANDLE Handle
,
726 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
727 IN EFI_ALLOCATE_TYPE Type
,
728 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
733 EFI_PXE_BASE_CODE_PROTOCOL
*Pxe
;
734 UINT64 TftpBufferSize
;
736 EFI_IP_ADDRESS ServerIp
;
737 IPv4_DEVICE_PATH
* IPv4DevicePathNode
;
738 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
739 EFI_IP_ADDRESS LocalIp
;
741 ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
));
743 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)RemainingDevicePath
;
744 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
746 Status
= gBS
->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid
, NULL
, (VOID
**)&Pxe
);
747 if (EFI_ERROR(Status
)) {
751 Status
= Pxe
->Start (Pxe
, FALSE
);
752 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
756 if (!IPv4DevicePathNode
->StaticIpAddress
) {
757 Status
= Pxe
->Dhcp(Pxe
, TRUE
);
759 CopyMem (&LocalIp
.v4
, &IPv4DevicePathNode
->LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
760 Status
= Pxe
->SetStationIp (Pxe
, &LocalIp
, NULL
);
762 if (EFI_ERROR(Status
)) {
766 CopyMem (&ServerIp
.v4
, &IPv4DevicePathNode
->RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
768 Status
= Pxe
->Mtftp (
770 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
776 (UINT8
*)FilePathDevicePath
->PathName
,
780 if (EFI_ERROR(Status
)) {
784 // Allocate a buffer to hold the whole file.
785 TftpBuffer
= AllocatePool(TftpBufferSize
);
786 if (TftpBuffer
== NULL
) {
787 return EFI_OUT_OF_RESOURCES
;
790 Status
= Pxe
->Mtftp (
792 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
798 (UINT8
*)FilePathDevicePath
->PathName
,
802 if (EFI_ERROR(Status
)) {
803 FreePool(TftpBuffer
);
804 } else if (ImageSize
!= NULL
) {
805 *ImageSize
= (UINTN
)TftpBufferSize
;
811 BDS_FILE_LOADER FileLoaders
[] = {
812 { BdsFileSystemSupport
, BdsFileSystemLoadImage
},
813 { BdsFirmwareVolumeSupport
, BdsFirmwareVolumeLoadImage
},
814 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
815 { BdsMemoryMapSupport
, BdsMemoryMapLoadImage
},
816 { BdsPxeSupport
, BdsPxeLoadImage
},
817 { BdsTftpSupport
, BdsTftpLoadImage
},
823 IN EFI_DEVICE_PATH
*DevicePath
,
824 IN EFI_ALLOCATE_TYPE Type
,
825 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
831 EFI_DEVICE_PATH
*RemainingDevicePath
;
832 BDS_FILE_LOADER
* FileLoader
;
834 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
835 if (EFI_ERROR (Status
)) {
839 FileLoader
= FileLoaders
;
840 while (FileLoader
->Support
!= NULL
) {
841 if (FileLoader
->Support (DevicePath
, Handle
, RemainingDevicePath
)) {
842 return FileLoader
->LoadImage (DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, FileSize
);
847 return EFI_UNSUPPORTED
;
851 Start an EFI Application from a Device Path
853 @param ParentImageHandle Handle of the calling image
854 @param DevicePath Location of the EFI Application
856 @retval EFI_SUCCESS All drivers have been connected
857 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
858 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
862 BdsStartEfiApplication (
863 IN EFI_HANDLE ParentImageHandle
,
864 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
865 IN UINTN LoadOptionsSize
,
870 EFI_HANDLE ImageHandle
;
871 EFI_PHYSICAL_ADDRESS BinaryBuffer
;
873 EFI_LOADED_IMAGE_PROTOCOL
* LoadedImage
;
875 // Find the nearest supported file loader
876 Status
= BdsLoadImage (DevicePath
, AllocateAnyPages
, &BinaryBuffer
, &BinarySize
);
877 if (EFI_ERROR(Status
)) {
881 // Load the image from the Buffer with Boot Services function
882 Status
= gBS
->LoadImage (TRUE
, ParentImageHandle
, DevicePath
, (VOID
*)(UINTN
)BinaryBuffer
, BinarySize
, &ImageHandle
);
883 if (EFI_ERROR(Status
)) {
887 // Passed LoadOptions to the EFI Application
888 if (LoadOptionsSize
!= 0) {
889 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &LoadedImage
);
890 if (EFI_ERROR(Status
)) {
894 LoadedImage
->LoadOptionsSize
= LoadOptionsSize
;
895 LoadedImage
->LoadOptions
= LoadOptions
;
898 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
899 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
901 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
902 // Clear the Watchdog Timer after the image returns
903 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);