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/BlockIo.h>
20 #include <Protocol/DevicePathToText.h>
21 #include <Protocol/FirmwareVolumeBlock.h>
22 #include <Protocol/PxeBaseCode.h>
23 #include <Protocol/SimpleFileSystem.h>
24 #include <Protocol/SimpleNetwork.h>
26 #include <Guid/FileSystemInfo.h>
28 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
31 BdsLoadOptionFileSystemList (
32 IN OUT LIST_ENTRY
* BdsLoadOptionList
36 BdsLoadOptionFileSystemCreateDevicePath (
38 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
42 BdsLoadOptionFileSystemUpdateDevicePath (
43 IN EFI_DEVICE_PATH
*OldDevicePath
,
45 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
49 BdsLoadOptionFileSystemIsSupported (
50 IN EFI_DEVICE_PATH
*DevicePath
54 BdsLoadOptionMemMapList (
55 IN OUT LIST_ENTRY
* BdsLoadOptionList
59 BdsLoadOptionMemMapCreateDevicePath (
61 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
65 BdsLoadOptionMemMapUpdateDevicePath (
66 IN EFI_DEVICE_PATH
*OldDevicePath
,
68 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
72 BdsLoadOptionMemMapIsSupported (
73 IN EFI_DEVICE_PATH
*DevicePath
77 BdsLoadOptionPxeList (
78 IN OUT LIST_ENTRY
* BdsLoadOptionList
82 BdsLoadOptionPxeCreateDevicePath (
84 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
88 BdsLoadOptionPxeUpdateDevicePath (
89 IN EFI_DEVICE_PATH
*OldDevicePath
,
91 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
95 BdsLoadOptionPxeIsSupported (
96 IN EFI_DEVICE_PATH
*DevicePath
100 BdsLoadOptionTftpList (
101 IN OUT LIST_ENTRY
* BdsLoadOptionList
105 BdsLoadOptionTftpCreateDevicePath (
107 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
111 BdsLoadOptionTftpUpdateDevicePath (
112 IN EFI_DEVICE_PATH
*OldDevicePath
,
114 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
118 BdsLoadOptionTftpIsSupported (
119 IN EFI_DEVICE_PATH
*DevicePath
122 BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList
[] = {
124 BDS_DEVICE_FILESYSTEM
,
125 BdsLoadOptionFileSystemList
,
126 BdsLoadOptionFileSystemIsSupported
,
127 BdsLoadOptionFileSystemCreateDevicePath
,
128 BdsLoadOptionFileSystemUpdateDevicePath
,
133 BdsLoadOptionMemMapList
,
134 BdsLoadOptionMemMapIsSupported
,
135 BdsLoadOptionMemMapCreateDevicePath
,
136 BdsLoadOptionMemMapUpdateDevicePath
,
141 BdsLoadOptionPxeList
,
142 BdsLoadOptionPxeIsSupported
,
143 BdsLoadOptionPxeCreateDevicePath
,
144 BdsLoadOptionPxeUpdateDevicePath
,
149 BdsLoadOptionTftpList
,
150 BdsLoadOptionTftpIsSupported
,
151 BdsLoadOptionTftpCreateDevicePath
,
152 BdsLoadOptionTftpUpdateDevicePath
,
158 BootDeviceListSupportedInit (
159 IN OUT LIST_ENTRY
*SupportedDeviceList
164 // Initialize list of supported devices
165 InitializeListHead (SupportedDeviceList
);
167 for (Index
= 0; Index
< BDS_DEVICE_MAX
; Index
++) {
168 BdsLoadOptionSupportList
[Index
].ListDevices (SupportedDeviceList
);
175 BootDeviceListSupportedFree (
176 IN LIST_ENTRY
*SupportedDeviceList
,
177 IN BDS_SUPPORTED_DEVICE
*Except
181 BDS_SUPPORTED_DEVICE
* SupportedDevice
;
183 Entry
= GetFirstNode (SupportedDeviceList
);
184 while (Entry
!= SupportedDeviceList
) {
185 SupportedDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
186 Entry
= RemoveEntryList (Entry
);
187 if (SupportedDevice
!= Except
) {
188 FreePool (SupportedDevice
);
196 BootDeviceGetDeviceSupport (
197 IN EFI_DEVICE_PATH
*DevicePath
,
198 OUT BDS_LOAD_OPTION_SUPPORT
**DeviceSupport
203 // Find which supported device is the most appropriate
204 for (Index
= 0; Index
< BDS_DEVICE_MAX
; Index
++) {
205 if (BdsLoadOptionSupportList
[Index
].IsSupported (DevicePath
)) {
206 *DeviceSupport
= &BdsLoadOptionSupportList
[Index
];
211 return EFI_UNSUPPORTED
;
216 IN EFI_DEVICE_PATH
* DevicePath
,
217 OUT ARM_BDS_LOADER_TYPE
*BootType
,
218 OUT UINT32
*Attributes
223 BOOLEAN IsBootLoader
;
224 BOOLEAN HasFDTSupport
;
226 EFI_DEVICE_PATH
* PrevDevicePathNode
;
227 EFI_DEVICE_PATH
* DevicePathNode
;
228 EFI_PHYSICAL_ADDRESS Image
;
230 EFI_IMAGE_DOS_HEADER
* DosHeader
;
231 UINTN PeCoffHeaderOffset
;
232 EFI_IMAGE_NT_HEADERS32
* NtHeader
;
235 // Check if the last node of the device path is a FilePath node
237 PrevDevicePathNode
= NULL
;
238 DevicePathNode
= DevicePath
;
239 while ((DevicePathNode
!= NULL
) && !IsDevicePathEnd (DevicePathNode
)) {
240 PrevDevicePathNode
= DevicePathNode
;
241 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
244 if ((PrevDevicePathNode
!= NULL
) &&
245 (PrevDevicePathNode
->Type
== MEDIA_DEVICE_PATH
) &&
246 (PrevDevicePathNode
->SubType
== MEDIA_FILEPATH_DP
))
248 FileName
= ((FILEPATH_DEVICE_PATH
*)PrevDevicePathNode
)->PathName
;
253 if (FileName
== NULL
) {
254 Print(L
"Is an EFI Application? ");
255 Status
= GetHIInputBoolean (&IsEfiApp
);
256 if (EFI_ERROR(Status
)) {
259 } else if (HasFilePathEfiExtension(FileName
)) {
262 // Check if the file exist
263 Status
= BdsLoadImage (DevicePath
, AllocateAnyPages
, &Image
, &FileSize
);
264 if (!EFI_ERROR (Status
)) {
266 DosHeader
= (EFI_IMAGE_DOS_HEADER
*)(UINTN
) Image
;
267 if (DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
269 // DOS image header is present,
270 // so read the PE header after the DOS image header.
272 PeCoffHeaderOffset
= DosHeader
->e_lfanew
;
274 PeCoffHeaderOffset
= 0;
278 // Check PE/COFF image.
280 NtHeader
= (EFI_IMAGE_NT_HEADERS32
*)(UINTN
) (Image
+ PeCoffHeaderOffset
);
281 if (NtHeader
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
288 gBS
->FreePages (Image
, EFI_SIZE_TO_PAGES(FileSize
));
290 // If we did not manage to open it then ask for the type
291 Print(L
"Is an EFI Application? ");
292 Status
= GetHIInputBoolean (&IsEfiApp
);
293 if (EFI_ERROR(Status
)) {
300 Print(L
"Is your application an OS loader? ");
301 Status
= GetHIInputBoolean (&IsBootLoader
);
302 if (EFI_ERROR(Status
)) {
306 *Attributes
|= LOAD_OPTION_CATEGORY_APP
;
308 *BootType
= BDS_LOADER_EFI_APPLICATION
;
310 Print(L
"Has FDT support? ");
311 Status
= GetHIInputBoolean (&HasFDTSupport
);
312 if (EFI_ERROR(Status
)) {
316 *BootType
= BDS_LOADER_KERNEL_LINUX_FDT
;
318 *BootType
= BDS_LOADER_KERNEL_LINUX_ATAG
;
326 BdsLoadOptionFileSystemList (
327 IN OUT LIST_ENTRY
* BdsLoadOptionList
332 EFI_HANDLE
*HandleBuffer
;
334 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
335 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
* FileProtocol
;
338 EFI_FILE_SYSTEM_INFO
* FsInfo
;
339 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
341 // List all the Simple File System Protocols
342 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
343 if (EFI_ERROR (Status
)) {
347 for (Index
= 0; Index
< HandleCount
; Index
++) {
348 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
349 if (!EFI_ERROR(Status
)) {
350 // Allocate BDS Supported Device structure
351 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE
));
354 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FileProtocol
);
355 ASSERT_EFI_ERROR(Status
);
357 FileProtocol
->OpenVolume (FileProtocol
, &Fs
);
359 // Generate a Description from the file system
362 Status
= Fs
->GetInfo (Fs
, &gEfiFileSystemInfoGuid
, &Size
, FsInfo
);
363 if (Status
== EFI_BUFFER_TOO_SMALL
) {
364 FsInfo
= AllocatePool (Size
);
365 Status
= Fs
->GetInfo (Fs
, &gEfiFileSystemInfoGuid
, &Size
, FsInfo
);
367 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"%s (%d MB)",FsInfo
->VolumeLabel
,(UINT32
)(FsInfo
->VolumeSize
/ (1024 * 1024)));
371 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
372 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_FILESYSTEM
];
374 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
382 BdsLoadOptionFileSystemCreateDevicePath (
384 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
388 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
389 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
390 UINTN BootFilePathSize
;
392 Print(L
"File path of the %s: ", FileName
);
393 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
394 if (EFI_ERROR(Status
)) {
398 BootFilePathSize
= StrSize (BootFilePath
);
399 if (BootFilePathSize
== 2) {
400 *DevicePathNodes
= NULL
;
401 return EFI_NOT_FOUND
;
404 // Create the FilePath Device Path node
405 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
406 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
407 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
408 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
409 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
410 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
411 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)FilePathDevicePath
;
417 BdsLoadOptionFileSystemUpdateDevicePath (
418 IN EFI_DEVICE_PATH
*OldDevicePath
,
420 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
424 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
425 UINTN BootFilePathSize
;
426 FILEPATH_DEVICE_PATH
* EndingDevicePath
;
427 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
428 EFI_DEVICE_PATH
* DevicePath
;
430 DevicePath
= DuplicateDevicePath (OldDevicePath
);
432 EndingDevicePath
= (FILEPATH_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
434 Print(L
"File path of the %s: ", FileName
);
435 StrnCpy (BootFilePath
, EndingDevicePath
->PathName
, BOOT_DEVICE_FILEPATH_MAX
);
436 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
437 if (EFI_ERROR(Status
)) {
441 BootFilePathSize
= StrSize(BootFilePath
);
442 if (BootFilePathSize
== 2) {
443 *NewDevicePath
= NULL
;
444 return EFI_NOT_FOUND
;
447 // Create the FilePath Device Path node
448 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
449 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
450 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
451 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
452 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
454 // Generate the new Device Path by replacing the last node by the updated node
455 SetDevicePathEndNode (EndingDevicePath
);
456 *NewDevicePath
= AppendDevicePathNode (DevicePath
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)FilePathDevicePath
);
457 FreePool(DevicePath
);
463 Check if a boot option path is a file system boot option path or not.
465 The device specified by the beginning of the path has to support the Simple File
466 System protocol. Furthermore, the remaining part of the path has to be composed of
467 a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP.
469 @param[in] DevicePath Complete device path of a boot option.
471 @retval FALSE The boot option path has not been identified as that of a
472 file system boot option.
473 @retval TRUE The boot option path is a file system boot option.
476 BdsLoadOptionFileSystemIsSupported (
477 IN EFI_DEVICE_PATH
*DevicePath
482 EFI_DEVICE_PATH
*RemainingDevicePath
;
483 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FileProtocol
;
485 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
486 if (EFI_ERROR (Status
)) {
490 Status
= gBS
->HandleProtocol (
492 &gEfiSimpleFileSystemProtocolGuid
,
493 (VOID
**)(&FileProtocol
)
495 if (EFI_ERROR (Status
)) {
499 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
))
508 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
509 IN EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePath
515 ParentSize
= GetDevicePathSize (ParentDevicePath
);
516 ChildSize
= GetDevicePathSize (ChildDevicePath
);
518 if (ParentSize
> ChildSize
) {
522 if (CompareMem (ParentDevicePath
, ChildDevicePath
, ParentSize
- END_DEVICE_PATH_LENGTH
) != 0) {
530 BdsLoadOptionMemMapList (
531 IN OUT LIST_ENTRY
* BdsLoadOptionList
536 EFI_HANDLE
*HandleBuffer
;
537 UINTN DevicePathHandleCount
;
538 EFI_HANDLE
*DevicePathHandleBuffer
;
542 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
543 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
544 EFI_DEVICE_PATH
* DevicePath
;
545 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FileProtocol
;
546 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
548 // List all the BlockIo Protocols
549 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
550 if (EFI_ERROR (Status
)) {
554 for (Index
= 0; Index
< HandleCount
; Index
++) {
555 // We only select handles WITH a Device Path AND not part of Media (to
556 // avoid duplication with HardDisk, CDROM, etc). Skip handles used by
557 // Simple Filesystem or used for Variable Storage.
560 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
],
561 &gEfiSimpleFileSystemProtocolGuid
,
562 (VOID
*)&FileProtocol
);
563 if (!EFI_ERROR(Status
)) {
564 // SimpleFilesystem supported on this handle, skip
568 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
],
569 &gEfiFirmwareVolumeBlockProtocolGuid
,
570 (VOID
*)&FvbProtocol
);
571 if (!EFI_ERROR(Status
)) {
572 // Firmware Volme Block / Variable storage supported on this handle, skip
576 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
],
577 &gEfiFirmwareVolumeBlock2ProtocolGuid
,
578 (VOID
*)&FvbProtocol
);
579 if (!EFI_ERROR(Status
)) {
580 // Firmware Volme Block / Variable storage supported on this handle, skip
584 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
585 if (!EFI_ERROR(Status
)) {
586 // BlockIo is not part of Media Device Path
587 DevicePath
= DevicePathProtocol
;
588 while (!IsDevicePathEndType (DevicePath
) && (DevicePathType (DevicePath
) != MEDIA_DEVICE_PATH
)) {
589 DevicePath
= NextDevicePathNode (DevicePath
);
591 if (DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) {
595 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
596 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDevicePathProtocolGuid
, NULL
, &DevicePathHandleCount
, &DevicePathHandleBuffer
);
597 ASSERT_EFI_ERROR (Status
);
599 for (Index2
= 0; (Index2
< DevicePathHandleCount
) && !IsParent
; Index2
++) {
600 if (HandleBuffer
[Index
] != DevicePathHandleBuffer
[Index2
]) {
601 gBS
->HandleProtocol (DevicePathHandleBuffer
[Index2
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
602 if (IsParentDevicePath (DevicePathProtocol
, DevicePath
)) {
611 // Allocate BDS Supported Device structure
612 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
614 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], SupportedDevice
->Description
);
615 ASSERT_EFI_ERROR (Status
);
617 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
618 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_MEMMAP
];
620 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
628 BdsLoadOptionMemMapCreateDevicePath (
630 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
634 MEMMAP_DEVICE_PATH
*MemMapDevicePath
;
635 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
636 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
638 Print(L
"Starting Address of the %s: ", FileName
);
639 Status
= GetHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
640 if (EFI_ERROR(Status
)) {
644 Print(L
"Ending Address of the %s: ", FileName
);
645 Status
= GetHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
646 if (EFI_ERROR(Status
)) {
650 // Create the MemMap Device Path Node
651 MemMapDevicePath
= (MEMMAP_DEVICE_PATH
*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH
) + END_DEVICE_PATH_LENGTH
);
652 MemMapDevicePath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
653 MemMapDevicePath
->Header
.SubType
= HW_MEMMAP_DP
;
654 SetDevicePathNodeLength (MemMapDevicePath
, sizeof(MEMMAP_DEVICE_PATH
));
655 MemMapDevicePath
->MemoryType
= EfiBootServicesData
;
656 MemMapDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
657 MemMapDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
659 // Set a Device Path End Node after the Memory Map Device Path Node
660 SetDevicePathEndNode (MemMapDevicePath
+ 1);
661 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)MemMapDevicePath
;
667 BdsLoadOptionMemMapUpdateDevicePath (
668 IN EFI_DEVICE_PATH
*OldDevicePath
,
670 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
674 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
675 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
676 MEMMAP_DEVICE_PATH
* EndingDevicePath
;
677 EFI_DEVICE_PATH
* DevicePath
;
679 DevicePath
= DuplicateDevicePath (OldDevicePath
);
680 EndingDevicePath
= (MEMMAP_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
682 Print(L
"Starting Address of the %s: ", FileName
);
683 UnicodeSPrint (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->StartingAddress
);
684 Status
= EditHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
685 if (EFI_ERROR(Status
)) {
689 Print(L
"Ending Address of the %s: ", FileName
);
690 UnicodeSPrint (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->EndingAddress
);
691 Status
= EditHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
692 if (EFI_ERROR(Status
)) {
696 EndingDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
697 EndingDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
699 if (EFI_ERROR(Status
)) {
700 FreePool(DevicePath
);
702 *NewDevicePath
= DevicePath
;
709 Check if a boot option path is a memory map boot option path or not.
711 The device specified by the beginning of the path has to support the BlockIo
712 protocol. Furthermore, the remaining part of the path has to be composed of
713 a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP.
715 @param[in] DevicePath Complete device path of a boot option.
717 @retval FALSE The boot option path has not been identified as that of a
718 memory map boot option.
719 @retval TRUE The boot option path is a a memory map boot option.
722 BdsLoadOptionMemMapIsSupported (
723 IN EFI_DEVICE_PATH
*DevicePath
728 EFI_DEVICE_PATH
*RemainingDevicePath
;
729 EFI_BLOCK_IO_PROTOCOL
*BlockIoProtocol
;
731 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
732 if (EFI_ERROR (Status
)) {
736 Status
= gBS
->HandleProtocol (
738 &gEfiBlockIoProtocolGuid
,
739 (VOID
**)(&BlockIoProtocol
)
741 if (EFI_ERROR (Status
)) {
745 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
))
752 BdsLoadOptionPxeList (
753 IN OUT LIST_ENTRY
* BdsLoadOptionList
758 EFI_HANDLE
*HandleBuffer
;
760 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
761 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
762 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
763 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
764 EFI_MAC_ADDRESS
*Mac
;
766 // List all the PXE Protocols
767 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
768 if (EFI_ERROR (Status
)) {
772 for (Index
= 0; Index
< HandleCount
; Index
++) {
773 // We only select the handle WITH a Device Path AND the PXE Protocol
774 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
775 if (!EFI_ERROR(Status
)) {
776 // Allocate BDS Supported Device structure
777 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
779 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&SimpleNet
);
780 if (!EFI_ERROR(Status
)) {
781 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
782 UnicodeSPrint (DeviceDescription
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac
->Addr
[0], Mac
->Addr
[1], Mac
->Addr
[2], Mac
->Addr
[3], Mac
->Addr
[4], Mac
->Addr
[5]);
784 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
785 ASSERT_EFI_ERROR (Status
);
787 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"PXE on %s",DeviceDescription
);
789 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
790 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_PXE
];
792 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
800 BdsLoadOptionPxeCreateDevicePath (
802 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
805 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocatePool (END_DEVICE_PATH_LENGTH
);
806 SetDevicePathEndNode (*DevicePathNodes
);
812 Update the parameters of a Pxe boot option
814 @param[in] OldDevicePath Current complete device path of the Pxe boot option.
815 This has to be a valid complete Pxe boot option path.
816 @param[in] FileName Description of the file the path is asked for
817 @param[out] NewDevicePath Pointer to the new complete device path.
819 @retval EFI_SUCCESS Update completed
820 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
823 BdsLoadOptionPxeUpdateDevicePath (
824 IN EFI_DEVICE_PATH
*OldDevicePath
,
826 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
830 // Make a copy of the complete device path that is made of :
831 // the device path of the device supporting the Pxe base code protocol
832 // followed by an end node.
834 *NewDevicePath
= DuplicateDevicePath (OldDevicePath
);
835 if (*NewDevicePath
== NULL
) {
836 return EFI_OUT_OF_RESOURCES
;
843 BdsLoadOptionPxeIsSupported (
844 IN EFI_DEVICE_PATH
*DevicePath
849 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
850 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
852 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
853 if (EFI_ERROR(Status
)) {
857 if (!IsDevicePathEnd(RemainingDevicePath
)) {
861 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
862 if (EFI_ERROR (Status
)) {
870 BdsLoadOptionTftpList (
871 IN OUT LIST_ENTRY
* BdsLoadOptionList
876 EFI_HANDLE
*HandleBuffer
;
878 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
879 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
880 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
881 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
882 EFI_MAC_ADDRESS
*Mac
;
884 // List all the PXE Protocols
885 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
886 if (EFI_ERROR (Status
)) {
890 for (Index
= 0; Index
< HandleCount
; Index
++) {
891 // We only select the handle WITH a Device Path AND the PXE Protocol AND the TFTP Protocol (the TFTP protocol is required to start PXE)
892 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
893 if (!EFI_ERROR(Status
)) {
894 // Allocate BDS Supported Device structure
895 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
897 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&SimpleNet
);
898 if (!EFI_ERROR(Status
)) {
899 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
900 UnicodeSPrint (DeviceDescription
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac
->Addr
[0], Mac
->Addr
[1], Mac
->Addr
[2], Mac
->Addr
[3], Mac
->Addr
[4], Mac
->Addr
[5]);
902 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
903 ASSERT_EFI_ERROR (Status
);
905 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"TFTP on %s",DeviceDescription
);
907 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
908 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_TFTP
];
910 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
918 BdsLoadOptionTftpCreateDevicePath (
920 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
925 EFI_IP_ADDRESS LocalIp
;
926 EFI_IP_ADDRESS RemoteIp
;
927 IPv4_DEVICE_PATH
* IPv4DevicePathNode
;
928 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
929 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
930 UINTN BootFilePathSize
;
932 Print(L
"Get the IP address from DHCP: ");
933 Status
= GetHIInputBoolean (&IsDHCP
);
934 if (EFI_ERROR(Status
)) {
939 Print(L
"Get the static IP address: ");
940 Status
= GetHIInputIP (&LocalIp
);
941 if (EFI_ERROR(Status
)) {
946 Print(L
"Get the TFTP server IP address: ");
947 Status
= GetHIInputIP (&RemoteIp
);
948 if (EFI_ERROR(Status
)) {
952 Print(L
"File path of the %s : ", FileName
);
953 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
954 if (EFI_ERROR(Status
)) {
958 BootFilePathSize
= StrSize(BootFilePath
);
959 if (BootFilePathSize
== 2) {
960 return EFI_NOT_FOUND
;
963 // Allocate the memory for the IPv4 + File Path Device Path Nodes
964 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)AllocatePool(sizeof(IPv4_DEVICE_PATH
) + SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
966 // Create the IPv4 Device Path
967 IPv4DevicePathNode
->Header
.Type
= MESSAGING_DEVICE_PATH
;
968 IPv4DevicePathNode
->Header
.SubType
= MSG_IPv4_DP
;
969 SetDevicePathNodeLength (&IPv4DevicePathNode
->Header
, sizeof(IPv4_DEVICE_PATH
));
970 CopyMem (&IPv4DevicePathNode
->LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
971 CopyMem (&IPv4DevicePathNode
->RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
972 IPv4DevicePathNode
->LocalPort
= 0;
973 IPv4DevicePathNode
->RemotePort
= 0;
974 IPv4DevicePathNode
->Protocol
= EFI_IP_PROTO_TCP
;
975 IPv4DevicePathNode
->StaticIpAddress
= (IsDHCP
!= TRUE
);
977 // Create the FilePath Device Path node
978 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
979 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
980 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
981 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
982 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
984 // Set the End Device Path Node
985 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
986 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)IPv4DevicePathNode
;
992 Update the parameters of a TFTP boot option
994 The function asks sequentially to update the IPv4 parameters as well as the boot file path,
995 providing the previously set value if any.
997 @param[in] OldDevicePath Current complete device path of the Tftp boot option.
998 This has to be a valid complete Tftp boot option path.
999 By complete, we mean that it is not only the Tftp
1000 specific end part built by the
1001 "BdsLoadOptionTftpCreateDevicePath()" function.
1002 This path is handled as read only.
1003 @param[in] FileName Description of the file the path is asked for
1004 @param[out] NewDevicePath Pointer to the new complete device path.
1006 @retval EFI_SUCCESS Update completed
1007 @retval EFI_ABORTED Update aborted by the user
1008 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
1011 BdsLoadOptionTftpUpdateDevicePath (
1012 IN EFI_DEVICE_PATH
*OldDevicePath
,
1013 IN CHAR16
*FileName
,
1014 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
1018 EFI_DEVICE_PATH
*DevicePath
;
1019 EFI_DEVICE_PATH
*DevicePathNode
;
1021 IPv4_DEVICE_PATH Ipv4Node
;
1023 EFI_IP_ADDRESS OldIp
;
1024 EFI_IP_ADDRESS LocalIp
;
1025 EFI_IP_ADDRESS RemoteIp
;
1027 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
1029 UINTN BootFilePathSize
;
1030 FILEPATH_DEVICE_PATH
*NewFilePathNode
;
1035 // Make a copy of the complete device path that is made of :
1036 // the device path of the device that support the Simple Network protocol
1037 // followed by an IPv4 node (type IPv4_DEVICE_PATH),
1038 // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up
1039 // by an end node. The IPv6 case is not handled yet.
1042 DevicePath
= DuplicateDevicePath (OldDevicePath
);
1043 if (DevicePath
== NULL
) {
1044 Status
= EFI_OUT_OF_RESOURCES
;
1049 // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the
1050 // call to this function, we know that the device path ends with an IPv4 node
1051 // followed by a file path node and finally an end node. To get the address of
1052 // the last IPv4 node, we loop over the whole device path, noting down the
1053 // address of each encountered IPv4 node.
1056 for (DevicePathNode
= DevicePath
;
1057 !IsDevicePathEnd (DevicePathNode
);
1058 DevicePathNode
= NextDevicePathNode (DevicePathNode
))
1060 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
)) {
1061 Ipv4NodePtr
= (UINT8
*)DevicePathNode
;
1065 // Copy for alignment of the IPv4 node data
1066 CopyMem (&Ipv4Node
, Ipv4NodePtr
, sizeof (IPv4_DEVICE_PATH
));
1068 Print (L
"Get the IP address from DHCP: ");
1069 Status
= GetHIInputBoolean (&IsDHCP
);
1070 if (EFI_ERROR (Status
)) {
1075 Print (L
"Local static IP address: ");
1076 if (Ipv4Node
.StaticIpAddress
) {
1077 // Copy local IPv4 address into IPv4 or IPv6 union
1078 CopyMem (&OldIp
.v4
, &Ipv4Node
.LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1080 Status
= EditHIInputIP (&OldIp
, &LocalIp
);
1082 Status
= GetHIInputIP (&LocalIp
);
1084 if (EFI_ERROR (Status
)) {
1089 Print (L
"TFTP server IP address: ");
1090 // Copy remote IPv4 address into IPv4 or IPv6 union
1091 CopyMem (&OldIp
.v4
, &Ipv4Node
.RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1093 Status
= EditHIInputIP (&OldIp
, &RemoteIp
);
1094 if (EFI_ERROR (Status
)) {
1098 // Get the path of the boot file and its size in number of bytes
1099 FileNodePtr
= Ipv4NodePtr
+ sizeof (IPv4_DEVICE_PATH
);
1100 BootFilePathSize
= DevicePathNodeLength (FileNodePtr
) - SIZE_OF_FILEPATH_DEVICE_PATH
;
1103 // Ask for update of the boot file path
1106 // Copy for 2-byte alignment of the Unicode string
1108 BootFilePath
, FileNodePtr
+ SIZE_OF_FILEPATH_DEVICE_PATH
,
1109 MIN (BootFilePathSize
, BOOT_DEVICE_FILEPATH_MAX
)
1111 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
- 1] = L
'\0';
1113 Print (L
"File path of the %s: ", FileName
);
1114 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
1115 if (EFI_ERROR (Status
)) {
1118 PathSize
= StrSize (BootFilePath
);
1122 // Empty string, give the user another try
1123 Print (L
"Empty string - Invalid path\n");
1124 } while (PathSize
<= 2) ;
1127 // Update the IPv4 node. IPv6 case not handled yet.
1129 if (IsDHCP
== TRUE
) {
1130 Ipv4Node
.StaticIpAddress
= FALSE
;
1132 Ipv4Node
.StaticIpAddress
= TRUE
;
1134 CopyMem (&Ipv4Node
.LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1135 CopyMem (&Ipv4Node
.RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1136 CopyMem (Ipv4NodePtr
, &Ipv4Node
, sizeof (IPv4_DEVICE_PATH
));
1139 // Create the new file path node
1141 NewFilePathNode
= (FILEPATH_DEVICE_PATH
*)AllocatePool (
1142 SIZE_OF_FILEPATH_DEVICE_PATH
+
1145 NewFilePathNode
->Header
.Type
= MEDIA_DEVICE_PATH
;
1146 NewFilePathNode
->Header
.SubType
= MEDIA_FILEPATH_DP
;
1147 SetDevicePathNodeLength (
1149 SIZE_OF_FILEPATH_DEVICE_PATH
+ PathSize
1151 CopyMem (NewFilePathNode
->PathName
, BootFilePath
, PathSize
);
1154 // Generate the new Device Path by replacing the file path node at address
1155 // "FileNodePtr" by the new one "NewFilePathNode" and return its address.
1157 SetDevicePathEndNode (FileNodePtr
);
1158 *NewDevicePath
= AppendDevicePathNode (
1160 (CONST EFI_DEVICE_PATH_PROTOCOL
*)NewFilePathNode
1164 if (DevicePath
!= NULL
) {
1165 FreePool (DevicePath
) ;
1172 BdsLoadOptionTftpIsSupported (
1173 IN EFI_DEVICE_PATH
*DevicePath
1178 EFI_DEVICE_PATH
*RemainingDevicePath
;
1179 EFI_DEVICE_PATH
*NextDevicePath
;
1180 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
1182 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
1183 if (EFI_ERROR(Status
)) {
1187 // Validate the Remaining Device Path
1188 if (IsDevicePathEnd(RemainingDevicePath
)) {
1191 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
) &&
1192 !IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv6_DP
)) {
1195 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
1196 if (IsDevicePathEnd(NextDevicePath
)) {
1199 if (!IS_DEVICE_PATH_NODE(NextDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
)) {
1203 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
1204 if (EFI_ERROR (Status
)) {