ArmPkg/BdsLib: Upgrade the library to use natively the Device Path

The previous version was using the string representation of the Device Path.
This new version takes as paramater the binary representation of the Device Path

It also tries to detect which kind of device support it refers by using the remaining
part of the Device Path after it has been loaded by gBS->ConnectController()

Lots of bug have been fixed as well in this new version.



git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11799 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
oliviermartin 2011-06-11 11:56:30 +00:00
parent e6b3b50834
commit a355a3654f
13 changed files with 1659 additions and 1177 deletions

View File

@ -125,7 +125,8 @@
# BdsLib
#
gArmTokenSpaceGuid.PcdArmMachineType|0|UINT32|0x0000001E
gArmTokenSpaceGuid.PcdLinuxKernelDP|L""|VOID*|0x0000001F
gArmTokenSpaceGuid.PcdLinuxAtag|""|VOID*|0x00000020
gArmTokenSpaceGuid.PcdFdtDP|L""|VOID*|0x00000021
# The compressed Linux kernel is expected to be under 128MB from the beginning of the System Memory
gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset|0x08000000|UINT32|0x0000001F
# The Linux ATAGs are expected to be under 0x4000 (16KB) from the beginning of the System Memory
gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset|0x4000|UINT32|0x00000020

View File

@ -0,0 +1,66 @@
/** @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.
*
**/
#ifndef __BDS_ENTRY_H__
#define __BDS_ENTRY_H__
/**
Connect all DXE drivers
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND No handles match the search.
@retval EFI_OUT_OF_RESOURCES There is not resource pool memory to store the matching results.
**/
EFI_STATUS
BdsConnectAllDrivers (
VOID
);
/**
Start a Linux kernel from a Device Path
@param LinuxKernel Device Path to the Linux Kernel
@param Parameters Linux kernel agruments
@param Fdt Device Path to the Flat Device Tree
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
@retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
**/
EFI_STATUS
BdsBootLinux (
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
IN CONST CHAR8* Arguments,
IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath
);
/**
Start an EFI Application from any Firmware Volume
@param EfiApp EFI Application Name
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
@retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
**/
EFI_STATUS
BdsLoadApplication (
IN EFI_HANDLE ParentImageHandle,
IN CHAR16* EfiApp
);
#endif

View File

@ -12,27 +12,26 @@
*
**/
#ifndef __BDS_ENTRY_H__
#define __BDS_ENTRY_H__
#ifndef _BDS_UNIX_LIB_H_
#define _BDS_UNIX_LIB_H_
EFI_STATUS
BdsConnectAllDrivers ( VOID );
/**
Start a Linux kernel from a Device Path
@param LinuxKernel Device Path to the Linux Kernel
@param Parameters Linux kernel agruments
@param Fdt Device Path to the Flat Device Tree
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
@retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
**/
EFI_STATUS
BdsBootLinux (
IN CONST CHAR16* LinuxKernel,
IN CONST CHAR8* ATag,
IN CONST CHAR16* Fdt
);
EFI_STATUS
BdsLoadApplication (
IN CHAR16* EfiApp
);
EFI_STATUS
BdsLoadApplicationFromPath (
IN CHAR16* EfiAppPath
);
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
IN CONST CHAR8* Arguments,
IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath
);
#endif

View File

@ -1,111 +1,217 @@
/** @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"
EFI_STATUS
BdsLoadPeCoff (
IN BDS_FILE *EfiAppFile
)
{
EFI_STATUS Status;
EFI_HANDLE ImageHandle;
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH NewNode;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
// Only support loading from FV right now
ASSERT(EfiAppFile->Type == BDS_FILETYPE_FV);
// Generate the Device Path for the file
DevicePath = DuplicateDevicePath(EfiAppFile->DevicePath);
EfiInitializeFwVolDevicepathNode (&NewNode, &(EfiAppFile->File.Fv.Guid));
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&NewNode);
Status = gBS->LoadImage (TRUE, gImageHandle, DevicePath, NULL, 0, &ImageHandle);
if (!EFI_ERROR (Status)) {
//
// Before calling the image, enable the Watchdog Timer for
// the 5 Minute period
//
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
Status = gBS->StartImage (ImageHandle, NULL, NULL);
//
// Clear the Watchdog Timer after the image returns
//
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
}
return Status;
}
EFI_STATUS BdsLoadApplicationFromPath(
IN CHAR16* EfiAppPath
) {
EFI_STATUS Status;
BDS_FILE EfiAppFile;
// Need to connect every drivers to ensure no dependencies are missing for the application
Status = BdsConnectAllDrivers();
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));
return Status;
}
// Locate the application from a device path
Status = BdsLoadFilePath(EfiAppPath, &EfiAppFile);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "ERROR: Do not find EFI application %s\n",EfiAppPath));
return Status;
}
// Start the application
Status = BdsLoadPeCoff(&EfiAppFile);
return Status;
}
EFI_STATUS BdsLoadApplication(
IN CHAR16* EfiApp
) {
EFI_STATUS Status;
UINTN NoHandles, HandleIndex;
EFI_HANDLE *Handles;
BDS_FILE EfiAppFile;
// Need to connect every drivers to ensure no dependencies are missing for the application
Status = BdsConnectAllDrivers();
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));
return Status;
}
// Search the application in any Firmware Volume
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles);
if (EFI_ERROR (Status) || (NoHandles == 0)) {
DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n"));
return Status;
}
// Search in all Firmware Volume for the EFI Application
for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) {
Status = BdsLoadFileFromFirmwareVolume(Handles[HandleIndex],EfiApp,EFI_FV_FILETYPE_APPLICATION,&EfiAppFile);
if (!EFI_ERROR (Status)) {
// Start the application
Status = BdsLoadPeCoff(&EfiAppFile);
return Status;
}
}
return Status;
}
/** @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/PeCoffLib.h>
#include <Library/DxeServicesLib.h>
//TODO: RemoveMe
#include <Protocol/DevicePathToText.h>
/**
Retrieves the magic value from the PE/COFF header.
@param Hdr The buffer in which to return the PE32, PE32+, or TE header.
@return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
@return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
**/
UINT16
PeCoffLoaderGetPeHeaderMagicValue (
IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
)
{
//
// NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
// in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
// Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
// then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
//
if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
}
//
// Return the magic value from the PC/COFF Optional Header
//
return Hdr.Pe32->OptionalHeader.Magic;
}
STATIC
BOOLEAN
IsLoadableImage (
VOID* Image
)
{
UINT16 Magic;
EFI_IMAGE_DOS_HEADER *DosHeader;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header;
if (Image == NULL) {
return FALSE;
}
DosHeader = (EFI_IMAGE_DOS_HEADER*)Image;
if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
Header.Pe32 = (EFI_IMAGE_NT_HEADERS32*)((UINT8*)Image + DosHeader->e_lfanew);
} else {
Header.Pe32 = (EFI_IMAGE_NT_HEADERS32*)(Image);
}
if (Header.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
// It is a TE Image
return TRUE;
} else if (Header.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
Magic = PeCoffLoaderGetPeHeaderMagicValue (Header);
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
// It is a PE32 Image
return TRUE;
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
// It is a PE32+ Image
return TRUE;
} else {
DEBUG ((EFI_D_ERROR,"BdsLoadBinaryFromPath(): Fail unrecognized PE Image\n"));
}
} else {
DEBUG ((EFI_D_ERROR,"BdsLoadBinaryFromPath(): Fail unrecognize image\n"));
}
return FALSE;
}
STATIC
EFI_STATUS
BdsLoadFileFromFirmwareVolume (
IN EFI_HANDLE FvHandle,
IN CHAR16 *FilePath,
IN EFI_FV_FILETYPE FileTypeFilter,
OUT EFI_DEVICE_PATH **EfiAppDevicePath
)
{
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
VOID *Key;
EFI_STATUS Status, FileStatus;
EFI_GUID NameGuid;
EFI_FV_FILETYPE FileType;
EFI_FV_FILE_ATTRIBUTES Attributes;
UINTN Size;
UINTN UiStringLen;
CHAR16 *UiSection;
UINT32 Authentication;
EFI_DEVICE_PATH *FvDevicePath;
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileDevicePath;
Status = gBS->HandleProtocol (FvHandle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FvProtocol);
if (EFI_ERROR(Status)) {
return Status;
}
// Length of FilePath
UiStringLen = StrLen (FilePath);
// Allocate Key
Key = AllocatePool (FvProtocol->KeySize);
ASSERT (Key != NULL);
ZeroMem (Key, FvProtocol->KeySize);
do {
// Search in all files
FileType = FileTypeFilter;
Status = FvProtocol->GetNextFile (FvProtocol, Key, &FileType, &NameGuid, &Attributes, &Size);
if (!EFI_ERROR (Status)) {
UiSection = NULL;
FileStatus = FvProtocol->ReadSection (
FvProtocol,
&NameGuid,
EFI_SECTION_USER_INTERFACE,
0,
(VOID **)&UiSection,
&Size,
&Authentication
);
if (!EFI_ERROR (FileStatus)) {
if (StrnCmp (FilePath, UiSection, UiStringLen) == 0) {
//
// We found a UiString match.
//
Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
// Generate the Device Path for the file
//DevicePath = DuplicateDevicePath(FvDevicePath);
EfiInitializeFwVolDevicepathNode (&FileDevicePath, &NameGuid);
*EfiAppDevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FileDevicePath);
FreePool (Key);
FreePool (UiSection);
return FileStatus;
}
FreePool (UiSection);
}
}
} while (!EFI_ERROR (Status));
FreePool(Key);
return Status;
}
/**
Start an EFI Application from any Firmware Volume
@param EfiApp EFI Application Name
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
@retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
**/
EFI_STATUS
BdsLoadApplication (
IN EFI_HANDLE ParentImageHandle,
IN CHAR16* EfiApp
)
{
EFI_STATUS Status;
UINTN NoHandles, HandleIndex;
EFI_HANDLE *Handles;
EFI_DEVICE_PATH *FvDevicePath;
EFI_DEVICE_PATH *EfiAppDevicePath;
// Need to connect every drivers to ensure no dependencies are missing for the application
Status = BdsConnectAllDrivers();
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));
return Status;
}
// Search the application in any Firmware Volume
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles);
if (EFI_ERROR (Status) || (NoHandles == 0)) {
DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n"));
return Status;
}
// Search in all Firmware Volume for the EFI Application
for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) {
Status = BdsLoadFileFromFirmwareVolume (Handles[HandleIndex], EfiApp, EFI_FV_FILETYPE_APPLICATION, &EfiAppDevicePath);
if (!EFI_ERROR (Status)) {
// Start the application
Status = BdsStartEfiApplication (ParentImageHandle, EfiAppDevicePath);
return Status;
}
}
return Status;
}

View File

@ -14,169 +14,829 @@
#include "BdsInternal.h"
// Count the number of DevicePath Node
static UINTN NumberNodeFromDevicePath(
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath
) {
UINTN NumberDevicePathNode = 0;
#include <Protocol/UsbIo.h>
#include <Protocol/DiskIo.h>
while (!IsDevicePathEnd (DevicePath)) {
NumberDevicePathNode++;
DevicePath = NextDevicePathNode(DevicePath);
}
return NumberDevicePathNode;
}
#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
// Extract the FilePath from the Device Path
CHAR16* BdsExtractFilePathFromDevicePath(
IN CONST CHAR16 *StrDevicePath,
IN UINTN NumberDevicePathNode
) {
UINTN Node;
CHAR16 *Str;
CHAR16*
BdsExtractFilePathFromDevicePath (
IN CONST CHAR16 *StrDevicePath,
IN UINTN NumberDevicePathNode
)
{
UINTN Node;
CHAR16 *Str;
Str = (CHAR16*)StrDevicePath;
Node = 0;
while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
if ((*Str == L'/') || (*Str == L'\\')) {
Node++;
}
Str++;
Str = (CHAR16*)StrDevicePath;
Node = 0;
while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
if ((*Str == L'/') || (*Str == L'\\')) {
Node++;
}
Str++;
}
if (*Str == L'\0') {
return NULL;
} else {
return Str;
}
if (*Str == L'\0') {
return NULL;
} else {
return Str;
}
}
BOOLEAN
BdsIsRemovableUsb (
IN EFI_DEVICE_PATH* DevicePath
)
{
return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
(DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));
}
EFI_STATUS
BdsLoadDevicePath(
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
OUT EFI_HANDLE *Handle
) {
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_STATUS Status;
BdsGetDeviceUsb (
IN EFI_DEVICE_PATH* RemovableDevicePath,
OUT EFI_HANDLE* DeviceHandle,
OUT EFI_DEVICE_PATH** NewDevicePath
)
{
EFI_STATUS Status;
UINTN Index;
UINTN UsbIoHandleCount;
EFI_HANDLE *UsbIoBuffer;
EFI_DEVICE_PATH* UsbIoDevicePath;
EFI_DEVICE_PATH* TmpDevicePath;
USB_WWID_DEVICE_PATH* WwidDevicePath1;
USB_WWID_DEVICE_PATH* WwidDevicePath2;
USB_CLASS_DEVICE_PATH* UsbClassDevicePath1;
USB_CLASS_DEVICE_PATH* UsbClassDevicePath2;
if ((DevicePath == NULL) || (Handle == NULL)) {
return EFI_INVALID_PARAMETER;
}
// Get all the UsbIo handles
UsbIoHandleCount = 0;
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) {
return Status;
}
do {
RemainingDevicePath = DevicePath;
// The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
// the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
// to point to the remaining part of the device path
Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&RemainingDevicePath,Handle);
if (!EFI_ERROR (Status)) {
// Recursive = FALSE: We do not want to start all the device tree
Status = gBS->ConnectController (*Handle, NULL, RemainingDevicePath, FALSE);
}
// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling
// NextDevicePathNode() will return an undetermined Device Path Node
if (!IsDevicePathEnd (RemainingDevicePath)) {
RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
}
} while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
if (!EFI_ERROR (Status)) {
// Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
// Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
RemainingDevicePath = DevicePath;
Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&RemainingDevicePath,Handle);
if (!EFI_ERROR (Status)) {
Status = gBS->ConnectController (*Handle, NULL, RemainingDevicePath, FALSE);
if (EFI_ERROR (Status)) {
// If the last node is a Memory Map Device Path just return EFI_SUCCESS.
if ((RemainingDevicePath->Type == HARDWARE_DEVICE_PATH) && (RemainingDevicePath->SubType == HW_MEMMAP_DP)) {
Status = EFI_SUCCESS;
}
// Check if one of the handles matches the USB description
for (Index = 0; Index < UsbIoHandleCount; Index++) {
Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &UsbIoDevicePath);
if (!EFI_ERROR(Status)) {
TmpDevicePath = UsbIoDevicePath;
while (!IsDevicePathEnd (TmpDevicePath)) {
// Check if the Device Path node is a USB Removable device Path node
if (BdsIsRemovableUsb (TmpDevicePath)) {
if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {
WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;
WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;
if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&
(WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&
(CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0))
{
*DeviceHandle = UsbIoBuffer[Index];
// Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
*NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));
return EFI_SUCCESS;
}
} else {
UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;
UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;
if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&
(UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&
(UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&
(UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&
(UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))
{
*DeviceHandle = UsbIoBuffer[Index];
// Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
*NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));
return EFI_SUCCESS;
}
}
}
} else if (IsDevicePathEnd (RemainingDevicePath)) {
// Case when the DevicePath contains a MemoryMap Device Path Node and all drivers are connected.
// Ensure the Device Path exists
RemainingDevicePath = DevicePath;
Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&RemainingDevicePath,Handle);
}
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
}
return Status;
}
}
return EFI_NOT_FOUND;
}
BOOLEAN
BdsIsRemovableHd (
IN EFI_DEVICE_PATH* DevicePath
)
{
return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);
}
EFI_STATUS
BdsLoadFilePath (
IN CONST CHAR16 *DeviceFilePath,
OUT BDS_FILE *File
) {
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
EFI_STATUS Status;
EFI_HANDLE Handle;
UINTN NumberDevicePathNode;
CHAR16 *FilePath;
//Do a sanity check on the Device file path
if (DeviceFilePath == NULL) {
return EFI_INVALID_PARAMETER;
}
// Convert the Device Path String into Device Path Protocol
Status = gBS->LocateProtocol(&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
ASSERT_EFI_ERROR(Status);
DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath(DeviceFilePath);
//Do a sanity check on the Device Path
if (DevicePath == NULL) {
return EFI_INVALID_PARAMETER;
}
// Count the number of DevicePath Node
NumberDevicePathNode = NumberNodeFromDevicePath(DevicePath);
// Extract the FilePath from the Device Path
FilePath = BdsExtractFilePathFromDevicePath(DeviceFilePath,NumberDevicePathNode);
Status = BdsLoadDevicePath(DevicePath,&Handle);
if (EFI_ERROR (Status)) {
return Status;
}
//If FilePath == NULL then let consider if a MemoryMap Device Path
if (FilePath == NULL) {
// Check if the Node is a MemoryMap Device Path
Status = BdsLoadFileFromMemMap(Handle,DevicePath,File);
} else {
Status = BdsLoadFileFromSimpleFileSystem(Handle,FilePath,File);
if (EFI_ERROR (Status)) {
Status = BdsLoadFileFromFirmwareVolume(Handle,FilePath,EFI_FV_FILETYPE_ALL,File);
}
}
if (!EFI_ERROR (Status)) {
File->DevicePath = DevicePath;
}
BdsGetDeviceHd (
IN EFI_DEVICE_PATH* RemovableDevicePath,
OUT EFI_HANDLE* DeviceHandle,
OUT EFI_DEVICE_PATH** NewDevicePath
)
{
EFI_STATUS Status;
UINTN Index;
UINTN PartitionHandleCount;
EFI_HANDLE *PartitionBuffer;
EFI_DEVICE_PATH* PartitionDevicePath;
EFI_DEVICE_PATH* TmpDevicePath;
HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1;
HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2;
// Get all the DiskIo handles
PartitionHandleCount = 0;
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);
if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) {
return Status;
}
// Check if one of the handles matches the Hard Disk Description
for (Index = 0; Index < PartitionHandleCount; Index++) {
Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &PartitionDevicePath);
if (!EFI_ERROR(Status)) {
TmpDevicePath = PartitionDevicePath;
while (!IsDevicePathEnd (TmpDevicePath)) {
// Check if the Device Path node is a HD Removable device Path node
if (BdsIsRemovableHd (TmpDevicePath)) {
HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;
HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;
if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&
(CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&
(HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))
{
*DeviceHandle = PartitionBuffer[Index];
// Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
*NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath));
return EFI_SUCCESS;
}
}
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
}
}
}
return EFI_NOT_FOUND;
}
EFI_STATUS BdsCopyRawFileToRuntimeMemory(
IN BDS_FILE *File,
OUT VOID **FileImage,
OUT UINTN *FileSize
) {
if (File == NULL) {
return EFI_INVALID_PARAMETER;
/*BOOLEAN
BdsIsRemovableCdrom (
IN EFI_DEVICE_PATH* DevicePath
)
{
return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
}
EFI_STATUS
BdsGetDeviceCdrom (
IN EFI_DEVICE_PATH* RemovableDevicePath,
OUT EFI_HANDLE* DeviceHandle,
OUT EFI_DEVICE_PATH** DevicePath
)
{
ASSERT(0);
return EFI_UNSUPPORTED;
}*/
typedef BOOLEAN
(*BDS_IS_REMOVABLE) (
IN EFI_DEVICE_PATH* DevicePath
);
typedef EFI_STATUS
(*BDS_GET_DEVICE) (
IN EFI_DEVICE_PATH* RemovableDevicePath,
OUT EFI_HANDLE* DeviceHandle,
OUT EFI_DEVICE_PATH** DevicePath
);
typedef struct {
BDS_IS_REMOVABLE IsRemovable;
BDS_GET_DEVICE GetDevice;
} BDS_REMOVABLE_DEVICE_SUPPORT;
BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = {
{ BdsIsRemovableUsb, BdsGetDeviceUsb },
{ BdsIsRemovableHd, BdsGetDeviceHd },
//{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
};
STATIC
BOOLEAN
IsRemovableDevice (
IN EFI_DEVICE_PATH* DevicePath
)
{
UINTN Index;
EFI_DEVICE_PATH* TmpDevicePath;
TmpDevicePath = DevicePath;
while (!IsDevicePathEnd (TmpDevicePath)) {
for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) {
return TRUE;
}
}
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
}
return FALSE;
}
STATIC
EFI_STATUS
TryRemovableDevice (
IN EFI_DEVICE_PATH* DevicePath,
OUT EFI_HANDLE* DeviceHandle,
OUT EFI_DEVICE_PATH** NewDevicePath
)
{
EFI_STATUS Status;
UINTN Index;
EFI_DEVICE_PATH* TmpDevicePath;
BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;
EFI_DEVICE_PATH* RemovableDevicePath;
BOOLEAN RemovableFound;
RemovableFound = FALSE;
TmpDevicePath = DevicePath;
while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
RemovableDevice = &RemovableDeviceSupport[Index];
if (RemovableDevice->IsRemovable(TmpDevicePath)) {
RemovableDevicePath = TmpDevicePath;
RemovableFound = TRUE;
break;
}
}
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
}
if (!RemovableFound) {
return EFI_NOT_FOUND;
}
// Search into the current started drivers
Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
if (Status == EFI_NOT_FOUND) {
// Connect all the drivers
BdsConnectAllDrivers ();
// Search again into all the drivers
Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
}
return Status;
}
EFI_STATUS
BdsConnectDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
OUT EFI_HANDLE *Handle,
OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
)
{
EFI_DEVICE_PATH* Remaining;
EFI_DEVICE_PATH* NewDevicePath;
EFI_STATUS Status;
if ((DevicePath == NULL) || (Handle == NULL)) {
return EFI_INVALID_PARAMETER;
}
do {
Remaining = DevicePath;
// The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
// the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
// to point to the remaining part of the device path
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
if (!EFI_ERROR (Status)) {
// Recursive = FALSE: We do not want to start all the device tree
Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
}
if (File->Type == BDS_FILETYPE_FS) {
return BdsCopyRawFileToRuntimeMemoryFS(File->File.Fs.Handle,FileImage,FileSize);
} else if (File->Type == BDS_FILETYPE_FV) {
return BdsCopyRawFileToRuntimeMemoryFV(&(File->File.Fv),FileImage,FileSize);
} else if (File->Type == BDS_FILETYPE_MEM) {
return BdsCopyRawFileToRuntimeMemoryMemMap(&(File->File.Mem),FileImage,FileSize);
} else {
return EFI_INVALID_PARAMETER;
/*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling
// NextDevicePathNode() will return an undetermined Device Path Node
if (!IsDevicePathEnd (RemainingDevicePath)) {
RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
}*/
} while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
if (!EFI_ERROR (Status)) {
// Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
// Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
Remaining = DevicePath;
Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&Remaining,Handle);
if (!EFI_ERROR (Status)) {
Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
if (EFI_ERROR (Status)) {
// If the last node is a Memory Map Device Path just return EFI_SUCCESS.
if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
Status = EFI_SUCCESS;
}
}
}
} else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
/*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
Status = EFI_SUCCESS;
} else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
Status = EFI_SUCCESS;
}*/
//TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
Status = EFI_SUCCESS;
} else {
Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath);
if (!EFI_ERROR (Status)) {
return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);
}
}
if (RemainingDevicePath) {
*RemainingDevicePath = Remaining;
}
return Status;
}
BOOLEAN
BdsFileSystemSupport (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
}
EFI_STATUS
BdsFileSystemLoadImage (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS* Image,
OUT UINTN *ImageSize
)
{
FILEPATH_DEVICE_PATH* FilePathDevicePath;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
EFI_FILE_PROTOCOL *Fs;
EFI_STATUS Status;
EFI_FILE_INFO *FileInfo;
EFI_FILE_PROTOCOL *File;
UINTN Size;
ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
if (EFI_ERROR(Status)) {
return Status;
}
//Try to Open the volume and get root directory
Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
if (EFI_ERROR(Status)) {
return Status;
}
File = NULL;
Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
Size = 0;
File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL);
FileInfo = AllocatePool (Size);
Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo);
if (EFI_ERROR(Status)) {
return Status;
}
// Get the file size
Size = FileInfo->FileSize;
if (ImageSize) {
*ImageSize = Size;
}
FreePool(FileInfo);
Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size),Image);
if (!EFI_ERROR(Status)) {
Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
}
return Status;
}
BOOLEAN
BdsMemoryMapSupport (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath
)
{
return IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
}
EFI_STATUS
BdsMemoryMapLoadImage (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS* Image,
OUT UINTN *ImageSize
)
{
EFI_STATUS Status;
MEMMAP_DEVICE_PATH* MemMapPathDevicePath;
UINTN Size;
ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP));
MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
if (Size == 0) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size),Image);
if (!EFI_ERROR(Status)) {
CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
if (ImageSize != NULL) {
*ImageSize = Size;
}
}
return Status;
}
BOOLEAN
BdsFirmwareVolumeSupport (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath
)
{
return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
}
EFI_STATUS
BdsFirmwareVolumeLoadImage (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS* Image,
OUT UINTN *ImageSize
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
EFI_GUID *FvNameGuid;
EFI_SECTION_TYPE SectionType;
EFI_FV_FILETYPE FvType;
EFI_FV_FILE_ATTRIBUTES Attrib;
UINT32 AuthenticationStatus;
VOID* ImageBuffer;
ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
if (EFI_ERROR(Status)) {
return Status;
}
FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
if (FvNameGuid == NULL) {
Status = EFI_INVALID_PARAMETER;
}
SectionType = EFI_SECTION_PE32;
AuthenticationStatus = 0;
//Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
ImageBuffer = NULL;
Status = FwVol->ReadSection (
FwVol,
FvNameGuid,
SectionType,
0,
&ImageBuffer,
ImageSize,
&AuthenticationStatus
);
if (!EFI_ERROR (Status)) {
#if 0
// In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
if (Type != AllocateAnyPages) {
Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
if (!EFI_ERROR(Status)) {
CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
FreePool (ImageBuffer);
}
}
#else
// We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
if (!EFI_ERROR(Status)) {
CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
FreePool (ImageBuffer);
}
#endif
} else {
// Try a raw file, since a PE32 SECTION does not exist
Status = FwVol->ReadFile (
FwVol,
FvNameGuid,
NULL,
ImageSize,
&FvType,
&Attrib,
&AuthenticationStatus
);
if (!EFI_ERROR(Status)) {
Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
if (!EFI_ERROR(Status)) {
Status = FwVol->ReadFile (
FwVol,
FvNameGuid,
(VOID*)(UINTN)(*Image),
ImageSize,
&FvType,
&Attrib,
&AuthenticationStatus
);
}
}
}
return Status;
}
BOOLEAN
BdsPxeSupport (
IN EFI_DEVICE_PATH* DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH* RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
if (!IsDevicePathEnd(RemainingDevicePath)) {
return FALSE;
}
Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
if (EFI_ERROR (Status)) {
return FALSE;
} else {
return TRUE;
}
}
EFI_STATUS
BdsPxeLoadImage (
IN EFI_DEVICE_PATH* DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH* RemainingDevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS *Image,
OUT UINTN *ImageSize
)
{
EFI_STATUS Status;
EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;
UINTN BufferSize;
// Get Load File Protocol attached to the PXE protocol
Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);
if (Status == EFI_BUFFER_TOO_SMALL) {
Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
if (EFI_ERROR(Status)) {
return Status;
}
Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
if (!EFI_ERROR(Status) && (ImageSize != NULL)) {
*ImageSize = BufferSize;
}
}
return Status;
}
BOOLEAN
BdsTftpSupport (
IN EFI_DEVICE_PATH* DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH* RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH *NextDevicePath;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
// 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;
}
}
EFI_STATUS
BdsTftpLoadImage (
IN EFI_DEVICE_PATH* DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH* RemainingDevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS *Image,
OUT UINTN *ImageSize
)
{
EFI_STATUS Status;
EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
UINT64 TftpBufferSize;
VOID* TftpBuffer;
EFI_IP_ADDRESS ServerIp;
IPv4_DEVICE_PATH* IPv4DevicePathNode;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
EFI_IP_ADDRESS LocalIp;
ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP));
IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
if (EFI_ERROR(Status)) {
return Status;
}
Status = Pxe->Start (Pxe, FALSE);
if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
return Status;
}
if (!IPv4DevicePathNode->StaticIpAddress) {
Status = Pxe->Dhcp(Pxe, TRUE);
} else {
CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);
}
if (EFI_ERROR(Status)) {
return Status;
}
CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
Status = Pxe->Mtftp (
Pxe,
EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
NULL,
FALSE,
&TftpBufferSize,
NULL,
&ServerIp,
(UINT8 *)FilePathDevicePath->PathName,
NULL,
TRUE
);
if (EFI_ERROR(Status)) {
return Status;
}
// Allocate a buffer to hold the whole file.
TftpBuffer = AllocatePool(TftpBufferSize);
if (TftpBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = Pxe->Mtftp (
Pxe,
EFI_PXE_BASE_CODE_TFTP_READ_FILE,
TftpBuffer,
FALSE,
&TftpBufferSize,
NULL,
&ServerIp,
(UINT8 *)FilePathDevicePath->PathName,
NULL,
FALSE
);
if (EFI_ERROR(Status)) {
FreePool(TftpBuffer);
} else if (ImageSize != NULL) {
*ImageSize = (UINTN)TftpBufferSize;
}
return Status;
}
BDS_FILE_LOADER FileLoaders[] = {
{ BdsFileSystemSupport, BdsFileSystemLoadImage },
{ BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
//{ BdsLoadFileSupport, BdsLoadFileLoadImage },
{ BdsMemoryMapSupport, BdsMemoryMapLoadImage },
{ BdsPxeSupport, BdsPxeLoadImage },
{ BdsTftpSupport, BdsTftpLoadImage },
{ NULL, NULL }
};
EFI_STATUS
BdsLoadImage (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS* Image,
OUT UINTN *FileSize
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_DEVICE_PATH *RemainingDevicePath;
BDS_FILE_LOADER* FileLoader;
Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
if (EFI_ERROR (Status)) {
return Status;
}
FileLoader = FileLoaders;
while (FileLoader->Support != NULL) {
if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) {
return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
}
FileLoader++;
}
return EFI_UNSUPPORTED;
}
EFI_STATUS
BdsStartEfiApplication (
IN EFI_HANDLE ParentImageHandle,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_STATUS Status;
EFI_HANDLE ImageHandle;
EFI_PHYSICAL_ADDRESS BinaryBuffer;
UINTN BinarySize;
// Find the nearest supported file loader
Status = BdsLoadImage (DevicePath, AllocateAnyPages,&BinaryBuffer,&BinarySize);
if (EFI_ERROR(Status)) {
return Status;
}
// Load the image from the Buffer with Boot Services function
Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
if (EFI_ERROR(Status)) {
return Status;
}
// Before calling the image, enable the Watchdog Timer for the 5 Minute period
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
// Start the image
Status = gBS->StartImage (ImageHandle, NULL, NULL);
// Clear the Watchdog Timer after the image returns
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
return Status;
}

View File

@ -1,86 +0,0 @@
/** @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"
EFI_STATUS BdsLoadFileFromSimpleFileSystem(
IN EFI_HANDLE Handle,
IN CHAR16 *FilePath,
OUT BDS_FILE *File
) {
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
EFI_FILE_PROTOCOL *Fs;
EFI_STATUS Status;
EFI_FILE_PROTOCOL *FileHandle = NULL;
if (File == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
if (EFI_ERROR(Status)) {
return Status;
}
//Try to Open the volume and get root directory
Status = FsProtocol->OpenVolume(FsProtocol, &Fs);
if (EFI_ERROR(Status)) {
return Status;
}
Status = Fs->Open(Fs, &FileHandle, FilePath, EFI_FILE_MODE_READ, 0);
File->Type = BDS_FILETYPE_FS;
File->FilePath = FilePath;
File->File.Fs.Handle = FileHandle;
return Status;
}
EFI_STATUS BdsCopyRawFileToRuntimeMemoryFS(
IN EFI_FILE_PROTOCOL *File,
OUT VOID **FileImage,
OUT UINTN *FileSize
) {
EFI_FILE_INFO *FileInfo;
UINTN Size;
VOID* Image;
EFI_STATUS Status;
Size = 0;
File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL);
FileInfo = AllocatePool (Size);
Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo);
if (EFI_ERROR(Status)) {
return Status;
}
// Get the file size
Size = FileInfo->FileSize;
if (FileSize) {
*FileSize = Size;
}
FreePool(FileInfo);
Image = AllocateRuntimePool(Size);
if (Image == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = File->Read(File, &Size, Image);
if (!EFI_ERROR(Status)) {
*FileImage = Image;
}
return Status;
}

View File

@ -1,136 +0,0 @@
/** @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"
EFI_STATUS BdsLoadFileFromFirmwareVolume(
IN EFI_HANDLE FvHandle,
IN CHAR16 *FilePath,
IN EFI_FV_FILETYPE FileTypeFilter,
OUT BDS_FILE *File
) {
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
VOID *Key;
EFI_STATUS Status, FileStatus;
EFI_GUID NameGuid;
EFI_FV_FILETYPE FileType;
EFI_FV_FILE_ATTRIBUTES Attributes;
UINTN Size;
UINTN UiStringLen;
CHAR16 *UiSection;
UINT32 Authentication;
if (File == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->HandleProtocol(FvHandle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FvProtocol);
if (EFI_ERROR(Status)) {
return Status;
}
// Length of FilePath
UiStringLen = StrLen (FilePath);
// Allocate Key
Key = AllocatePool (FvProtocol->KeySize);
ASSERT (Key != NULL);
ZeroMem (Key, FvProtocol->KeySize);
do {
// Search in all files
FileType = FileTypeFilter;
Status = FvProtocol->GetNextFile (FvProtocol, Key, &FileType, &NameGuid, &Attributes, &Size);
if (!EFI_ERROR (Status)) {
UiSection = NULL;
FileStatus = FvProtocol->ReadSection (
FvProtocol,
&NameGuid,
EFI_SECTION_USER_INTERFACE,
0,
(VOID **)&UiSection,
&Size,
&Authentication
);
if (!EFI_ERROR (FileStatus)) {
if (StrnCmp (FilePath, UiSection, UiStringLen) == 0) {
//
// We found a UiString match.
//
//*FileGuid = NameGuid;
File->Type = BDS_FILETYPE_FV;
File->FilePath = FilePath;
CopyGuid (&(File->File.Fv.Guid),&NameGuid);
File->File.Fv.FvProtocol = FvProtocol;
File->File.Fv.FileType = FileType;
Status = gBS->HandleProtocol(FvHandle,&gEfiDevicePathProtocolGuid, (VOID **)&(File->DevicePath));
FreePool (Key);
FreePool (UiSection);
return FileStatus;
}
FreePool (UiSection);
}
}
} while (!EFI_ERROR (Status));
FreePool(Key);
return Status;
}
EFI_STATUS BdsCopyRawFileToRuntimeMemoryFV(
IN BDS_FV_FILE *FvFile,
OUT VOID **FileImage,
OUT UINTN *FileSize
) {
EFI_STATUS Status = EFI_INVALID_PARAMETER;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
EFI_FV_FILETYPE FileType;
EFI_GUID* NameGuid;
EFI_FV_FILE_ATTRIBUTES Attributes;
UINT32 Authentication;
FvProtocol = FvFile->FvProtocol;
FileType = FvFile->FileType;
NameGuid = &(FvFile->Guid);
if (FileType == EFI_FV_FILETYPE_RAW) {
*FileImage = NULL;
*FileSize = 0;
Status = FvProtocol->ReadFile(
FvProtocol,NameGuid, // IN
FileImage,FileSize, // IN OUT
&FileType,&Attributes,&Authentication // OUT
);
ASSERT_EFI_ERROR(Status);
// This raw file also contains a header
*FileSize = *FileSize - 4;
*FileImage = (UINT8*)FileImage + 4;
} else if (FileType == EFI_FV_FILETYPE_FREEFORM) {
Status = FvProtocol->ReadSection (
FvProtocol,NameGuid,EFI_SECTION_RAW,0, // IN
FileImage,FileSize, // IN OUT
&Authentication // OUT
);
ASSERT_EFI_ERROR(Status);
} else {
ASSERT(0); //Maybe support application as well ???
}
return Status;
}

View File

@ -1,73 +0,0 @@
/** @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"
EFI_STATUS BdsLoadFileFromMemMap (
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
OUT BDS_FILE *File
) {
EFI_DEVICE_PATH_PROTOCOL *LastDevicePath;
if ((File == NULL) || (DevicePath == NULL) || (IsDevicePathEnd (DevicePath))) {
return EFI_INVALID_PARAMETER;
}
// Check if the last node of the device Path is a Memory Map Device Node
LastDevicePath = DevicePath;
DevicePath = NextDevicePathNode(DevicePath);
while (!IsDevicePathEnd (DevicePath)) {
LastDevicePath = DevicePath;
DevicePath = NextDevicePathNode(DevicePath);
}
if ((LastDevicePath->Type != HARDWARE_DEVICE_PATH) || (LastDevicePath->SubType != HW_MEMMAP_DP)) {
return EFI_UNSUPPORTED;
}
File->Type = BDS_FILETYPE_MEM;
File->File.Mem.MemoryType = ((MEMMAP_DEVICE_PATH*)LastDevicePath)->MemoryType;
File->File.Mem.StartingAddress = ((MEMMAP_DEVICE_PATH*)LastDevicePath)->StartingAddress;
File->File.Mem.EndingAddress = ((MEMMAP_DEVICE_PATH*)LastDevicePath)->EndingAddress;
return EFI_SUCCESS;
}
EFI_STATUS BdsCopyRawFileToRuntimeMemoryMemMap(
IN BDS_MEM_FILE *MemFile,
OUT VOID **FileImage,
OUT UINTN *FileSize
) {
UINTN Size;
VOID* Image;
Size = MemFile->EndingAddress - MemFile->StartingAddress;
if ((Size == 0) || (FileImage == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (FileSize != NULL) {
*FileSize = Size;
}
Image = AllocateRuntimePool(Size);
if (Image == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*FileImage = CopyMem(Image,(CONST VOID*)(UINTN)MemFile->StartingAddress,Size);
return EFI_SUCCESS;
}

View File

@ -1,223 +1,285 @@
/** @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/DxeServicesTableLib.h>
#include <Library/HobLib.h>
EFI_STATUS
ShutdownUefiBootServices( VOID )
{
EFI_STATUS Status;
UINTN MemoryMapSize;
EFI_MEMORY_DESCRIPTOR *MemoryMap;
UINTN MapKey;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
UINTN Pages;
MemoryMap = NULL;
MemoryMapSize = 0;
do {
Status = gBS->GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
if (Status == EFI_BUFFER_TOO_SMALL) {
Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
MemoryMap = AllocatePages (Pages);
//
// Get System MemoryMap
//
Status = gBS->GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
// Don't do anything between the GetMemoryMap() and ExitBootServices()
if (!EFI_ERROR (Status)) {
Status = gBS->ExitBootServices (gImageHandle, MapKey);
if (EFI_ERROR (Status)) {
FreePages (MemoryMap, Pages);
MemoryMap = NULL;
MemoryMapSize = 0;
}
}
}
} while (EFI_ERROR (Status));
return Status;
}
EFI_STATUS
BdsConnectAllDrivers( VOID ) {
UINTN HandleCount, Index;
EFI_HANDLE *HandleBuffer;
EFI_STATUS Status;
do {
// Locate all the driver handles
Status = gBS->LocateHandleBuffer (
AllHandles,
NULL,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
break;
}
// Connect every handles
for (Index = 0; Index < HandleCount; Index++) {
gBS->ConnectController(HandleBuffer[Index], NULL, NULL, TRUE);
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
// Check if new handles have been created after the start of the previous handles
Status = gDS->Dispatch ();
} while (!EFI_ERROR(Status));
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
InsertSystemMemoryResources (
LIST_ENTRY *ResourceList,
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob
)
{
BDS_SYSTEM_MEMORY_RESOURCE *NewResource;
LIST_ENTRY *Link;
LIST_ENTRY *NextLink;
LIST_ENTRY AttachedResources;
BDS_SYSTEM_MEMORY_RESOURCE *Resource;
EFI_PHYSICAL_ADDRESS NewResourceEnd;
if (IsListEmpty (ResourceList)) {
NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));
NewResource->PhysicalStart = ResHob->PhysicalStart;
NewResource->ResourceLength = ResHob->ResourceLength;
InsertTailList (ResourceList, &NewResource->Link);
return EFI_SUCCESS;
}
InitializeListHead (&AttachedResources);
Link = ResourceList->ForwardLink;
ASSERT (Link != NULL);
while (Link != ResourceList) {
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;
// Sanity Check. The resources should not overlapped.
ASSERT(!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))));
ASSERT(!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) &&
((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength))));
// The new resource is attached after this resource descriptor
if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) {
Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;
NextLink = RemoveEntryList (&Resource->Link);
InsertTailList (&AttachedResources, &Resource->Link);
Link = NextLink;
}
// The new resource is attached before this resource descriptor
else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) {
Resource->PhysicalStart = ResHob->PhysicalStart;
Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;
NextLink = RemoveEntryList (&Resource->Link);
InsertTailList (&AttachedResources, &Resource->Link);
Link = NextLink;
} else {
Link = Link->ForwardLink;
}
}
if (!IsListEmpty (&AttachedResources)) {
// See if we can merge the attached resource with other resources
NewResource = (BDS_SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);
Link = RemoveEntryList (&NewResource->Link);
while (!IsListEmpty (&AttachedResources)) {
// Merge resources
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;
// Ensure they overlap each other
ASSERT(
((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) ||
(((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength)))
);
NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength);
NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart);
NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart;
Link = RemoveEntryList (Link);
}
} else {
// None of the Resource of the list is attached to this ResHob. Create a new entry for it
NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));
NewResource->PhysicalStart = ResHob->PhysicalStart;
NewResource->ResourceLength = ResHob->ResourceLength;
}
InsertTailList (ResourceList, &NewResource->Link);
return EFI_SUCCESS;
}
EFI_STATUS
GetSystemMemoryResources (
IN LIST_ENTRY *ResourceList
)
{
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;
InitializeListHead (ResourceList);
// Find the first System Memory Resource Descriptor
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) {
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
// Did not find any
if (ResHob == NULL) {
return EFI_NOT_FOUND;
} else {
InsertSystemMemoryResources (ResourceList, ResHob);
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
while (ResHob != NULL) {
if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
InsertSystemMemoryResources (ResourceList, ResHob);
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
return EFI_SUCCESS;
}
/** @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/DxeServicesTableLib.h>
#include <Library/HobLib.h>
#include <Library/TimerLib.h>
#include <Library/PrintLib.h>
#include <Library/SerialPortLib.h>
STATIC CHAR8 *mTokenList[] = {
/*"SEC",*/
"PEI",
"DXE",
"BDS",
NULL
};
EFI_STATUS
ShutdownUefiBootServices (
VOID
)
{
EFI_STATUS Status;
UINTN MemoryMapSize;
EFI_MEMORY_DESCRIPTOR *MemoryMap;
UINTN MapKey;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
UINTN Pages;
MemoryMap = NULL;
MemoryMapSize = 0;
do {
Status = gBS->GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
if (Status == EFI_BUFFER_TOO_SMALL) {
Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
MemoryMap = AllocatePages (Pages);
//
// Get System MemoryMap
//
Status = gBS->GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
// Don't do anything between the GetMemoryMap() and ExitBootServices()
if (!EFI_ERROR (Status)) {
Status = gBS->ExitBootServices (gImageHandle, MapKey);
if (EFI_ERROR (Status)) {
FreePages (MemoryMap, Pages);
MemoryMap = NULL;
MemoryMapSize = 0;
}
}
}
} while (EFI_ERROR (Status));
return Status;
}
/**
Connect all DXE drivers
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND No handles match the search.
@retval EFI_OUT_OF_RESOURCES There is not resource pool memory to store the matching results.
**/
EFI_STATUS
BdsConnectAllDrivers (
VOID
)
{
UINTN HandleCount, Index;
EFI_HANDLE *HandleBuffer;
EFI_STATUS Status;
do {
// Locate all the driver handles
Status = gBS->LocateHandleBuffer (
AllHandles,
NULL,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
break;
}
// Connect every handles
for (Index = 0; Index < HandleCount; Index++) {
gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
// Check if new handles have been created after the start of the previous handles
Status = gDS->Dispatch ();
} while (!EFI_ERROR(Status));
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
InsertSystemMemoryResources (
LIST_ENTRY *ResourceList,
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob
)
{
BDS_SYSTEM_MEMORY_RESOURCE *NewResource;
LIST_ENTRY *Link;
LIST_ENTRY *NextLink;
LIST_ENTRY AttachedResources;
BDS_SYSTEM_MEMORY_RESOURCE *Resource;
EFI_PHYSICAL_ADDRESS NewResourceEnd;
if (IsListEmpty (ResourceList)) {
NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));
NewResource->PhysicalStart = ResHob->PhysicalStart;
NewResource->ResourceLength = ResHob->ResourceLength;
InsertTailList (ResourceList, &NewResource->Link);
return EFI_SUCCESS;
}
InitializeListHead (&AttachedResources);
Link = ResourceList->ForwardLink;
ASSERT (Link != NULL);
while (Link != ResourceList) {
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;
// Sanity Check. The resources should not overlapped.
ASSERT(!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))));
ASSERT(!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) &&
((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength))));
// The new resource is attached after this resource descriptor
if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) {
Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;
NextLink = RemoveEntryList (&Resource->Link);
InsertTailList (&AttachedResources, &Resource->Link);
Link = NextLink;
}
// The new resource is attached before this resource descriptor
else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) {
Resource->PhysicalStart = ResHob->PhysicalStart;
Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;
NextLink = RemoveEntryList (&Resource->Link);
InsertTailList (&AttachedResources, &Resource->Link);
Link = NextLink;
} else {
Link = Link->ForwardLink;
}
}
if (!IsListEmpty (&AttachedResources)) {
// See if we can merge the attached resource with other resources
NewResource = (BDS_SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);
Link = RemoveEntryList (&NewResource->Link);
while (!IsListEmpty (&AttachedResources)) {
// Merge resources
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;
// Ensure they overlap each other
ASSERT(
((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) ||
(((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength)))
);
NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength);
NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart);
NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart;
Link = RemoveEntryList (Link);
}
} else {
// None of the Resource of the list is attached to this ResHob. Create a new entry for it
NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));
NewResource->PhysicalStart = ResHob->PhysicalStart;
NewResource->ResourceLength = ResHob->ResourceLength;
}
InsertTailList (ResourceList, &NewResource->Link);
return EFI_SUCCESS;
}
EFI_STATUS
GetSystemMemoryResources (
IN LIST_ENTRY *ResourceList
)
{
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;
InitializeListHead (ResourceList);
// Find the first System Memory Resource Descriptor
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) {
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
// Did not find any
if (ResHob == NULL) {
return EFI_NOT_FOUND;
} else {
InsertSystemMemoryResources (ResourceList, ResHob);
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
while (ResHob != NULL) {
if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
InsertSystemMemoryResources (ResourceList, ResHob);
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
return EFI_SUCCESS;
}
VOID
PrintPerformance (
VOID
)
{
UINTN Key;
CONST VOID *Handle;
CONST CHAR8 *Token, *Module;
UINT64 Start, Stop, TimeStamp;
UINT64 Delta, TicksPerSecond, Milliseconds;
UINTN Index;
CHAR8 Buffer[100];
UINTN CharCount;
TicksPerSecond = GetPerformanceCounterProperties (NULL, NULL);
TimeStamp = 0;
Key = 0;
do {
Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop);
if (Key != 0) {
for (Index = 0; mTokenList[Index] != NULL; Index++) {
if (AsciiStriCmp (mTokenList[Index], Token) == 0) {
Delta = Start - Stop;
TimeStamp += Delta;
Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL);
CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"%6a %6ld ms\n", Token, Milliseconds);
SerialPortWrite ((UINT8 *) Buffer, CharCount);
break;
}
}
}
} while (Key != 0);
CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL));
SerialPortWrite ((UINT8 *) Buffer, CharCount);
}

View File

@ -24,6 +24,7 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/BdsUnixLib.h>
#include <Library/PerformanceLib.h>
#include <Guid/FileInfo.h>
@ -31,106 +32,58 @@
#include <Protocol/DevicePathFromText.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/FirmwareVolume2.h>
#include <Protocol/LoadFile.h>
#include <Protocol/PxeBaseCode.h>
typedef enum { BDS_FILETYPE_MEM, BDS_FILETYPE_FS, BDS_FILETYPE_FV } BDS_FILE_TYPE;
typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath
);
typedef EFI_STATUS (*BDS_FILE_LOADER_LOAD_IMAGE) (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH *RemainingDevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS* Image,
OUT UINTN *ImageSize
);
typedef struct {
UINT32 MemoryType;
EFI_PHYSICAL_ADDRESS StartingAddress;
EFI_PHYSICAL_ADDRESS EndingAddress;
} BDS_MEM_FILE;
typedef struct {
EFI_FILE_PROTOCOL *Handle;
} BDS_FS_FILE;
typedef struct {
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
EFI_FV_FILETYPE FileType;
EFI_GUID Guid;
} BDS_FV_FILE;
typedef struct _BDS_FILE {
CHAR16* FilePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
BDS_FILE_TYPE Type;
union {
BDS_MEM_FILE Mem;
BDS_FS_FILE Fs;
BDS_FV_FILE Fv;
} File;
} BDS_FILE;
BDS_FILE_LOADER_SUPPORT Support;
BDS_FILE_LOADER_LOAD_IMAGE LoadImage;
} BDS_FILE_LOADER;
typedef struct _BDS_SYSTEM_MEMORY_RESOURCE {
LIST_ENTRY Link; // This attribute must be the first entry of this structure (to avoid pointer computation)
EFI_PHYSICAL_ADDRESS PhysicalStart;
UINT64 ResourceLength;
LIST_ENTRY Link; // This attribute must be the first entry of this structure (to avoid pointer computation)
EFI_PHYSICAL_ADDRESS PhysicalStart;
UINT64 ResourceLength;
} BDS_SYSTEM_MEMORY_RESOURCE;
// BdsHelper.c
EFI_STATUS
ShutdownUefiBootServices( VOID );
ShutdownUefiBootServices (
VOID
);
EFI_STATUS
GetSystemMemoryResources (LIST_ENTRY *ResourceList);
GetSystemMemoryResources (
LIST_ENTRY *ResourceList
);
// BdsFilePath.c
EFI_STATUS BdsLoadDevicePath(
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
OUT EFI_HANDLE *Handle
);
EFI_STATUS BdsLoadFilePath(
IN CONST CHAR16 *DeviceFilePath,
OUT BDS_FILE *File
);
EFI_STATUS BdsCopyRawFileToRuntimeMemory(
IN BDS_FILE *File,
OUT VOID **FileImage,
OUT UINTN *FileSize
);
// BdsFilePathFs.c
EFI_STATUS BdsLoadFileFromSimpleFileSystem(
IN EFI_HANDLE Handle,
IN CHAR16 *FilePath,
OUT BDS_FILE *File
);
EFI_STATUS BdsCopyRawFileToRuntimeMemoryFS(
IN EFI_FILE_PROTOCOL *File,
OUT VOID **FileImage,
OUT UINTN *FileSize
);
// BdsFilePathFv.c
EFI_STATUS BdsLoadFileFromFirmwareVolume(
IN EFI_HANDLE FvHandle,
IN CHAR16 *FilePath,
IN EFI_FV_FILETYPE FileTypeFilter,
OUT BDS_FILE *File
);
EFI_STATUS BdsCopyRawFileToRuntimeMemoryFV(
IN BDS_FV_FILE *FvFile,
OUT VOID **FileImage,
OUT UINTN *FileSize
);
// BdsFilePathMem.c
EFI_STATUS BdsLoadFileFromMemMap (
IN EFI_HANDLE Handle,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
OUT BDS_FILE *File
);
EFI_STATUS BdsCopyRawFileToRuntimeMemoryMemMap(
IN BDS_MEM_FILE *MemFile,
OUT VOID **FileImage,
OUT UINTN *FileSize
);
VOID
PrintPerformance (
VOID
);
EFI_STATUS
BdsLoadImage (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_ALLOCATE_TYPE Type,
IN OUT EFI_PHYSICAL_ADDRESS* Image,
OUT UINTN *FileSize
);
#endif

View File

@ -15,15 +15,12 @@
INF_VERSION = 0x00010005
BASE_NAME = BdsLib
FILE_GUID = ddbf73a0-bb25-11df-8e4e-0002a5d5c51b
MODULE_TYPE = UEFI_DRIVER
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = BdsLib
[Sources.common]
BdsFilePath.c
BdsFilePathFs.c
BdsFilePathFv.c
BdsFilePathMem.c
BdsLinuxLoader.c
BdsAppLoader.c
BdsHelper.c
@ -34,13 +31,12 @@
ArmPkg/ArmPkg.dec
[LibraryClasses]
DevicePathLib
BaseLib
HobLib
DebugLib
UefiDriverEntryPoint
DxeServicesTableLib
ArmLib
BaseLib
DebugLib
DevicePathLib
HobLib
PerformanceLib
[Guids]
gEfiFileInfoGuid
@ -51,11 +47,20 @@
gEfiDevicePathFromTextProtocolGuid
gEfiSimpleFileSystemProtocolGuid
gEfiFirmwareVolume2ProtocolGuid
gEfiLoadFileProtocolGuid
gEfiPxeBaseCodeProtocolGuid
gEfiDiskIoProtocolGuid
gEfiUsbIoProtocolGuid
[FeaturePcd]
[FixedPcd]
gArmTokenSpaceGuid.PcdSystemMemoryBase
gArmTokenSpaceGuid.PcdSystemMemorySize
gArmTokenSpaceGuid.PcdArmMachineType
gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset
gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset
[Pcd]

View File

@ -19,58 +19,53 @@
#include <Library/ArmLib.h>
#include <Library/HobLib.h>
STATIC
EFI_STATUS
GetARMLinuxMachineType (
IN BOOLEAN FdtSupported,
OUT UINT32 *MachineType
) {
if (FdtSupported)
{
// FDT requires that the machine type is set to the maximum 32-bit number.
*MachineType = 0xFFFFFFFF;
}
else
{
// Non-FDT requires a specific machine type.
// This OS Boot loader supports just one machine type,
// but that could change in the future.
*MachineType = PcdGet32(PcdArmMachineType);
}
#define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32)
return EFI_SUCCESS;
}
#define LINUX_ATAG_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset))
#define LINUX_KERNEL_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxKernelMaxOffset))
// Point to the current ATAG
STATIC LINUX_ATAG *mLinuxKernelCurrentAtag;
STATIC
VOID
SetupCoreTag( IN UINT32 PageSize )
SetupCoreTag (
IN UINT32 PageSize
)
{
Params->header.size = tag_size(atag_core);
Params->header.type = ATAG_CORE;
mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_CORE);
mLinuxKernelCurrentAtag->header.type = ATAG_CORE;
Params->body.core_tag.flags = 1; /* ensure read-only */
Params->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */
Params->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/
mLinuxKernelCurrentAtag->body.core_tag.flags = 1; /* ensure read-only */
mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */
mLinuxKernelCurrentAtag->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/
Params = next_tag_address(Params); /* move pointer to next tag */
// move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
STATIC
VOID
SetupMemTag( IN UINTN StartAddress, IN UINT32 Size )
SetupMemTag (
IN UINTN StartAddress,
IN UINT32 Size
)
{
Params->header.size = tag_size(atag_mem);
Params->header.type = ATAG_MEM;
mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_MEM);
mLinuxKernelCurrentAtag->header.type = ATAG_MEM;
Params->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */
Params->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */
mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */
mLinuxKernelCurrentAtag->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */
Params = next_tag_address(Params); /* move pointer to next tag */
// move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
STATIC
VOID
SetupCmdlineTag( IN CONST CHAR8 *CmdLine )
SetupCmdlineTag (
IN CONST CHAR8 *CmdLine
)
{
UINT32 LineLength;
@ -81,98 +76,92 @@ SetupCmdlineTag( IN CONST CHAR8 *CmdLine )
* Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer.
* Remember, you have at least one null string terminator character.
*/
if( LineLength > 1 )
{
Params->header.size = ((UINT32)sizeof(struct atag_header) + LineLength + (UINT32)3) >> 2;
Params->header.type = ATAG_CMDLINE;
if(LineLength > 1) {
mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof(LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2;
mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE;
/* place CommandLine into tag */
AsciiStrCpy(Params->body.cmdline_tag.cmdline, CmdLine);
AsciiStrCpy(mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine);
Params = next_tag_address(Params); /* move pointer to next tag */
// move pointer to next tag
mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
}
}
STATIC
VOID
SetupEndTag( VOID )
SetupEndTag (
VOID
)
{
// Empty tag ends list; this has zero length and no body
Params->header.type = ATAG_NONE;
Params->header.size = 0;
mLinuxKernelCurrentAtag->header.type = ATAG_NONE;
mLinuxKernelCurrentAtag->header.size = 0;
/* We can not calculate the next address by using the standard macro:
* Params = next_tag_address(Params);
* because it relies on the header.size, which here it is 0 (zero).
* The easiest way is to add the sizeof(Params->header).
* The easiest way is to add the sizeof(mLinuxKernelCurrentAtag->header).
*/
Params = (struct atag *)((UINT32)Params + sizeof(Params->header));
mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof(mLinuxKernelCurrentAtag->header));
}
STATIC
EFI_STATUS
PrepareAtagList(
IN OUT struct atag **AtagStartAddress,
IN CONST CHAR8* CommandLineString,
OUT UINT32 *AtagSize
) {
LIST_ENTRY *ResourceLink;
LIST_ENTRY ResourceList;
PrepareAtagList (
IN CONST CHAR8* CommandLineString,
OUT LINUX_ATAG **AtagBase,
OUT UINT32 *AtagSize
)
{
EFI_STATUS Status;
LIST_ENTRY *ResourceLink;
LIST_ENTRY ResourceList;
EFI_PHYSICAL_ADDRESS AtagStartAddress;
BDS_SYSTEM_MEMORY_RESOURCE *Resource;
// If no address supplied then this function will decide where to put it
if( *AtagStartAddress == 0 )
{
/* WARNING: At the time of writing (2010-July-30) the linux kernel expects
* the atag list it in the first 1MB of memory and preferably at address 0x100.
* This has a very high risk of overwriting UEFI code, but as
* the linux kernel does not expect any runtime services from uefi
* and there is no afterlife section following the linux kernel termination,
* it does not matter if we stamp over that memory area.
*
* The proposed workaround is to create the atag list somewhere in boot services memory
* and then transfer it to address 0x100 (or to runtime services memory) immediately
* before starting the kernel.
* An additional benefit of this is that when we copy the ATAG list to it's final place,
* we can trim down the memory allocation size. Before we create the list we don't know
* how much space it is going to take, so we are over-allocating space.
*/
*AtagStartAddress = (struct atag *) AllocatePool(ATAG_MAX_SIZE);
AtagStartAddress = LINUX_ATAG_MAX_OFFSET;
Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR,"Failed to allocate Atag at 0x%lX (%r)\n",AtagStartAddress,Status));
Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress);
ASSERT_EFI_ERROR(Status);
}
// Ensure the pointer is not NULL.
ASSERT( *AtagStartAddress != (struct atag *)NULL );
// Ready to setup the atag list
Params = *AtagStartAddress;
mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress;
// Standard core tag 4k PageSize
SetupCoreTag( (UINT32)SIZE_4KB );
// Physical memory setup
GetSystemMemoryResources(&ResourceList);
GetSystemMemoryResources (&ResourceList);
ResourceLink = ResourceList.ForwardLink;
while (ResourceLink != NULL && ResourceLink != &ResourceList) {
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink;
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceLink;
DEBUG((EFI_D_INFO,"- [0x%08X,0x%08X]\n",(UINT32)Resource->PhysicalStart,(UINT32)Resource->PhysicalStart+(UINT32)Resource->ResourceLength));
SetupMemTag( (UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength );
ResourceLink = ResourceLink->ForwardLink;
}
// CommandLine setting root device
SetupCmdlineTag( CommandLineString );
SetupCmdlineTag (CommandLineString);
// end of tags
SetupEndTag();
// Calculate atag list size
*AtagSize = (UINT32)Params - (UINT32)*AtagStartAddress + 1;
*AtagBase = (LINUX_ATAG*)(UINTN)AtagStartAddress;
*AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
PreparePlatformHardware( VOID )
PreparePlatformHardware (
VOID
)
{
//Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.
@ -185,153 +174,131 @@ PreparePlatformHardware( VOID )
ArmDisableInstructionCache ();
// turn off MMU
ArmInvalidateTlb();
ArmDisableMmu();
return EFI_SUCCESS;
}
/*************************************************
* R0, R1, R2 correspond to registers R0, R1, R2
*************************************************/
//STATIC
EFI_STATUS
StartLinuxKernel( IN VOID* KernelAddress, IN UINTN R0, IN UINTN R1, IN UINTN R2 )
{
VOID (*Kernel)(UINT32 Zero, UINT32 Arch, UINTN AtagListParams);
/**
Start a Linux kernel from a Device Path
// set the kernel address
Kernel = (VOID (*)(UINT32, UINT32, UINTN)) KernelAddress;
@param LinuxKernel Device Path to the Linux Kernel
@param Parameters Linux kernel agruments
@param Fdt Device Path to the Flat Device Tree
@retval EFI_SUCCESS All drivers have been connected
@retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
@retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
**/
EFI_STATUS
BdsBootLinux (
IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
IN CONST CHAR8* Arguments,
IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath
)
{
EFI_STATUS Status;
UINT32 LinuxImageSize;
UINT32 KernelParamsSize;
VOID* KernelParamsAddress = NULL;
UINT32 MachineType;
BOOLEAN FdtSupported = FALSE;
LINUX_KERNEL LinuxKernel;
EFI_PHYSICAL_ADDRESS LinuxImage;;
PERF_START (NULL, "BDS", NULL, 0);
// Load the Linux kernel from a device path
LinuxImage = LINUX_KERNEL_MAX_OFFSET;
Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "ERROR: Do not find Linux kernel.\n"));
return Status;
}
LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage;
// Load the FDT binary from a device path
KernelParamsAddress = (VOID*)LINUX_ATAG_MAX_OFFSET;
Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, (EFI_PHYSICAL_ADDRESS*)&KernelParamsAddress, &KernelParamsSize);
if (!EFI_ERROR(Status)) {
FdtSupported = TRUE;
}
//
// Setup the Linux Kernel Parameters
//
if (!FdtSupported) {
// Non-FDT requires a specific machine type.
// This OS Boot loader supports just one machine type,
// but that could change in the future.
MachineType = PcdGet32(PcdArmMachineType);
// By setting address=0 we leave the memory allocation to the function
Status = PrepareAtagList (Arguments, (LINUX_ATAG**)&KernelParamsAddress, &KernelParamsSize);
if(EFI_ERROR(Status)) {
Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status);
goto Exit;
}
} else {
MachineType = 0xFFFFFFFF;
}
// Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on
// ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event.
Status = ShutdownUefiBootServices ();
if(EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));
goto Exit;
}
// Move the kernel parameters to any address inside the first 1MB.
// This is necessary because the ARM Linux kernel requires
// the FTD / ATAG List to reside entirely inside the first 1MB of
// physical memory.
if ((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) {
//Note: There is no requirement on the alignment
KernelParamsAddress = CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), KernelParamsAddress, KernelParamsSize);
}
if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) {
//Note: There is no requirement on the alignment
LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize);
}
//TODO: Check there is no overlapping between kernel and Atag
//
// Switch off interrupts, caches, mmu, etc
//
Status = PreparePlatformHardware ();
ASSERT_EFI_ERROR(Status);
// Register and print out performance information
PERF_END (NULL, "BDS", NULL, 0);
if (PerformanceMeasurementEnabled ()) {
PrintPerformance ();
}
//
// Start the Linux Kernel
//
// Outside BootServices, so can't use Print();
DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n"));
// jump to kernel with register set
Kernel( R0, R1, R2 );
LinuxKernel ((UINTN)0, (UINTN)MachineType, (UINTN)KernelParamsAddress);
// Kernel should never exit
// After Life services are not provided
ASSERT( FALSE );
return EFI_SUCCESS;
}
EFI_STATUS BdsBootLinux(
IN CONST CHAR16* LinuxKernel,
IN CONST CHAR8* ATag,
IN CONST CHAR16* Fdt
) {
BDS_FILE LinuxKernelFile;
BDS_FILE FdtFile;
EFI_STATUS Status;
VOID* LinuxImage;
UINT32 KernelParamsSize;
VOID* KernelParamsAddress = NULL;
UINTN KernelParamsNewAddress;
UINTN *AtagAddress;
UINT32 MachineType;
BOOLEAN FdtSupported = FALSE;
EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;
// Load the Linux kernel from a device path
Status = BdsLoadFilePath(LinuxKernel, &LinuxKernelFile);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "ERROR: Do not find Linux kernel %s\n",LinuxKernel));
return Status;
}
// Copy the Linux Kernel from the raw file to Runtime memory
Status = BdsCopyRawFileToRuntimeMemory(&LinuxKernelFile,&LinuxImage,NULL);
if (EFI_ERROR(Status)) {
goto Exit;
}
// Load the FDT binary from a device path
Status = BdsLoadFilePath(Fdt, &FdtFile);
if (!EFI_ERROR(Status)) {
// Copy the FDT binary from the raw file to Runtime memory
Status = BdsCopyRawFileToRuntimeMemory(&FdtFile,&KernelParamsAddress,&KernelParamsSize);
if (EFI_ERROR(Status)) {
goto Exit;
} else {
FdtSupported = TRUE;
}
}
/**********************************************************
* Setup the platform type
**********************************************************/
Status = GetARMLinuxMachineType(FdtSupported, &MachineType);
if(EFI_ERROR(Status))
{
Print(L"ERROR : Can not prepare ARM Linux machine type. Status=0x%X\n", Status);
goto Exit;
}
if (!FdtSupported) {
/**********************************************************
* Setup the ATAG list
**********************************************************/
// By setting address=0 we leave the memory allocation to the function
AtagAddress = 0;
Status = PrepareAtagList( (struct atag **)&AtagAddress, ATag, &KernelParamsSize );
KernelParamsAddress = (VOID*)AtagAddress;
if(EFI_ERROR(Status))
{
Print(L"ERROR : Can not prepare ATAG list. Status=0x%X\n", Status);
goto Exit;
}
}
/**********************************************************
* Switch off interrupts, caches, mmu, etc
**********************************************************/
Status = PreparePlatformHardware();
if(EFI_ERROR(Status))
{
Print(L"ERROR : Can not prepare platform hardware. Status=0x%X\n", Status);
goto Exit;
}
// Initialize the ATag destination
KernelParamsNewAddress = 0x100;
// Update the ATag destination by finding the start address of the first System Memory Resource Descriptor Hob
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
while (ResHob != NULL) {
if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
KernelParamsNewAddress = (UINTN)ResHob->PhysicalStart + 0x100;
break;
}
ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (VOID *)((UINTN)ResHob + ResHob->Header.HobLength));
}
// Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on
// ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event.
Status = ShutdownUefiBootServices();
if(EFI_ERROR(Status))
{
Print(L"ERROR : Can not shutdown UEFI boot services. Status=0x%X\n", Status);
goto Exit;
}
// Move the kernel parameters to any address inside the first 1MB.
// This is necessary because the ARM Linux kernel requires
// the FTD / ATAG List to reside entirely inside the first 1MB of
// physical memory.
CopyMem((VOID*)KernelParamsNewAddress, KernelParamsAddress, KernelParamsSize);
//**********************************************************
// * Start the Linux Kernel
// **********************************************************
// Lift off ...
Status = StartLinuxKernel(LinuxImage, (UINTN)0, (UINTN)MachineType, KernelParamsNewAddress );
// Only be here if we fail to start Linux
DEBUG((EFI_D_ERROR, "ERROR : Can not start the kernel. Status=0x%X\n", Status));
ASSERT(FALSE);
Exit:
// Free Runtimee Memory (kernel and FDT)
return Status;
// Only be here if we fail to start Linux
Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status);
// Free Runtimee Memory (kernel and FDT)
return Status;
}

View File

@ -15,8 +15,7 @@
#ifndef __BDSLINUXLOADER_H
#define __BDSLINUXLOADER_H
#define ATAG_MAX_SIZE 0x4000
//PcdKernelParamsMaxMemorySize
#define ATAG_MAX_SIZE 0x3000
/* ATAG : list of possible tags */
#define ATAG_NONE 0x00000000
@ -31,64 +30,24 @@
#define ATAG_CMDLINE 0x54410009
#define ATAG_ARM_MP_CORE 0x5441000A
// Some system addresses
// These should probably come from the platform header file or from pcd values
#define DRAM_BASE 0x10000000
#define ZIMAGE_LOAD_ADDRESS (DRAM_BASE + 0x8000)
#define INITRD_LOAD_ADDRESS (DRAM_BASE + 0x800000)
#define SIZE_1B 0x00000001
#define SIZE_2B 0x00000002
#define SIZE_4B 0x00000004
#define SIZE_8B 0x00000008
#define SIZE_16B 0x00000010
#define SIZE_32B 0x00000020
#define SIZE_64B 0x00000040
#define SIZE_128B 0x00000080
#define SIZE_256B 0x00000100
#define SIZE_512B 0x00000200
#define SIZE_1KB 0x00000400
#define SIZE_2KB 0x00000800
#define SIZE_4KB 0x00001000
#define SIZE_8KB 0x00002000
#define SIZE_16KB 0x00004000
#define SIZE_32KB 0x00008000
#define SIZE_64KB 0x00010000
#define SIZE_128KB 0x00020000
#define SIZE_256KB 0x00040000
#define SIZE_512KB 0x00080000
#define SIZE_1MB 0x00100000
#define SIZE_2MB 0x00200000
#define SIZE_4MB 0x00400000
#define SIZE_8MB 0x00800000
#define SIZE_16MB 0x01000000
#define SIZE_32MB 0x02000000
#define SIZE_64MB 0x04000000
#define SIZE_100MB 0x06400000
#define SIZE_128MB 0x08000000
#define SIZE_256MB 0x10000000
#define SIZE_512MB 0x20000000
#define SIZE_1GB 0x40000000
#define SIZE_2GB 0x80000000
/* structures for each atag */
struct atag_header {
typedef struct {
UINT32 size; /* length of tag in words including this header */
UINT32 type; /* tag type */
};
} LINUX_ATAG_HEADER;
struct atag_core {
typedef struct {
UINT32 flags;
UINT32 pagesize;
UINT32 rootdev;
};
} LINUX_ATAG_CORE;
struct atag_mem {
typedef struct {
UINT32 size;
UINTN start;
};
} LINUX_ATAG_MEM;
struct atag_videotext {
typedef struct {
UINT8 x;
UINT8 y;
UINT16 video_page;
@ -98,29 +57,29 @@ struct atag_videotext {
UINT8 video_lines;
UINT8 video_isvga;
UINT16 video_points;
};
} LINUX_ATAG_VIDEOTEXT;
struct atag_ramdisk {
typedef struct {
UINT32 flags;
UINT32 size;
UINTN start;
};
} LINUX_ATAG_RAMDISK;
struct atag_initrd2 {
typedef struct {
UINT32 start;
UINT32 size;
};
} LINUX_ATAG_INITRD2;
struct atag_serialnr {
typedef struct {
UINT32 low;
UINT32 high;
};
} LINUX_ATAG_SERIALNR;
struct atag_revision {
typedef struct {
UINT32 rev;
};
} LINUX_ATAG_REVISION;
struct atag_videolfb {
typedef struct {
UINT16 lfb_width;
UINT16 lfb_height;
UINT16 lfb_depth;
@ -135,31 +94,30 @@ struct atag_videolfb {
UINT8 blue_pos;
UINT8 rsvd_size;
UINT8 rsvd_pos;
};
} LINUX_ATAG_VIDEOLFB;
struct atag_cmdline {
typedef struct {
CHAR8 cmdline[1];
};
} LINUX_ATAG_CMDLINE;
struct atag {
struct atag_header header;
typedef struct {
LINUX_ATAG_HEADER header;
union {
struct atag_core core_tag;
struct atag_mem mem_tag;
struct atag_videotext videotext_tag;
struct atag_ramdisk ramdisk_tag;
struct atag_initrd2 initrd2_tag;
struct atag_serialnr serialnr_tag;
struct atag_revision revision_tag;
struct atag_videolfb videolfb_tag;
struct atag_cmdline cmdline_tag;
LINUX_ATAG_CORE core_tag;
LINUX_ATAG_MEM mem_tag;
LINUX_ATAG_VIDEOTEXT videotext_tag;
LINUX_ATAG_RAMDISK ramdisk_tag;
LINUX_ATAG_INITRD2 initrd2_tag;
LINUX_ATAG_SERIALNR serialnr_tag;
LINUX_ATAG_REVISION revision_tag;
LINUX_ATAG_VIDEOLFB videolfb_tag;
LINUX_ATAG_CMDLINE cmdline_tag;
} body;
};
} LINUX_ATAG;
#define next_tag_address(t) ((struct atag *)((UINT32)(t) + (((t)->header.size) << 2) ))
#define tag_size(type) ((UINT32)((sizeof(struct atag_header) + sizeof(struct type)) >> 2))
typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase);
STATIC struct atag *Params; /* used to point at the current tag */
#define next_tag_address(t) ((LINUX_ATAG*)((UINT32)(t) + (((t)->header.size) << 2) ))
#define tag_size(type) ((UINT32)((sizeof(LINUX_ATAG_HEADER) + sizeof(type)) >> 2))
#endif