/** @file | |
* | |
* Copyright (c) 2011-2014, ARM Limited. All rights reserved. | |
* | |
* This program and the accompanying materials | |
* are licensed and made available under the terms and conditions of the BSD License | |
* which accompanies this distribution. The full text of the license may be found at | |
* http://opensource.org/licenses/bsd-license.php | |
* | |
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
* | |
**/ | |
#include "BdsInternal.h" | |
#include <Library/NetLib.h> | |
#include <Protocol/BlockIo.h> | |
#include <Protocol/DevicePathToText.h> | |
#include <Protocol/FirmwareVolumeBlock.h> | |
#include <Protocol/PxeBaseCode.h> | |
#include <Protocol/SimpleFileSystem.h> | |
#include <Protocol/SimpleNetwork.h> | |
#include <Protocol/Dhcp4.h> | |
#include <Protocol/Mtftp4.h> | |
#include <Guid/FileSystemInfo.h> | |
#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype))) | |
EFI_STATUS | |
BdsLoadOptionFileSystemList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
); | |
EFI_STATUS | |
BdsLoadOptionFileSystemCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
); | |
EFI_STATUS | |
BdsLoadOptionFileSystemUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
); | |
BOOLEAN | |
BdsLoadOptionFileSystemIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
); | |
EFI_STATUS | |
BdsLoadOptionMemMapList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
); | |
EFI_STATUS | |
BdsLoadOptionMemMapCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
); | |
EFI_STATUS | |
BdsLoadOptionMemMapUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
); | |
BOOLEAN | |
BdsLoadOptionMemMapIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
); | |
EFI_STATUS | |
BdsLoadOptionPxeList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
); | |
EFI_STATUS | |
BdsLoadOptionPxeCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
); | |
EFI_STATUS | |
BdsLoadOptionPxeUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
); | |
BOOLEAN | |
BdsLoadOptionPxeIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
); | |
EFI_STATUS | |
BdsLoadOptionTftpList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
); | |
EFI_STATUS | |
BdsLoadOptionTftpCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
); | |
EFI_STATUS | |
BdsLoadOptionTftpUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
); | |
BOOLEAN | |
BdsLoadOptionTftpIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
); | |
BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = { | |
{ | |
BDS_DEVICE_FILESYSTEM, | |
BdsLoadOptionFileSystemList, | |
BdsLoadOptionFileSystemIsSupported, | |
BdsLoadOptionFileSystemCreateDevicePath, | |
BdsLoadOptionFileSystemUpdateDevicePath, | |
TRUE | |
}, | |
{ | |
BDS_DEVICE_MEMMAP, | |
BdsLoadOptionMemMapList, | |
BdsLoadOptionMemMapIsSupported, | |
BdsLoadOptionMemMapCreateDevicePath, | |
BdsLoadOptionMemMapUpdateDevicePath, | |
TRUE | |
}, | |
{ | |
BDS_DEVICE_PXE, | |
BdsLoadOptionPxeList, | |
BdsLoadOptionPxeIsSupported, | |
BdsLoadOptionPxeCreateDevicePath, | |
BdsLoadOptionPxeUpdateDevicePath, | |
FALSE | |
}, | |
{ | |
BDS_DEVICE_TFTP, | |
BdsLoadOptionTftpList, | |
BdsLoadOptionTftpIsSupported, | |
BdsLoadOptionTftpCreateDevicePath, | |
BdsLoadOptionTftpUpdateDevicePath, | |
TRUE | |
} | |
}; | |
EFI_STATUS | |
BootDeviceListSupportedInit ( | |
IN OUT LIST_ENTRY *SupportedDeviceList | |
) | |
{ | |
UINTN Index; | |
// Initialize list of supported devices | |
InitializeListHead (SupportedDeviceList); | |
for (Index = 0; Index < BDS_DEVICE_MAX; Index++) { | |
BdsLoadOptionSupportList[Index].ListDevices (SupportedDeviceList); | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
BootDeviceListSupportedFree ( | |
IN LIST_ENTRY *SupportedDeviceList, | |
IN BDS_SUPPORTED_DEVICE *Except | |
) | |
{ | |
LIST_ENTRY *Entry; | |
BDS_SUPPORTED_DEVICE* SupportedDevice; | |
Entry = GetFirstNode (SupportedDeviceList); | |
while (Entry != SupportedDeviceList) { | |
SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry); | |
Entry = RemoveEntryList (Entry); | |
if (SupportedDevice != Except) { | |
FreePool (SupportedDevice); | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
BootDeviceGetDeviceSupport ( | |
IN EFI_DEVICE_PATH *DevicePath, | |
OUT BDS_LOAD_OPTION_SUPPORT **DeviceSupport | |
) | |
{ | |
UINTN Index; | |
// Find which supported device is the most appropriate | |
for (Index = 0; Index < BDS_DEVICE_MAX; Index++) { | |
if (BdsLoadOptionSupportList[Index].IsSupported (DevicePath)) { | |
*DeviceSupport = &BdsLoadOptionSupportList[Index]; | |
return EFI_SUCCESS; | |
} | |
} | |
return EFI_UNSUPPORTED; | |
} | |
EFI_STATUS | |
BdsLoadOptionFileSystemList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleCount; | |
EFI_HANDLE *HandleBuffer; | |
UINTN Index; | |
BDS_SUPPORTED_DEVICE *SupportedDevice; | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileProtocol; | |
EFI_FILE_HANDLE Fs; | |
UINTN Size; | |
EFI_FILE_SYSTEM_INFO* FsInfo; | |
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; | |
// List all the Simple File System Protocols | |
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleCount; Index++) { | |
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); | |
if (!EFI_ERROR(Status)) { | |
// Allocate BDS Supported Device structure | |
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE)); | |
FileProtocol = NULL; | |
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileProtocol); | |
ASSERT_EFI_ERROR(Status); | |
FileProtocol->OpenVolume (FileProtocol, &Fs); | |
// Generate a Description from the file system | |
Size = 0; | |
FsInfo = NULL; | |
Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
FsInfo = AllocatePool (Size); | |
Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo); | |
} | |
UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"%s (%d MB)",FsInfo->VolumeLabel,(UINT32)(FsInfo->VolumeSize / (1024 * 1024))); | |
FreePool(FsInfo); | |
Fs->Close (Fs); | |
SupportedDevice->DevicePathProtocol = DevicePathProtocol; | |
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_FILESYSTEM]; | |
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link); | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
BdsLoadOptionFileSystemCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
) | |
{ | |
EFI_STATUS Status; | |
FILEPATH_DEVICE_PATH* FilePathDevicePath; | |
CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; | |
UINTN BootFilePathSize; | |
Print(L"File path of the %s: ", FileName); | |
Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); | |
if (EFI_ERROR(Status)) { | |
return EFI_ABORTED; | |
} | |
BootFilePathSize = StrSize (BootFilePath); | |
if (BootFilePathSize == 2) { | |
*DevicePathNodes = NULL; | |
return EFI_NOT_FOUND; | |
} | |
// Create the FilePath Device Path node | |
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH); | |
FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH; | |
FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP; | |
SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize); | |
CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize); | |
SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize)); | |
*DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath; | |
return Status; | |
} | |
EFI_STATUS | |
BdsLoadOptionFileSystemUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; | |
UINTN BootFilePathSize; | |
FILEPATH_DEVICE_PATH* EndingDevicePath; | |
FILEPATH_DEVICE_PATH* FilePathDevicePath; | |
EFI_DEVICE_PATH* DevicePath; | |
DevicePath = DuplicateDevicePath (OldDevicePath); | |
EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath); | |
Print(L"File path of the %s: ", FileName); | |
StrnCpy (BootFilePath, EndingDevicePath->PathName, BOOT_DEVICE_FILEPATH_MAX); | |
Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); | |
if (EFI_ERROR(Status)) { | |
return Status; | |
} | |
BootFilePathSize = StrSize(BootFilePath); | |
if (BootFilePathSize == 2) { | |
*NewDevicePath = NULL; | |
return EFI_NOT_FOUND; | |
} | |
// Create the FilePath Device Path node | |
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize); | |
FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH; | |
FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP; | |
SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize); | |
CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize); | |
// Generate the new Device Path by replacing the last node by the updated node | |
SetDevicePathEndNode (EndingDevicePath); | |
*NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath); | |
FreePool(DevicePath); | |
return EFI_SUCCESS; | |
} | |
/** | |
Check if a boot option path is a file system boot option path or not. | |
The device specified by the beginning of the path has to support the Simple File | |
System protocol. Furthermore, the remaining part of the path has to be composed of | |
a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP. | |
@param[in] DevicePath Complete device path of a boot option. | |
@retval FALSE The boot option path has not been identified as that of a | |
file system boot option. | |
@retval TRUE The boot option path is a file system boot option. | |
**/ | |
BOOLEAN | |
BdsLoadOptionFileSystemIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE Handle; | |
EFI_DEVICE_PATH *RemainingDevicePath; | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileProtocol; | |
Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); | |
if (EFI_ERROR (Status)) { | |
return FALSE; | |
} | |
Status = gBS->HandleProtocol ( | |
Handle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
(VOID **)(&FileProtocol) | |
); | |
if (EFI_ERROR (Status)) { | |
return FALSE; | |
} | |
if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) | |
return FALSE; | |
return TRUE; | |
} | |
STATIC | |
BOOLEAN | |
IsParentDevicePath ( | |
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, | |
IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath | |
) | |
{ | |
UINTN ParentSize; | |
UINTN ChildSize; | |
ParentSize = GetDevicePathSize (ParentDevicePath); | |
ChildSize = GetDevicePathSize (ChildDevicePath); | |
if (ParentSize > ChildSize) { | |
return FALSE; | |
} | |
if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) { | |
return FALSE; | |
} | |
return TRUE; | |
} | |
EFI_STATUS | |
BdsLoadOptionMemMapList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleCount; | |
EFI_HANDLE *HandleBuffer; | |
UINTN DevicePathHandleCount; | |
EFI_HANDLE *DevicePathHandleBuffer; | |
BOOLEAN IsParent; | |
UINTN Index; | |
UINTN Index2; | |
BDS_SUPPORTED_DEVICE *SupportedDevice; | |
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; | |
EFI_DEVICE_PATH* DevicePath; | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileProtocol; | |
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; | |
// List all the BlockIo Protocols | |
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleCount; Index++) { | |
// We only select handles WITH a Device Path AND not part of Media (to | |
// avoid duplication with HardDisk, CDROM, etc). Skip handles used by | |
// Simple Filesystem or used for Variable Storage. | |
Status = gBS->HandleProtocol (HandleBuffer[Index], | |
&gEfiSimpleFileSystemProtocolGuid, | |
(VOID *)&FileProtocol); | |
if (!EFI_ERROR(Status)) { | |
// SimpleFilesystem supported on this handle, skip | |
continue; | |
} | |
Status = gBS->HandleProtocol (HandleBuffer[Index], | |
&gEfiFirmwareVolumeBlockProtocolGuid, | |
(VOID *)&FvbProtocol); | |
if (!EFI_ERROR(Status)) { | |
// Firmware Volme Block / Variable storage supported on this handle, skip | |
continue; | |
} | |
Status = gBS->HandleProtocol (HandleBuffer[Index], | |
&gEfiFirmwareVolumeBlock2ProtocolGuid, | |
(VOID *)&FvbProtocol); | |
if (!EFI_ERROR(Status)) { | |
// Firmware Volme Block / Variable storage supported on this handle, skip | |
continue; | |
} | |
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); | |
if (!EFI_ERROR(Status)) { | |
// BlockIo is not part of Media Device Path | |
DevicePath = DevicePathProtocol; | |
while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) { | |
DevicePath = NextDevicePathNode (DevicePath); | |
} | |
if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) { | |
continue; | |
} | |
// Open all the handle supporting the DevicePath protocol and verify this handle has not got any child | |
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer); | |
ASSERT_EFI_ERROR (Status); | |
IsParent = FALSE; | |
for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) { | |
if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) { | |
gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath); | |
if (IsParentDevicePath (DevicePathProtocol, DevicePath)) { | |
IsParent = TRUE; | |
} | |
} | |
} | |
if (IsParent) { | |
continue; | |
} | |
// Allocate BDS Supported Device structure | |
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE)); | |
Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description); | |
ASSERT_EFI_ERROR (Status); | |
SupportedDevice->DevicePathProtocol = DevicePathProtocol; | |
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP]; | |
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link); | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
BdsLoadOptionMemMapCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
) | |
{ | |
EFI_STATUS Status; | |
MEMMAP_DEVICE_PATH *MemMapDevicePath; | |
CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX]; | |
CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX]; | |
Print(L"Starting Address of the %s: ", FileName); | |
Status = GetHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX); | |
if (EFI_ERROR(Status)) { | |
return EFI_ABORTED; | |
} | |
Print(L"Ending Address of the %s: ", FileName); | |
Status = GetHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX); | |
if (EFI_ERROR(Status)) { | |
return EFI_ABORTED; | |
} | |
// Create the MemMap Device Path Node | |
MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH) + END_DEVICE_PATH_LENGTH); | |
MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH; | |
MemMapDevicePath->Header.SubType = HW_MEMMAP_DP; | |
SetDevicePathNodeLength (MemMapDevicePath, sizeof(MEMMAP_DEVICE_PATH)); | |
MemMapDevicePath->MemoryType = EfiBootServicesData; | |
MemMapDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress); | |
MemMapDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress); | |
// Set a Device Path End Node after the Memory Map Device Path Node | |
SetDevicePathEndNode (MemMapDevicePath + 1); | |
*DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath; | |
return Status; | |
} | |
EFI_STATUS | |
BdsLoadOptionMemMapUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX]; | |
CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX]; | |
MEMMAP_DEVICE_PATH* EndingDevicePath; | |
EFI_DEVICE_PATH* DevicePath; | |
DevicePath = DuplicateDevicePath (OldDevicePath); | |
EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath); | |
Print(L"Starting Address of the %s: ", FileName); | |
UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress); | |
Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX); | |
if (EFI_ERROR(Status)) { | |
return EFI_ABORTED; | |
} | |
Print(L"Ending Address of the %s: ", FileName); | |
UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress); | |
Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX); | |
if (EFI_ERROR(Status)) { | |
return EFI_ABORTED; | |
} | |
EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress); | |
EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress); | |
if (EFI_ERROR(Status)) { | |
FreePool(DevicePath); | |
} else { | |
*NewDevicePath = DevicePath; | |
} | |
return Status; | |
} | |
/** | |
Check if a boot option path is a memory map boot option path or not. | |
The device specified by the beginning of the path has to support the BlockIo | |
protocol. Furthermore, the remaining part of the path has to be composed of | |
a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP. | |
@param[in] DevicePath Complete device path of a boot option. | |
@retval FALSE The boot option path has not been identified as that of a | |
memory map boot option. | |
@retval TRUE The boot option path is a a memory map boot option. | |
**/ | |
BOOLEAN | |
BdsLoadOptionMemMapIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE Handle; | |
EFI_DEVICE_PATH *RemainingDevicePath; | |
EFI_BLOCK_IO_PROTOCOL *BlockIoProtocol; | |
Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); | |
if (EFI_ERROR (Status)) { | |
return FALSE; | |
} | |
Status = gBS->HandleProtocol ( | |
Handle, | |
&gEfiBlockIoProtocolGuid, | |
(VOID **)(&BlockIoProtocol) | |
); | |
if (EFI_ERROR (Status)) { | |
return FALSE; | |
} | |
if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) | |
return FALSE; | |
return TRUE; | |
} | |
EFI_STATUS | |
BdsLoadOptionPxeList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleCount; | |
EFI_HANDLE *HandleBuffer; | |
UINTN Index; | |
BDS_SUPPORTED_DEVICE *SupportedDevice; | |
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; | |
EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet; | |
CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX]; | |
EFI_MAC_ADDRESS *Mac; | |
// List all the PXE Protocols | |
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleCount; Index++) { | |
// We only select the handle WITH a Device Path AND the PXE Protocol | |
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); | |
if (!EFI_ERROR(Status)) { | |
// Allocate BDS Supported Device structure | |
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE)); | |
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleNetworkProtocolGuid, (VOID **)&SimpleNet); | |
if (!EFI_ERROR(Status)) { | |
Mac = &SimpleNet->Mode->CurrentAddress; | |
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]); | |
} else { | |
Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription); | |
ASSERT_EFI_ERROR (Status); | |
} | |
UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription); | |
SupportedDevice->DevicePathProtocol = DevicePathProtocol; | |
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE]; | |
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link); | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
BdsLoadOptionPxeCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
) | |
{ | |
*DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH); | |
SetDevicePathEndNode (*DevicePathNodes); | |
return EFI_SUCCESS; | |
} | |
/** | |
Update the parameters of a Pxe boot option | |
@param[in] OldDevicePath Current complete device path of the Pxe boot option. | |
This has to be a valid complete Pxe boot option path. | |
@param[in] FileName Description of the file the path is asked for | |
@param[out] NewDevicePath Pointer to the new complete device path. | |
@retval EFI_SUCCESS Update completed | |
@retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource | |
**/ | |
EFI_STATUS | |
BdsLoadOptionPxeUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
) | |
{ | |
// | |
// Make a copy of the complete device path that is made of : | |
// the device path of the device supporting the Pxe base code protocol | |
// followed by an end node. | |
// | |
*NewDevicePath = DuplicateDevicePath (OldDevicePath); | |
if (*NewDevicePath == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} else { | |
return EFI_SUCCESS; | |
} | |
} | |
BOOLEAN | |
BdsLoadOptionPxeIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE Handle; | |
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; | |
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; | |
Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); | |
if (EFI_ERROR(Status)) { | |
return FALSE; | |
} | |
if (!IsDevicePathEnd(RemainingDevicePath)) { | |
return FALSE; | |
} | |
Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); | |
if (EFI_ERROR (Status)) { | |
return FALSE; | |
} else { | |
return TRUE; | |
} | |
} | |
/** | |
Add to the list of boot devices the devices allowing a TFTP boot | |
@param[in] BdsLoadOptionList List of devices to boot from | |
@retval EFI_SUCCESS Update completed | |
@retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource | |
**/ | |
EFI_STATUS | |
BdsLoadOptionTftpList ( | |
IN OUT LIST_ENTRY* BdsLoadOptionList | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleCount; | |
EFI_HANDLE *HandleBuffer; | |
EFI_HANDLE Handle; | |
UINTN Index; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol; | |
VOID *Interface; | |
EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetworkProtocol; | |
BDS_SUPPORTED_DEVICE *SupportedDevice; | |
EFI_MAC_ADDRESS *Mac; | |
// | |
// List all the handles on which the Simple Network Protocol is installed. | |
// | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
&gEfiSimpleNetworkProtocolGuid, | |
NULL, | |
&HandleCount, | |
&HandleBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleCount; Index++) { | |
Handle = HandleBuffer[Index]; | |
// | |
// We select the handles that support : | |
// . the Device Path Protocol | |
// . the MTFTP4 Protocol | |
// | |
Status = gBS->HandleProtocol ( | |
Handle, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **)&DevicePathProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
Status = gBS->HandleProtocol ( | |
Handle, | |
&gEfiMtftp4ServiceBindingProtocolGuid, | |
&Interface | |
); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
Status = gBS->HandleProtocol ( | |
Handle, | |
&gEfiSimpleNetworkProtocolGuid, | |
(VOID **)&SimpleNetworkProtocol | |
); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
// Allocate BDS Supported Device structure | |
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof (BDS_SUPPORTED_DEVICE)); | |
if (SupportedDevice == NULL) { | |
continue; | |
} | |
Mac = &SimpleNetworkProtocol->Mode->CurrentAddress; | |
UnicodeSPrint ( | |
SupportedDevice->Description, | |
BOOT_DEVICE_DESCRIPTION_MAX, | |
L"TFTP on 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] | |
); | |
SupportedDevice->DevicePathProtocol = DevicePathProtocol; | |
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP]; | |
InsertTailList (BdsLoadOptionList, &SupportedDevice->Link); | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
BdsLoadOptionTftpCreateDevicePath ( | |
IN CHAR16* FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes | |
) | |
{ | |
EFI_STATUS Status; | |
BOOLEAN IsDHCP; | |
EFI_IP_ADDRESS LocalIp; | |
EFI_IP_ADDRESS SubnetMask; | |
EFI_IP_ADDRESS GatewayIp; | |
EFI_IP_ADDRESS RemoteIp; | |
IPv4_DEVICE_PATH *IPv4DevicePathNode; | |
FILEPATH_DEVICE_PATH *FilePathDevicePath; | |
CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; | |
UINTN BootFilePathSize; | |
Print (L"Get the IP address from DHCP: "); | |
Status = GetHIInputBoolean (&IsDHCP); | |
if (EFI_ERROR (Status)) { | |
return EFI_ABORTED; | |
} | |
if (!IsDHCP) { | |
Print (L"Local static IP address: "); | |
Status = GetHIInputIP (&LocalIp); | |
if (EFI_ERROR (Status)) { | |
return EFI_ABORTED; | |
} | |
Print (L"Get the network mask: "); | |
Status = GetHIInputIP (&SubnetMask); | |
if (EFI_ERROR (Status)) { | |
return EFI_ABORTED; | |
} | |
Print (L"Get the gateway IP address: "); | |
Status = GetHIInputIP (&GatewayIp); | |
if (EFI_ERROR (Status)) { | |
return EFI_ABORTED; | |
} | |
} | |
Print (L"Get the TFTP server IP address: "); | |
Status = GetHIInputIP (&RemoteIp); | |
if (EFI_ERROR (Status)) { | |
return EFI_ABORTED; | |
} | |
Print (L"File path of the %s : ", FileName); | |
Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); | |
if (EFI_ERROR (Status)) { | |
return EFI_ABORTED; | |
} | |
BootFilePathSize = StrSize(BootFilePath); | |
if (BootFilePathSize == 2) { | |
return EFI_NOT_FOUND; | |
} | |
// Allocate the memory for the IPv4 + File Path Device Path Nodes | |
IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH); | |
// Create the IPv4 Device Path | |
IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH; | |
IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP; | |
SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH)); | |
if (!IsDHCP) { | |
CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS)); | |
CopyMem (&IPv4DevicePathNode->SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS)); | |
CopyMem (&IPv4DevicePathNode->GatewayIpAddress, &GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS)); | |
} | |
CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS)); | |
IPv4DevicePathNode->LocalPort = 0; | |
IPv4DevicePathNode->RemotePort = 0; | |
IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP; | |
IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE); | |
// Create the FilePath Device Path node | |
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); | |
FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH; | |
FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP; | |
SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize); | |
CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize); | |
// Set the End Device Path Node | |
SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize)); | |
*DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode; | |
return Status; | |
} | |
/** | |
Update the parameters of a TFTP boot option | |
The function asks sequentially to update the IPv4 parameters as well as the boot file path, | |
providing the previously set value if any. | |
@param[in] OldDevicePath Current complete device path of the Tftp boot option. | |
This has to be a valid complete Tftp boot option path. | |
By complete, we mean that it is not only the Tftp | |
specific end part built by the | |
"BdsLoadOptionTftpCreateDevicePath()" function. | |
This path is handled as read only. | |
@param[in] FileName Description of the file the path is asked for | |
@param[out] NewDevicePath Pointer to the new complete device path. | |
@retval EFI_SUCCESS Update completed | |
@retval EFI_ABORTED Update aborted by the user | |
@retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource | |
**/ | |
EFI_STATUS | |
BdsLoadOptionTftpUpdateDevicePath ( | |
IN EFI_DEVICE_PATH *OldDevicePath, | |
IN CHAR16 *FileName, | |
OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_DEVICE_PATH *DevicePath; | |
EFI_DEVICE_PATH *DevicePathNode; | |
UINT8 *Ipv4NodePtr; | |
IPv4_DEVICE_PATH Ipv4Node; | |
BOOLEAN IsDHCP; | |
EFI_IP_ADDRESS OldIp; | |
EFI_IP_ADDRESS OldSubnetMask; | |
EFI_IP_ADDRESS OldGatewayIp; | |
EFI_IP_ADDRESS LocalIp; | |
EFI_IP_ADDRESS SubnetMask; | |
EFI_IP_ADDRESS GatewayIp; | |
EFI_IP_ADDRESS RemoteIp; | |
UINT8 *FileNodePtr; | |
CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; | |
UINTN PathSize; | |
UINTN BootFilePathSize; | |
FILEPATH_DEVICE_PATH *NewFilePathNode; | |
Ipv4NodePtr = NULL; | |
// | |
// Make a copy of the complete device path that is made of : | |
// the device path of the device that support the Simple Network protocol | |
// followed by an IPv4 node (type IPv4_DEVICE_PATH), | |
// followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up | |
// by an end node. The IPv6 case is not handled yet. | |
// | |
DevicePath = DuplicateDevicePath (OldDevicePath); | |
if (DevicePath == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ErrorExit; | |
} | |
// | |
// Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the | |
// call to this function, we know that the device path ends with an IPv4 node | |
// followed by a file path node and finally an end node. To get the address of | |
// the last IPv4 node, we loop over the whole device path, noting down the | |
// address of each encountered IPv4 node. | |
// | |
for (DevicePathNode = DevicePath; | |
!IsDevicePathEnd (DevicePathNode); | |
DevicePathNode = NextDevicePathNode (DevicePathNode)) | |
{ | |
if (IS_DEVICE_PATH_NODE (DevicePathNode, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)) { | |
Ipv4NodePtr = (UINT8*)DevicePathNode; | |
} | |
} | |
// Copy for alignment of the IPv4 node data | |
CopyMem (&Ipv4Node, Ipv4NodePtr, sizeof (IPv4_DEVICE_PATH)); | |
Print (L"Get the IP address from DHCP: "); | |
Status = GetHIInputBoolean (&IsDHCP); | |
if (EFI_ERROR (Status)) { | |
goto ErrorExit; | |
} | |
if (!IsDHCP) { | |
Print (L"Local static IP address: "); | |
if (Ipv4Node.StaticIpAddress) { | |
CopyMem (&OldIp.v4, &Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
Status = EditHIInputIP (&OldIp, &LocalIp); | |
} else { | |
Status = GetHIInputIP (&LocalIp); | |
} | |
if (EFI_ERROR (Status)) { | |
goto ErrorExit; | |
} | |
Print (L"Get the network mask: "); | |
if (Ipv4Node.StaticIpAddress) { | |
CopyMem (&OldSubnetMask.v4, &Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); | |
Status = EditHIInputIP (&OldSubnetMask, &SubnetMask); | |
} else { | |
Status = GetHIInputIP (&SubnetMask); | |
} | |
if (EFI_ERROR (Status)) { | |
goto ErrorExit; | |
} | |
Print (L"Get the gateway IP address: "); | |
if (Ipv4Node.StaticIpAddress) { | |
CopyMem (&OldGatewayIp.v4, &Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
Status = EditHIInputIP (&OldGatewayIp, &GatewayIp); | |
} else { | |
Status = GetHIInputIP (&GatewayIp); | |
} | |
if (EFI_ERROR (Status)) { | |
goto ErrorExit; | |
} | |
} | |
Print (L"TFTP server IP address: "); | |
// Copy remote IPv4 address into IPv4 or IPv6 union | |
CopyMem (&OldIp.v4, &Ipv4Node.RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
Status = EditHIInputIP (&OldIp, &RemoteIp); | |
if (EFI_ERROR (Status)) { | |
goto ErrorExit; | |
} | |
// Get the path of the boot file and its size in number of bytes | |
FileNodePtr = Ipv4NodePtr + sizeof (IPv4_DEVICE_PATH); | |
BootFilePathSize = DevicePathNodeLength (FileNodePtr) - SIZE_OF_FILEPATH_DEVICE_PATH; | |
// | |
// Ask for update of the boot file path | |
// | |
do { | |
// Copy for 2-byte alignment of the Unicode string | |
CopyMem ( | |
BootFilePath, FileNodePtr + SIZE_OF_FILEPATH_DEVICE_PATH, | |
MIN (BootFilePathSize, BOOT_DEVICE_FILEPATH_MAX) | |
); | |
BootFilePath[BOOT_DEVICE_FILEPATH_MAX - 1] = L'\0'; | |
Print (L"File path of the %s: ", FileName); | |
Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); | |
if (EFI_ERROR (Status)) { | |
goto ErrorExit; | |
} | |
PathSize = StrSize (BootFilePath); | |
if (PathSize > 2) { | |
break; | |
} | |
// Empty string, give the user another try | |
Print (L"Empty string - Invalid path\n"); | |
} while (PathSize <= 2) ; | |
// | |
// Update the IPv4 node. IPv6 case not handled yet. | |
// | |
if (IsDHCP) { | |
Ipv4Node.StaticIpAddress = FALSE; | |
ZeroMem (&Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
ZeroMem (&Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); | |
ZeroMem (&Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
} else { | |
Ipv4Node.StaticIpAddress = TRUE; | |
CopyMem (&Ipv4Node.LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS)); | |
CopyMem (&Ipv4Node.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS)); | |
CopyMem (&Ipv4Node.GatewayIpAddress, &GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS)); | |
} | |
CopyMem (&Ipv4Node.RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS)); | |
CopyMem (Ipv4NodePtr, &Ipv4Node, sizeof (IPv4_DEVICE_PATH)); | |
// | |
// Create the new file path node | |
// | |
NewFilePathNode = (FILEPATH_DEVICE_PATH*)AllocatePool ( | |
SIZE_OF_FILEPATH_DEVICE_PATH + | |
PathSize | |
); | |
NewFilePathNode->Header.Type = MEDIA_DEVICE_PATH; | |
NewFilePathNode->Header.SubType = MEDIA_FILEPATH_DP; | |
SetDevicePathNodeLength ( | |
NewFilePathNode, | |
SIZE_OF_FILEPATH_DEVICE_PATH + PathSize | |
); | |
CopyMem (NewFilePathNode->PathName, BootFilePath, PathSize); | |
// | |
// Generate the new Device Path by replacing the file path node at address | |
// "FileNodePtr" by the new one "NewFilePathNode" and return its address. | |
// | |
SetDevicePathEndNode (FileNodePtr); | |
*NewDevicePath = AppendDevicePathNode ( | |
DevicePath, | |
(CONST EFI_DEVICE_PATH_PROTOCOL*)NewFilePathNode | |
); | |
ErrorExit: | |
if (DevicePath != NULL) { | |
FreePool (DevicePath) ; | |
} | |
return Status; | |
} | |
BOOLEAN | |
BdsLoadOptionTftpIsSupported ( | |
IN EFI_DEVICE_PATH *DevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE Handle; | |
EFI_DEVICE_PATH *RemainingDevicePath; | |
EFI_DEVICE_PATH *NextDevicePath; | |
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; | |
Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); | |
if (EFI_ERROR(Status)) { | |
return FALSE; | |
} | |
// Validate the Remaining Device Path | |
if (IsDevicePathEnd(RemainingDevicePath)) { | |
return FALSE; | |
} | |
if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) && | |
!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) { | |
return FALSE; | |
} | |
NextDevicePath = NextDevicePathNode (RemainingDevicePath); | |
if (IsDevicePathEnd(NextDevicePath)) { | |
return FALSE; | |
} | |
if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) { | |
return FALSE; | |
} | |
Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); | |
if (EFI_ERROR (Status)) { | |
return FALSE; | |
} else { | |
return TRUE; | |
} | |
} |