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>
27 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
30 Constant strings and define related to the message indicating the amount of
31 progress in the dowloading of a TFTP file.
34 // Frame for the progression slider
35 STATIC CONST CHAR16 mTftpProgressFrame
[] = L
"[ ]";
37 // Number of steps in the progression slider
38 #define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
40 // Size in number of characters plus one (final zero) of the message to
41 // indicate the progress of a tftp download. The format is "[(progress slider:
42 // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
43 // are thus the number of characters in mTftpProgressFrame[] plus 11 characters
44 // (2 // spaces, "Kb" and seven characters for the number of KBytes).
45 #define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
47 // String to delete the tftp progress message to be able to update it :
48 // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
49 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";
52 // Extract the FilePath from the Device Path
54 BdsExtractFilePathFromDevicePath (
55 IN CONST CHAR16
*StrDevicePath
,
56 IN UINTN NumberDevicePathNode
62 Str
= (CHAR16
*)StrDevicePath
;
64 while ((Str
!= NULL
) && (*Str
!= L
'\0') && (Node
< NumberDevicePathNode
)) {
65 if ((*Str
== L
'/') || (*Str
== L
'\\')) {
80 IN EFI_DEVICE_PATH
* DevicePath
83 return ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
84 ((DevicePathSubType (DevicePath
) == MSG_USB_CLASS_DP
) ||
85 (DevicePathSubType (DevicePath
) == MSG_USB_WWID_DP
)));
90 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
91 OUT EFI_HANDLE
* DeviceHandle
,
92 OUT EFI_DEVICE_PATH
** NewDevicePath
97 UINTN UsbIoHandleCount
;
98 EFI_HANDLE
*UsbIoBuffer
;
99 EFI_DEVICE_PATH
* UsbIoDevicePath
;
100 EFI_DEVICE_PATH
* TmpDevicePath
;
101 USB_WWID_DEVICE_PATH
* WwidDevicePath1
;
102 USB_WWID_DEVICE_PATH
* WwidDevicePath2
;
103 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath1
;
104 USB_CLASS_DEVICE_PATH
* UsbClassDevicePath2
;
106 // Get all the UsbIo handles
107 UsbIoHandleCount
= 0;
108 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiUsbIoProtocolGuid
, NULL
, &UsbIoHandleCount
, &UsbIoBuffer
);
109 if (EFI_ERROR (Status
) || (UsbIoHandleCount
== 0)) {
113 // Check if one of the handles matches the USB description
114 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
115 Status
= gBS
->HandleProtocol (UsbIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**) &UsbIoDevicePath
);
116 if (!EFI_ERROR (Status
)) {
117 TmpDevicePath
= UsbIoDevicePath
;
118 while (!IsDevicePathEnd (TmpDevicePath
)) {
119 // Check if the Device Path node is a USB Removable device Path node
120 if (BdsIsRemovableUsb (TmpDevicePath
)) {
121 if (TmpDevicePath
->SubType
== MSG_USB_WWID_DP
) {
122 WwidDevicePath1
= (USB_WWID_DEVICE_PATH
*)RemovableDevicePath
;
123 WwidDevicePath2
= (USB_WWID_DEVICE_PATH
*)TmpDevicePath
;
124 if ((WwidDevicePath1
->VendorId
== WwidDevicePath2
->VendorId
) &&
125 (WwidDevicePath1
->ProductId
== WwidDevicePath2
->ProductId
) &&
126 (CompareMem (WwidDevicePath1
+1, WwidDevicePath2
+1, DevicePathNodeLength(WwidDevicePath1
)-sizeof (USB_WWID_DEVICE_PATH
)) == 0))
128 *DeviceHandle
= UsbIoBuffer
[Index
];
129 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
130 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode (RemovableDevicePath
));
134 UsbClassDevicePath1
= (USB_CLASS_DEVICE_PATH
*)RemovableDevicePath
;
135 UsbClassDevicePath2
= (USB_CLASS_DEVICE_PATH
*)TmpDevicePath
;
136 if ((UsbClassDevicePath1
->VendorId
!= 0xFFFF) && (UsbClassDevicePath1
->VendorId
== UsbClassDevicePath2
->VendorId
) &&
137 (UsbClassDevicePath1
->ProductId
!= 0xFFFF) && (UsbClassDevicePath1
->ProductId
== UsbClassDevicePath2
->ProductId
) &&
138 (UsbClassDevicePath1
->DeviceClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceClass
== UsbClassDevicePath2
->DeviceClass
) &&
139 (UsbClassDevicePath1
->DeviceSubClass
!= 0xFF) && (UsbClassDevicePath1
->DeviceSubClass
== UsbClassDevicePath2
->DeviceSubClass
) &&
140 (UsbClassDevicePath1
->DeviceProtocol
!= 0xFF) && (UsbClassDevicePath1
->DeviceProtocol
== UsbClassDevicePath2
->DeviceProtocol
))
142 *DeviceHandle
= UsbIoBuffer
[Index
];
143 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
144 *NewDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePathNode (RemovableDevicePath
));
149 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
155 return EFI_NOT_FOUND
;
160 IN EFI_DEVICE_PATH
* DevicePath
163 return IS_DEVICE_PATH_NODE (DevicePath
, MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
);
168 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
169 OUT EFI_HANDLE
* DeviceHandle
,
170 OUT EFI_DEVICE_PATH
** NewDevicePath
175 UINTN PartitionHandleCount
;
176 EFI_HANDLE
*PartitionBuffer
;
177 EFI_DEVICE_PATH
* PartitionDevicePath
;
178 EFI_DEVICE_PATH
* TmpDevicePath
;
179 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath1
;
180 HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath2
;
182 // Get all the DiskIo handles
183 PartitionHandleCount
= 0;
184 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDiskIoProtocolGuid
, NULL
, &PartitionHandleCount
, &PartitionBuffer
);
185 if (EFI_ERROR (Status
) || (PartitionHandleCount
== 0)) {
189 // Check if one of the handles matches the Hard Disk Description
190 for (Index
= 0; Index
< PartitionHandleCount
; Index
++) {
191 Status
= gBS
->HandleProtocol (PartitionBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**) &PartitionDevicePath
);
192 if (!EFI_ERROR (Status
)) {
193 TmpDevicePath
= PartitionDevicePath
;
194 while (!IsDevicePathEnd (TmpDevicePath
)) {
195 // Check if the Device Path node is a HD Removable device Path node
196 if (BdsIsRemovableHd (TmpDevicePath
)) {
197 HardDriveDevicePath1
= (HARDDRIVE_DEVICE_PATH
*)RemovableDevicePath
;
198 HardDriveDevicePath2
= (HARDDRIVE_DEVICE_PATH
*)TmpDevicePath
;
199 if ((HardDriveDevicePath1
->SignatureType
== HardDriveDevicePath2
->SignatureType
) &&
200 (CompareGuid ((EFI_GUID
*)HardDriveDevicePath1
->Signature
, (EFI_GUID
*)HardDriveDevicePath2
->Signature
) == TRUE
) &&
201 (HardDriveDevicePath1
->PartitionNumber
== HardDriveDevicePath2
->PartitionNumber
))
203 *DeviceHandle
= PartitionBuffer
[Index
];
204 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
205 *NewDevicePath
= AppendDevicePath (PartitionDevicePath
, NextDevicePathNode (RemovableDevicePath
));
209 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
215 return EFI_NOT_FOUND
;
219 BdsIsRemovableCdrom (
220 IN EFI_DEVICE_PATH* DevicePath
223 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
228 IN EFI_DEVICE_PATH* RemovableDevicePath,
229 OUT EFI_HANDLE* DeviceHandle,
230 OUT EFI_DEVICE_PATH** DevicePath
234 return EFI_UNSUPPORTED;
238 (*BDS_IS_REMOVABLE
) (
239 IN EFI_DEVICE_PATH
* DevicePath
244 IN EFI_DEVICE_PATH
* RemovableDevicePath
,
245 OUT EFI_HANDLE
* DeviceHandle
,
246 OUT EFI_DEVICE_PATH
** DevicePath
250 BDS_IS_REMOVABLE IsRemovable
;
251 BDS_GET_DEVICE GetDevice
;
252 } BDS_REMOVABLE_DEVICE_SUPPORT
;
254 BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport
[] = {
255 { BdsIsRemovableUsb
, BdsGetDeviceUsb
},
256 { BdsIsRemovableHd
, BdsGetDeviceHd
},
257 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
263 IN EFI_DEVICE_PATH
* DevicePath
267 EFI_DEVICE_PATH
* TmpDevicePath
;
269 TmpDevicePath
= DevicePath
;
270 while (!IsDevicePathEnd (TmpDevicePath
)) {
271 for (Index
= 0; Index
< sizeof (RemovableDeviceSupport
) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
272 if (RemovableDeviceSupport
[Index
].IsRemovable (TmpDevicePath
)) {
276 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
285 IN EFI_DEVICE_PATH
* DevicePath
,
286 OUT EFI_HANDLE
* DeviceHandle
,
287 OUT EFI_DEVICE_PATH
** NewDevicePath
292 EFI_DEVICE_PATH
* TmpDevicePath
;
293 BDS_REMOVABLE_DEVICE_SUPPORT
* RemovableDevice
;
294 EFI_DEVICE_PATH
* RemovableDevicePath
;
295 BOOLEAN RemovableFound
;
297 RemovableDevice
= NULL
;
298 RemovableDevicePath
= NULL
;
299 RemovableFound
= FALSE
;
300 TmpDevicePath
= DevicePath
;
302 while (!IsDevicePathEnd (TmpDevicePath
) && !RemovableFound
) {
303 for (Index
= 0; Index
< sizeof (RemovableDeviceSupport
) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT
); Index
++) {
304 RemovableDevice
= &RemovableDeviceSupport
[Index
];
305 if (RemovableDevice
->IsRemovable (TmpDevicePath
)) {
306 RemovableDevicePath
= TmpDevicePath
;
307 RemovableFound
= TRUE
;
311 TmpDevicePath
= NextDevicePathNode (TmpDevicePath
);
314 if (!RemovableFound
) {
315 return EFI_NOT_FOUND
;
318 // Search into the current started drivers
319 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
320 if (Status
== EFI_NOT_FOUND
) {
321 // Connect all the drivers
322 BdsConnectAllDrivers ();
324 // Search again into all the drivers
325 Status
= RemovableDevice
->GetDevice (RemovableDevicePath
, DeviceHandle
, NewDevicePath
);
333 BdsConnectAndUpdateDevicePath (
334 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
,
335 OUT EFI_HANDLE
*Handle
,
336 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
339 EFI_DEVICE_PATH
* Remaining
;
340 EFI_DEVICE_PATH
* NewDevicePath
;
342 EFI_HANDLE PreviousHandle
;
344 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
) || (Handle
== NULL
)) {
345 return EFI_INVALID_PARAMETER
;
348 PreviousHandle
= NULL
;
350 Remaining
= *DevicePath
;
352 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
353 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
354 // to point to the remaining part of the device path
355 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
357 if (!EFI_ERROR (Status
)) {
358 if (*Handle
== PreviousHandle
) {
360 // If no forward progress is made try invoking the Dispatcher.
361 // A new FV may have been added to the system and new drivers
363 // Status == EFI_SUCCESS means a driver was dispatched
364 // Status == EFI_NOT_FOUND means no new drivers were dispatched
366 Status
= gDS
->Dispatch ();
369 if (!EFI_ERROR (Status
)) {
370 PreviousHandle
= *Handle
;
372 // Recursive = FALSE: We do not want to start the whole device tree
373 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
376 } while (!EFI_ERROR (Status
) && !IsDevicePathEnd (Remaining
));
378 if (!EFI_ERROR (Status
)) {
379 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
380 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
381 Remaining
= *DevicePath
;
382 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, Handle
);
383 if (!EFI_ERROR (Status
)) {
384 Status
= gBS
->ConnectController (*Handle
, NULL
, Remaining
, FALSE
);
385 if (EFI_ERROR (Status
)) {
386 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
387 if ((Remaining
->Type
== HARDWARE_DEVICE_PATH
) && (Remaining
->SubType
== HW_MEMMAP_DP
)) {
388 Status
= EFI_SUCCESS
;
392 } else if (!IsDevicePathEnd (Remaining
) && !IsRemovableDevice (Remaining
)) {
394 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
395 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
396 Status = EFI_SUCCESS;
397 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
398 Status = EFI_SUCCESS;
401 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
402 Status
= EFI_SUCCESS
;
404 Status
= TryRemovableDevice (*DevicePath
, Handle
, &NewDevicePath
);
405 if (!EFI_ERROR (Status
)) {
406 Status
= BdsConnectAndUpdateDevicePath (&NewDevicePath
, Handle
, RemainingDevicePath
);
407 *DevicePath
= NewDevicePath
;
412 if (RemainingDevicePath
) {
413 *RemainingDevicePath
= Remaining
;
420 Connect a Device Path and return the handle of the driver that support this DevicePath
422 @param DevicePath Device Path of the File to connect
423 @param Handle Handle of the driver that support this DevicePath
424 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
426 @retval EFI_SUCCESS A driver that matches the Device Path has been found
427 @retval EFI_NOT_FOUND No handles match the search.
428 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
432 BdsConnectDevicePath (
433 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
434 OUT EFI_HANDLE
*Handle
,
435 OUT EFI_DEVICE_PATH_PROTOCOL
**RemainingDevicePath
438 return BdsConnectAndUpdateDevicePath (&DevicePath
, Handle
, RemainingDevicePath
);
442 BdsFileSystemSupport (
443 IN EFI_DEVICE_PATH
*DevicePath
,
444 IN EFI_HANDLE Handle
,
445 IN EFI_DEVICE_PATH
*RemainingDevicePath
449 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
451 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
453 return (!EFI_ERROR (Status
) && IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
));
457 BdsFileSystemLoadImage (
458 IN EFI_DEVICE_PATH
*DevicePath
,
459 IN EFI_HANDLE Handle
,
460 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
461 IN EFI_ALLOCATE_TYPE Type
,
462 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
466 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
467 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FsProtocol
;
468 EFI_FILE_PROTOCOL
*Fs
;
470 EFI_FILE_INFO
*FileInfo
;
471 EFI_FILE_PROTOCOL
*File
;
474 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
));
476 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)RemainingDevicePath
;
478 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FsProtocol
);
479 if (EFI_ERROR (Status
)) {
483 // Try to Open the volume and get root directory
484 Status
= FsProtocol
->OpenVolume (FsProtocol
, &Fs
);
485 if (EFI_ERROR (Status
)) {
490 Status
= Fs
->Open (Fs
, &File
, FilePathDevicePath
->PathName
, EFI_FILE_MODE_READ
, 0);
491 if (EFI_ERROR (Status
)) {
496 File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, NULL
);
497 FileInfo
= AllocatePool (Size
);
498 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
499 if (EFI_ERROR (Status
)) {
504 Size
= FileInfo
->FileSize
;
510 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
511 // Try to allocate in any pages if failed to allocate memory at the defined location
512 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
513 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
515 if (!EFI_ERROR (Status
)) {
516 Status
= File
->Read (File
, &Size
, (VOID
*)(UINTN
)(*Image
));
523 BdsMemoryMapSupport (
524 IN EFI_DEVICE_PATH
*DevicePath
,
525 IN EFI_HANDLE Handle
,
526 IN EFI_DEVICE_PATH
*RemainingDevicePath
529 return IS_DEVICE_PATH_NODE (DevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
) ||
530 IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
);
534 BdsMemoryMapLoadImage (
535 IN EFI_DEVICE_PATH
*DevicePath
,
536 IN EFI_HANDLE Handle
,
537 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
538 IN EFI_ALLOCATE_TYPE Type
,
539 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
544 MEMMAP_DEVICE_PATH
* MemMapPathDevicePath
;
547 if (IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
)) {
548 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)RemainingDevicePath
;
550 ASSERT (IS_DEVICE_PATH_NODE (DevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
));
551 MemMapPathDevicePath
= (MEMMAP_DEVICE_PATH
*)DevicePath
;
554 Size
= MemMapPathDevicePath
->EndingAddress
- MemMapPathDevicePath
->StartingAddress
;
556 return EFI_INVALID_PARAMETER
;
559 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
560 // Try to allocate in any pages if failed to allocate memory at the defined location
561 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
562 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(Size
), Image
);
564 if (!EFI_ERROR (Status
)) {
565 CopyMem ((VOID
*)(UINTN
)(*Image
), (CONST VOID
*)(UINTN
)MemMapPathDevicePath
->StartingAddress
, Size
);
567 if (ImageSize
!= NULL
) {
576 BdsFirmwareVolumeSupport (
577 IN EFI_DEVICE_PATH
*DevicePath
,
578 IN EFI_HANDLE Handle
,
579 IN EFI_DEVICE_PATH
*RemainingDevicePath
582 return IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
);
586 BdsFirmwareVolumeLoadImage (
587 IN EFI_DEVICE_PATH
*DevicePath
,
588 IN EFI_HANDLE Handle
,
589 IN EFI_DEVICE_PATH
*RemainingDevicePath
,
590 IN EFI_ALLOCATE_TYPE Type
,
591 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
596 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FwVol
;
597 EFI_GUID
*FvNameGuid
;
598 EFI_SECTION_TYPE SectionType
;
599 EFI_FV_FILETYPE FvType
;
600 EFI_FV_FILE_ATTRIBUTES Attrib
;
601 UINT32 AuthenticationStatus
;
604 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_PIWG_FW_FILE_DP
));
606 Status
= gBS
->HandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&FwVol
);
607 if (EFI_ERROR (Status
)) {
611 FvNameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)RemainingDevicePath
);
612 if (FvNameGuid
== NULL
) {
613 Status
= EFI_INVALID_PARAMETER
;
616 SectionType
= EFI_SECTION_PE32
;
617 AuthenticationStatus
= 0;
618 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
620 Status
= FwVol
->ReadSection (
627 &AuthenticationStatus
629 if (!EFI_ERROR (Status
)) {
631 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
632 if (Type
!= AllocateAnyPages
) {
633 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
),Image
);
634 if (!EFI_ERROR (Status
)) {
635 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
636 FreePool (ImageBuffer
);
640 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
641 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
642 // Try to allocate in any pages if failed to allocate memory at the defined location
643 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
644 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
646 if (!EFI_ERROR (Status
)) {
647 CopyMem ((VOID
*)(UINTN
)(*Image
), ImageBuffer
, *ImageSize
);
648 FreePool (ImageBuffer
);
652 // Try a raw file, since a PE32 SECTION does not exist
653 Status
= FwVol
->ReadFile (
660 &AuthenticationStatus
662 if (!EFI_ERROR (Status
)) {
663 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
664 // Try to allocate in any pages if failed to allocate memory at the defined location
665 if ((Status
== EFI_OUT_OF_RESOURCES
) && (Type
!= AllocateAnyPages
)) {
666 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(*ImageSize
), Image
);
668 if (!EFI_ERROR (Status
)) {
669 Status
= FwVol
->ReadFile (
672 (VOID
*)(UINTN
)(*Image
),
676 &AuthenticationStatus
686 IN EFI_DEVICE_PATH
* DevicePath
,
687 IN EFI_HANDLE Handle
,
688 IN EFI_DEVICE_PATH
* RemainingDevicePath
692 EFI_PXE_BASE_CODE_PROTOCOL
* PxeBcProtocol
;
694 if (!IsDevicePathEnd (RemainingDevicePath
)) {
698 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
699 if (EFI_ERROR (Status
)) {
708 IN EFI_DEVICE_PATH
* DevicePath
,
709 IN EFI_HANDLE Handle
,
710 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
711 IN EFI_ALLOCATE_TYPE Type
,
712 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
717 EFI_LOAD_FILE_PROTOCOL
*LoadFileProtocol
;
719 EFI_PXE_BASE_CODE_PROTOCOL
*Pxe
;
721 // Get Load File Protocol attached to the PXE protocol
722 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFileProtocol
);
723 if (EFI_ERROR (Status
)) {
727 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, NULL
);
728 if (Status
== EFI_BUFFER_TOO_SMALL
) {
729 Status
= gBS
->AllocatePages (Type
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES(BufferSize
), Image
);
730 if (EFI_ERROR (Status
)) {
734 Status
= LoadFileProtocol
->LoadFile (LoadFileProtocol
, DevicePath
, TRUE
, &BufferSize
, (VOID
*)(UINTN
)(*Image
));
735 if (!EFI_ERROR (Status
) && (ImageSize
!= NULL
)) {
736 *ImageSize
= BufferSize
;
740 if (Status
== EFI_ALREADY_STARTED
) {
741 Status
= gBS
->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid
, NULL
, (VOID
**)&Pxe
);
742 if (!EFI_ERROR(Status
)) {
743 // If PXE is already started, we stop it
746 return BdsPxeLoadImage (DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, ImageSize
);
754 IN EFI_DEVICE_PATH
*DevicePath
,
755 IN EFI_HANDLE Handle
,
756 IN EFI_DEVICE_PATH
*RemainingDevicePath
760 EFI_DEVICE_PATH
*NextDevicePath
;
763 // Validate the Remaining Device Path
764 if (IsDevicePathEnd (RemainingDevicePath
)) {
767 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
) &&
768 !IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv6_DP
)) {
771 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
772 if (IsDevicePathEnd (NextDevicePath
)) {
775 if (!IS_DEVICE_PATH_NODE (NextDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
)) {
779 Status
= gBS
->HandleProtocol (
780 Handle
, &gEfiDevicePathProtocolGuid
,
783 if (EFI_ERROR (Status
)) {
788 // Check that the controller (identified by its handle "Handle") supports the
789 // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
790 // EFI MTFTPv4 Protocol needed to download the image through TFTP.
792 Status
= gBS
->HandleProtocol (
793 Handle
, &gEfiMtftp4ServiceBindingProtocolGuid
,
796 if (EFI_ERROR (Status
)) {
804 Worker function that get the size in numbers of bytes of a file from a TFTP
805 server before to download the file.
807 @param[in] Mtftp4 MTFTP4 protocol interface
808 @param[in] FilePath Path of the file, Ascii encoded
809 @param[out] FileSize Address where to store the file size in number of
812 @retval EFI_SUCCESS The size of the file was returned.
813 @retval !EFI_SUCCESS The size of the file was not returned.
819 IN EFI_MTFTP4_PROTOCOL
*Mtftp4
,
825 EFI_MTFTP4_OPTION ReqOpt
[1];
826 EFI_MTFTP4_PACKET
*Packet
;
828 EFI_MTFTP4_OPTION
*TableOfOptions
;
829 EFI_MTFTP4_OPTION
*Option
;
833 ReqOpt
[0].OptionStr
= (UINT8
*)"tsize";
836 ReqOpt
[0].ValueStr
= OptBuf
;
838 Status
= Mtftp4
->GetInfo (
849 if (EFI_ERROR (Status
)) {
853 Status
= Mtftp4
->ParseOptions (
860 if (EFI_ERROR (Status
)) {
864 Option
= TableOfOptions
;
865 while (OptCnt
!= 0) {
866 if (AsciiStrnCmp ((CHAR8
*)Option
->OptionStr
, "tsize", 5) == 0) {
867 *FileSize
= AsciiStrDecimalToUint64 ((CHAR8
*)Option
->ValueStr
);
873 FreePool (TableOfOptions
);
876 Status
= EFI_UNSUPPORTED
;
885 Update the progress of a file download
886 This procedure is called each time a new TFTP packet is received.
888 @param[in] This MTFTP4 protocol interface
889 @param[in] Token Parameters for the download of the file
890 @param[in] PacketLen Length of the packet
891 @param[in] Packet Address of the packet
893 @retval EFI_SUCCESS All packets are accepted.
899 IN EFI_MTFTP4_PROTOCOL
*This
,
900 IN EFI_MTFTP4_TOKEN
*Token
,
902 IN EFI_MTFTP4_PACKET
*Packet
905 BDS_TFTP_CONTEXT
*Context
;
906 CHAR16 Progress
[TFTP_PROGRESS_MESSAGE_SIZE
];
914 if ((NTOHS (Packet
->OpCode
)) == EFI_MTFTP4_OPCODE_DATA
) {
915 Context
= (BDS_TFTP_CONTEXT
*)Token
->Context
;
917 if (Context
->DownloadedNbOfBytes
== 0) {
918 if (Context
->FileSize
> 0) {
919 Print (L
"%s 0 Kb", mTftpProgressFrame
);
926 // The data is the packet are prepended with two UINT16 :
927 // . OpCode = EFI_MTFTP4_OPCODE_DATA
928 // . Block = the number of this block of data
930 Context
->DownloadedNbOfBytes
+= PacketLen
- sizeof (Packet
->OpCode
) - sizeof (Packet
->Data
.Block
);
931 NbOfKb
= Context
->DownloadedNbOfBytes
/ 1024;
934 if (Context
->FileSize
> 0) {
935 LastStep
= (Context
->LastReportedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
936 Step
= (Context
->DownloadedNbOfBytes
* TFTP_PROGRESS_SLIDER_STEPS
) / Context
->FileSize
;
937 if (Step
> LastStep
) {
938 Print (mTftpProgressDelete
);
939 StrCpy (Progress
, mTftpProgressFrame
);
940 for (Index
= 1; Index
< Step
; Index
++) {
941 Progress
[Index
] = L
'=';
943 Progress
[Step
] = L
'>';
946 Progress
+ (sizeof (mTftpProgressFrame
) / sizeof (CHAR16
)) - 1,
947 sizeof (Progress
) - sizeof (mTftpProgressFrame
),
951 Context
->LastReportedNbOfBytes
= Context
->DownloadedNbOfBytes
;
955 // Case when we do not know the size of the final file.
956 // We print the updated size every 50KB of downloaded data
958 LastNbOf50Kb
= Context
->LastReportedNbOfBytes
/ (50*1024);
959 NbOf50Kb
= Context
->DownloadedNbOfBytes
/ (50*1024);
960 if (NbOf50Kb
> LastNbOf50Kb
) {
961 Print (L
"\b\b\b\b\b\b\b\b\b\b");
962 UnicodeSPrint (Progress
, sizeof (Progress
), L
"%7d Kb", NbOfKb
);
963 Context
->LastReportedNbOfBytes
= Context
->DownloadedNbOfBytes
;
966 if (Progress
[0] != L
'\0') {
967 Print (L
"%s", Progress
);
975 Download an image from a TFTP server
977 @param[in] DevicePath Device path of the TFTP boot option
978 @param[in] ControllerHandle Handle of the network controller
979 @param[in] RemainingDevicePath Device path of the TFTP boot option but
980 the first node that identifies the network controller
981 @param[in] Type Type to allocate memory pages
982 @param[out] Image Address of the bufer where the image is stored in
984 @param[out] ImageSize Size in number of bytes of the i;age in case of
987 @retval EFI_SUCCESS The image was returned.
988 @retval !EFI_SUCCESS Something went wrong.
993 IN EFI_DEVICE_PATH
* DevicePath
,
994 IN EFI_HANDLE ControllerHandle
,
995 IN EFI_DEVICE_PATH
* RemainingDevicePath
,
996 IN EFI_ALLOCATE_TYPE Type
,
997 IN OUT EFI_PHYSICAL_ADDRESS
*Image
,
1002 EFI_HANDLE Dhcp4ChildHandle
;
1003 EFI_DHCP4_PROTOCOL
*Dhcp4
;
1004 BOOLEAN Dhcp4ToStop
;
1005 EFI_HANDLE Mtftp4ChildHandle
;
1006 EFI_MTFTP4_PROTOCOL
*Mtftp4
;
1007 EFI_DHCP4_CONFIG_DATA Dhcp4CfgData
;
1008 EFI_DHCP4_MODE_DATA Dhcp4Mode
;
1009 EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData
;
1010 IPv4_DEVICE_PATH
*IPv4DevicePathNode
;
1011 FILEPATH_DEVICE_PATH
*FilePathDevicePathNode
;
1012 CHAR8
*AsciiFilePath
;
1013 EFI_MTFTP4_TOKEN Mtftp4Token
;
1015 UINT64 TftpBufferSize
;
1016 BDS_TFTP_CONTEXT
*TftpContext
;
1018 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
));
1019 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)RemainingDevicePath
;
1021 Dhcp4ChildHandle
= NULL
;
1023 Dhcp4ToStop
= FALSE
;
1024 Mtftp4ChildHandle
= NULL
;
1026 AsciiFilePath
= NULL
;
1029 if (!IPv4DevicePathNode
->StaticIpAddress
) {
1031 // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
1032 // install the DHCP4 protocol on it. Then, open the DHCP protocol.
1034 Status
= NetLibCreateServiceChild (
1037 &gEfiDhcp4ServiceBindingProtocolGuid
,
1040 if (!EFI_ERROR (Status
)) {
1041 Status
= gBS
->OpenProtocol (
1043 &gEfiDhcp4ProtocolGuid
,
1047 EFI_OPEN_PROTOCOL_BY_DRIVER
1050 if (EFI_ERROR (Status
)) {
1051 Print (L
"Unable to open DHCP4 protocol\n");
1057 // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
1058 // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
1060 Status
= NetLibCreateServiceChild (
1063 &gEfiMtftp4ServiceBindingProtocolGuid
,
1066 if (!EFI_ERROR (Status
)) {
1067 Status
= gBS
->OpenProtocol (
1069 &gEfiMtftp4ProtocolGuid
,
1073 EFI_OPEN_PROTOCOL_BY_DRIVER
1076 if (EFI_ERROR (Status
)) {
1077 Print (L
"Unable to open MTFTP4 protocol\n");
1081 if (!IPv4DevicePathNode
->StaticIpAddress
) {
1083 // Configure the DHCP4, all default settings. It is acceptable for the configuration to
1084 // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
1085 // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
1086 // process has been started but is not completed yet.
1088 ZeroMem (&Dhcp4CfgData
, sizeof (EFI_DHCP4_CONFIG_DATA
));
1089 Status
= Dhcp4
->Configure (Dhcp4
, &Dhcp4CfgData
);
1090 if (EFI_ERROR (Status
)) {
1091 if (Status
!= EFI_ACCESS_DENIED
) {
1092 Print (L
"Error while configuring the DHCP4 protocol\n");
1098 // Start the DHCP configuration. This may have already been done thus do not leave in error
1099 // if the return code is EFI_ALREADY_STARTED.
1101 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
1102 if (EFI_ERROR (Status
)) {
1103 if (Status
!= EFI_ALREADY_STARTED
) {
1104 Print (L
"DHCP configuration failed\n");
1111 Status
= Dhcp4
->GetModeData (Dhcp4
, &Dhcp4Mode
);
1112 if (EFI_ERROR (Status
)) {
1116 if (Dhcp4Mode
.State
!= Dhcp4Bound
) {
1117 Status
= EFI_TIMEOUT
;
1118 Print (L
"DHCP configuration failed\n");
1124 // Configure the TFTP4 protocol
1127 ZeroMem (&Mtftp4CfgData
, sizeof (EFI_MTFTP4_CONFIG_DATA
));
1128 Mtftp4CfgData
.UseDefaultSetting
= FALSE
;
1129 Mtftp4CfgData
.TimeoutValue
= 4;
1130 Mtftp4CfgData
.TryCount
= 6;
1132 if (IPv4DevicePathNode
->StaticIpAddress
) {
1133 CopyMem (&Mtftp4CfgData
.StationIp
, &IPv4DevicePathNode
->LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1134 CopyMem (&Mtftp4CfgData
.SubnetMask
, &IPv4DevicePathNode
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1135 CopyMem (&Mtftp4CfgData
.GatewayIp
, &IPv4DevicePathNode
->GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1137 CopyMem (&Mtftp4CfgData
.StationIp
, &Dhcp4Mode
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
1138 CopyMem (&Mtftp4CfgData
.SubnetMask
, &Dhcp4Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1139 CopyMem (&Mtftp4CfgData
.GatewayIp
, &Dhcp4Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
1142 CopyMem (&Mtftp4CfgData
.ServerIp
, &IPv4DevicePathNode
->RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1144 Status
= Mtftp4
->Configure (Mtftp4
, &Mtftp4CfgData
);
1145 if (EFI_ERROR (Status
)) {
1146 Print (L
"Error while configuring the MTFTP4 protocol\n");
1151 // Convert the Unicode path of the file to Ascii
1154 FilePathDevicePathNode
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
1155 AsciiFilePath
= AllocatePool ((StrLen (FilePathDevicePathNode
->PathName
) + 1) * sizeof (CHAR8
));
1156 if (AsciiFilePath
== NULL
) {
1157 Status
= EFI_OUT_OF_RESOURCES
;
1160 UnicodeStrToAsciiStr (FilePathDevicePathNode
->PathName
, AsciiFilePath
);
1163 // Try to get the size of the file in bytes from the server. If it fails,
1164 // start with a 8MB buffer to download the file.
1167 if (Mtftp4GetFileSize (Mtftp4
, AsciiFilePath
, &FileSize
) == EFI_SUCCESS
) {
1168 TftpBufferSize
= FileSize
;
1170 TftpBufferSize
= SIZE_8MB
;
1173 TftpContext
= AllocatePool (sizeof (BDS_TFTP_CONTEXT
));
1174 if (TftpContext
== NULL
) {
1175 Status
= EFI_OUT_OF_RESOURCES
;
1178 TftpContext
->FileSize
= FileSize
;
1180 for (; TftpBufferSize
<= FixedPcdGet32 (PcdMaxTftpFileSize
);
1181 TftpBufferSize
= (TftpBufferSize
+ SIZE_8MB
) & (~(SIZE_8MB
-1))) {
1183 // Allocate a buffer to hold the whole file.
1185 Status
= gBS
->AllocatePages (
1187 EfiBootServicesCode
,
1188 EFI_SIZE_TO_PAGES (TftpBufferSize
),
1191 if (EFI_ERROR (Status
)) {
1192 Print (L
"Failed to allocate space for image\n");
1196 TftpContext
->DownloadedNbOfBytes
= 0;
1197 TftpContext
->LastReportedNbOfBytes
= 0;
1199 ZeroMem (&Mtftp4Token
, sizeof (EFI_MTFTP4_TOKEN
));
1200 Mtftp4Token
.Filename
= (UINT8
*)AsciiFilePath
;
1201 Mtftp4Token
.BufferSize
= TftpBufferSize
;
1202 Mtftp4Token
.Buffer
= (VOID
*)(UINTN
)*Image
;
1203 Mtftp4Token
.CheckPacket
= Mtftp4CheckPacket
;
1204 Mtftp4Token
.Context
= (VOID
*)TftpContext
;
1206 Print (L
"Downloading the file <%s> from the TFTP server\n", FilePathDevicePathNode
->PathName
);
1207 Status
= Mtftp4
->ReadFile (Mtftp4
, &Mtftp4Token
);
1209 if (EFI_ERROR (Status
)) {
1210 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1211 Print (L
"Downloading failed, file larger than expected.\n");
1212 gBS
->FreePages (*Image
, EFI_SIZE_TO_PAGES (TftpBufferSize
));
1219 *ImageSize
= Mtftp4Token
.BufferSize
;
1224 if (Dhcp4ChildHandle
!= NULL
) {
1225 if (Dhcp4
!= NULL
) {
1227 Dhcp4
->Stop (Dhcp4
);
1229 gBS
->CloseProtocol (
1231 &gEfiDhcp4ProtocolGuid
,
1236 NetLibDestroyServiceChild (
1239 &gEfiDhcp4ServiceBindingProtocolGuid
,
1244 if (Mtftp4ChildHandle
!= NULL
) {
1245 if (Mtftp4
!= NULL
) {
1246 if (AsciiFilePath
!= NULL
) {
1247 FreePool (AsciiFilePath
);
1249 if (TftpContext
!= NULL
) {
1250 FreePool (TftpContext
);
1252 gBS
->CloseProtocol (
1254 &gEfiMtftp4ProtocolGuid
,
1259 NetLibDestroyServiceChild (
1262 &gEfiMtftp4ServiceBindingProtocolGuid
,
1267 if (EFI_ERROR (Status
)) {
1268 Print (L
"Failed to download the file - Error=%r\n", Status
);
1274 BDS_FILE_LOADER FileLoaders
[] = {
1275 { BdsFileSystemSupport
, BdsFileSystemLoadImage
},
1276 { BdsFirmwareVolumeSupport
, BdsFirmwareVolumeLoadImage
},
1277 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
1278 { BdsMemoryMapSupport
, BdsMemoryMapLoadImage
},
1279 { BdsPxeSupport
, BdsPxeLoadImage
},
1280 { BdsTftpSupport
, BdsTftpLoadImage
},
1285 BdsLoadImageAndUpdateDevicePath (
1286 IN OUT EFI_DEVICE_PATH
**DevicePath
,
1287 IN EFI_ALLOCATE_TYPE Type
,
1288 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
1294 EFI_DEVICE_PATH
*RemainingDevicePath
;
1295 BDS_FILE_LOADER
* FileLoader
;
1297 Status
= BdsConnectAndUpdateDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
1298 if (EFI_ERROR (Status
)) {
1302 FileLoader
= FileLoaders
;
1303 while (FileLoader
->Support
!= NULL
) {
1304 if (FileLoader
->Support (*DevicePath
, Handle
, RemainingDevicePath
)) {
1305 return FileLoader
->LoadImage (*DevicePath
, Handle
, RemainingDevicePath
, Type
, Image
, FileSize
);
1310 return EFI_UNSUPPORTED
;
1315 IN EFI_DEVICE_PATH
*DevicePath
,
1316 IN EFI_ALLOCATE_TYPE Type
,
1317 IN OUT EFI_PHYSICAL_ADDRESS
* Image
,
1321 return BdsLoadImageAndUpdateDevicePath (&DevicePath
, Type
, Image
, FileSize
);
1325 Start an EFI Application from a Device Path
1327 @param ParentImageHandle Handle of the calling image
1328 @param DevicePath Location of the EFI Application
1330 @retval EFI_SUCCESS All drivers have been connected
1331 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
1332 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
1336 BdsStartEfiApplication (
1337 IN EFI_HANDLE ParentImageHandle
,
1338 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1339 IN UINTN LoadOptionsSize
,
1340 IN VOID
* LoadOptions
1344 EFI_HANDLE ImageHandle
;
1345 EFI_PHYSICAL_ADDRESS BinaryBuffer
;
1347 EFI_LOADED_IMAGE_PROTOCOL
* LoadedImage
;
1349 // Find the nearest supported file loader
1350 Status
= BdsLoadImageAndUpdateDevicePath (&DevicePath
, AllocateAnyPages
, &BinaryBuffer
, &BinarySize
);
1351 if (EFI_ERROR (Status
)) {
1355 // Load the image from the Buffer with Boot Services function
1356 Status
= gBS
->LoadImage (TRUE
, ParentImageHandle
, DevicePath
, (VOID
*)(UINTN
)BinaryBuffer
, BinarySize
, &ImageHandle
);
1357 if (EFI_ERROR (Status
)) {
1361 // Passed LoadOptions to the EFI Application
1362 if (LoadOptionsSize
!= 0) {
1363 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &LoadedImage
);
1364 if (EFI_ERROR (Status
)) {
1368 LoadedImage
->LoadOptionsSize
= LoadOptionsSize
;
1369 LoadedImage
->LoadOptions
= LoadOptions
;
1372 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
1373 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1375 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
1376 // Clear the Watchdog Timer after the image returns
1377 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);