]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/Library/FdtLib/FdtConfigurationTable.c
EmbeddedPkg/FdtLib: Added support to load Fdt from Semihosting
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / FdtConfigurationTable.c
diff --git a/EmbeddedPkg/Library/FdtLib/FdtConfigurationTable.c b/EmbeddedPkg/Library/FdtLib/FdtConfigurationTable.c
new file mode 100644 (file)
index 0000000..42c5d44
--- /dev/null
@@ -0,0 +1,178 @@
+/** @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