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/PxeBaseCode.h>
22 #include <Protocol/SimpleFileSystem.h>
23 #include <Protocol/SimpleNetwork.h>
25 #include <Guid/FileSystemInfo.h>
27 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
30 BdsLoadOptionFileSystemList (
31 IN OUT LIST_ENTRY
* BdsLoadOptionList
35 BdsLoadOptionFileSystemCreateDevicePath (
37 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
41 BdsLoadOptionFileSystemUpdateDevicePath (
42 IN EFI_DEVICE_PATH
*OldDevicePath
,
44 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
48 BdsLoadOptionFileSystemIsSupported (
49 IN EFI_DEVICE_PATH
*DevicePath
53 BdsLoadOptionMemMapList (
54 IN OUT LIST_ENTRY
* BdsLoadOptionList
58 BdsLoadOptionMemMapCreateDevicePath (
60 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
64 BdsLoadOptionMemMapUpdateDevicePath (
65 IN EFI_DEVICE_PATH
*OldDevicePath
,
67 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
71 BdsLoadOptionMemMapIsSupported (
72 IN EFI_DEVICE_PATH
*DevicePath
76 BdsLoadOptionPxeList (
77 IN OUT LIST_ENTRY
* BdsLoadOptionList
81 BdsLoadOptionPxeCreateDevicePath (
83 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
87 BdsLoadOptionPxeUpdateDevicePath (
88 IN EFI_DEVICE_PATH
*OldDevicePath
,
90 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
94 BdsLoadOptionPxeIsSupported (
95 IN EFI_DEVICE_PATH
*DevicePath
99 BdsLoadOptionTftpList (
100 IN OUT LIST_ENTRY
* BdsLoadOptionList
104 BdsLoadOptionTftpCreateDevicePath (
106 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
110 BdsLoadOptionTftpUpdateDevicePath (
111 IN EFI_DEVICE_PATH
*OldDevicePath
,
113 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
117 BdsLoadOptionTftpIsSupported (
118 IN EFI_DEVICE_PATH
*DevicePath
121 BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList
[] = {
123 BDS_DEVICE_FILESYSTEM
,
124 BdsLoadOptionFileSystemList
,
125 BdsLoadOptionFileSystemIsSupported
,
126 BdsLoadOptionFileSystemCreateDevicePath
,
127 BdsLoadOptionFileSystemUpdateDevicePath
,
132 BdsLoadOptionMemMapList
,
133 BdsLoadOptionMemMapIsSupported
,
134 BdsLoadOptionMemMapCreateDevicePath
,
135 BdsLoadOptionMemMapUpdateDevicePath
,
140 BdsLoadOptionPxeList
,
141 BdsLoadOptionPxeIsSupported
,
142 BdsLoadOptionPxeCreateDevicePath
,
143 BdsLoadOptionPxeUpdateDevicePath
,
148 BdsLoadOptionTftpList
,
149 BdsLoadOptionTftpIsSupported
,
150 BdsLoadOptionTftpCreateDevicePath
,
151 BdsLoadOptionTftpUpdateDevicePath
,
157 BootDeviceListSupportedInit (
158 IN OUT LIST_ENTRY
*SupportedDeviceList
163 // Initialize list of supported devices
164 InitializeListHead (SupportedDeviceList
);
166 for (Index
= 0; Index
< BDS_DEVICE_MAX
; Index
++) {
167 BdsLoadOptionSupportList
[Index
].ListDevices (SupportedDeviceList
);
174 BootDeviceListSupportedFree (
175 IN LIST_ENTRY
*SupportedDeviceList
,
176 IN BDS_SUPPORTED_DEVICE
*Except
180 BDS_SUPPORTED_DEVICE
* SupportedDevice
;
182 Entry
= GetFirstNode (SupportedDeviceList
);
183 while (Entry
!= SupportedDeviceList
) {
184 SupportedDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
185 Entry
= RemoveEntryList (Entry
);
186 if (SupportedDevice
!= Except
) {
187 FreePool (SupportedDevice
);
195 BootDeviceGetDeviceSupport (
196 IN EFI_DEVICE_PATH
*DevicePath
,
197 OUT BDS_LOAD_OPTION_SUPPORT
**DeviceSupport
202 // Find which supported device is the most appropriate
203 for (Index
= 0; Index
< BDS_DEVICE_MAX
; Index
++) {
204 if (BdsLoadOptionSupportList
[Index
].IsSupported (DevicePath
)) {
205 *DeviceSupport
= &BdsLoadOptionSupportList
[Index
];
210 return EFI_UNSUPPORTED
;
215 IN EFI_DEVICE_PATH
* DevicePath
,
216 OUT ARM_BDS_LOADER_TYPE
*BootType
,
217 OUT UINT32
*Attributes
222 BOOLEAN IsBootLoader
;
223 BOOLEAN HasFDTSupport
;
225 EFI_DEVICE_PATH
* PrevDevicePathNode
;
226 EFI_DEVICE_PATH
* DevicePathNode
;
227 EFI_PHYSICAL_ADDRESS Image
;
229 EFI_IMAGE_DOS_HEADER
* DosHeader
;
230 UINTN PeCoffHeaderOffset
;
231 EFI_IMAGE_NT_HEADERS32
* NtHeader
;
234 // Check if the last node of the device path is a FilePath node
236 PrevDevicePathNode
= NULL
;
237 DevicePathNode
= DevicePath
;
238 while ((DevicePathNode
!= NULL
) && !IsDevicePathEnd (DevicePathNode
)) {
239 PrevDevicePathNode
= DevicePathNode
;
240 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
243 if ((PrevDevicePathNode
!= NULL
) &&
244 (PrevDevicePathNode
->Type
== MEDIA_DEVICE_PATH
) &&
245 (PrevDevicePathNode
->SubType
== MEDIA_FILEPATH_DP
))
247 FileName
= ((FILEPATH_DEVICE_PATH
*)PrevDevicePathNode
)->PathName
;
252 if (FileName
== NULL
) {
253 Print(L
"Is an EFI Application? ");
254 Status
= GetHIInputBoolean (&IsEfiApp
);
255 if (EFI_ERROR(Status
)) {
258 } else if (HasFilePathEfiExtension(FileName
)) {
261 // Check if the file exist
262 Status
= BdsLoadImage (DevicePath
, AllocateAnyPages
, &Image
, &FileSize
);
263 if (!EFI_ERROR (Status
)) {
265 DosHeader
= (EFI_IMAGE_DOS_HEADER
*)(UINTN
) Image
;
266 if (DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
268 // DOS image header is present,
269 // so read the PE header after the DOS image header.
271 PeCoffHeaderOffset
= DosHeader
->e_lfanew
;
273 PeCoffHeaderOffset
= 0;
277 // Check PE/COFF image.
279 NtHeader
= (EFI_IMAGE_NT_HEADERS32
*)(UINTN
) (Image
+ PeCoffHeaderOffset
);
280 if (NtHeader
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
287 gBS
->FreePages (Image
, EFI_SIZE_TO_PAGES(FileSize
));
289 // If we did not manage to open it then ask for the type
290 Print(L
"Is an EFI Application? ");
291 Status
= GetHIInputBoolean (&IsEfiApp
);
292 if (EFI_ERROR(Status
)) {
299 Print(L
"Is your application an OS loader? ");
300 Status
= GetHIInputBoolean (&IsBootLoader
);
301 if (EFI_ERROR(Status
)) {
305 *Attributes
|= LOAD_OPTION_CATEGORY_APP
;
307 *BootType
= BDS_LOADER_EFI_APPLICATION
;
309 Print(L
"Has FDT support? ");
310 Status
= GetHIInputBoolean (&HasFDTSupport
);
311 if (EFI_ERROR(Status
)) {
315 *BootType
= BDS_LOADER_KERNEL_LINUX_FDT
;
317 *BootType
= BDS_LOADER_KERNEL_LINUX_ATAG
;
325 BdsLoadOptionFileSystemList (
326 IN OUT LIST_ENTRY
* BdsLoadOptionList
331 EFI_HANDLE
*HandleBuffer
;
333 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
334 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
* FileProtocol
;
337 EFI_FILE_SYSTEM_INFO
* FsInfo
;
338 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
340 // List all the Simple File System Protocols
341 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
342 if (EFI_ERROR (Status
)) {
346 for (Index
= 0; Index
< HandleCount
; Index
++) {
347 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
348 if (!EFI_ERROR(Status
)) {
349 // Allocate BDS Supported Device structure
350 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE
));
353 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FileProtocol
);
354 ASSERT_EFI_ERROR(Status
);
356 FileProtocol
->OpenVolume (FileProtocol
, &Fs
);
358 // Generate a Description from the file system
361 Status
= Fs
->GetInfo (Fs
, &gEfiFileSystemInfoGuid
, &Size
, FsInfo
);
362 if (Status
== EFI_BUFFER_TOO_SMALL
) {
363 FsInfo
= AllocatePool (Size
);
364 Status
= Fs
->GetInfo (Fs
, &gEfiFileSystemInfoGuid
, &Size
, FsInfo
);
366 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"%s (%d MB)",FsInfo
->VolumeLabel
,(UINT32
)(FsInfo
->VolumeSize
/ (1024 * 1024)));
370 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
371 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_FILESYSTEM
];
373 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
381 BdsLoadOptionFileSystemCreateDevicePath (
383 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
387 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
388 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
389 UINTN BootFilePathSize
;
391 Print(L
"File path of the %s: ", FileName
);
392 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
393 if (EFI_ERROR(Status
)) {
397 BootFilePathSize
= StrSize (BootFilePath
);
398 if (BootFilePathSize
== 2) {
399 *DevicePathNodes
= NULL
;
400 return EFI_NOT_FOUND
;
403 // Create the FilePath Device Path node
404 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
405 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
406 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
407 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
408 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
409 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
410 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)FilePathDevicePath
;
416 BdsLoadOptionFileSystemUpdateDevicePath (
417 IN EFI_DEVICE_PATH
*OldDevicePath
,
419 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
423 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
424 UINTN BootFilePathSize
;
425 FILEPATH_DEVICE_PATH
* EndingDevicePath
;
426 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
427 EFI_DEVICE_PATH
* DevicePath
;
429 DevicePath
= DuplicateDevicePath (OldDevicePath
);
431 EndingDevicePath
= (FILEPATH_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
433 Print(L
"File path of the %s: ", FileName
);
434 StrnCpy (BootFilePath
, EndingDevicePath
->PathName
, BOOT_DEVICE_FILEPATH_MAX
);
435 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
436 if (EFI_ERROR(Status
)) {
440 BootFilePathSize
= StrSize(BootFilePath
);
441 if (BootFilePathSize
== 2) {
442 *NewDevicePath
= NULL
;
443 return EFI_NOT_FOUND
;
446 // Create the FilePath Device Path node
447 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
448 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
449 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
450 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
451 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
453 // Generate the new Device Path by replacing the last node by the updated node
454 SetDevicePathEndNode (EndingDevicePath
);
455 *NewDevicePath
= AppendDevicePathNode (DevicePath
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)FilePathDevicePath
);
456 FreePool(DevicePath
);
462 Check if a boot option path is a file system boot option path or not.
464 The device specified by the beginning of the path has to support the Simple File
465 System protocol. Furthermore, the remaining part of the path has to be composed of
466 a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP.
468 @param[in] DevicePath Complete device path of a boot option.
470 @retval FALSE The boot option path has not been identified as that of a
471 file system boot option.
472 @retval TRUE The boot option path is a file system boot option.
475 BdsLoadOptionFileSystemIsSupported (
476 IN EFI_DEVICE_PATH
*DevicePath
481 EFI_DEVICE_PATH
*RemainingDevicePath
;
482 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FileProtocol
;
484 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
485 if (EFI_ERROR (Status
)) {
489 Status
= gBS
->HandleProtocol (
491 &gEfiSimpleFileSystemProtocolGuid
,
492 (VOID
**)(&FileProtocol
)
494 if (EFI_ERROR (Status
)) {
498 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
))
507 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
508 IN EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePath
514 ParentSize
= GetDevicePathSize (ParentDevicePath
);
515 ChildSize
= GetDevicePathSize (ChildDevicePath
);
517 if (ParentSize
> ChildSize
) {
521 if (CompareMem (ParentDevicePath
, ChildDevicePath
, ParentSize
- END_DEVICE_PATH_LENGTH
) != 0) {
529 BdsLoadOptionMemMapList (
530 IN OUT LIST_ENTRY
* BdsLoadOptionList
535 EFI_HANDLE
*HandleBuffer
;
536 UINTN DevicePathHandleCount
;
537 EFI_HANDLE
*DevicePathHandleBuffer
;
541 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
542 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
543 EFI_DEVICE_PATH
* DevicePath
;
545 // List all the BlockIo Protocols
546 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
547 if (EFI_ERROR (Status
)) {
551 for (Index
= 0; Index
< HandleCount
; Index
++) {
552 // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)
553 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
554 if (!EFI_ERROR(Status
)) {
555 // BlockIo is not part of Media Device Path
556 DevicePath
= DevicePathProtocol
;
557 while (!IsDevicePathEndType (DevicePath
) && (DevicePathType (DevicePath
) != MEDIA_DEVICE_PATH
)) {
558 DevicePath
= NextDevicePathNode (DevicePath
);
560 if (DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) {
564 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
565 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDevicePathProtocolGuid
, NULL
, &DevicePathHandleCount
, &DevicePathHandleBuffer
);
566 ASSERT_EFI_ERROR (Status
);
568 for (Index2
= 0; (Index2
< DevicePathHandleCount
) && !IsParent
; Index2
++) {
569 if (HandleBuffer
[Index
] != DevicePathHandleBuffer
[Index2
]) {
570 gBS
->HandleProtocol (DevicePathHandleBuffer
[Index2
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
571 if (IsParentDevicePath (DevicePathProtocol
, DevicePath
)) {
580 // Allocate BDS Supported Device structure
581 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
583 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], SupportedDevice
->Description
);
584 ASSERT_EFI_ERROR (Status
);
586 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
587 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_MEMMAP
];
589 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
597 BdsLoadOptionMemMapCreateDevicePath (
599 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
603 MEMMAP_DEVICE_PATH
*MemMapDevicePath
;
604 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
605 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
607 Print(L
"Starting Address of the %s: ", FileName
);
608 Status
= GetHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
609 if (EFI_ERROR(Status
)) {
613 Print(L
"Ending Address of the %s: ", FileName
);
614 Status
= GetHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
615 if (EFI_ERROR(Status
)) {
619 // Create the MemMap Device Path Node
620 MemMapDevicePath
= (MEMMAP_DEVICE_PATH
*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH
) + END_DEVICE_PATH_LENGTH
);
621 MemMapDevicePath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
622 MemMapDevicePath
->Header
.SubType
= HW_MEMMAP_DP
;
623 SetDevicePathNodeLength (MemMapDevicePath
, sizeof(MEMMAP_DEVICE_PATH
));
624 MemMapDevicePath
->MemoryType
= EfiBootServicesData
;
625 MemMapDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
626 MemMapDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
628 // Set a Device Path End Node after the Memory Map Device Path Node
629 SetDevicePathEndNode (MemMapDevicePath
+ 1);
630 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)MemMapDevicePath
;
636 BdsLoadOptionMemMapUpdateDevicePath (
637 IN EFI_DEVICE_PATH
*OldDevicePath
,
639 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
643 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
644 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
645 MEMMAP_DEVICE_PATH
* EndingDevicePath
;
646 EFI_DEVICE_PATH
* DevicePath
;
648 DevicePath
= DuplicateDevicePath (OldDevicePath
);
649 EndingDevicePath
= (MEMMAP_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
651 Print(L
"Starting Address of the %s: ", FileName
);
652 UnicodeSPrint (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->StartingAddress
);
653 Status
= EditHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
654 if (EFI_ERROR(Status
)) {
658 Print(L
"Ending Address of the %s: ", FileName
);
659 UnicodeSPrint (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->EndingAddress
);
660 Status
= EditHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
661 if (EFI_ERROR(Status
)) {
665 EndingDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
666 EndingDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
668 if (EFI_ERROR(Status
)) {
669 FreePool(DevicePath
);
671 *NewDevicePath
= DevicePath
;
678 Check if a boot option path is a memory map boot option path or not.
680 The device specified by the beginning of the path has to support the BlockIo
681 protocol. Furthermore, the remaining part of the path has to be composed of
682 a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP.
684 @param[in] DevicePath Complete device path of a boot option.
686 @retval FALSE The boot option path has not been identified as that of a
687 memory map boot option.
688 @retval TRUE The boot option path is a a memory map boot option.
691 BdsLoadOptionMemMapIsSupported (
692 IN EFI_DEVICE_PATH
*DevicePath
697 EFI_DEVICE_PATH
*RemainingDevicePath
;
698 EFI_BLOCK_IO_PROTOCOL
*BlockIoProtocol
;
700 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
701 if (EFI_ERROR (Status
)) {
705 Status
= gBS
->HandleProtocol (
707 &gEfiBlockIoProtocolGuid
,
708 (VOID
**)(&BlockIoProtocol
)
710 if (EFI_ERROR (Status
)) {
714 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
))
721 BdsLoadOptionPxeList (
722 IN OUT LIST_ENTRY
* BdsLoadOptionList
727 EFI_HANDLE
*HandleBuffer
;
729 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
730 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
731 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
732 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
733 EFI_MAC_ADDRESS
*Mac
;
735 // List all the PXE Protocols
736 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
737 if (EFI_ERROR (Status
)) {
741 for (Index
= 0; Index
< HandleCount
; Index
++) {
742 // We only select the handle WITH a Device Path AND the PXE Protocol
743 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
744 if (!EFI_ERROR(Status
)) {
745 // Allocate BDS Supported Device structure
746 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
748 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&SimpleNet
);
749 if (!EFI_ERROR(Status
)) {
750 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
751 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]);
753 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
754 ASSERT_EFI_ERROR (Status
);
756 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"PXE on %s",DeviceDescription
);
758 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
759 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_PXE
];
761 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
769 BdsLoadOptionPxeCreateDevicePath (
771 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
774 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocatePool (END_DEVICE_PATH_LENGTH
);
775 SetDevicePathEndNode (*DevicePathNodes
);
781 Update the parameters of a Pxe boot option
783 @param[in] OldDevicePath Current complete device path of the Pxe boot option.
784 This has to be a valid complete Pxe boot option path.
785 @param[in] FileName Description of the file the path is asked for
786 @param[out] NewDevicePath Pointer to the new complete device path.
788 @retval EFI_SUCCESS Update completed
789 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
792 BdsLoadOptionPxeUpdateDevicePath (
793 IN EFI_DEVICE_PATH
*OldDevicePath
,
795 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
799 // Make a copy of the complete device path that is made of :
800 // the device path of the device supporting the Pxe base code protocol
801 // followed by an end node.
803 *NewDevicePath
= DuplicateDevicePath (OldDevicePath
);
804 if (*NewDevicePath
== NULL
) {
805 return EFI_OUT_OF_RESOURCES
;
812 BdsLoadOptionPxeIsSupported (
813 IN EFI_DEVICE_PATH
*DevicePath
818 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
819 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
821 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
822 if (EFI_ERROR(Status
)) {
826 if (!IsDevicePathEnd(RemainingDevicePath
)) {
830 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
831 if (EFI_ERROR (Status
)) {
839 BdsLoadOptionTftpList (
840 IN OUT LIST_ENTRY
* BdsLoadOptionList
845 EFI_HANDLE
*HandleBuffer
;
847 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
848 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
849 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
850 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
851 EFI_MAC_ADDRESS
*Mac
;
853 // List all the PXE Protocols
854 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
855 if (EFI_ERROR (Status
)) {
859 for (Index
= 0; Index
< HandleCount
; Index
++) {
860 // 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)
861 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
862 if (!EFI_ERROR(Status
)) {
863 // Allocate BDS Supported Device structure
864 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
866 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&SimpleNet
);
867 if (!EFI_ERROR(Status
)) {
868 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
869 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]);
871 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
872 ASSERT_EFI_ERROR (Status
);
874 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"TFTP on %s",DeviceDescription
);
876 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
877 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_TFTP
];
879 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
887 BdsLoadOptionTftpCreateDevicePath (
889 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
894 EFI_IP_ADDRESS LocalIp
;
895 EFI_IP_ADDRESS RemoteIp
;
896 IPv4_DEVICE_PATH
* IPv4DevicePathNode
;
897 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
898 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
899 UINTN BootFilePathSize
;
901 Print(L
"Get the IP address from DHCP: ");
902 Status
= GetHIInputBoolean (&IsDHCP
);
903 if (EFI_ERROR(Status
)) {
908 Print(L
"Get the static IP address: ");
909 Status
= GetHIInputIP (&LocalIp
);
910 if (EFI_ERROR(Status
)) {
915 Print(L
"Get the TFTP server IP address: ");
916 Status
= GetHIInputIP (&RemoteIp
);
917 if (EFI_ERROR(Status
)) {
921 Print(L
"File path of the %s : ", FileName
);
922 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
923 if (EFI_ERROR(Status
)) {
927 BootFilePathSize
= StrSize(BootFilePath
);
928 if (BootFilePathSize
== 2) {
929 return EFI_NOT_FOUND
;
932 // Allocate the memory for the IPv4 + File Path Device Path Nodes
933 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)AllocatePool(sizeof(IPv4_DEVICE_PATH
) + SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
935 // Create the IPv4 Device Path
936 IPv4DevicePathNode
->Header
.Type
= MESSAGING_DEVICE_PATH
;
937 IPv4DevicePathNode
->Header
.SubType
= MSG_IPv4_DP
;
938 SetDevicePathNodeLength (&IPv4DevicePathNode
->Header
, sizeof(IPv4_DEVICE_PATH
));
939 CopyMem (&IPv4DevicePathNode
->LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
940 CopyMem (&IPv4DevicePathNode
->RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
941 IPv4DevicePathNode
->LocalPort
= 0;
942 IPv4DevicePathNode
->RemotePort
= 0;
943 IPv4DevicePathNode
->Protocol
= EFI_IP_PROTO_TCP
;
944 IPv4DevicePathNode
->StaticIpAddress
= (IsDHCP
!= TRUE
);
946 // Create the FilePath Device Path node
947 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
948 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
949 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
950 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
951 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
953 // Set the End Device Path Node
954 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
955 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)IPv4DevicePathNode
;
961 Update the parameters of a TFTP boot option
963 The function asks sequentially to update the IPv4 parameters as well as the boot file path,
964 providing the previously set value if any.
966 @param[in] OldDevicePath Current complete device path of the Tftp boot option.
967 This has to be a valid complete Tftp boot option path.
968 By complete, we mean that it is not only the Tftp
969 specific end part built by the
970 "BdsLoadOptionTftpCreateDevicePath()" function.
971 This path is handled as read only.
972 @param[in] FileName Description of the file the path is asked for
973 @param[out] NewDevicePath Pointer to the new complete device path.
975 @retval EFI_SUCCESS Update completed
976 @retval EFI_ABORTED Update aborted by the user
977 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
980 BdsLoadOptionTftpUpdateDevicePath (
981 IN EFI_DEVICE_PATH
*OldDevicePath
,
983 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
987 EFI_DEVICE_PATH
*DevicePath
;
988 EFI_DEVICE_PATH
*DevicePathNode
;
990 IPv4_DEVICE_PATH Ipv4Node
;
992 EFI_IP_ADDRESS OldIp
;
993 EFI_IP_ADDRESS LocalIp
;
994 EFI_IP_ADDRESS RemoteIp
;
996 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
998 UINTN BootFilePathSize
;
999 FILEPATH_DEVICE_PATH
*NewFilePathNode
;
1004 // Make a copy of the complete device path that is made of :
1005 // the device path of the device that support the Simple Network protocol
1006 // followed by an IPv4 node (type IPv4_DEVICE_PATH),
1007 // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up
1008 // by an end node. The IPv6 case is not handled yet.
1011 DevicePath
= DuplicateDevicePath (OldDevicePath
);
1012 if (DevicePath
== NULL
) {
1013 Status
= EFI_OUT_OF_RESOURCES
;
1018 // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the
1019 // call to this function, we know that the device path ends with an IPv4 node
1020 // followed by a file path node and finally an end node. To get the address of
1021 // the last IPv4 node, we loop over the whole device path, noting down the
1022 // address of each encountered IPv4 node.
1025 for (DevicePathNode
= DevicePath
;
1026 !IsDevicePathEnd (DevicePathNode
);
1027 DevicePathNode
= NextDevicePathNode (DevicePathNode
))
1029 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
)) {
1030 Ipv4NodePtr
= (UINT8
*)DevicePathNode
;
1034 // Copy for alignment of the IPv4 node data
1035 CopyMem (&Ipv4Node
, Ipv4NodePtr
, sizeof (IPv4_DEVICE_PATH
));
1037 Print (L
"Get the IP address from DHCP: ");
1038 Status
= GetHIInputBoolean (&IsDHCP
);
1039 if (EFI_ERROR (Status
)) {
1044 Print (L
"Local static IP address: ");
1045 if (Ipv4Node
.StaticIpAddress
) {
1046 // Copy local IPv4 address into IPv4 or IPv6 union
1047 CopyMem (&OldIp
.v4
, &Ipv4Node
.LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1049 Status
= EditHIInputIP (&OldIp
, &LocalIp
);
1051 Status
= GetHIInputIP (&LocalIp
);
1053 if (EFI_ERROR (Status
)) {
1058 Print (L
"TFTP server IP address: ");
1059 // Copy remote IPv4 address into IPv4 or IPv6 union
1060 CopyMem (&OldIp
.v4
, &Ipv4Node
.RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1062 Status
= EditHIInputIP (&OldIp
, &RemoteIp
);
1063 if (EFI_ERROR (Status
)) {
1067 // Get the path of the boot file and its size in number of bytes
1068 FileNodePtr
= Ipv4NodePtr
+ sizeof (IPv4_DEVICE_PATH
);
1069 BootFilePathSize
= DevicePathNodeLength (FileNodePtr
) - SIZE_OF_FILEPATH_DEVICE_PATH
;
1072 // Ask for update of the boot file path
1075 // Copy for 2-byte alignment of the Unicode string
1077 BootFilePath
, FileNodePtr
+ SIZE_OF_FILEPATH_DEVICE_PATH
,
1078 MIN (BootFilePathSize
, BOOT_DEVICE_FILEPATH_MAX
)
1080 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
- 1] = L
'\0';
1082 Print (L
"File path of the %s: ", FileName
);
1083 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
1084 if (EFI_ERROR (Status
)) {
1087 PathSize
= StrSize (BootFilePath
);
1091 // Empty string, give the user another try
1092 Print (L
"Empty string - Invalid path\n");
1093 } while (PathSize
<= 2) ;
1096 // Update the IPv4 node. IPv6 case not handled yet.
1098 if (IsDHCP
== TRUE
) {
1099 Ipv4Node
.StaticIpAddress
= FALSE
;
1101 Ipv4Node
.StaticIpAddress
= TRUE
;
1103 CopyMem (&Ipv4Node
.LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1104 CopyMem (&Ipv4Node
.RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1105 CopyMem (Ipv4NodePtr
, &Ipv4Node
, sizeof (IPv4_DEVICE_PATH
));
1108 // Create the new file path node
1110 NewFilePathNode
= (FILEPATH_DEVICE_PATH
*)AllocatePool (
1111 SIZE_OF_FILEPATH_DEVICE_PATH
+
1114 NewFilePathNode
->Header
.Type
= MEDIA_DEVICE_PATH
;
1115 NewFilePathNode
->Header
.SubType
= MEDIA_FILEPATH_DP
;
1116 SetDevicePathNodeLength (
1118 SIZE_OF_FILEPATH_DEVICE_PATH
+ PathSize
1120 CopyMem (NewFilePathNode
->PathName
, BootFilePath
, PathSize
);
1123 // Generate the new Device Path by replacing the file path node at address
1124 // "FileNodePtr" by the new one "NewFilePathNode" and return its address.
1126 SetDevicePathEndNode (FileNodePtr
);
1127 *NewDevicePath
= AppendDevicePathNode (
1129 (CONST EFI_DEVICE_PATH_PROTOCOL
*)NewFilePathNode
1133 if (DevicePath
!= NULL
) {
1134 FreePool (DevicePath
) ;
1141 BdsLoadOptionTftpIsSupported (
1142 IN EFI_DEVICE_PATH
*DevicePath
1147 EFI_DEVICE_PATH
*RemainingDevicePath
;
1148 EFI_DEVICE_PATH
*NextDevicePath
;
1149 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
1151 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
1152 if (EFI_ERROR(Status
)) {
1156 // Validate the Remaining Device Path
1157 if (IsDevicePathEnd(RemainingDevicePath
)) {
1160 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
) &&
1161 !IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv6_DP
)) {
1164 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
1165 if (IsDevicePathEnd(NextDevicePath
)) {
1168 if (!IS_DEVICE_PATH_NODE(NextDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
)) {
1172 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
1173 if (EFI_ERROR (Status
)) {