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>
25 #include <Protocol/Dhcp4.h>
26 #include <Protocol/Mtftp4.h>
28 #include <Guid/FileSystemInfo.h>
30 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
33 BdsLoadOptionFileSystemList (
34 IN OUT LIST_ENTRY
* BdsLoadOptionList
38 BdsLoadOptionFileSystemCreateDevicePath (
40 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
44 BdsLoadOptionFileSystemUpdateDevicePath (
45 IN EFI_DEVICE_PATH
*OldDevicePath
,
47 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
51 BdsLoadOptionFileSystemIsSupported (
52 IN EFI_DEVICE_PATH
*DevicePath
56 BdsLoadOptionMemMapList (
57 IN OUT LIST_ENTRY
* BdsLoadOptionList
61 BdsLoadOptionMemMapCreateDevicePath (
63 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
67 BdsLoadOptionMemMapUpdateDevicePath (
68 IN EFI_DEVICE_PATH
*OldDevicePath
,
70 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
74 BdsLoadOptionMemMapIsSupported (
75 IN EFI_DEVICE_PATH
*DevicePath
79 BdsLoadOptionPxeList (
80 IN OUT LIST_ENTRY
* BdsLoadOptionList
84 BdsLoadOptionPxeCreateDevicePath (
86 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
90 BdsLoadOptionPxeUpdateDevicePath (
91 IN EFI_DEVICE_PATH
*OldDevicePath
,
93 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
97 BdsLoadOptionPxeIsSupported (
98 IN EFI_DEVICE_PATH
*DevicePath
102 BdsLoadOptionTftpList (
103 IN OUT LIST_ENTRY
* BdsLoadOptionList
107 BdsLoadOptionTftpCreateDevicePath (
109 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
113 BdsLoadOptionTftpUpdateDevicePath (
114 IN EFI_DEVICE_PATH
*OldDevicePath
,
116 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
120 BdsLoadOptionTftpIsSupported (
121 IN EFI_DEVICE_PATH
*DevicePath
124 BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList
[] = {
126 BDS_DEVICE_FILESYSTEM
,
127 BdsLoadOptionFileSystemList
,
128 BdsLoadOptionFileSystemIsSupported
,
129 BdsLoadOptionFileSystemCreateDevicePath
,
130 BdsLoadOptionFileSystemUpdateDevicePath
,
135 BdsLoadOptionMemMapList
,
136 BdsLoadOptionMemMapIsSupported
,
137 BdsLoadOptionMemMapCreateDevicePath
,
138 BdsLoadOptionMemMapUpdateDevicePath
,
143 BdsLoadOptionPxeList
,
144 BdsLoadOptionPxeIsSupported
,
145 BdsLoadOptionPxeCreateDevicePath
,
146 BdsLoadOptionPxeUpdateDevicePath
,
151 BdsLoadOptionTftpList
,
152 BdsLoadOptionTftpIsSupported
,
153 BdsLoadOptionTftpCreateDevicePath
,
154 BdsLoadOptionTftpUpdateDevicePath
,
160 BootDeviceListSupportedInit (
161 IN OUT LIST_ENTRY
*SupportedDeviceList
166 // Initialize list of supported devices
167 InitializeListHead (SupportedDeviceList
);
169 for (Index
= 0; Index
< BDS_DEVICE_MAX
; Index
++) {
170 BdsLoadOptionSupportList
[Index
].ListDevices (SupportedDeviceList
);
177 BootDeviceListSupportedFree (
178 IN LIST_ENTRY
*SupportedDeviceList
,
179 IN BDS_SUPPORTED_DEVICE
*Except
183 BDS_SUPPORTED_DEVICE
* SupportedDevice
;
185 Entry
= GetFirstNode (SupportedDeviceList
);
186 while (Entry
!= SupportedDeviceList
) {
187 SupportedDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
188 Entry
= RemoveEntryList (Entry
);
189 if (SupportedDevice
!= Except
) {
190 FreePool (SupportedDevice
);
198 BootDeviceGetDeviceSupport (
199 IN EFI_DEVICE_PATH
*DevicePath
,
200 OUT BDS_LOAD_OPTION_SUPPORT
**DeviceSupport
205 // Find which supported device is the most appropriate
206 for (Index
= 0; Index
< BDS_DEVICE_MAX
; Index
++) {
207 if (BdsLoadOptionSupportList
[Index
].IsSupported (DevicePath
)) {
208 *DeviceSupport
= &BdsLoadOptionSupportList
[Index
];
213 return EFI_UNSUPPORTED
;
217 BdsLoadOptionFileSystemList (
218 IN OUT LIST_ENTRY
* BdsLoadOptionList
223 EFI_HANDLE
*HandleBuffer
;
225 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
226 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
* FileProtocol
;
229 EFI_FILE_SYSTEM_INFO
* FsInfo
;
230 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
232 // List all the Simple File System Protocols
233 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
234 if (EFI_ERROR (Status
)) {
238 for (Index
= 0; Index
< HandleCount
; Index
++) {
239 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
240 if (!EFI_ERROR(Status
)) {
241 // Allocate BDS Supported Device structure
242 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE
));
245 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&FileProtocol
);
246 ASSERT_EFI_ERROR(Status
);
248 FileProtocol
->OpenVolume (FileProtocol
, &Fs
);
250 // Generate a Description from the file system
253 Status
= Fs
->GetInfo (Fs
, &gEfiFileSystemInfoGuid
, &Size
, FsInfo
);
254 if (Status
== EFI_BUFFER_TOO_SMALL
) {
255 FsInfo
= AllocatePool (Size
);
256 Status
= Fs
->GetInfo (Fs
, &gEfiFileSystemInfoGuid
, &Size
, FsInfo
);
258 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"%s (%d MB)",FsInfo
->VolumeLabel
,(UINT32
)(FsInfo
->VolumeSize
/ (1024 * 1024)));
262 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
263 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_FILESYSTEM
];
265 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
273 BdsLoadOptionFileSystemCreateDevicePath (
275 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
279 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
280 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
281 UINTN BootFilePathSize
;
283 Print(L
"File path of the %s: ", FileName
);
284 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
285 if (EFI_ERROR(Status
)) {
289 BootFilePathSize
= StrSize (BootFilePath
);
290 if (BootFilePathSize
== 2) {
291 *DevicePathNodes
= NULL
;
292 return EFI_NOT_FOUND
;
295 // Create the FilePath Device Path node
296 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
297 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
298 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
299 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
300 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
301 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
302 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)FilePathDevicePath
;
308 BdsLoadOptionFileSystemUpdateDevicePath (
309 IN EFI_DEVICE_PATH
*OldDevicePath
,
311 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
315 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
316 UINTN BootFilePathSize
;
317 FILEPATH_DEVICE_PATH
* EndingDevicePath
;
318 FILEPATH_DEVICE_PATH
* FilePathDevicePath
;
319 EFI_DEVICE_PATH
* DevicePath
;
321 DevicePath
= DuplicateDevicePath (OldDevicePath
);
323 EndingDevicePath
= (FILEPATH_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
325 Print(L
"File path of the %s: ", FileName
);
326 StrnCpy (BootFilePath
, EndingDevicePath
->PathName
, BOOT_DEVICE_FILEPATH_MAX
);
327 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
328 if (EFI_ERROR(Status
)) {
332 BootFilePathSize
= StrSize(BootFilePath
);
333 if (BootFilePathSize
== 2) {
334 *NewDevicePath
= NULL
;
335 return EFI_NOT_FOUND
;
338 // Create the FilePath Device Path node
339 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
340 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
341 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
342 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
343 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
345 // Generate the new Device Path by replacing the last node by the updated node
346 SetDevicePathEndNode (EndingDevicePath
);
347 *NewDevicePath
= AppendDevicePathNode (DevicePath
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)FilePathDevicePath
);
348 FreePool(DevicePath
);
354 Check if a boot option path is a file system boot option path or not.
356 The device specified by the beginning of the path has to support the Simple File
357 System protocol. Furthermore, the remaining part of the path has to be composed of
358 a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP.
360 @param[in] DevicePath Complete device path of a boot option.
362 @retval FALSE The boot option path has not been identified as that of a
363 file system boot option.
364 @retval TRUE The boot option path is a file system boot option.
367 BdsLoadOptionFileSystemIsSupported (
368 IN EFI_DEVICE_PATH
*DevicePath
373 EFI_DEVICE_PATH
*RemainingDevicePath
;
374 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FileProtocol
;
376 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
377 if (EFI_ERROR (Status
)) {
381 Status
= gBS
->HandleProtocol (
383 &gEfiSimpleFileSystemProtocolGuid
,
384 (VOID
**)(&FileProtocol
)
386 if (EFI_ERROR (Status
)) {
390 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
))
399 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
400 IN EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePath
406 ParentSize
= GetDevicePathSize (ParentDevicePath
);
407 ChildSize
= GetDevicePathSize (ChildDevicePath
);
409 if (ParentSize
> ChildSize
) {
413 if (CompareMem (ParentDevicePath
, ChildDevicePath
, ParentSize
- END_DEVICE_PATH_LENGTH
) != 0) {
421 BdsLoadOptionMemMapList (
422 IN OUT LIST_ENTRY
* BdsLoadOptionList
427 EFI_HANDLE
*HandleBuffer
;
428 UINTN DevicePathHandleCount
;
429 EFI_HANDLE
*DevicePathHandleBuffer
;
433 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
434 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
435 EFI_DEVICE_PATH
* DevicePath
;
436 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*FileProtocol
;
437 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
439 // List all the BlockIo Protocols
440 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
441 if (EFI_ERROR (Status
)) {
445 for (Index
= 0; Index
< HandleCount
; Index
++) {
446 // We only select handles WITH a Device Path AND not part of Media (to
447 // avoid duplication with HardDisk, CDROM, etc). Skip handles used by
448 // Simple Filesystem or used for Variable Storage.
451 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
],
452 &gEfiSimpleFileSystemProtocolGuid
,
453 (VOID
*)&FileProtocol
);
454 if (!EFI_ERROR(Status
)) {
455 // SimpleFilesystem supported on this handle, skip
459 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
],
460 &gEfiFirmwareVolumeBlockProtocolGuid
,
461 (VOID
*)&FvbProtocol
);
462 if (!EFI_ERROR(Status
)) {
463 // Firmware Volme Block / Variable storage supported on this handle, skip
467 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
],
468 &gEfiFirmwareVolumeBlock2ProtocolGuid
,
469 (VOID
*)&FvbProtocol
);
470 if (!EFI_ERROR(Status
)) {
471 // Firmware Volme Block / Variable storage supported on this handle, skip
475 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
476 if (!EFI_ERROR(Status
)) {
477 // BlockIo is not part of Media Device Path
478 DevicePath
= DevicePathProtocol
;
479 while (!IsDevicePathEndType (DevicePath
) && (DevicePathType (DevicePath
) != MEDIA_DEVICE_PATH
)) {
480 DevicePath
= NextDevicePathNode (DevicePath
);
482 if (DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) {
486 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
487 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiDevicePathProtocolGuid
, NULL
, &DevicePathHandleCount
, &DevicePathHandleBuffer
);
488 ASSERT_EFI_ERROR (Status
);
490 for (Index2
= 0; (Index2
< DevicePathHandleCount
) && !IsParent
; Index2
++) {
491 if (HandleBuffer
[Index
] != DevicePathHandleBuffer
[Index2
]) {
492 gBS
->HandleProtocol (DevicePathHandleBuffer
[Index2
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
493 if (IsParentDevicePath (DevicePathProtocol
, DevicePath
)) {
502 // Allocate BDS Supported Device structure
503 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
505 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], SupportedDevice
->Description
);
506 ASSERT_EFI_ERROR (Status
);
508 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
509 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_MEMMAP
];
511 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
519 BdsLoadOptionMemMapCreateDevicePath (
521 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
525 MEMMAP_DEVICE_PATH
*MemMapDevicePath
;
526 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
527 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
529 Print(L
"Starting Address of the %s: ", FileName
);
530 Status
= GetHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
531 if (EFI_ERROR(Status
)) {
535 Print(L
"Ending Address of the %s: ", FileName
);
536 Status
= GetHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
537 if (EFI_ERROR(Status
)) {
541 // Create the MemMap Device Path Node
542 MemMapDevicePath
= (MEMMAP_DEVICE_PATH
*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH
) + END_DEVICE_PATH_LENGTH
);
543 MemMapDevicePath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
544 MemMapDevicePath
->Header
.SubType
= HW_MEMMAP_DP
;
545 SetDevicePathNodeLength (MemMapDevicePath
, sizeof(MEMMAP_DEVICE_PATH
));
546 MemMapDevicePath
->MemoryType
= EfiBootServicesData
;
547 MemMapDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
548 MemMapDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
550 // Set a Device Path End Node after the Memory Map Device Path Node
551 SetDevicePathEndNode (MemMapDevicePath
+ 1);
552 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)MemMapDevicePath
;
558 BdsLoadOptionMemMapUpdateDevicePath (
559 IN EFI_DEVICE_PATH
*OldDevicePath
,
561 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
565 CHAR16 StrStartingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
566 CHAR16 StrEndingAddress
[BOOT_DEVICE_ADDRESS_MAX
];
567 MEMMAP_DEVICE_PATH
* EndingDevicePath
;
568 EFI_DEVICE_PATH
* DevicePath
;
570 DevicePath
= DuplicateDevicePath (OldDevicePath
);
571 EndingDevicePath
= (MEMMAP_DEVICE_PATH
*)GetLastDevicePathNode (DevicePath
);
573 Print(L
"Starting Address of the %s: ", FileName
);
574 UnicodeSPrint (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->StartingAddress
);
575 Status
= EditHIInputStr (StrStartingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
576 if (EFI_ERROR(Status
)) {
580 Print(L
"Ending Address of the %s: ", FileName
);
581 UnicodeSPrint (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
, L
"0x%X", (UINTN
)EndingDevicePath
->EndingAddress
);
582 Status
= EditHIInputStr (StrEndingAddress
, BOOT_DEVICE_ADDRESS_MAX
);
583 if (EFI_ERROR(Status
)) {
587 EndingDevicePath
->StartingAddress
= StrHexToUint64 (StrStartingAddress
);
588 EndingDevicePath
->EndingAddress
= StrHexToUint64 (StrEndingAddress
);
590 if (EFI_ERROR(Status
)) {
591 FreePool(DevicePath
);
593 *NewDevicePath
= DevicePath
;
600 Check if a boot option path is a memory map boot option path or not.
602 The device specified by the beginning of the path has to support the BlockIo
603 protocol. Furthermore, the remaining part of the path has to be composed of
604 a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP.
606 @param[in] DevicePath Complete device path of a boot option.
608 @retval FALSE The boot option path has not been identified as that of a
609 memory map boot option.
610 @retval TRUE The boot option path is a a memory map boot option.
613 BdsLoadOptionMemMapIsSupported (
614 IN EFI_DEVICE_PATH
*DevicePath
619 EFI_DEVICE_PATH
*RemainingDevicePath
;
620 EFI_BLOCK_IO_PROTOCOL
*BlockIoProtocol
;
622 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
623 if (EFI_ERROR (Status
)) {
627 Status
= gBS
->HandleProtocol (
629 &gEfiBlockIoProtocolGuid
,
630 (VOID
**)(&BlockIoProtocol
)
632 if (EFI_ERROR (Status
)) {
636 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath
, HARDWARE_DEVICE_PATH
, HW_MEMMAP_DP
))
643 BdsLoadOptionPxeList (
644 IN OUT LIST_ENTRY
* BdsLoadOptionList
649 EFI_HANDLE
*HandleBuffer
;
651 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
652 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
653 EFI_SIMPLE_NETWORK_PROTOCOL
* SimpleNet
;
654 CHAR16 DeviceDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
655 EFI_MAC_ADDRESS
*Mac
;
657 // List all the PXE Protocols
658 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiPxeBaseCodeProtocolGuid
, NULL
, &HandleCount
, &HandleBuffer
);
659 if (EFI_ERROR (Status
)) {
663 for (Index
= 0; Index
< HandleCount
; Index
++) {
664 // We only select the handle WITH a Device Path AND the PXE Protocol
665 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
666 if (!EFI_ERROR(Status
)) {
667 // Allocate BDS Supported Device structure
668 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE
));
670 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&SimpleNet
);
671 if (!EFI_ERROR(Status
)) {
672 Mac
= &SimpleNet
->Mode
->CurrentAddress
;
673 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]);
675 Status
= GenerateDeviceDescriptionName (HandleBuffer
[Index
], DeviceDescription
);
676 ASSERT_EFI_ERROR (Status
);
678 UnicodeSPrint (SupportedDevice
->Description
,BOOT_DEVICE_DESCRIPTION_MAX
,L
"PXE on %s",DeviceDescription
);
680 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
681 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_PXE
];
683 InsertTailList (BdsLoadOptionList
,&SupportedDevice
->Link
);
691 BdsLoadOptionPxeCreateDevicePath (
693 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
696 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*) AllocatePool (END_DEVICE_PATH_LENGTH
);
697 SetDevicePathEndNode (*DevicePathNodes
);
703 Update the parameters of a Pxe boot option
705 @param[in] OldDevicePath Current complete device path of the Pxe boot option.
706 This has to be a valid complete Pxe boot option path.
707 @param[in] FileName Description of the file the path is asked for
708 @param[out] NewDevicePath Pointer to the new complete device path.
710 @retval EFI_SUCCESS Update completed
711 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
714 BdsLoadOptionPxeUpdateDevicePath (
715 IN EFI_DEVICE_PATH
*OldDevicePath
,
717 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
721 // Make a copy of the complete device path that is made of :
722 // the device path of the device supporting the Pxe base code protocol
723 // followed by an end node.
725 *NewDevicePath
= DuplicateDevicePath (OldDevicePath
);
726 if (*NewDevicePath
== NULL
) {
727 return EFI_OUT_OF_RESOURCES
;
734 BdsLoadOptionPxeIsSupported (
735 IN EFI_DEVICE_PATH
*DevicePath
740 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
741 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
743 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
744 if (EFI_ERROR(Status
)) {
748 if (!IsDevicePathEnd(RemainingDevicePath
)) {
752 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
753 if (EFI_ERROR (Status
)) {
761 Add to the list of boot devices the devices allowing a TFTP boot
763 @param[in] BdsLoadOptionList List of devices to boot from
765 @retval EFI_SUCCESS Update completed
766 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
769 BdsLoadOptionTftpList (
770 IN OUT LIST_ENTRY
* BdsLoadOptionList
775 EFI_HANDLE
*HandleBuffer
;
778 EFI_DEVICE_PATH_PROTOCOL
*DevicePathProtocol
;
780 EFI_SIMPLE_NETWORK_PROTOCOL
*SimpleNetworkProtocol
;
781 BDS_SUPPORTED_DEVICE
*SupportedDevice
;
782 EFI_MAC_ADDRESS
*Mac
;
785 // List all the handles on which the Simple Network Protocol is installed.
787 Status
= gBS
->LocateHandleBuffer (
789 &gEfiSimpleNetworkProtocolGuid
,
794 if (EFI_ERROR (Status
)) {
798 for (Index
= 0; Index
< HandleCount
; Index
++) {
799 Handle
= HandleBuffer
[Index
];
801 // We select the handles that support :
802 // . the Device Path Protocol
803 // . the MTFTP4 Protocol
805 Status
= gBS
->HandleProtocol (
807 &gEfiDevicePathProtocolGuid
,
808 (VOID
**)&DevicePathProtocol
810 if (EFI_ERROR (Status
)) {
814 Status
= gBS
->HandleProtocol (
816 &gEfiMtftp4ServiceBindingProtocolGuid
,
819 if (EFI_ERROR (Status
)) {
823 Status
= gBS
->HandleProtocol (
825 &gEfiSimpleNetworkProtocolGuid
,
826 (VOID
**)&SimpleNetworkProtocol
828 if (EFI_ERROR (Status
)) {
832 // Allocate BDS Supported Device structure
833 SupportedDevice
= (BDS_SUPPORTED_DEVICE
*)AllocatePool (sizeof (BDS_SUPPORTED_DEVICE
));
834 if (SupportedDevice
== NULL
) {
838 Mac
= &SimpleNetworkProtocol
->Mode
->CurrentAddress
;
840 SupportedDevice
->Description
,
841 BOOT_DEVICE_DESCRIPTION_MAX
,
842 L
"TFTP on MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
843 Mac
->Addr
[0], Mac
->Addr
[1], Mac
->Addr
[2], Mac
->Addr
[3], Mac
->Addr
[4], Mac
->Addr
[5]
846 SupportedDevice
->DevicePathProtocol
= DevicePathProtocol
;
847 SupportedDevice
->Support
= &BdsLoadOptionSupportList
[BDS_DEVICE_TFTP
];
849 InsertTailList (BdsLoadOptionList
, &SupportedDevice
->Link
);
856 BdsLoadOptionTftpCreateDevicePath (
858 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePathNodes
863 EFI_IP_ADDRESS LocalIp
;
864 EFI_IP_ADDRESS SubnetMask
;
865 EFI_IP_ADDRESS GatewayIp
;
866 EFI_IP_ADDRESS RemoteIp
;
867 IPv4_DEVICE_PATH
*IPv4DevicePathNode
;
868 FILEPATH_DEVICE_PATH
*FilePathDevicePath
;
869 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
870 UINTN BootFilePathSize
;
872 Print (L
"Get the IP address from DHCP: ");
873 Status
= GetHIInputBoolean (&IsDHCP
);
874 if (EFI_ERROR (Status
)) {
879 Print (L
"Local static IP address: ");
880 Status
= GetHIInputIP (&LocalIp
);
881 if (EFI_ERROR (Status
)) {
884 Print (L
"Get the network mask: ");
885 Status
= GetHIInputIP (&SubnetMask
);
886 if (EFI_ERROR (Status
)) {
889 Print (L
"Get the gateway IP address: ");
890 Status
= GetHIInputIP (&GatewayIp
);
891 if (EFI_ERROR (Status
)) {
896 Print (L
"Get the TFTP server IP address: ");
897 Status
= GetHIInputIP (&RemoteIp
);
898 if (EFI_ERROR (Status
)) {
902 Print (L
"File path of the %s : ", FileName
);
903 Status
= GetHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
904 if (EFI_ERROR (Status
)) {
908 BootFilePathSize
= StrSize(BootFilePath
);
909 if (BootFilePathSize
== 2) {
910 return EFI_NOT_FOUND
;
913 // Allocate the memory for the IPv4 + File Path Device Path Nodes
914 IPv4DevicePathNode
= (IPv4_DEVICE_PATH
*)AllocatePool(sizeof(IPv4_DEVICE_PATH
) + SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
+ END_DEVICE_PATH_LENGTH
);
916 // Create the IPv4 Device Path
917 IPv4DevicePathNode
->Header
.Type
= MESSAGING_DEVICE_PATH
;
918 IPv4DevicePathNode
->Header
.SubType
= MSG_IPv4_DP
;
919 SetDevicePathNodeLength (&IPv4DevicePathNode
->Header
, sizeof(IPv4_DEVICE_PATH
));
922 CopyMem (&IPv4DevicePathNode
->LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
923 CopyMem (&IPv4DevicePathNode
->SubnetMask
, &SubnetMask
.v4
, sizeof (EFI_IPv4_ADDRESS
));
924 CopyMem (&IPv4DevicePathNode
->GatewayIpAddress
, &GatewayIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
927 CopyMem (&IPv4DevicePathNode
->RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
928 IPv4DevicePathNode
->LocalPort
= 0;
929 IPv4DevicePathNode
->RemotePort
= 0;
930 IPv4DevicePathNode
->Protocol
= EFI_IP_PROTO_TCP
;
931 IPv4DevicePathNode
->StaticIpAddress
= (IsDHCP
!= TRUE
);
933 // Create the FilePath Device Path node
934 FilePathDevicePath
= (FILEPATH_DEVICE_PATH
*)(IPv4DevicePathNode
+ 1);
935 FilePathDevicePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
936 FilePathDevicePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
937 SetDevicePathNodeLength (FilePathDevicePath
, SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
);
938 CopyMem (FilePathDevicePath
->PathName
, BootFilePath
, BootFilePathSize
);
940 // Set the End Device Path Node
941 SetDevicePathEndNode ((VOID
*)((UINTN
)FilePathDevicePath
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ BootFilePathSize
));
942 *DevicePathNodes
= (EFI_DEVICE_PATH_PROTOCOL
*)IPv4DevicePathNode
;
948 Update the parameters of a TFTP boot option
950 The function asks sequentially to update the IPv4 parameters as well as the boot file path,
951 providing the previously set value if any.
953 @param[in] OldDevicePath Current complete device path of the Tftp boot option.
954 This has to be a valid complete Tftp boot option path.
955 By complete, we mean that it is not only the Tftp
956 specific end part built by the
957 "BdsLoadOptionTftpCreateDevicePath()" function.
958 This path is handled as read only.
959 @param[in] FileName Description of the file the path is asked for
960 @param[out] NewDevicePath Pointer to the new complete device path.
962 @retval EFI_SUCCESS Update completed
963 @retval EFI_ABORTED Update aborted by the user
964 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
967 BdsLoadOptionTftpUpdateDevicePath (
968 IN EFI_DEVICE_PATH
*OldDevicePath
,
970 OUT EFI_DEVICE_PATH_PROTOCOL
**NewDevicePath
974 EFI_DEVICE_PATH
*DevicePath
;
975 EFI_DEVICE_PATH
*DevicePathNode
;
977 IPv4_DEVICE_PATH Ipv4Node
;
979 EFI_IP_ADDRESS OldIp
;
980 EFI_IP_ADDRESS OldSubnetMask
;
981 EFI_IP_ADDRESS OldGatewayIp
;
982 EFI_IP_ADDRESS LocalIp
;
983 EFI_IP_ADDRESS SubnetMask
;
984 EFI_IP_ADDRESS GatewayIp
;
985 EFI_IP_ADDRESS RemoteIp
;
987 CHAR16 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
];
989 UINTN BootFilePathSize
;
990 FILEPATH_DEVICE_PATH
*NewFilePathNode
;
995 // Make a copy of the complete device path that is made of :
996 // the device path of the device that support the Simple Network protocol
997 // followed by an IPv4 node (type IPv4_DEVICE_PATH),
998 // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up
999 // by an end node. The IPv6 case is not handled yet.
1002 DevicePath
= DuplicateDevicePath (OldDevicePath
);
1003 if (DevicePath
== NULL
) {
1004 Status
= EFI_OUT_OF_RESOURCES
;
1009 // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the
1010 // call to this function, we know that the device path ends with an IPv4 node
1011 // followed by a file path node and finally an end node. To get the address of
1012 // the last IPv4 node, we loop over the whole device path, noting down the
1013 // address of each encountered IPv4 node.
1016 for (DevicePathNode
= DevicePath
;
1017 !IsDevicePathEnd (DevicePathNode
);
1018 DevicePathNode
= NextDevicePathNode (DevicePathNode
))
1020 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MESSAGING_DEVICE_PATH
, MSG_IPv4_DP
)) {
1021 Ipv4NodePtr
= (UINT8
*)DevicePathNode
;
1025 // Copy for alignment of the IPv4 node data
1026 CopyMem (&Ipv4Node
, Ipv4NodePtr
, sizeof (IPv4_DEVICE_PATH
));
1028 Print (L
"Get the IP address from DHCP: ");
1029 Status
= GetHIInputBoolean (&IsDHCP
);
1030 if (EFI_ERROR (Status
)) {
1035 Print (L
"Local static IP address: ");
1036 if (Ipv4Node
.StaticIpAddress
) {
1037 CopyMem (&OldIp
.v4
, &Ipv4Node
.LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1038 Status
= EditHIInputIP (&OldIp
, &LocalIp
);
1040 Status
= GetHIInputIP (&LocalIp
);
1042 if (EFI_ERROR (Status
)) {
1046 Print (L
"Get the network mask: ");
1047 if (Ipv4Node
.StaticIpAddress
) {
1048 CopyMem (&OldSubnetMask
.v4
, &Ipv4Node
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1049 Status
= EditHIInputIP (&OldSubnetMask
, &SubnetMask
);
1051 Status
= GetHIInputIP (&SubnetMask
);
1053 if (EFI_ERROR (Status
)) {
1057 Print (L
"Get the gateway IP address: ");
1058 if (Ipv4Node
.StaticIpAddress
) {
1059 CopyMem (&OldGatewayIp
.v4
, &Ipv4Node
.GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1060 Status
= EditHIInputIP (&OldGatewayIp
, &GatewayIp
);
1062 Status
= GetHIInputIP (&GatewayIp
);
1064 if (EFI_ERROR (Status
)) {
1069 Print (L
"TFTP server IP address: ");
1070 // Copy remote IPv4 address into IPv4 or IPv6 union
1071 CopyMem (&OldIp
.v4
, &Ipv4Node
.RemoteIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1073 Status
= EditHIInputIP (&OldIp
, &RemoteIp
);
1074 if (EFI_ERROR (Status
)) {
1078 // Get the path of the boot file and its size in number of bytes
1079 FileNodePtr
= Ipv4NodePtr
+ sizeof (IPv4_DEVICE_PATH
);
1080 BootFilePathSize
= DevicePathNodeLength (FileNodePtr
) - SIZE_OF_FILEPATH_DEVICE_PATH
;
1083 // Ask for update of the boot file path
1086 // Copy for 2-byte alignment of the Unicode string
1088 BootFilePath
, FileNodePtr
+ SIZE_OF_FILEPATH_DEVICE_PATH
,
1089 MIN (BootFilePathSize
, BOOT_DEVICE_FILEPATH_MAX
)
1091 BootFilePath
[BOOT_DEVICE_FILEPATH_MAX
- 1] = L
'\0';
1093 Print (L
"File path of the %s: ", FileName
);
1094 Status
= EditHIInputStr (BootFilePath
, BOOT_DEVICE_FILEPATH_MAX
);
1095 if (EFI_ERROR (Status
)) {
1098 PathSize
= StrSize (BootFilePath
);
1102 // Empty string, give the user another try
1103 Print (L
"Empty string - Invalid path\n");
1104 } while (PathSize
<= 2) ;
1107 // Update the IPv4 node. IPv6 case not handled yet.
1110 Ipv4Node
.StaticIpAddress
= FALSE
;
1111 ZeroMem (&Ipv4Node
.LocalIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1112 ZeroMem (&Ipv4Node
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
1113 ZeroMem (&Ipv4Node
.GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
1115 Ipv4Node
.StaticIpAddress
= TRUE
;
1116 CopyMem (&Ipv4Node
.LocalIpAddress
, &LocalIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1117 CopyMem (&Ipv4Node
.SubnetMask
, &SubnetMask
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1118 CopyMem (&Ipv4Node
.GatewayIpAddress
, &GatewayIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1121 CopyMem (&Ipv4Node
.RemoteIpAddress
, &RemoteIp
.v4
, sizeof (EFI_IPv4_ADDRESS
));
1122 CopyMem (Ipv4NodePtr
, &Ipv4Node
, sizeof (IPv4_DEVICE_PATH
));
1125 // Create the new file path node
1127 NewFilePathNode
= (FILEPATH_DEVICE_PATH
*)AllocatePool (
1128 SIZE_OF_FILEPATH_DEVICE_PATH
+
1131 NewFilePathNode
->Header
.Type
= MEDIA_DEVICE_PATH
;
1132 NewFilePathNode
->Header
.SubType
= MEDIA_FILEPATH_DP
;
1133 SetDevicePathNodeLength (
1135 SIZE_OF_FILEPATH_DEVICE_PATH
+ PathSize
1137 CopyMem (NewFilePathNode
->PathName
, BootFilePath
, PathSize
);
1140 // Generate the new Device Path by replacing the file path node at address
1141 // "FileNodePtr" by the new one "NewFilePathNode" and return its address.
1143 SetDevicePathEndNode (FileNodePtr
);
1144 *NewDevicePath
= AppendDevicePathNode (
1146 (CONST EFI_DEVICE_PATH_PROTOCOL
*)NewFilePathNode
1150 if (DevicePath
!= NULL
) {
1151 FreePool (DevicePath
) ;
1158 BdsLoadOptionTftpIsSupported (
1159 IN EFI_DEVICE_PATH
*DevicePath
1164 EFI_DEVICE_PATH
*RemainingDevicePath
;
1165 EFI_DEVICE_PATH
*NextDevicePath
;
1166 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBcProtocol
;
1168 Status
= BdsConnectDevicePath (DevicePath
, &Handle
, &RemainingDevicePath
);
1169 if (EFI_ERROR(Status
)) {
1173 // Validate the Remaining Device Path
1174 if (IsDevicePathEnd(RemainingDevicePath
)) {
1177 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv4_DP
) &&
1178 !IS_DEVICE_PATH_NODE(RemainingDevicePath
,MESSAGING_DEVICE_PATH
,MSG_IPv6_DP
)) {
1181 NextDevicePath
= NextDevicePathNode (RemainingDevicePath
);
1182 if (IsDevicePathEnd(NextDevicePath
)) {
1185 if (!IS_DEVICE_PATH_NODE(NextDevicePath
,MEDIA_DEVICE_PATH
,MEDIA_FILEPATH_DP
)) {
1189 Status
= gBS
->HandleProtocol (Handle
, &gEfiPxeBaseCodeProtocolGuid
, (VOID
**)&PxeBcProtocol
);
1190 if (EFI_ERROR (Status
)) {