3 * Copyright (c) 2011-2014, 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>
20 #include <Protocol/SimpleNetwork.h>
22 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
24 // Extract the FilePath from the Device Path
26 BdsExtractFilePathFromDevicePath (
27 IN CONST CHAR16
*StrDevicePath
,
28 IN UINTN NumberDevicePathNode
34 Str
= (CHAR16
*)StrDevicePath
;
36 while ((Str
!= NULL
) && (*Str
!= L
'\0') && (Node
< NumberDevicePathNode
)) {
37 if ((*Str
== L
'/') || (*Str
== L
'\\')) {
52 IN EFI_DEVICE_PATH
* DevicePath
55 return ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
56 ((DevicePathSubType (DevicePath
) == MSG_USB_CLASS_DP
) ||
57 (DevicePathSubType (DevicePath
) == MSG_USB_WWID_DP
)));
62 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
63 OUT EFI_HANDLE
* DeviceHandle
,
64 OUT EFI_DEVICE_PATH
** NewDevicePath
69 UINTN UsbIoHandleCount
;
70 EFI_HANDLE
*UsbIoBuffer
;
71 EFI_DEVICE_PATH
* UsbIoDevicePath
;
72 EFI_DEVICE_PATH
* TmpDevicePath
;
73 USB_WWID_DEVICE_PATH
* WwidDevicePath1
;
74 USB_WWID_DEVICE_PATH
* WwidDevicePath2
;
75 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath1
;
76 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath2
;
78 // Get all the UsbIo handles
80 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiUsbIoProtocolGuid
, NULL
, &UsbIoHandleCount
, &UsbIoBuffer
);
81 if (EFI_ERROR (Status
) || (UsbIoHandleCount
== 0)) {
85 // Check if one of the handles matches the USB description
86 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
87 Status
= gBS
->HandleProtocol (UsbIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**) &UsbIoDevicePath
);
88 if (!EFI_ERROR (Status
)) {
89 TmpDevicePath
= UsbIoDevicePath
;
90 while (!IsDevicePathEnd (TmpDevicePath
)) {
91 // Check if the Device Path node is a USB Removable device Path node
92 if (BdsIsRemovableUsb (TmpDevicePath
)) {
93 if (TmpDevicePath
->SubType
== MSG_USB_WWID_DP
) {
94 WwidDevicePath1
= (USB_WWID_DEVICE_PATH
*)RemovableDevicePath
;
95 WwidDevicePath2
= (USB_WWID_DEVICE_PATH
*)TmpDevicePath
;
96 if ((WwidDevicePath1
->VendorId
== WwidDevicePath2
->VendorId
) &&
97 (WwidDevicePath1
->ProductId
== WwidDevicePath2
->ProductId
) &&
98 (CompareMem (WwidDevicePath1
+1, WwidDevicePath2
+1, DevicePathNodeLength(WwidDevicePath1
)-sizeof (USB_WWID_DEVICE_PATH
)) == 0))
100 *DeviceHandle
= UsbIoBuffer
[Index
];
101 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
102 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode (RemovableDevicePath
));
106 UsbClassDevicePath1
= (USB_CLASS_DEVICE_PATH
*)RemovableDevicePath
;
107 UsbClassDevicePath2
= (USB_CLASS_DEVICE_PATH
*)TmpDevicePath
;
108 if ((UsbClassDevicePath1
->VendorId
!= 0xFFFF) && (UsbClassDevicePath1
->VendorId
== UsbClassDevicePath2
->VendorId
) &&
109 (UsbClassDevicePath1
->ProductId
!= 0xFFFF) && (UsbClassDevicePath1
->ProductId
== UsbClassDevicePath2
->ProductId
) &&
110 (UsbClassDevicePath1
->DeviceClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceClass
== UsbClassDevicePath2
->DeviceClass
) &&
111 (UsbClassDevicePath1
->DeviceSubClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceSubClass
== UsbClassDevicePath2
->DeviceSubClass
) &&
112 (UsbClassDevicePath1
->DeviceProtocol
!= 0xFF) && (UsbClassDevicePath1
->DeviceProtocol
== UsbClassDevicePath2
->DeviceProtocol
))
114 *DeviceHandle
= UsbIoBuffer
[Index
];
115 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
116 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode (RemovableDevicePath
));
121 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
127 return EFI_NOT_FOUND
;
132 IN EFI_DEVICE_PATH
* DevicePath
135 return IS_DEVICE_PATH_NODE (DevicePath
, MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
);
140 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
141 OUT EFI_HANDLE
* DeviceHandle
,
142 OUT EFI_DEVICE_PATH
** NewDevicePath
147 UINTN PartitionHandleCount
;
148 EFI_HANDLE
*PartitionBuffer
;
149 EFI_DEVICE_PATH
* PartitionDevicePath
;
150 EFI_DEVICE_PATH
* TmpDevicePath
;
151 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath1
;
152 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath2
;
154 // Get all the DiskIo handles
155 PartitionHandleCount
= 0;
156 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDiskIoProtocolGuid
, NULL
, &PartitionHandleCount
, &PartitionBuffer
);
157 if (EFI_ERROR (Status
) || (PartitionHandleCount
== 0)) {
161 // Check if one of the handles matches the Hard Disk Description
162 for (Index
= 0; Index
< PartitionHandleCount
; Index
++) {
163 Status
= gBS
->HandleProtocol (PartitionBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**) &PartitionDevicePath
);
164 if (!EFI_ERROR (Status
)) {
165 TmpDevicePath
= PartitionDevicePath
;
166 while (!IsDevicePathEnd (TmpDevicePath
)) {
167 // Check if the Device Path node is a HD Removable device Path node
168 if (BdsIsRemovableHd (TmpDevicePath
)) {
169 HardDriveDevicePath1
= (HARDDRIVE_DEVICE_PATH
*)RemovableDevicePath
;
170 HardDriveDevicePath2
= (HARDDRIVE_DEVICE_PATH
*)TmpDevicePath
;
171 if ((HardDriveDevicePath1
->SignatureType
== HardDriveDevicePath2
->SignatureType
) &&
172 (CompareGuid ((EFI_GUID
*)HardDriveDevicePath1
->Signature
, (EFI_GUID
*)HardDriveDevicePath2
->Signature
) == TRUE
) &&
173 (HardDriveDevicePath1
->PartitionNumber
== HardDriveDevicePath2
->PartitionNumber
))
175 *DeviceHandle
= PartitionBuffer
[Index
];
176 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
177 *NewDevicePath
= AppendDevicePath (PartitionDevicePath
, NextDevicePathNode (RemovableDevicePath
));
181 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
187 return EFI_NOT_FOUND
;
191 BdsIsRemovableCdrom (
192 IN EFI_DEVICE_PATH* DevicePath
195 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
200 IN EFI_DEVICE_PATH* RemovableDevicePath,
201 OUT EFI_HANDLE* DeviceHandle,
202 OUT EFI_DEVICE_PATH** DevicePath
206 return EFI_UNSUPPORTED;
210 (*BDS_IS_REMOVABLE
) (
211 IN EFI_DEVICE_PATH
* DevicePath
216 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
217 OUT EFI_HANDLE
* DeviceHandle
,
218 OUT EFI_DEVICE_PATH
** DevicePath
222 BDS_IS_REMOVABLE IsRemovable
;
223 BDS_GET_DEVICE GetDevice
;
224 } BDS_REMOVABLE_DEVICE_SUPPORT
;
226 BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport
[] = {
227 { BdsIsRemovableUsb
, BdsGetDeviceUsb
},
228 { BdsIsRemovableHd
, BdsGetDeviceHd
},
229 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
235 IN EFI_DEVICE_PATH
* DevicePath
239 EFI_DEVICE_PATH
* TmpDevicePath
;
241 TmpDevicePath
= DevicePath
;
242 while (!IsDevicePathEnd (TmpDevicePath
)) {
243 for (Index
= 0; Index
< sizeof (RemovableDeviceSupport
) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
244 if (RemovableDeviceSupport
[Index
].IsRemovable (TmpDevicePath
)) {
248 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
257 IN EFI_DEVICE_PATH
* DevicePath
,
258 OUT EFI_HANDLE
* DeviceHandle
,
259 OUT EFI_DEVICE_PATH
** NewDevicePath
264 EFI_DEVICE_PATH
* TmpDevicePath
;
265 BDS_REMOVABLE_DEVICE_SUPPORT
* RemovableDevice
;
266 EFI_DEVICE_PATH
* RemovableDevicePath
;
267 BOOLEAN RemovableFound
;
269 RemovableDevice
= NULL
;
270 RemovableDevicePath
= NULL
;
271 RemovableFound
= FALSE
;
272 TmpDevicePath
= DevicePath
;
274 while (!IsDevicePathEnd (TmpDevicePath
) && !RemovableFound
) {
275 for (Index
= 0; Index
< sizeof (RemovableDeviceSupport
) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
276 RemovableDevice
= &RemovableDeviceSupport
[Index
];
277 if (RemovableDevice
->IsRemovable (TmpDevicePath
)) {
278 RemovableDevicePath
= TmpDevicePath
;
279 RemovableFound
= TRUE
;
283 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
286 if (!RemovableFound
) {
287 return EFI_NOT_FOUND
;
290 // Search into the current started drivers
291 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
292 if (Status
== EFI_NOT_FOUND
) {
293 // Connect all the drivers
294 BdsConnectAllDrivers ();
296 // Search again into all the drivers
297 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
305 BdsConnectAndUpdateDevicePath (
306 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
,
307 OUT EFI_HANDLE
*Handle
,
308 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
311 EFI_DEVICE_PATH
* Remaining
;
312 EFI_DEVICE_PATH
* NewDevicePath
;
314 EFI_HANDLE PreviousHandle
;
316 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
) || (Handle
== NULL
)) {
317 return EFI_INVALID_PARAMETER
;
320 PreviousHandle
= NULL
;
322 Remaining
= *DevicePath
;
324 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
325 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
326 // to point to the remaining part of the device path
327 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
329 if (!EFI_ERROR (Status
)) {
330 if (*Handle
== PreviousHandle
) {
332 // If no forward progress is made try invoking the Dispatcher.
333 // A new FV may have been added to the system and new drivers
335 // Status == EFI_SUCCESS means a driver was dispatched
336 // Status == EFI_NOT_FOUND means no new drivers were dispatched
338 Status
= gDS
->Dispatch ();
341 if (!EFI_ERROR (Status
)) {
342 PreviousHandle
= *Handle
;
344 // Recursive = FALSE: We do not want to start the whole device tree
345 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
348 } while (!EFI_ERROR (Status
) && !IsDevicePathEnd (Remaining
));
350 if (!EFI_ERROR (Status
)) {
351 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
352 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
353 Remaining
= *DevicePath
;
354 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
355 if (!EFI_ERROR (Status
)) {
356 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
357 if (EFI_ERROR (Status
)) {
358 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
359 if ((Remaining
->Type
== HARDWARE_DEVICE_PATH
) && (Remaining
->SubType
== HW_MEMMAP_DP
)) {
360 Status
= EFI_SUCCESS
;
364 } else if (!IsDevicePathEnd (Remaining
) && !IsRemovableDevice (Remaining
)) {
366 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
367 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
368 Status = EFI_SUCCESS;
369 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
370 Status = EFI_SUCCESS;
373 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
374 Status
= EFI_SUCCESS
;
376 Status
= TryRemovableDevice (*DevicePath
, Handle
, &NewDevicePath
);
377 if (!EFI_ERROR (Status
)) {
378 Status
= BdsConnectAndUpdateDevicePath (&NewDevicePath
, Handle
, RemainingDevicePath
);
379 *DevicePath
= NewDevicePath
;
384 if (RemainingDevicePath
) {
385 *RemainingDevicePath
= Remaining
;
392 Connect a Device Path and return the handle of the driver that support this DevicePath
394 @param DevicePath Device Path of the File to connect
395 @param Handle Handle of the driver that support this DevicePath
396 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
398 @retval EFI_SUCCESS A driver that matches the Device Path has been found
399 @retval EFI_NOT_FOUND No handles match the search.
400 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
404 BdsConnectDevicePath (
405 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
406 OUT EFI_HANDLE
*Handle
,
407 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
410 return BdsConnectAndUpdateDevicePath (&DevicePath
, Handle
, RemainingDevicePath
);
414 BdsFileSystemSupport (
415 IN EFI_DEVICE_PATH
*DevicePath
,
416 IN EFI_HANDLE Handle
,
417 IN EFI_DEVICE_PATH
*RemainingDevicePath
421 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
423 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
425 return (!EFI_ERROR (Status
) && IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
));
429 BdsFileSystemLoadImage (
430 IN EFI_DEVICE_PATH
*DevicePath
,
431 IN EFI_HANDLE Handle
,
432 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
433 IN EFI_ALLOCATE_TYPE Type
,
434 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
438 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
439 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
440 EFI_FILE_PROTOCOL
*Fs
;
442 EFI_FILE_INFO
*FileInfo
;
443 EFI_FILE_PROTOCOL
*File
;
446 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
));
448 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)RemainingDevicePath
;
450 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
451 if (EFI_ERROR (Status
)) {
455 // Try to Open the volume and get root directory
456 Status
= FsProtocol
->OpenVolume (FsProtocol
, &Fs
);
457 if (EFI_ERROR (Status
)) {
462 Status
= Fs
->Open (Fs
, &File
, FilePathDevicePath
->PathName
, EFI_FILE_MODE_READ
, 0);
463 if (EFI_ERROR (Status
)) {
468 File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, NULL
);
469 FileInfo
= AllocatePool (Size
);
470 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
471 if (EFI_ERROR (Status
)) {
476 Size
= FileInfo
->FileSize
;
482 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
483 // Try to allocate in any pages if failed to allocate memory at the defined location
484 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
485 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
487 if (!EFI_ERROR (Status
)) {
488 Status
= File
->Read (File
, &Size
, (VOID
*)(UINTN
)(*Image
));
495 BdsMemoryMapSupport (
496 IN EFI_DEVICE_PATH
*DevicePath
,
497 IN EFI_HANDLE Handle
,
498 IN EFI_DEVICE_PATH
*RemainingDevicePath
501 return IS_DEVICE_PATH_NODE (DevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
) ||
502 IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
);
506 BdsMemoryMapLoadImage (
507 IN EFI_DEVICE_PATH
*DevicePath
,
508 IN EFI_HANDLE Handle
,
509 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
510 IN EFI_ALLOCATE_TYPE Type
,
511 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
516 MEMMAP_DEVICE_PATH
* MemMapPathDevicePath
;
519 if (IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
)) {
520 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)RemainingDevicePath
;
522 ASSERT (IS_DEVICE_PATH_NODE (DevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
));
523 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)DevicePath
;
526 Size
= MemMapPathDevicePath
->EndingAddress
- MemMapPathDevicePath
->StartingAddress
;
528 return EFI_INVALID_PARAMETER
;
531 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
532 // Try to allocate in any pages if failed to allocate memory at the defined location
533 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
534 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
536 if (!EFI_ERROR (Status
)) {
537 CopyMem ((VOID
*)(UINTN
)(*Image
), (CONST VOID
*)(UINTN
)MemMapPathDevicePath
->StartingAddress
, Size
);
539 if (ImageSize
!= NULL
) {
548 BdsFirmwareVolumeSupport (
549 IN EFI_DEVICE_PATH
*DevicePath
,
550 IN EFI_HANDLE Handle
,
551 IN EFI_DEVICE_PATH
*RemainingDevicePath
554 return IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
);
558 BdsFirmwareVolumeLoadImage (
559 IN EFI_DEVICE_PATH
*DevicePath
,
560 IN EFI_HANDLE Handle
,
561 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
562 IN EFI_ALLOCATE_TYPE Type
,
563 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
568 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVol
;
569 EFI_GUID
*FvNameGuid
;
570 EFI_SECTION_TYPE SectionType
;
571 EFI_FV_FILETYPE FvType
;
572 EFI_FV_FILE_ATTRIBUTES Attrib
;
573 UINT32 AuthenticationStatus
;
576 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
));
578 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&FwVol
);
579 if (EFI_ERROR (Status
)) {
583 FvNameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)RemainingDevicePath
);
584 if (FvNameGuid
== NULL
) {
585 Status
= EFI_INVALID_PARAMETER
;
588 SectionType
= EFI_SECTION_PE32
;
589 AuthenticationStatus
= 0;
590 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
592 Status
= FwVol
->ReadSection (
599 &AuthenticationStatus
601 if (!EFI_ERROR (Status
)) {
603 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
604 if (Type
!= AllocateAnyPages
) {
605 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
),Image
);
606 if (!EFI_ERROR (Status
)) {
607 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
608 FreePool (ImageBuffer
);
612 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
613 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
614 // Try to allocate in any pages if failed to allocate memory at the defined location
615 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
616 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
618 if (!EFI_ERROR (Status
)) {
619 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
620 FreePool (ImageBuffer
);
624 // Try a raw file, since a PE32 SECTION does not exist
625 Status
= FwVol
->ReadFile (
632 &AuthenticationStatus
634 if (!EFI_ERROR (Status
)) {
635 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
636 // Try to allocate in any pages if failed to allocate memory at the defined location
637 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
638 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
640 if (!EFI_ERROR (Status
)) {
641 Status
= FwVol
->ReadFile (
644 (VOID
*)(UINTN
)(*Image
),
648 &AuthenticationStatus
658 IN EFI_DEVICE_PATH
* DevicePath
,
659 IN EFI_HANDLE Handle
,
660 IN EFI_DEVICE_PATH
* RemainingDevicePath
664 EFI_PXE_BASE_CODE_PROTOCOL
* PxeBcProtocol
;
666 if (!IsDevicePathEnd (RemainingDevicePath
)) {
670 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
671 if (EFI_ERROR (Status
)) {
680 IN EFI_DEVICE_PATH
* DevicePath
,
681 IN EFI_HANDLE Handle
,
682 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
683 IN EFI_ALLOCATE_TYPE Type
,
684 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
689 EFI_LOAD_FILE_PROTOCOL
*LoadFileProtocol
;
691 EFI_PXE_BASE_CODE_PROTOCOL
*Pxe
;
693 // Get Load File Protocol attached to the PXE protocol
694 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFileProtocol
);
695 if (EFI_ERROR (Status
)) {
699 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, NULL
);
700 if (Status
== EFI_BUFFER_TOO_SMALL
) {
701 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(BufferSize
), Image
);
702 if (EFI_ERROR (Status
)) {
706 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, (VOID
*)(UINTN
)(*Image
));
707 if (!EFI_ERROR (Status
) && (ImageSize
!= NULL
)) {
708 *ImageSize
= BufferSize
;
712 if (Status
== EFI_ALREADY_STARTED
) {
713 Status
= gBS
->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid
, NULL
, (VOID
**)&Pxe
);
714 if (!EFI_ERROR(Status
)) {
715 // If PXE is already started, we stop it
718 return BdsPxeLoadImage (DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, ImageSize
);
726 IN EFI_DEVICE_PATH
* DevicePath
,
727 IN EFI_HANDLE Handle
,
728 IN EFI_DEVICE_PATH
* RemainingDevicePath
732 EFI_DEVICE_PATH
*NextDevicePath
;
733 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
735 // Validate the Remaining Device Path
736 if (IsDevicePathEnd (RemainingDevicePath
)) {
739 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
) &&
740 !IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv6_DP
)) {
743 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
744 if (IsDevicePathEnd (NextDevicePath
)) {
747 if (!IS_DEVICE_PATH_NODE (NextDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
)) {
751 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
752 if (EFI_ERROR (Status
)) {
761 IN EFI_DEVICE_PATH
* DevicePath
,
762 IN EFI_HANDLE Handle
,
763 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
764 IN EFI_ALLOCATE_TYPE Type
,
765 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
770 EFI_PXE_BASE_CODE_PROTOCOL
*Pxe
;
771 UINT64 TftpBufferSize
;
772 UINT64 TftpTransferSize
;
773 EFI_IP_ADDRESS ServerIp
;
774 IPv4_DEVICE_PATH
* IPv4DevicePathNode
;
775 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
776 EFI_IP_ADDRESS LocalIp
;
777 CHAR8
* AsciiPathName
;
778 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
780 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
));
782 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)RemainingDevicePath
;
783 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
785 Status
= gBS
->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid
, NULL
, (VOID
**)&Pxe
);
786 if (EFI_ERROR (Status
)) {
790 Status
= Pxe
->Start (Pxe
, FALSE
);
791 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
796 if (!IPv4DevicePathNode
->StaticIpAddress
) {
797 Status
= Pxe
->Dhcp (Pxe
, TRUE
);
799 CopyMem (&LocalIp
.v4
, &IPv4DevicePathNode
->LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
800 Status
= Pxe
->SetStationIp (Pxe
, &LocalIp
, NULL
);
803 // If an IP Address has already been set and a different static IP address is requested then restart
804 // the Network service.
805 if (Status
== EFI_ALREADY_STARTED
) {
806 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&Snp
);
807 if (!EFI_ERROR (Status
) && IPv4DevicePathNode
->StaticIpAddress
&&
808 (CompareMem (&Snp
->Mode
->CurrentAddress
, &IPv4DevicePathNode
->LocalIpAddress
, sizeof(EFI_MAC_ADDRESS
)) != 0))
811 Status
= Pxe
->Start (Pxe
, FALSE
);
812 if (EFI_ERROR(Status
)) {
815 // After restarting the PXE protocol, we want to try again with our new IP Address
816 Status
= EFI_ALREADY_STARTED
;
819 } while (Status
== EFI_ALREADY_STARTED
);
821 if (EFI_ERROR(Status
)) {
825 CopyMem (&ServerIp
.v4
, &IPv4DevicePathNode
->RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
827 // Convert the Unicode PathName to Ascii
828 AsciiPathName
= AllocatePool ((StrLen (FilePathDevicePath
->PathName
) + 1) * sizeof (CHAR8
));
829 if (AsciiPathName
== NULL
) {
830 return EFI_OUT_OF_RESOURCES
;
832 UnicodeStrToAsciiStr (FilePathDevicePath
->PathName
, AsciiPathName
);
834 // Try to get the size (required the TFTP server to have "tsize" extension)
835 Status
= Pxe
->Mtftp (
837 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
843 (UINT8
*)AsciiPathName
,
847 // Pxe.Mtftp replies EFI_PROTOCOL_ERROR if tsize is not supported by the TFTP server
848 if (EFI_ERROR (Status
) && (Status
!= EFI_PROTOCOL_ERROR
)) {
849 if (Status
== EFI_TFTP_ERROR
) {
850 DEBUG((EFI_D_ERROR
, "TFTP Error: Fail to get the size of the file\n"));
857 // 1) the file size is unknown (tsize extension not supported)
858 // 2) tsize returned the file size
860 if (Status
== EFI_PROTOCOL_ERROR
) {
861 for (TftpBufferSize
= SIZE_8MB
; TftpBufferSize
<= FixedPcdGet32 (PcdMaxTftpFileSize
); TftpBufferSize
+= SIZE_8MB
) {
862 // Allocate a buffer to hold the whole file.
863 Status
= gBS
->AllocatePages (
866 EFI_SIZE_TO_PAGES (TftpBufferSize
),
869 if (EFI_ERROR (Status
)) {
870 DEBUG ((EFI_D_ERROR
, "Failed to allocate space for image: %r\n", Status
));
874 TftpTransferSize
= TftpBufferSize
;
875 Status
= Pxe
->Mtftp (
877 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
878 (VOID
*)(UINTN
)*Image
,
883 (UINT8
*)AsciiPathName
,
887 if (EFI_ERROR (Status
)) {
888 gBS
->FreePages (*Image
, EFI_SIZE_TO_PAGES (TftpBufferSize
));
890 *ImageSize
= (UINTN
)TftpBufferSize
;
895 // Allocate a buffer to hold the whole file.
896 Status
= gBS
->AllocatePages (
899 EFI_SIZE_TO_PAGES (TftpBufferSize
),
902 if (EFI_ERROR (Status
)) {
903 DEBUG ((EFI_D_ERROR
, "Failed to allocate space for kernel image: %r\n", Status
));
907 Status
= Pxe
->Mtftp (
909 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
910 (VOID
*)(UINTN
)*Image
,
915 (UINT8
*)AsciiPathName
,
919 if (EFI_ERROR (Status
)) {
920 gBS
->FreePages (*Image
, EFI_SIZE_TO_PAGES (TftpBufferSize
));
922 *ImageSize
= (UINTN
)TftpBufferSize
;
927 FreePool (AsciiPathName
);
931 BDS_FILE_LOADER FileLoaders
[] = {
932 { BdsFileSystemSupport
, BdsFileSystemLoadImage
},
933 { BdsFirmwareVolumeSupport
, BdsFirmwareVolumeLoadImage
},
934 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
935 { BdsMemoryMapSupport
, BdsMemoryMapLoadImage
},
936 { BdsPxeSupport
, BdsPxeLoadImage
},
937 { BdsTftpSupport
, BdsTftpLoadImage
},
942 BdsLoadImageAndUpdateDevicePath (
943 IN OUT EFI_DEVICE_PATH
**DevicePath
,
944 IN EFI_ALLOCATE_TYPE Type
,
945 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
951 EFI_DEVICE_PATH
*RemainingDevicePath
;
952 BDS_FILE_LOADER
* FileLoader
;
954 Status
= BdsConnectAndUpdateDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
955 if (EFI_ERROR (Status
)) {
959 FileLoader
= FileLoaders
;
960 while (FileLoader
->Support
!= NULL
) {
961 if (FileLoader
->Support (*DevicePath
, Handle
, RemainingDevicePath
)) {
962 return FileLoader
->LoadImage (*DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, FileSize
);
967 return EFI_UNSUPPORTED
;
972 IN EFI_DEVICE_PATH
*DevicePath
,
973 IN EFI_ALLOCATE_TYPE Type
,
974 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
978 return BdsLoadImageAndUpdateDevicePath (&DevicePath
, Type
, Image
, FileSize
);
982 Start an EFI Application from a Device Path
984 @param ParentImageHandle Handle of the calling image
985 @param DevicePath Location of the EFI Application
987 @retval EFI_SUCCESS All drivers have been connected
988 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
989 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
993 BdsStartEfiApplication (
994 IN EFI_HANDLE ParentImageHandle
,
995 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
996 IN UINTN LoadOptionsSize
,
1001 EFI_HANDLE ImageHandle
;
1002 EFI_PHYSICAL_ADDRESS BinaryBuffer
;
1004 EFI_LOADED_IMAGE_PROTOCOL
* LoadedImage
;
1006 // Find the nearest supported file loader
1007 Status
= BdsLoadImageAndUpdateDevicePath (&DevicePath
, AllocateAnyPages
, &BinaryBuffer
, &BinarySize
);
1008 if (EFI_ERROR (Status
)) {
1012 // Load the image from the Buffer with Boot Services function
1013 Status
= gBS
->LoadImage (TRUE
, ParentImageHandle
, DevicePath
, (VOID
*)(UINTN
)BinaryBuffer
, BinarySize
, &ImageHandle
);
1014 if (EFI_ERROR (Status
)) {
1018 // Passed LoadOptions to the EFI Application
1019 if (LoadOptionsSize
!= 0) {
1020 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &LoadedImage
);
1021 if (EFI_ERROR (Status
)) {
1025 LoadedImage
->LoadOptionsSize
= LoadOptionsSize
;
1026 LoadedImage
->LoadOptions
= LoadOptions
;
1029 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
1030 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1032 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
1033 // Clear the Watchdog Timer after the image returns
1034 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);