ArmPlatformPkg/Bds: Upgrade the BDS to be more conformed to the UEFI Specification

The UEFI Specification defines some requirement related to the Boot Manager.
This new version of the BDS support most of the features:
- TimeOut, BootNext, BootOrder, Boot### environment variable for boot device selection
- ConOut. ConIn, ConErr environment variables for console intialization
- Boot EFI application defined by a Device Path
- Support removable devices
- Support FileSystem, MemMap, PXE and TFTP boot devices



git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11800 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
oliviermartin
2011-06-11 11:58:23 +00:00
parent a355a3654f
commit ea46ebbe6a
12 changed files with 2746 additions and 351 deletions

View File

@@ -0,0 +1,867 @@
/** @file
*
* Copyright (c) 2011, 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/PxeBaseCode.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/SimpleNetwork.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 BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionFileSystemUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionFileSystemIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
EFI_STATUS
BdsLoadOptionMemMapList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionMemMapCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionMemMapUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionMemMapIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
EFI_STATUS
BdsLoadOptionPxeList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionPxeCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionPxeUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionPxeIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
EFI_STATUS
BdsLoadOptionTftpList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionTftpCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionTftpUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionTftpIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {
{
BDS_DEVICE_FILESYSTEM,
BdsLoadOptionFileSystemList,
BdsLoadOptionFileSystemIsSupported,
BdsLoadOptionFileSystemCreateDevicePath,
BdsLoadOptionFileSystemUpdateDevicePath
},
{
BDS_DEVICE_MEMMAP,
BdsLoadOptionMemMapList,
BdsLoadOptionMemMapIsSupported,
BdsLoadOptionMemMapCreateDevicePath,
BdsLoadOptionMemMapUpdateDevicePath
},
{
BDS_DEVICE_PXE,
BdsLoadOptionPxeList,
BdsLoadOptionPxeIsSupported,
BdsLoadOptionPxeCreateDevicePath,
BdsLoadOptionPxeUpdateDevicePath
},
{
BDS_DEVICE_TFTP,
BdsLoadOptionTftpList,
BdsLoadOptionTftpIsSupported,
BdsLoadOptionTftpCreateDevicePath,
BdsLoadOptionTftpUpdateDevicePath
}
};
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
)
{
LIST_ENTRY *Entry;
BDS_SUPPORTED_DEVICE* SupportedDevice;
Entry = GetFirstNode (SupportedDeviceList);
while (Entry != SupportedDeviceList) {
SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
Entry = RemoveEntryList (Entry);
FreePool(SupportedDevice);
}
return EFI_SUCCESS;
}
EFI_STATUS
BootDeviceGetDeviceSupport (
IN BDS_LOAD_OPTION *BootOption,
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(BootOption)) {
*DeviceSupport = &BdsLoadOptionSupportList[Index];
return EFI_SUCCESS;
}
}
return EFI_UNSUPPORTED;
}
STATIC
EFI_STATUS
BootDeviceGetType (
IN CHAR16* FileName,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
BOOLEAN IsEfiApp;
BOOLEAN IsBootLoader;
BOOLEAN HasFDTSupport;
if (FileName == NULL) {
Print(L"Is an EFI Application? ");
Status = GetHIInputBoolean (&IsEfiApp);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
} else if (HasFilePathEfiExtension(FileName)) {
IsEfiApp = TRUE;
} else {
IsEfiApp = FALSE;
}
if (IsEfiApp) {
Print(L"Is your application is an OS loader? ");
Status = GetHIInputBoolean (&IsBootLoader);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
if (!IsBootLoader) {
*Attributes |= LOAD_OPTION_CATEGORY_APP;
}
*BootType = BDS_LOADER_EFI_APPLICATION;
} else {
Print(L"Has FDT support? ");
Status = GetHIInputBoolean (&HasFDTSupport);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
if (HasFDTSupport) {
*BootType = BDS_LOADER_KERNEL_LINUX_FDT;
} else {
*BootType = BDS_LOADER_KERNEL_LINUX_ATAG;
}
}
return EFI_SUCCESS;
}
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 BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
CHAR16 *BootFilePath;
UINTN BootFilePathSize;
Print(L"File path of the EFI Application or the kernel: ");
Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
// Convert Ascii into Unicode
BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
BootFilePathSize = StrSize(BootFilePath);
// 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);
FreePool (BootFilePath);
Status = BootDeviceGetType (FilePathDevicePath->PathName, BootType, Attributes);
if (EFI_ERROR(Status)) {
FreePool (FilePathDevicePath);
} else {
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;
}
return Status;
}
EFI_STATUS
BdsLoadOptionFileSystemUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
CHAR16 *BootFilePath;
UINTN BootFilePathSize;
FILEPATH_DEVICE_PATH* EndingDevicePath;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
EFI_DEVICE_PATH* DevicePath;
DevicePath = DuplicateDevicePath (BootOption->FilePathList);
EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
Print(L"File path of the EFI Application or the kernel: ");
UnicodeStrToAsciiStr (EndingDevicePath->PathName,AsciiBootFilePath);
Status = EditHIInputAscii(AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
if (EFI_ERROR(Status)) {
return Status;
}
// Convert Ascii into Unicode
BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
BootFilePathSize = StrSize(BootFilePath);
// 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);
FreePool (BootFilePath);
// 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 BootDeviceGetType (FilePathDevicePath->PathName, BootType, Attributes);
}
BOOLEAN
BdsLoadOptionFileSystemIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_DEVICE_PATH* DevicePathNode;
DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);
return IS_DEVICE_PATH_NODE(DevicePathNode,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP);
}
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;
// 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 the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)
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 BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
MEMMAP_DEVICE_PATH* MemMapDevicePath;
CHAR8 AsciiStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
CHAR8 AsciiEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
Print(L"Starting Address of the binary: ");
Status = GetHIInputAscii (AsciiStartingAddress,BOOT_DEVICE_ADDRESS_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
Print(L"Ending Address of the binary: ");
Status = GetHIInputAscii (AsciiEndingAddress,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));
MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;
MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;
MemMapDevicePath->MemoryType = EfiBootServicesData;
MemMapDevicePath->StartingAddress = AsciiStrHexToUint64 (AsciiStartingAddress);
MemMapDevicePath->EndingAddress = AsciiStrHexToUint64 (AsciiEndingAddress);
Status = BootDeviceGetType (NULL, BootType, Attributes);
if (EFI_ERROR(Status)) {
FreePool (MemMapDevicePath);
} else {
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;
}
return Status;
}
EFI_STATUS
BdsLoadOptionMemMapUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
ASSERT(0);
//TODO: Implement me
return EFI_SUCCESS;
}
BOOLEAN
BdsLoadOptionMemMapIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_DEVICE_PATH* DevicePathNode;
DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);
return IS_DEVICE_PATH_NODE(DevicePathNode,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
}
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->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (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 BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
SetDevicePathEndNode (*DevicePathNode);
*BootType = BDS_LOADER_EFI_APPLICATION;
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionPxeUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
ASSERT (0);
return EFI_SUCCESS;
}
BOOLEAN
BdsLoadOptionPxeIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &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;
}
}
EFI_STATUS
BdsLoadOptionTftpList (
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 AND the TFTP Protocol (the TFTP protocol is required to start PXE)
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->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (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"TFP on %s",DeviceDescription);
SupportedDevice->DevicePathProtocol = DevicePathProtocol;
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionTftpCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
BOOLEAN IsDHCP;
EFI_IP_ADDRESS LocalIp;
EFI_IP_ADDRESS RemoteIp;
IPv4_DEVICE_PATH* IPv4DevicePathNode;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
CHAR16* BootFilePath;
UINTN BootFilePathSize;
Print(L"Get the IP address from DHCP: ");
Status = GetHIInputBoolean (&IsDHCP);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
if (!IsDHCP) {
Print(L"Get the static IP address: ");
Status = GetHIInputIP (&LocalIp);
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 EFI Application or the kernel: ");
Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
// Convert Ascii into Unicode
BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
BootFilePathSize = StrSize(BootFilePath);
// 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);
// Create the IPv4 Device Path
IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;
IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;
SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));
CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.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);
FreePool (BootFilePath);
Status = BootDeviceGetType (NULL, BootType, Attributes);
if (EFI_ERROR(Status)) {
FreePool (IPv4DevicePathNode);
} else {
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;
}
return Status;
}
EFI_STATUS
BdsLoadOptionTftpUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
ASSERT (0);
return EFI_SUCCESS;
}
BOOLEAN
BdsLoadOptionTftpIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_DEVICE_PATH *RemainingDevicePath;
EFI_DEVICE_PATH *NextDevicePath;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &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;
}
}