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(RemainingDevicePath
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
);
478 BdsMemoryMapLoadImage (
479 IN EFI_DEVICE_PATH
*DevicePath
,
480 IN EFI_HANDLE Handle
,
481 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
482 IN EFI_ALLOCATE_TYPE Type
,
483 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
488 MEMMAP_DEVICE_PATH
* MemMapPathDevicePath
;
491 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
));
493 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)RemainingDevicePath
;
495 Size
= MemMapPathDevicePath
->EndingAddress
- MemMapPathDevicePath
->StartingAddress
;
497 return EFI_INVALID_PARAMETER
;
500 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
501 // Try to allocate in any pages if failed to allocate memory at the defined location
502 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
503 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
505 if (!EFI_ERROR(Status
)) {
506 CopyMem ((VOID
*)(UINTN
)(*Image
), (CONST VOID
*)(UINTN
)MemMapPathDevicePath
->StartingAddress
, Size
);
508 if (ImageSize
!= NULL
) {
517 BdsFirmwareVolumeSupport (
518 IN EFI_DEVICE_PATH
*DevicePath
,
519 IN EFI_HANDLE Handle
,
520 IN EFI_DEVICE_PATH
*RemainingDevicePath
523 return IS_DEVICE_PATH_NODE(RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
);
527 BdsFirmwareVolumeLoadImage (
528 IN EFI_DEVICE_PATH
*DevicePath
,
529 IN EFI_HANDLE Handle
,
530 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
531 IN EFI_ALLOCATE_TYPE Type
,
532 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
537 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVol
;
538 EFI_GUID
*FvNameGuid
;
539 EFI_SECTION_TYPE SectionType
;
540 EFI_FV_FILETYPE FvType
;
541 EFI_FV_FILE_ATTRIBUTES Attrib
;
542 UINT32 AuthenticationStatus
;
545 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
));
547 Status
= gBS
->HandleProtocol(Handle
,&gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&FwVol
);
548 if (EFI_ERROR(Status
)) {
552 FvNameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)RemainingDevicePath
);
553 if (FvNameGuid
== NULL
) {
554 Status
= EFI_INVALID_PARAMETER
;
557 SectionType
= EFI_SECTION_PE32
;
558 AuthenticationStatus
= 0;
559 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
561 Status
= FwVol
->ReadSection (
568 &AuthenticationStatus
570 if (!EFI_ERROR (Status
)) {
572 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
573 if (Type
!= AllocateAnyPages
) {
574 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
),Image
);
575 if (!EFI_ERROR(Status
)) {
576 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
577 FreePool (ImageBuffer
);
581 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
582 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
583 // Try to allocate in any pages if failed to allocate memory at the defined location
584 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
585 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
587 if (!EFI_ERROR(Status
)) {
588 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
589 FreePool (ImageBuffer
);
593 // Try a raw file, since a PE32 SECTION does not exist
594 Status
= FwVol
->ReadFile (
601 &AuthenticationStatus
603 if (!EFI_ERROR(Status
)) {
604 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
605 // Try to allocate in any pages if failed to allocate memory at the defined location
606 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
607 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
609 if (!EFI_ERROR(Status
)) {
610 Status
= FwVol
->ReadFile (
613 (VOID
*)(UINTN
)(*Image
),
617 &AuthenticationStatus
627 IN EFI_DEVICE_PATH
* DevicePath
,
628 IN EFI_HANDLE Handle
,
629 IN EFI_DEVICE_PATH
* RemainingDevicePath
633 EFI_PXE_BASE_CODE_PROTOCOL
* PxeBcProtocol
;
635 if (!IsDevicePathEnd(RemainingDevicePath
)) {
639 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
640 if (EFI_ERROR (Status
)) {
649 IN EFI_DEVICE_PATH
* DevicePath
,
650 IN EFI_HANDLE Handle
,
651 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
652 IN EFI_ALLOCATE_TYPE Type
,
653 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
658 EFI_LOAD_FILE_PROTOCOL
*LoadFileProtocol
;
661 // Get Load File Protocol attached to the PXE protocol
662 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFileProtocol
);
663 if (EFI_ERROR (Status
)) {
667 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, NULL
);
668 if (Status
== EFI_BUFFER_TOO_SMALL
) {
669 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(BufferSize
), Image
);
670 if (EFI_ERROR(Status
)) {
674 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, (VOID
*)(UINTN
)(*Image
));
675 if (!EFI_ERROR(Status
) && (ImageSize
!= NULL
)) {
676 *ImageSize
= BufferSize
;
685 IN EFI_DEVICE_PATH
* DevicePath
,
686 IN EFI_HANDLE Handle
,
687 IN EFI_DEVICE_PATH
* RemainingDevicePath
691 EFI_DEVICE_PATH
*NextDevicePath
;
692 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
694 // Validate the Remaining Device Path
695 if (IsDevicePathEnd(RemainingDevicePath
)) {
698 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
) &&
699 !IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv6_DP
)) {
702 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
703 if (IsDevicePathEnd(NextDevicePath
)) {
706 if (!IS_DEVICE_PATH_NODE(NextDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
)) {
710 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
711 if (EFI_ERROR (Status
)) {
720 IN EFI_DEVICE_PATH
* DevicePath
,
721 IN EFI_HANDLE Handle
,
722 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
723 IN EFI_ALLOCATE_TYPE Type
,
724 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
729 EFI_PXE_BASE_CODE_PROTOCOL
*Pxe
;
730 UINT64 TftpBufferSize
;
732 EFI_IP_ADDRESS ServerIp
;
733 IPv4_DEVICE_PATH
* IPv4DevicePathNode
;
734 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
735 EFI_IP_ADDRESS LocalIp
;
737 ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
));
739 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)RemainingDevicePath
;
740 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
742 Status
= gBS
->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid
, NULL
, (VOID
**)&Pxe
);
743 if (EFI_ERROR(Status
)) {
747 Status
= Pxe
->Start (Pxe
, FALSE
);
748 if (EFI_ERROR(Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
752 if (!IPv4DevicePathNode
->StaticIpAddress
) {
753 Status
= Pxe
->Dhcp(Pxe
, TRUE
);
755 CopyMem (&LocalIp
.v4
, &IPv4DevicePathNode
->LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
756 Status
= Pxe
->SetStationIp (Pxe
, &LocalIp
, NULL
);
758 if (EFI_ERROR(Status
)) {
762 CopyMem (&ServerIp
.v4
, &IPv4DevicePathNode
->RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
764 Status
= Pxe
->Mtftp (
766 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
772 (UINT8
*)FilePathDevicePath
->PathName
,
776 if (EFI_ERROR(Status
)) {
780 // Allocate a buffer to hold the whole file.
781 TftpBuffer
= AllocatePool(TftpBufferSize
);
782 if (TftpBuffer
== NULL
) {
783 return EFI_OUT_OF_RESOURCES
;
786 Status
= Pxe
->Mtftp (
788 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
794 (UINT8
*)FilePathDevicePath
->PathName
,
798 if (EFI_ERROR(Status
)) {
799 FreePool(TftpBuffer
);
800 } else if (ImageSize
!= NULL
) {
801 *ImageSize
= (UINTN
)TftpBufferSize
;
807 BDS_FILE_LOADER FileLoaders
[] = {
808 { BdsFileSystemSupport
, BdsFileSystemLoadImage
},
809 { BdsFirmwareVolumeSupport
, BdsFirmwareVolumeLoadImage
},
810 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
811 { BdsMemoryMapSupport
, BdsMemoryMapLoadImage
},
812 { BdsPxeSupport
, BdsPxeLoadImage
},
813 { BdsTftpSupport
, BdsTftpLoadImage
},
819 IN EFI_DEVICE_PATH
*DevicePath
,
820 IN EFI_ALLOCATE_TYPE Type
,
821 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
827 EFI_DEVICE_PATH
*RemainingDevicePath
;
828 BDS_FILE_LOADER
* FileLoader
;
830 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
831 if (EFI_ERROR (Status
)) {
835 FileLoader
= FileLoaders
;
836 while (FileLoader
->Support
!= NULL
) {
837 if (FileLoader
->Support (DevicePath
, Handle
, RemainingDevicePath
)) {
838 return FileLoader
->LoadImage (DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, FileSize
);
843 return EFI_UNSUPPORTED
;
847 Start an EFI Application from a Device Path
849 @param ParentImageHandle Handle of the calling image
850 @param DevicePath Location of the EFI Application
852 @retval EFI_SUCCESS All drivers have been connected
853 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
854 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
858 BdsStartEfiApplication (
859 IN EFI_HANDLE ParentImageHandle
,
860 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
861 IN UINTN LoadOptionsSize
,
866 EFI_HANDLE ImageHandle
;
867 EFI_PHYSICAL_ADDRESS BinaryBuffer
;
869 EFI_LOADED_IMAGE_PROTOCOL
* LoadedImage
;
871 // Find the nearest supported file loader
872 Status
= BdsLoadImage (DevicePath
, AllocateAnyPages
, &BinaryBuffer
, &BinarySize
);
873 if (EFI_ERROR(Status
)) {
877 // Load the image from the Buffer with Boot Services function
878 Status
= gBS
->LoadImage (TRUE
, ParentImageHandle
, DevicePath
, (VOID
*)(UINTN
)BinaryBuffer
, BinarySize
, &ImageHandle
);
879 if (EFI_ERROR(Status
)) {
883 // Passed LoadOptions to the EFI Application
884 if (LoadOptionsSize
!= 0) {
885 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &LoadedImage
);
886 if (EFI_ERROR(Status
)) {
890 LoadedImage
->LoadOptionsSize
= LoadOptionsSize
;
891 LoadedImage
->LoadOptions
= LoadOptions
;
894 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
895 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
897 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
898 // Clear the Watchdog Timer after the image returns
899 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);