EmbeddedPkg/FdtLib: Added support to load Fdt from Semihosting

The FDT is also installed into the UEFI configuration table to be used
by the OS loader.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.martin@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15905 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Olivier Martin 2014-08-26 10:18:28 +00:00 committed by oliviermartin
parent 749d91f7aa
commit af16798ef7
3 changed files with 208 additions and 2 deletions

View File

@ -15,6 +15,7 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
@ -78,4 +79,19 @@ static inline char *strchr(const char *s, int c) {
return AsciiStrStr (s, pattern);
}
/**
Load and Install FDT from Semihosting
@param Filename Name of the file to load from semihosting
@return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
from semihosting
@return EFI_NOT_FOUND Fail to locate the file in semihosting
@return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
**/
EFI_STATUS
InstallFdtFromSemihosting (
IN CONST CHAR16* FileName
);
#endif /* _LIBFDT_ENV_H */

View File

@ -0,0 +1,178 @@
/** @file
*
* Copyright (c) 2014, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/DevicePath.h>
#include <Protocol/SimpleFileSystem.h>
#include <Guid/Fdt.h>
#include <Guid/FileInfo.h>
#include <libfdt.h>
//
// Device path for SemiHosting
//
STATIC CONST struct {
VENDOR_DEVICE_PATH Guid;
EFI_DEVICE_PATH_PROTOCOL End;
} mSemihostingDevicePath = {
{
{ HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },
{ 0xC5B9C74A, 0x6D72, 0x4719, { 0x99, 0xAB, 0xC5, 0x9F, 0x19, 0x90, 0x91, 0xEB } }
},
{ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
};
/**
This function declares the passed FDT into the UEFI Configuration Table
@param FdtBlob Base address of the Fdt Blob in System Memory
@param FdtSize Size of the Fdt Blob in System Memory
@return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
@return !EFI_SUCCESS Error returned by BS.InstallConfigurationTable()
**/
STATIC
EFI_STATUS
InstallFdtIntoConfigurationTable (
IN VOID* FdtBlob,
IN UINTN FdtSize
)
{
EFI_STATUS Status;
// Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on
// production device and this ASSERT() becomes not valid.
ASSERT (fdt_check_header (FdtBlob) == 0);
// Ensure the Size of the Device Tree is smaller than the size of the read file
ASSERT ((UINTN)fdt_totalsize (FdtBlob) <= FdtSize);
// Install the FDT into the Configuration Table
Status = gBS->InstallConfigurationTable (&gFdtTableGuid, FdtBlob);
return Status;
}
/**
Load and Install FDT from Semihosting
@param Filename Name of the file to load from semihosting
@return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
from semihosting
@return EFI_NOT_FOUND Fail to locate the file in semihosting
@return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
**/
EFI_STATUS
InstallFdtFromSemihosting (
IN CONST CHAR16* FileName
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH* Remaining;
EFI_HANDLE Handle;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SemihostingFs;
EFI_FILE_PROTOCOL *Fs;
EFI_FILE_PROTOCOL *File;
EFI_PHYSICAL_ADDRESS FdtBase;
EFI_FILE_INFO *FileInfo;
UINTN FdtSize;
UINTN FileInfoSize;
// Ensure the Semihosting driver is initialized
Remaining = (EFI_DEVICE_PATH*)&mSemihostingDevicePath;
// 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)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
// Recursive = FALSE: We do not want to start the whole device tree
Status = gBS->ConnectController (Handle, NULL, Remaining, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
// Locate the FileSystem
Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SemihostingFs);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
// Try to Open the volume and get root directory
Status = SemihostingFs->OpenVolume (SemihostingFs, &Fs);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_WARN, "Warning: Fail to open semihosting filesystem that should contain FDT file.\n"));
return Status;
}
File = NULL;
Status = Fs->Open (Fs, &File, (CHAR16*)FileName, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_WARN, "Warning: Fail to load FDT file '%s'.\n", FileName));
Fs->Close (Fs);
return Status;
}
FileInfoSize = 0;
File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, NULL);
FileInfo = AllocatePool (FileInfoSize);
if (FileInfo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto CLOSE_FILES;
}
Status = File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, FileInfo);
if (EFI_ERROR (Status)) {
FreePool (FileInfo);
goto CLOSE_FILES;
}
// Get the file size
FdtSize = FileInfo->FileSize;
FreePool (FileInfo);
// The FDT blob is attached to the Configuration Table. It is recommended to load it as Runtime Service Data
// to prevent the kernel to overwrite its data
Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (FdtSize), &FdtBase);
if (!EFI_ERROR (Status)) {
Status = File->Read (File, &FdtSize, (VOID*)(UINTN)(FdtBase));
if (EFI_ERROR (Status)) {
gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));
} else {
// Install the FDT as part of the UEFI Configuration Table
Status = InstallFdtIntoConfigurationTable ((VOID*)(UINTN)FdtBase, FdtSize);
if (EFI_ERROR (Status)) {
gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));
}
}
}
CLOSE_FILES:
File->Close (File);
Fs->Close (Fs);
return Status;
}

View File

@ -1,5 +1,5 @@
#/* @file
# Copyright (c) 2011-2012, ARM Limited. All rights reserved.
# Copyright (c) 2011-2014, ARM Limited. All rights reserved.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
@ -22,10 +22,11 @@
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = ARM
# VALID_ARCHITECTURES = ARM AARCH64
#
[Sources]
FdtConfigurationTable.c
fdt_ro.c
fdt_rw.c
fdt_strerror.c
@ -36,3 +37,14 @@
[Packages]
MdePkg/MdePkg.dec
EmbeddedPkg/EmbeddedPkg.dec
[LibraryClasses]
UefiBootServicesTableLib
[Protocols]
gEfiDevicePathProtocolGuid
gEfiSimpleFileSystemProtocolGuid
[Guids]
gEfiFileInfoGuid
gFdtTableGuid