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 is 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 BdsLoadOptionFileSystemIsSupported (
463 IN EFI_DEVICE_PATH
*DevicePath
466 EFI_DEVICE_PATH
* DevicePathNode
;
468 DevicePathNode
= GetLastDevicePathNode (DevicePath
);
470 return IS_DEVICE_PATH_NODE(DevicePathNode
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
);
476 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
477 IN EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePath
483 ParentSize
= GetDevicePathSize (ParentDevicePath
);
484 ChildSize
= GetDevicePathSize (ChildDevicePath
);
486 if (ParentSize
> ChildSize
) {
490 if (CompareMem (ParentDevicePath
, ChildDevicePath
, ParentSize
- END_DEVICE_PATH_LENGTH
) != 0) {
498 BdsLoadOptionMemMapList (
499 IN OUT LIST_ENTRY
* BdsLoadOptionList
504 EFI_HANDLE
*HandleBuffer
;
505 UINTN DevicePathHandleCount
;
506 EFI_HANDLE
*DevicePathHandleBuffer
;
510 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
511 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
512 EFI_DEVICE_PATH
* DevicePath
;
514 // List all the BlockIo Protocols
515 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
516 if (EFI_ERROR (Status
)) {
520 for (Index
= 0; Index
< HandleCount
; Index
++) {
521 // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)
522 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
523 if (!EFI_ERROR(Status
)) {
524 // BlockIo is not part of Media Device Path
525 DevicePath
= DevicePathProtocol
;
526 while (!IsDevicePathEndType (DevicePath
) && (DevicePathType (DevicePath
) != MEDIA_DEVICE_PATH
)) {
527 DevicePath
= NextDevicePathNode (DevicePath
);
529 if (DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) {
533 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
534 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDevicePathProtocolGuid
, NULL
, &DevicePathHandleCount
, &DevicePathHandleBuffer
);
535 ASSERT_EFI_ERROR (Status
);
537 for (Index2
= 0; (Index2
< DevicePathHandleCount
) && !IsParent
; Index2
++) {
538 if (HandleBuffer
[Index
] != DevicePathHandleBuffer
[Index2
]) {
539 gBS
->HandleProtocol (DevicePathHandleBuffer
[Index2
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
540 if (IsParentDevicePath (DevicePathProtocol
, DevicePath
)) {
549 // Allocate BDS Supported Device structure
550 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
552 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], SupportedDevice
->Description
);
553 ASSERT_EFI_ERROR (Status
);
555 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
556 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_MEMMAP
];
558 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
566 BdsLoadOptionMemMapCreateDevicePath (
568 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
572 MEMMAP_DEVICE_PATH
*MemMapDevicePath
;
573 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
574 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
576 Print(L
"Starting Address of the %s: ", FileName
);
577 Status
= GetHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
578 if (EFI_ERROR(Status
)) {
582 Print(L
"Ending Address of the %s: ", FileName
);
583 Status
= GetHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
584 if (EFI_ERROR(Status
)) {
588 // Create the MemMap Device Path Node
589 MemMapDevicePath
= (MEMMAP_DEVICE_PATH
*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH
) + END_DEVICE_PATH_LENGTH
);
590 MemMapDevicePath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
591 MemMapDevicePath
->Header
.SubType
= HW_MEMMAP_DP
;
592 SetDevicePathNodeLength (MemMapDevicePath
, sizeof(MEMMAP_DEVICE_PATH
));
593 MemMapDevicePath
->MemoryType
= EfiBootServicesData
;
594 MemMapDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
595 MemMapDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
597 // Set a Device Path End Node after the Memory Map Device Path Node
598 SetDevicePathEndNode (MemMapDevicePath
+ 1);
599 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)MemMapDevicePath
;
605 BdsLoadOptionMemMapUpdateDevicePath (
606 IN EFI_DEVICE_PATH
*OldDevicePath
,
608 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
612 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
613 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
614 MEMMAP_DEVICE_PATH
* EndingDevicePath
;
615 EFI_DEVICE_PATH
* DevicePath
;
617 DevicePath
= DuplicateDevicePath (OldDevicePath
);
618 EndingDevicePath
= (MEMMAP_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
620 Print(L
"Starting Address of the %s: ", FileName
);
621 UnicodeSPrint (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->StartingAddress
);
622 Status
= EditHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
623 if (EFI_ERROR(Status
)) {
627 Print(L
"Ending Address of the %s: ", FileName
);
628 UnicodeSPrint (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->EndingAddress
);
629 Status
= EditHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
630 if (EFI_ERROR(Status
)) {
634 EndingDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
635 EndingDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
637 if (EFI_ERROR(Status
)) {
638 FreePool(DevicePath
);
640 *NewDevicePath
= DevicePath
;
647 BdsLoadOptionMemMapIsSupported (
648 IN EFI_DEVICE_PATH
*DevicePath
651 EFI_DEVICE_PATH
* DevicePathNode
;
653 DevicePathNode
= GetLastDevicePathNode (DevicePath
);
655 return IS_DEVICE_PATH_NODE(DevicePathNode
,HARDWARE_DEVICE_PATH
,HW_MEMMAP_DP
);
659 BdsLoadOptionPxeList (
660 IN OUT LIST_ENTRY
* BdsLoadOptionList
665 EFI_HANDLE
*HandleBuffer
;
667 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
668 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
669 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
670 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
671 EFI_MAC_ADDRESS
*Mac
;
673 // List all the PXE Protocols
674 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
675 if (EFI_ERROR (Status
)) {
679 for (Index
= 0; Index
< HandleCount
; Index
++) {
680 // We only select the handle WITH a Device Path AND the PXE Protocol
681 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
682 if (!EFI_ERROR(Status
)) {
683 // Allocate BDS Supported Device structure
684 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
686 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&SimpleNet
);
687 if (!EFI_ERROR(Status
)) {
688 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
689 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]);
691 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
692 ASSERT_EFI_ERROR (Status
);
694 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"PXE on %s",DeviceDescription
);
696 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
697 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_PXE
];
699 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
707 BdsLoadOptionPxeCreateDevicePath (
709 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
712 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocatePool (END_DEVICE_PATH_LENGTH
);
713 SetDevicePathEndNode (*DevicePathNodes
);
719 Update the parameters of a Pxe boot option
721 @param[in] OldDevicePath Current complete device path of the Pxe boot option.
722 This has to be a valid complete Pxe boot option path.
723 @param[in] FileName Description of the file the path is asked for
724 @param[out] NewDevicePath Pointer to the new complete device path.
726 @retval EFI_SUCCESS Update completed
727 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
730 BdsLoadOptionPxeUpdateDevicePath (
731 IN EFI_DEVICE_PATH
*OldDevicePath
,
733 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
737 // Make a copy of the complete device path that is made of :
738 // the device path of the device supporting the Pxe base code protocol
739 // followed by an end node.
741 *NewDevicePath
= DuplicateDevicePath (OldDevicePath
);
742 if (*NewDevicePath
== NULL
) {
743 return EFI_OUT_OF_RESOURCES
;
750 BdsLoadOptionPxeIsSupported (
751 IN EFI_DEVICE_PATH
*DevicePath
756 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
757 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
759 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
760 if (EFI_ERROR(Status
)) {
764 if (!IsDevicePathEnd(RemainingDevicePath
)) {
768 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
769 if (EFI_ERROR (Status
)) {
777 BdsLoadOptionTftpList (
778 IN OUT LIST_ENTRY
* BdsLoadOptionList
783 EFI_HANDLE
*HandleBuffer
;
785 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
786 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
787 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
788 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
789 EFI_MAC_ADDRESS
*Mac
;
791 // List all the PXE Protocols
792 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
793 if (EFI_ERROR (Status
)) {
797 for (Index
= 0; Index
< HandleCount
; Index
++) {
798 // 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)
799 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
800 if (!EFI_ERROR(Status
)) {
801 // Allocate BDS Supported Device structure
802 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
804 Status
= gBS
->LocateProtocol (&gEfiSimpleNetworkProtocolGuid
, NULL
, (VOID
**)&SimpleNet
);
805 if (!EFI_ERROR(Status
)) {
806 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
807 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]);
809 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
810 ASSERT_EFI_ERROR (Status
);
812 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"TFTP on %s",DeviceDescription
);
814 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
815 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_TFTP
];
817 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
825 BdsLoadOptionTftpCreateDevicePath (
827 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
832 EFI_IP_ADDRESS LocalIp
;
833 EFI_IP_ADDRESS RemoteIp
;
834 IPv4_DEVICE_PATH
* IPv4DevicePathNode
;
835 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
836 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
837 UINTN BootFilePathSize
;
839 Print(L
"Get the IP address from DHCP: ");
840 Status
= GetHIInputBoolean (&IsDHCP
);
841 if (EFI_ERROR(Status
)) {
846 Print(L
"Get the static IP address: ");
847 Status
= GetHIInputIP (&LocalIp
);
848 if (EFI_ERROR(Status
)) {
853 Print(L
"Get the TFTP server IP address: ");
854 Status
= GetHIInputIP (&RemoteIp
);
855 if (EFI_ERROR(Status
)) {
859 Print(L
"File path of the %s : ", FileName
);
860 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
861 if (EFI_ERROR(Status
)) {
865 BootFilePathSize
= StrSize(BootFilePath
);
866 if (BootFilePathSize
== 2) {
867 return EFI_NOT_FOUND
;
870 // Allocate the memory for the IPv4 + File Path Device Path Nodes
871 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)AllocatePool(sizeof(IPv4_DEVICE_PATH
) + SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
873 // Create the IPv4 Device Path
874 IPv4DevicePathNode
->Header
.Type
= MESSAGING_DEVICE_PATH
;
875 IPv4DevicePathNode
->Header
.SubType
= MSG_IPv4_DP
;
876 SetDevicePathNodeLength (&IPv4DevicePathNode
->Header
, sizeof(IPv4_DEVICE_PATH
));
877 CopyMem (&IPv4DevicePathNode
->LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
878 CopyMem (&IPv4DevicePathNode
->RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
879 IPv4DevicePathNode
->LocalPort
= 0;
880 IPv4DevicePathNode
->RemotePort
= 0;
881 IPv4DevicePathNode
->Protocol
= EFI_IP_PROTO_TCP
;
882 IPv4DevicePathNode
->StaticIpAddress
= (IsDHCP
!= TRUE
);
884 // Create the FilePath Device Path node
885 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
886 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
887 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
888 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
889 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
891 // Set the End Device Path Node
892 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
893 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)IPv4DevicePathNode
;
899 Update the parameters of a TFTP boot option
901 The function asks sequentially to update the IPv4 parameters as well as the boot file path,
902 providing the previously set value if any.
904 @param[in] OldDevicePath Current complete device path of the Tftp boot option.
905 This has to be a valid complete Tftp boot option path.
906 By complete, we mean that it is not only the Tftp
907 specific end part built by the
908 "BdsLoadOptionTftpCreateDevicePath()" function.
909 This path is handled as read only.
910 @param[in] FileName Description of the file the path is asked for
911 @param[out] NewDevicePath Pointer to the new complete device path.
913 @retval EFI_SUCCESS Update completed
914 @retval EFI_ABORTED Update aborted by the user
915 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
918 BdsLoadOptionTftpUpdateDevicePath (
919 IN EFI_DEVICE_PATH
*OldDevicePath
,
921 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
925 EFI_DEVICE_PATH
*DevicePath
;
926 EFI_DEVICE_PATH
*DevicePathNode
;
928 IPv4_DEVICE_PATH Ipv4Node
;
930 EFI_IP_ADDRESS OldIp
;
931 EFI_IP_ADDRESS LocalIp
;
932 EFI_IP_ADDRESS RemoteIp
;
934 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
936 UINTN BootFilePathSize
;
937 FILEPATH_DEVICE_PATH
*NewFilePathNode
;
942 // Make a copy of the complete device path that is made of :
943 // the device path of the device that support the Simple Network protocol
944 // followed by an IPv4 node (type IPv4_DEVICE_PATH),
945 // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up
946 // by an end node. The IPv6 case is not handled yet.
949 DevicePath
= DuplicateDevicePath (OldDevicePath
);
950 if (DevicePath
== NULL
) {
951 Status
= EFI_OUT_OF_RESOURCES
;
956 // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the
957 // call to this function, we know that the device path ends with an IPv4 node
958 // followed by a file path node and finally an end node. To get the address of
959 // the last IPv4 node, we loop over the whole device path, noting down the
960 // address of each encountered IPv4 node.
963 for (DevicePathNode
= DevicePath
;
964 !IsDevicePathEnd (DevicePathNode
);
965 DevicePathNode
= NextDevicePathNode (DevicePathNode
))
967 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
)) {
968 Ipv4NodePtr
= (UINT8
*)DevicePathNode
;
972 // Copy for alignment of the IPv4 node data
973 CopyMem (&Ipv4Node
, Ipv4NodePtr
, sizeof (IPv4_DEVICE_PATH
));
975 Print (L
"Get the IP address from DHCP: ");
976 Status
= GetHIInputBoolean (&IsDHCP
);
977 if (EFI_ERROR (Status
)) {
982 Print (L
"Local static IP address: ");
983 if (Ipv4Node
.StaticIpAddress
) {
984 // Copy local IPv4 address into IPv4 or IPv6 union
985 CopyMem (&OldIp
.v4
, &Ipv4Node
.LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
987 Status
= EditHIInputIP (&OldIp
, &LocalIp
);
989 Status
= GetHIInputIP (&LocalIp
);
991 if (EFI_ERROR (Status
)) {
996 Print (L
"TFTP server IP address: ");
997 // Copy remote IPv4 address into IPv4 or IPv6 union
998 CopyMem (&OldIp
.v4
, &Ipv4Node
.RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1000 Status
= EditHIInputIP (&OldIp
, &RemoteIp
);
1001 if (EFI_ERROR (Status
)) {
1005 // Get the path of the boot file and its size in number of bytes
1006 FileNodePtr
= Ipv4NodePtr
+ sizeof (IPv4_DEVICE_PATH
);
1007 BootFilePathSize
= DevicePathNodeLength (FileNodePtr
) - SIZE_OF_FILEPATH_DEVICE_PATH
;
1010 // Ask for update of the boot file path
1013 // Copy for 2-byte alignment of the Unicode string
1015 BootFilePath
, FileNodePtr
+ SIZE_OF_FILEPATH_DEVICE_PATH
,
1016 MIN (BootFilePathSize
, BOOT_DEVICE_FILEPATH_MAX
)
1018 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
- 1] = L
'\0';
1020 Print (L
"File path of the %s: ", FileName
);
1021 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
1022 if (EFI_ERROR (Status
)) {
1025 PathSize
= StrSize (BootFilePath
);
1029 // Empty string, give the user another try
1030 Print (L
"Empty string - Invalid path\n");
1031 } while (PathSize
<= 2) ;
1034 // Update the IPv4 node. IPv6 case not handled yet.
1036 if (IsDHCP
== TRUE
) {
1037 Ipv4Node
.StaticIpAddress
= FALSE
;
1039 Ipv4Node
.StaticIpAddress
= TRUE
;
1041 CopyMem (&Ipv4Node
.LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1042 CopyMem (&Ipv4Node
.RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1043 CopyMem (Ipv4NodePtr
, &Ipv4Node
, sizeof (IPv4_DEVICE_PATH
));
1046 // Create the new file path node
1048 NewFilePathNode
= (FILEPATH_DEVICE_PATH
*)AllocatePool (
1049 SIZE_OF_FILEPATH_DEVICE_PATH
+
1052 NewFilePathNode
->Header
.Type
= MEDIA_DEVICE_PATH
;
1053 NewFilePathNode
->Header
.SubType
= MEDIA_FILEPATH_DP
;
1054 SetDevicePathNodeLength (
1056 SIZE_OF_FILEPATH_DEVICE_PATH
+ PathSize
1058 CopyMem (NewFilePathNode
->PathName
, BootFilePath
, PathSize
);
1061 // Generate the new Device Path by replacing the file path node at address
1062 // "FileNodePtr" by the new one "NewFilePathNode" and return its address.
1064 SetDevicePathEndNode (FileNodePtr
);
1065 *NewDevicePath
= AppendDevicePathNode (
1067 (CONST EFI_DEVICE_PATH_PROTOCOL
*)NewFilePathNode
1071 if (DevicePath
!= NULL
) {
1072 FreePool (DevicePath
) ;
1079 BdsLoadOptionTftpIsSupported (
1080 IN EFI_DEVICE_PATH
*DevicePath
1085 EFI_DEVICE_PATH
*RemainingDevicePath
;
1086 EFI_DEVICE_PATH
*NextDevicePath
;
1087 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
1089 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
1090 if (EFI_ERROR(Status
)) {
1094 // Validate the Remaining Device Path
1095 if (IsDevicePathEnd(RemainingDevicePath
)) {
1098 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
) &&
1099 !IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv6_DP
)) {
1102 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
1103 if (IsDevicePathEnd(NextDevicePath
)) {
1106 if (!IS_DEVICE_PATH_NODE(NextDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
)) {
1110 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
1111 if (EFI_ERROR (Status
)) {