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 <Library/NetLib.h>
19 #include <Protocol/Bds.h>
20 #include <Protocol/UsbIo.h>
21 #include <Protocol/DiskIo.h>
22 #include <Protocol/LoadedImage.h>
23 #include <Protocol/SimpleNetwork.h>
24 #include <Protocol/Dhcp4.h>
25 #include <Protocol/Mtftp4.h>
28 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
30 /* Type and defines to set up the DHCP4 options */
33 EFI_DHCP4_PACKET_OPTION Head
;
37 #define DHCP_TAG_PARA_LIST 55
38 #define DHCP_TAG_NETMASK 1
39 #define DHCP_TAG_ROUTER 3
42 Constant strings and define related to the message indicating the amount of
43 progress in the dowloading of a TFTP file.
46 // Frame for the progression slider
47 STATIC CONST CHAR16 mTftpProgressFrame
[] = L
"[ ]";
49 // Number of steps in the progression slider
50 #define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
52 // Size in number of characters plus one (final zero) of the message to
53 // indicate the progress of a tftp download. The format is "[(progress slider:
54 // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
55 // are thus the number of characters in mTftpProgressFrame[] plus 11 characters
56 // (2 // spaces, "Kb" and seven characters for the number of KBytes).
57 #define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
59 // String to delete the tftp progress message to be able to update it :
60 // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
61 STATIC CONST CHAR16 mTftpProgressDelete
[] = L
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
64 // Extract the FilePath from the Device Path
66 BdsExtractFilePathFromDevicePath (
67 IN CONST CHAR16
*StrDevicePath
,
68 IN UINTN NumberDevicePathNode
74 Str
= (CHAR16
*)StrDevicePath
;
76 while ((Str
!= NULL
) && (*Str
!= L
'\0') && (Node
< NumberDevicePathNode
)) {
77 if ((*Str
== L
'/') || (*Str
== L
'\\')) {
92 IN EFI_DEVICE_PATH
* DevicePath
95 return ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
96 ((DevicePathSubType (DevicePath
) == MSG_USB_CLASS_DP
) ||
97 (DevicePathSubType (DevicePath
) == MSG_USB_WWID_DP
)));
102 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
103 OUT EFI_HANDLE
* DeviceHandle
,
104 OUT EFI_DEVICE_PATH
** NewDevicePath
109 UINTN UsbIoHandleCount
;
110 EFI_HANDLE
*UsbIoBuffer
;
111 EFI_DEVICE_PATH
* UsbIoDevicePath
;
112 EFI_DEVICE_PATH
* TmpDevicePath
;
113 USB_WWID_DEVICE_PATH
* WwidDevicePath1
;
114 USB_WWID_DEVICE_PATH
* WwidDevicePath2
;
115 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath1
;
116 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath2
;
118 // Get all the UsbIo handles
119 UsbIoHandleCount
= 0;
120 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiUsbIoProtocolGuid
, NULL
, &UsbIoHandleCount
, &UsbIoBuffer
);
121 if (EFI_ERROR (Status
) || (UsbIoHandleCount
== 0)) {
125 // Check if one of the handles matches the USB description
126 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
127 Status
= gBS
->HandleProtocol (UsbIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**) &UsbIoDevicePath
);
128 if (!EFI_ERROR (Status
)) {
129 TmpDevicePath
= UsbIoDevicePath
;
130 while (!IsDevicePathEnd (TmpDevicePath
)) {
131 // Check if the Device Path node is a USB Removable device Path node
132 if (BdsIsRemovableUsb (TmpDevicePath
)) {
133 if (TmpDevicePath
->SubType
== MSG_USB_WWID_DP
) {
134 WwidDevicePath1
= (USB_WWID_DEVICE_PATH
*)RemovableDevicePath
;
135 WwidDevicePath2
= (USB_WWID_DEVICE_PATH
*)TmpDevicePath
;
136 if ((WwidDevicePath1
->VendorId
== WwidDevicePath2
->VendorId
) &&
137 (WwidDevicePath1
->ProductId
== WwidDevicePath2
->ProductId
) &&
138 (CompareMem (WwidDevicePath1
+1, WwidDevicePath2
+1, DevicePathNodeLength(WwidDevicePath1
)-sizeof (USB_WWID_DEVICE_PATH
)) == 0))
140 *DeviceHandle
= UsbIoBuffer
[Index
];
141 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
142 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode (RemovableDevicePath
));
146 UsbClassDevicePath1
= (USB_CLASS_DEVICE_PATH
*)RemovableDevicePath
;
147 UsbClassDevicePath2
= (USB_CLASS_DEVICE_PATH
*)TmpDevicePath
;
148 if ((UsbClassDevicePath1
->VendorId
!= 0xFFFF) && (UsbClassDevicePath1
->VendorId
== UsbClassDevicePath2
->VendorId
) &&
149 (UsbClassDevicePath1
->ProductId
!= 0xFFFF) && (UsbClassDevicePath1
->ProductId
== UsbClassDevicePath2
->ProductId
) &&
150 (UsbClassDevicePath1
->DeviceClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceClass
== UsbClassDevicePath2
->DeviceClass
) &&
151 (UsbClassDevicePath1
->DeviceSubClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceSubClass
== UsbClassDevicePath2
->DeviceSubClass
) &&
152 (UsbClassDevicePath1
->DeviceProtocol
!= 0xFF) && (UsbClassDevicePath1
->DeviceProtocol
== UsbClassDevicePath2
->DeviceProtocol
))
154 *DeviceHandle
= UsbIoBuffer
[Index
];
155 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
156 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode (RemovableDevicePath
));
161 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
167 return EFI_NOT_FOUND
;
172 IN EFI_DEVICE_PATH
* DevicePath
175 return IS_DEVICE_PATH_NODE (DevicePath
, MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
);
180 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
181 OUT EFI_HANDLE
* DeviceHandle
,
182 OUT EFI_DEVICE_PATH
** NewDevicePath
187 UINTN PartitionHandleCount
;
188 EFI_HANDLE
*PartitionBuffer
;
189 EFI_DEVICE_PATH
* PartitionDevicePath
;
190 EFI_DEVICE_PATH
* TmpDevicePath
;
191 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath1
;
192 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath2
;
194 // Get all the DiskIo handles
195 PartitionHandleCount
= 0;
196 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDiskIoProtocolGuid
, NULL
, &PartitionHandleCount
, &PartitionBuffer
);
197 if (EFI_ERROR (Status
) || (PartitionHandleCount
== 0)) {
201 // Check if one of the handles matches the Hard Disk Description
202 for (Index
= 0; Index
< PartitionHandleCount
; Index
++) {
203 Status
= gBS
->HandleProtocol (PartitionBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**) &PartitionDevicePath
);
204 if (!EFI_ERROR (Status
)) {
205 TmpDevicePath
= PartitionDevicePath
;
206 while (!IsDevicePathEnd (TmpDevicePath
)) {
207 // Check if the Device Path node is a HD Removable device Path node
208 if (BdsIsRemovableHd (TmpDevicePath
)) {
209 HardDriveDevicePath1
= (HARDDRIVE_DEVICE_PATH
*)RemovableDevicePath
;
210 HardDriveDevicePath2
= (HARDDRIVE_DEVICE_PATH
*)TmpDevicePath
;
211 if ((HardDriveDevicePath1
->SignatureType
== HardDriveDevicePath2
->SignatureType
) &&
212 (CompareGuid ((EFI_GUID
*)HardDriveDevicePath1
->Signature
, (EFI_GUID
*)HardDriveDevicePath2
->Signature
) == TRUE
) &&
213 (HardDriveDevicePath1
->PartitionNumber
== HardDriveDevicePath2
->PartitionNumber
))
215 *DeviceHandle
= PartitionBuffer
[Index
];
216 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
217 *NewDevicePath
= AppendDevicePath (PartitionDevicePath
, NextDevicePathNode (RemovableDevicePath
));
221 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
227 return EFI_NOT_FOUND
;
231 BdsIsRemovableCdrom (
232 IN EFI_DEVICE_PATH* DevicePath
235 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
240 IN EFI_DEVICE_PATH* RemovableDevicePath,
241 OUT EFI_HANDLE* DeviceHandle,
242 OUT EFI_DEVICE_PATH** DevicePath
246 return EFI_UNSUPPORTED;
250 (*BDS_IS_REMOVABLE
) (
251 IN EFI_DEVICE_PATH
* DevicePath
256 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
257 OUT EFI_HANDLE
* DeviceHandle
,
258 OUT EFI_DEVICE_PATH
** DevicePath
262 BDS_IS_REMOVABLE IsRemovable
;
263 BDS_GET_DEVICE GetDevice
;
264 } BDS_REMOVABLE_DEVICE_SUPPORT
;
266 BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport
[] = {
267 { BdsIsRemovableUsb
, BdsGetDeviceUsb
},
268 { BdsIsRemovableHd
, BdsGetDeviceHd
},
269 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
275 IN EFI_DEVICE_PATH
* DevicePath
279 EFI_DEVICE_PATH
* TmpDevicePath
;
281 TmpDevicePath
= DevicePath
;
282 while (!IsDevicePathEnd (TmpDevicePath
)) {
283 for (Index
= 0; Index
< sizeof (RemovableDeviceSupport
) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
284 if (RemovableDeviceSupport
[Index
].IsRemovable (TmpDevicePath
)) {
288 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
297 IN EFI_DEVICE_PATH
* DevicePath
,
298 OUT EFI_HANDLE
* DeviceHandle
,
299 OUT EFI_DEVICE_PATH
** NewDevicePath
304 EFI_DEVICE_PATH
* TmpDevicePath
;
305 BDS_REMOVABLE_DEVICE_SUPPORT
* RemovableDevice
;
306 EFI_DEVICE_PATH
* RemovableDevicePath
;
307 BOOLEAN RemovableFound
;
309 RemovableDevice
= NULL
;
310 RemovableDevicePath
= NULL
;
311 RemovableFound
= FALSE
;
312 TmpDevicePath
= DevicePath
;
314 while (!IsDevicePathEnd (TmpDevicePath
) && !RemovableFound
) {
315 for (Index
= 0; Index
< sizeof (RemovableDeviceSupport
) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
316 RemovableDevice
= &RemovableDeviceSupport
[Index
];
317 if (RemovableDevice
->IsRemovable (TmpDevicePath
)) {
318 RemovableDevicePath
= TmpDevicePath
;
319 RemovableFound
= TRUE
;
323 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
326 if (!RemovableFound
) {
327 return EFI_NOT_FOUND
;
330 // Search into the current started drivers
331 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
332 if (Status
== EFI_NOT_FOUND
) {
333 // Connect all the drivers
334 BdsConnectAllDrivers ();
336 // Search again into all the drivers
337 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
345 BdsConnectAndUpdateDevicePath (
346 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
,
347 OUT EFI_HANDLE
*Handle
,
348 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
351 EFI_DEVICE_PATH
* Remaining
;
352 EFI_DEVICE_PATH
* NewDevicePath
;
354 EFI_HANDLE PreviousHandle
;
356 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
) || (Handle
== NULL
)) {
357 return EFI_INVALID_PARAMETER
;
360 PreviousHandle
= NULL
;
362 Remaining
= *DevicePath
;
364 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
365 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
366 // to point to the remaining part of the device path
367 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
369 if (!EFI_ERROR (Status
)) {
370 if (*Handle
== PreviousHandle
) {
372 // If no forward progress is made try invoking the Dispatcher.
373 // A new FV may have been added to the system and new drivers
375 // Status == EFI_SUCCESS means a driver was dispatched
376 // Status == EFI_NOT_FOUND means no new drivers were dispatched
378 Status
= gDS
->Dispatch ();
381 if (!EFI_ERROR (Status
)) {
382 PreviousHandle
= *Handle
;
384 // Recursive = FALSE: We do not want to start the whole device tree
385 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
388 } while (!EFI_ERROR (Status
) && !IsDevicePathEnd (Remaining
));
390 if (!EFI_ERROR (Status
)) {
391 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
392 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
393 Remaining
= *DevicePath
;
394 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
395 if (!EFI_ERROR (Status
)) {
396 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
397 if (EFI_ERROR (Status
)) {
398 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
399 if ((Remaining
->Type
== HARDWARE_DEVICE_PATH
) && (Remaining
->SubType
== HW_MEMMAP_DP
)) {
400 Status
= EFI_SUCCESS
;
404 } else if (!IsDevicePathEnd (Remaining
) && !IsRemovableDevice (Remaining
)) {
406 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
407 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
408 Status = EFI_SUCCESS;
409 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
410 Status = EFI_SUCCESS;
413 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
414 Status
= EFI_SUCCESS
;
416 Status
= TryRemovableDevice (*DevicePath
, Handle
, &NewDevicePath
);
417 if (!EFI_ERROR (Status
)) {
418 Status
= BdsConnectAndUpdateDevicePath (&NewDevicePath
, Handle
, RemainingDevicePath
);
419 *DevicePath
= NewDevicePath
;
424 if (RemainingDevicePath
) {
425 *RemainingDevicePath
= Remaining
;
432 Connect a Device Path and return the handle of the driver that support this DevicePath
434 @param DevicePath Device Path of the File to connect
435 @param Handle Handle of the driver that support this DevicePath
436 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
438 @retval EFI_SUCCESS A driver that matches the Device Path has been found
439 @retval EFI_NOT_FOUND No handles match the search.
440 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
444 BdsConnectDevicePath (
445 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
446 OUT EFI_HANDLE
*Handle
,
447 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
450 return BdsConnectAndUpdateDevicePath (&DevicePath
, Handle
, RemainingDevicePath
);
454 BdsFileSystemSupport (
455 IN EFI_DEVICE_PATH
*DevicePath
,
456 IN EFI_HANDLE Handle
,
457 IN EFI_DEVICE_PATH
*RemainingDevicePath
461 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
463 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
465 return (!EFI_ERROR (Status
) && IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
));
469 BdsFileSystemLoadImage (
470 IN OUT EFI_DEVICE_PATH
**DevicePath
,
471 IN EFI_HANDLE Handle
,
472 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
473 IN EFI_ALLOCATE_TYPE Type
,
474 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
479 FILEPATH_DEVICE_PATH
*FilePathDevicePath
;
480 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
481 EFI_FILE_PROTOCOL
*Fs
;
482 EFI_FILE_INFO
*FileInfo
;
483 EFI_FILE_PROTOCOL
*File
;
486 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
));
488 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)RemainingDevicePath
;
490 Status
= gBS
->OpenProtocol (
492 &gEfiSimpleFileSystemProtocolGuid
,
496 EFI_OPEN_PROTOCOL_BY_DRIVER
498 if (EFI_ERROR (Status
)) {
502 // Try to Open the volume and get root directory
503 Status
= FsProtocol
->OpenVolume (FsProtocol
, &Fs
);
504 if (EFI_ERROR (Status
)) {
508 Status
= Fs
->Open (Fs
, &File
, FilePathDevicePath
->PathName
, EFI_FILE_MODE_READ
, 0);
509 if (EFI_ERROR (Status
)) {
514 File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, NULL
);
515 FileInfo
= AllocatePool (Size
);
516 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
517 if (EFI_ERROR (Status
)) {
522 Size
= FileInfo
->FileSize
;
528 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
529 // Try to allocate in any pages if failed to allocate memory at the defined location
530 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
531 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
533 if (!EFI_ERROR (Status
)) {
534 Status
= File
->Read (File
, &Size
, (VOID
*)(UINTN
)(*Image
));
543 &gEfiSimpleFileSystemProtocolGuid
,
551 BdsMemoryMapSupport (
552 IN EFI_DEVICE_PATH
*DevicePath
,
553 IN EFI_HANDLE Handle
,
554 IN EFI_DEVICE_PATH
*RemainingDevicePath
557 return IS_DEVICE_PATH_NODE (DevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
) ||
558 IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
);
562 BdsMemoryMapLoadImage (
563 IN OUT EFI_DEVICE_PATH
**DevicePath
,
564 IN EFI_HANDLE Handle
,
565 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
566 IN EFI_ALLOCATE_TYPE Type
,
567 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
572 MEMMAP_DEVICE_PATH
* MemMapPathDevicePath
;
575 if (IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
)) {
576 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)RemainingDevicePath
;
578 ASSERT (IS_DEVICE_PATH_NODE (*DevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
));
579 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)*DevicePath
;
582 Size
= MemMapPathDevicePath
->EndingAddress
- MemMapPathDevicePath
->StartingAddress
;
584 return EFI_INVALID_PARAMETER
;
587 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
588 // Try to allocate in any pages if failed to allocate memory at the defined location
589 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
590 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
592 if (!EFI_ERROR (Status
)) {
593 CopyMem ((VOID
*)(UINTN
)(*Image
), (CONST VOID
*)(UINTN
)MemMapPathDevicePath
->StartingAddress
, Size
);
595 if (ImageSize
!= NULL
) {
604 BdsFirmwareVolumeSupport (
605 IN EFI_DEVICE_PATH
*DevicePath
,
606 IN EFI_HANDLE Handle
,
607 IN EFI_DEVICE_PATH
*RemainingDevicePath
610 return IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
);
614 BdsFirmwareVolumeLoadImage (
615 IN OUT EFI_DEVICE_PATH
**DevicePath
,
616 IN EFI_HANDLE Handle
,
617 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
618 IN EFI_ALLOCATE_TYPE Type
,
619 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
624 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVol
;
625 EFI_GUID
*FvNameGuid
;
626 EFI_SECTION_TYPE SectionType
;
627 EFI_FV_FILETYPE FvType
;
628 EFI_FV_FILE_ATTRIBUTES Attrib
;
629 UINT32 AuthenticationStatus
;
632 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
));
634 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&FwVol
);
635 if (EFI_ERROR (Status
)) {
639 FvNameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)RemainingDevicePath
);
640 if (FvNameGuid
== NULL
) {
641 Status
= EFI_INVALID_PARAMETER
;
644 SectionType
= EFI_SECTION_PE32
;
645 AuthenticationStatus
= 0;
646 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
648 Status
= FwVol
->ReadSection (
655 &AuthenticationStatus
657 if (!EFI_ERROR (Status
)) {
659 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
660 if (Type
!= AllocateAnyPages
) {
661 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
),Image
);
662 if (!EFI_ERROR (Status
)) {
663 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
664 FreePool (ImageBuffer
);
668 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
669 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
670 // Try to allocate in any pages if failed to allocate memory at the defined location
671 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
672 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
674 if (!EFI_ERROR (Status
)) {
675 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
676 FreePool (ImageBuffer
);
680 // Try a raw file, since a PE32 SECTION does not exist
681 Status
= FwVol
->ReadFile (
688 &AuthenticationStatus
690 if (!EFI_ERROR (Status
)) {
691 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
692 // Try to allocate in any pages if failed to allocate memory at the defined location
693 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
694 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
696 if (!EFI_ERROR (Status
)) {
697 Status
= FwVol
->ReadFile (
704 &AuthenticationStatus
714 IN EFI_DEVICE_PATH
* DevicePath
,
715 IN EFI_HANDLE Handle
,
716 IN EFI_DEVICE_PATH
* RemainingDevicePath
720 EFI_PXE_BASE_CODE_PROTOCOL
* PxeBcProtocol
;
722 if (!IsDevicePathEnd (RemainingDevicePath
)) {
726 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
727 if (EFI_ERROR (Status
)) {
736 IN OUT EFI_DEVICE_PATH
**DevicePath
,
737 IN EFI_HANDLE Handle
,
738 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
739 IN EFI_ALLOCATE_TYPE Type
,
740 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
745 EFI_LOAD_FILE_PROTOCOL
*LoadFileProtocol
;
747 EFI_PXE_BASE_CODE_PROTOCOL
*Pxe
;
749 // Get Load File Protocol attached to the PXE protocol
750 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFileProtocol
);
751 if (EFI_ERROR (Status
)) {
755 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, RemainingDevicePath
, TRUE
, &BufferSize
, NULL
);
756 if (Status
== EFI_BUFFER_TOO_SMALL
) {
757 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(BufferSize
), Image
);
758 if (EFI_ERROR (Status
)) {
762 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, RemainingDevicePath
, TRUE
, &BufferSize
, (VOID
*)(UINTN
)(*Image
));
763 if (!EFI_ERROR (Status
) && (ImageSize
!= NULL
)) {
764 *ImageSize
= BufferSize
;
768 if (Status
== EFI_ALREADY_STARTED
) {
769 Status
= gBS
->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid
, NULL
, (VOID
**)&Pxe
);
770 if (!EFI_ERROR(Status
)) {
771 // If PXE is already started, we stop it
774 return BdsPxeLoadImage (DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, ImageSize
);
782 IN EFI_DEVICE_PATH
*DevicePath
,
783 IN EFI_HANDLE Handle
,
784 IN EFI_DEVICE_PATH
*RemainingDevicePath
788 EFI_DEVICE_PATH
*NextDevicePath
;
791 // Validate the Remaining Device Path
792 if (IsDevicePathEnd (RemainingDevicePath
)) {
795 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
) &&
796 !IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv6_DP
)) {
799 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
800 if (IsDevicePathEnd (NextDevicePath
)) {
803 if (!IS_DEVICE_PATH_NODE (NextDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
)) {
807 Status
= gBS
->HandleProtocol (
808 Handle
, &gEfiDevicePathProtocolGuid
,
811 if (EFI_ERROR (Status
)) {
816 // Check that the controller (identified by its handle "Handle") supports the
817 // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
818 // EFI MTFTPv4 Protocol needed to download the image through TFTP.
820 Status
= gBS
->HandleProtocol (
821 Handle
, &gEfiMtftp4ServiceBindingProtocolGuid
,
824 if (EFI_ERROR (Status
)) {
832 Worker function that get the size in numbers of bytes of a file from a TFTP
833 server before to download the file.
835 @param[in] Mtftp4 MTFTP4 protocol interface
836 @param[in] FilePath Path of the file, Ascii encoded
837 @param[out] FileSize Address where to store the file size in number of
840 @retval EFI_SUCCESS The size of the file was returned.
841 @retval !EFI_SUCCESS The size of the file was not returned.
847 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
853 EFI_MTFTP4_OPTION ReqOpt
[1];
854 EFI_MTFTP4_PACKET
*Packet
;
856 EFI_MTFTP4_OPTION
*TableOfOptions
;
857 EFI_MTFTP4_OPTION
*Option
;
861 ReqOpt
[0].OptionStr
= (UINT8
*)"tsize";
864 ReqOpt
[0].ValueStr
= OptBuf
;
866 Status
= Mtftp4
->GetInfo (
877 if (EFI_ERROR (Status
)) {
881 Status
= Mtftp4
->ParseOptions (
888 if (EFI_ERROR (Status
)) {
892 Option
= TableOfOptions
;
893 while (OptCnt
!= 0) {
894 if (AsciiStrnCmp ((CHAR8
*)Option
->OptionStr
, "tsize", 5) == 0) {
895 *FileSize
= AsciiStrDecimalToUint64 ((CHAR8
*)Option
->ValueStr
);
901 FreePool (TableOfOptions
);
904 Status
= EFI_UNSUPPORTED
;
913 Update the progress of a file download
914 This procedure is called each time a new TFTP packet is received.
916 @param[in] This MTFTP4 protocol interface
917 @param[in] Token Parameters for the download of the file
918 @param[in] PacketLen Length of the packet
919 @param[in] Packet Address of the packet
921 @retval EFI_SUCCESS All packets are accepted.
927 IN EFI_MTFTP4_PROTOCOL
*This
,
928 IN EFI_MTFTP4_TOKEN
*Token
,
930 IN EFI_MTFTP4_PACKET
*Packet
933 BDS_TFTP_CONTEXT
*Context
;
934 CHAR16 Progress
[TFTP_PROGRESS_MESSAGE_SIZE
];
942 if ((NTOHS (Packet
->OpCode
)) == EFI_MTFTP4_OPCODE_DATA
) {
943 Context
= (BDS_TFTP_CONTEXT
*)Token
->Context
;
945 if (Context
->DownloadedNbOfBytes
== 0) {
946 if (Context
->FileSize
> 0) {
947 Print (L
"%s 0 Kb", mTftpProgressFrame
);
954 // The data is the packet are prepended with two UINT16 :
955 // . OpCode = EFI_MTFTP4_OPCODE_DATA
956 // . Block = the number of this block of data
958 Context
->DownloadedNbOfBytes
+= PacketLen
- sizeof (Packet
->OpCode
) - sizeof (Packet
->Data
.Block
);
959 NbOfKb
= Context
->DownloadedNbOfBytes
/ 1024;
962 if (Context
->FileSize
> 0) {
963 LastStep
= (Context
->LastReportedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
964 Step
= (Context
->DownloadedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
965 if (Step
> LastStep
) {
966 Print (mTftpProgressDelete
);
967 StrCpy (Progress
, mTftpProgressFrame
);
968 for (Index
= 1; Index
< Step
; Index
++) {
969 Progress
[Index
] = L
'=';
971 Progress
[Step
] = L
'>';
974 Progress
+ (sizeof (mTftpProgressFrame
) / sizeof (CHAR16
)) - 1,
975 sizeof (Progress
) - sizeof (mTftpProgressFrame
),
979 Context
->LastReportedNbOfBytes
= Context
->DownloadedNbOfBytes
;
983 // Case when we do not know the size of the final file.
984 // We print the updated size every 50KB of downloaded data
986 LastNbOf50Kb
= Context
->LastReportedNbOfBytes
/ (50*1024);
987 NbOf50Kb
= Context
->DownloadedNbOfBytes
/ (50*1024);
988 if (NbOf50Kb
> LastNbOf50Kb
) {
989 Print (L
"\b\b\b\b\b\b\b\b\b\b");
990 UnicodeSPrint (Progress
, sizeof (Progress
), L
"%7d Kb", NbOfKb
);
991 Context
->LastReportedNbOfBytes
= Context
->DownloadedNbOfBytes
;
994 if (Progress
[0] != L
'\0') {
995 Print (L
"%s", Progress
);
1003 Download an image from a TFTP server
1005 @param[in] DevicePath Device path of the TFTP boot option
1006 @param[in] ControllerHandle Handle of the network controller
1007 @param[in] RemainingDevicePath Device path of the TFTP boot option but
1008 the first node that identifies the network controller
1009 @param[in] Type Type to allocate memory pages
1010 @param[out] Image Address of the bufer where the image is stored in
1012 @param[out] ImageSize Size in number of bytes of the i;age in case of
1015 @retval EFI_SUCCESS The image was returned.
1016 @retval !EFI_SUCCESS Something went wrong.
1021 IN OUT EFI_DEVICE_PATH
**DevicePath
,
1022 IN EFI_HANDLE ControllerHandle
,
1023 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
1024 IN EFI_ALLOCATE_TYPE Type
,
1025 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
1026 OUT UINTN
*ImageSize
1030 EFI_HANDLE Dhcp4ChildHandle
;
1031 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1032 BOOLEAN Dhcp4ToStop
;
1033 EFI_HANDLE Mtftp4ChildHandle
;
1034 EFI_MTFTP4_PROTOCOL
*Mtftp4
;
1035 DHCP4_OPTION ParaList
;
1036 EFI_DHCP4_PACKET_OPTION
*OptionList
[2];
1037 EFI_DHCP4_CONFIG_DATA Dhcp4CfgData
;
1038 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
1039 EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData
;
1040 IPv4_DEVICE_PATH
*IPv4DevicePathNode
;
1042 CHAR8
*AsciiFilePath
;
1043 EFI_MTFTP4_TOKEN Mtftp4Token
;
1045 UINT64 TftpBufferSize
;
1046 BDS_TFTP_CONTEXT
*TftpContext
;
1048 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
));
1049 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)RemainingDevicePath
;
1051 Dhcp4ChildHandle
= NULL
;
1053 Dhcp4ToStop
= FALSE
;
1054 Mtftp4ChildHandle
= NULL
;
1056 AsciiFilePath
= NULL
;
1059 if (!IPv4DevicePathNode
->StaticIpAddress
) {
1061 // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
1062 // install the DHCP4 protocol on it. Then, open the DHCP protocol.
1064 Status
= NetLibCreateServiceChild (
1067 &gEfiDhcp4ServiceBindingProtocolGuid
,
1070 if (!EFI_ERROR (Status
)) {
1071 Status
= gBS
->OpenProtocol (
1073 &gEfiDhcp4ProtocolGuid
,
1077 EFI_OPEN_PROTOCOL_BY_DRIVER
1080 if (EFI_ERROR (Status
)) {
1081 Print (L
"Unable to open DHCP4 protocol\n");
1087 // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
1088 // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
1090 Status
= NetLibCreateServiceChild (
1093 &gEfiMtftp4ServiceBindingProtocolGuid
,
1096 if (!EFI_ERROR (Status
)) {
1097 Status
= gBS
->OpenProtocol (
1099 &gEfiMtftp4ProtocolGuid
,
1103 EFI_OPEN_PROTOCOL_BY_DRIVER
1106 if (EFI_ERROR (Status
)) {
1107 Print (L
"Unable to open MTFTP4 protocol\n");
1111 if (!IPv4DevicePathNode
->StaticIpAddress
) {
1113 // Configure the DHCP4, all default settings. It is acceptable for the configuration to
1114 // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
1115 // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
1116 // process has been started but is not completed yet.
1118 ZeroMem (&Dhcp4CfgData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
1119 ParaList
.Head
.OpCode
= DHCP_TAG_PARA_LIST
;
1120 ParaList
.Head
.Length
= 2;
1121 ParaList
.Head
.Data
[0] = DHCP_TAG_NETMASK
;
1122 ParaList
.Route
= DHCP_TAG_ROUTER
;
1123 OptionList
[0] = &ParaList
.Head
;
1124 Dhcp4CfgData
.OptionCount
= 1;
1125 Dhcp4CfgData
.OptionList
= OptionList
;
1127 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4CfgData
);
1128 if (EFI_ERROR (Status
)) {
1129 if (Status
!= EFI_ACCESS_DENIED
) {
1130 Print (L
"Error while configuring the DHCP4 protocol\n");
1136 // Start the DHCP configuration. This may have already been done thus do not leave in error
1137 // if the return code is EFI_ALREADY_STARTED.
1139 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
1140 if (EFI_ERROR (Status
)) {
1141 if (Status
!= EFI_ALREADY_STARTED
) {
1142 Print (L
"DHCP configuration failed\n");
1149 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
1150 if (EFI_ERROR (Status
)) {
1154 if (Dhcp4Mode
.State
!= Dhcp4Bound
) {
1155 Status
= EFI_TIMEOUT
;
1156 Print (L
"DHCP configuration failed\n");
1162 // Configure the TFTP4 protocol
1165 ZeroMem (&Mtftp4CfgData
, sizeof (EFI_MTFTP4_CONFIG_DATA
));
1166 Mtftp4CfgData
.UseDefaultSetting
= FALSE
;
1167 Mtftp4CfgData
.TimeoutValue
= 4;
1168 Mtftp4CfgData
.TryCount
= 6;
1170 if (IPv4DevicePathNode
->StaticIpAddress
) {
1171 CopyMem (&Mtftp4CfgData
.StationIp
, &IPv4DevicePathNode
->LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1172 CopyMem (&Mtftp4CfgData
.SubnetMask
, &IPv4DevicePathNode
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1173 CopyMem (&Mtftp4CfgData
.GatewayIp
, &IPv4DevicePathNode
->GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1175 CopyMem (&Mtftp4CfgData
.StationIp
, &Dhcp4Mode
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
1176 CopyMem (&Mtftp4CfgData
.SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1177 CopyMem (&Mtftp4CfgData
.GatewayIp
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
1180 CopyMem (&Mtftp4CfgData
.ServerIp
, &IPv4DevicePathNode
->RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1182 Status
= Mtftp4
->Configure (Mtftp4
, &Mtftp4CfgData
);
1183 if (EFI_ERROR (Status
)) {
1184 Print (L
"Error while configuring the MTFTP4 protocol\n");
1188 // The Device Path might contain multiple FilePath nodes
1189 PathName
= ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL
*)(IPv4DevicePathNode
+ 1), FALSE
, FALSE
);
1190 AsciiFilePath
= AllocatePool (StrLen (PathName
) + 1);
1191 UnicodeStrToAsciiStr (PathName
, AsciiFilePath
);
1194 // Try to get the size of the file in bytes from the server. If it fails,
1195 // start with a 8MB buffer to download the file.
1198 if (Mtftp4GetFileSize (Mtftp4
, AsciiFilePath
, &FileSize
) == EFI_SUCCESS
) {
1199 TftpBufferSize
= FileSize
;
1201 TftpBufferSize
= SIZE_16MB
;
1204 TftpContext
= AllocatePool (sizeof (BDS_TFTP_CONTEXT
));
1205 if (TftpContext
== NULL
) {
1206 Status
= EFI_OUT_OF_RESOURCES
;
1209 TftpContext
->FileSize
= FileSize
;
1211 for (; TftpBufferSize
<= FixedPcdGet32 (PcdMaxTftpFileSize
);
1212 TftpBufferSize
= (TftpBufferSize
+ SIZE_16MB
) & (~(SIZE_16MB
-1))) {
1214 // Allocate a buffer to hold the whole file.
1216 Status
= gBS
->AllocatePages (
1218 EfiBootServicesCode
,
1219 EFI_SIZE_TO_PAGES (TftpBufferSize
),
1222 if (EFI_ERROR (Status
)) {
1223 Print (L
"Failed to allocate space for image\n");
1227 TftpContext
->DownloadedNbOfBytes
= 0;
1228 TftpContext
->LastReportedNbOfBytes
= 0;
1230 ZeroMem (&Mtftp4Token
, sizeof (EFI_MTFTP4_TOKEN
));
1231 Mtftp4Token
.Filename
= (UINT8
*)AsciiFilePath
;
1232 Mtftp4Token
.BufferSize
= TftpBufferSize
;
1233 Mtftp4Token
.Buffer
= (VOID
*)(UINTN
)*Image
;
1234 Mtftp4Token
.CheckPacket
= Mtftp4CheckPacket
;
1235 Mtftp4Token
.Context
= (VOID
*)TftpContext
;
1237 Print (L
"Downloading the file <%a> from the TFTP server\n", AsciiFilePath
);
1238 Status
= Mtftp4
->ReadFile (Mtftp4
, &Mtftp4Token
);
1240 if (EFI_ERROR (Status
)) {
1241 gBS
->FreePages (*Image
, EFI_SIZE_TO_PAGES (TftpBufferSize
));
1242 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1243 Print (L
"Downloading failed, file larger than expected.\n");
1250 *ImageSize
= Mtftp4Token
.BufferSize
;
1255 if (Dhcp4ChildHandle
!= NULL
) {
1256 if (Dhcp4
!= NULL
) {
1258 Dhcp4
->Stop (Dhcp4
);
1260 gBS
->CloseProtocol (
1262 &gEfiDhcp4ProtocolGuid
,
1267 NetLibDestroyServiceChild (
1270 &gEfiDhcp4ServiceBindingProtocolGuid
,
1275 if (Mtftp4ChildHandle
!= NULL
) {
1276 if (Mtftp4
!= NULL
) {
1277 if (AsciiFilePath
!= NULL
) {
1278 FreePool (AsciiFilePath
);
1280 if (TftpContext
!= NULL
) {
1281 FreePool (TftpContext
);
1283 gBS
->CloseProtocol (
1285 &gEfiMtftp4ProtocolGuid
,
1290 NetLibDestroyServiceChild (
1293 &gEfiMtftp4ServiceBindingProtocolGuid
,
1298 if (EFI_ERROR (Status
)) {
1300 Print (L
"Failed to download the file - Error=%r\n", Status
);
1306 BDS_FILE_LOADER FileLoaders
[] = {
1307 { BdsFileSystemSupport
, BdsFileSystemLoadImage
},
1308 { BdsFirmwareVolumeSupport
, BdsFirmwareVolumeLoadImage
},
1309 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
1310 { BdsMemoryMapSupport
, BdsMemoryMapLoadImage
},
1311 { BdsPxeSupport
, BdsPxeLoadImage
},
1312 { BdsTftpSupport
, BdsTftpLoadImage
},
1317 BdsLoadImageAndUpdateDevicePath (
1318 IN OUT EFI_DEVICE_PATH
**DevicePath
,
1319 IN EFI_ALLOCATE_TYPE Type
,
1320 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
1326 EFI_DEVICE_PATH
*RemainingDevicePath
;
1327 BDS_FILE_LOADER
* FileLoader
;
1329 Status
= BdsConnectAndUpdateDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
1330 if (EFI_ERROR (Status
)) {
1334 FileLoader
= FileLoaders
;
1335 while (FileLoader
->Support
!= NULL
) {
1336 if (FileLoader
->Support (*DevicePath
, Handle
, RemainingDevicePath
)) {
1337 return FileLoader
->LoadImage (DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, FileSize
);
1342 return EFI_UNSUPPORTED
;
1347 IN EFI_DEVICE_PATH
*DevicePath
,
1348 IN EFI_ALLOCATE_TYPE Type
,
1349 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
1353 return BdsLoadImageAndUpdateDevicePath (&DevicePath
, Type
, Image
, FileSize
);
1357 Start an EFI Application from a Device Path
1359 @param ParentImageHandle Handle of the calling image
1360 @param DevicePath Location of the EFI Application
1362 @retval EFI_SUCCESS All drivers have been connected
1363 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
1364 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
1368 BdsStartEfiApplication (
1369 IN EFI_HANDLE ParentImageHandle
,
1370 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1371 IN UINTN LoadOptionsSize
,
1372 IN VOID
* LoadOptions
1376 EFI_HANDLE ImageHandle
;
1377 EFI_PHYSICAL_ADDRESS BinaryBuffer
;
1379 EFI_LOADED_IMAGE_PROTOCOL
* LoadedImage
;
1381 // Find the nearest supported file loader
1382 Status
= BdsLoadImageAndUpdateDevicePath (&DevicePath
, AllocateAnyPages
, &BinaryBuffer
, &BinarySize
);
1383 if (EFI_ERROR (Status
)) {
1387 // Load the image from the Buffer with Boot Services function
1388 Status
= gBS
->LoadImage (TRUE
, ParentImageHandle
, DevicePath
, (VOID
*)(UINTN
)BinaryBuffer
, BinarySize
, &ImageHandle
);
1389 if (EFI_ERROR (Status
)) {
1393 // Passed LoadOptions to the EFI Application
1394 if (LoadOptionsSize
!= 0) {
1395 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &LoadedImage
);
1396 if (EFI_ERROR (Status
)) {
1400 LoadedImage
->LoadOptionsSize
= LoadOptionsSize
;
1401 LoadedImage
->LoadOptions
= LoadOptions
;
1404 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
1405 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1407 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
1408 // Clear the Watchdog Timer after the image returns
1409 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);