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