]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Bds/BootMenu.c
ArmPlatformPkg/Bds: Restore the setting of the FDT device path in the boot manager
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
index 76c66fd0bb3f867442dbdbc3473774e4d715dc4b..d2dccbc9f274782719efdef8b8e29823967cabdc 100644 (file)
@@ -16,7 +16,7 @@
 \r
 #include <Guid/ArmGlobalVariableHob.h>\r
 \r
 \r
 #include <Guid/ArmGlobalVariableHob.h>\r
 \r
-extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r
+#include <libfdt.h>\r
 \r
 /**\r
   Worker function that displays the list of boot options that is passed in.\r
 \r
 /**\r
   Worker function that displays the list of boot options that is passed in.\r
@@ -824,6 +824,152 @@ ErrorExit:
   return Status ;\r
 }\r
 \r
   return Status ;\r
 }\r
 \r
+EFI_STATUS\r
+UpdateFdtPath (\r
+  IN LIST_ENTRY *BootOptionsList\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  BDS_SUPPORTED_DEVICE      *SupportedBootDevice;\r
+  EFI_DEVICE_PATH_PROTOCOL  *FdtDevicePathNodes;\r
+  EFI_DEVICE_PATH_PROTOCOL  *FdtDevicePath;\r
+  CHAR16                    *FdtTextDevicePath;\r
+  EFI_PHYSICAL_ADDRESS      FdtBlobBase;\r
+  UINTN                     FdtBlobSize;\r
+  UINTN                     NumPages;\r
+  EFI_PHYSICAL_ADDRESS      FdtConfigurationTableBase;\r
+\r
+  SupportedBootDevice = NULL;\r
+\r
+  Status = SelectBootDevice (&SupportedBootDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto EXIT;\r
+  }\r
+\r
+  // Create the specific device path node\r
+  Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto EXIT;\r
+  }\r
+\r
+  if (FdtDevicePathNodes != NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+\r
+    FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
+    FreePool (FdtDevicePathNodes);\r
+    if (FdtDevicePath == NULL) {\r
+      goto EXIT;\r
+    }\r
+\r
+    FdtTextDevicePath = ConvertDevicePathToText (FdtDevicePath, TRUE, TRUE);\r
+    if (FdtTextDevicePath == NULL) {\r
+      goto EXIT;\r
+    }\r
+\r
+    Status = gRT->SetVariable (\r
+                    (CHAR16*)L"Fdt",\r
+                    &gFdtVariableGuid,\r
+                    EFI_VARIABLE_RUNTIME_ACCESS |\r
+                    EFI_VARIABLE_NON_VOLATILE   |\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                    StrSize (FdtTextDevicePath),\r
+                    FdtTextDevicePath\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    FreePool (FdtTextDevicePath);\r
+  } else {\r
+    Status = gRT->SetVariable (\r
+           (CHAR16*)L"Fdt",\r
+           &gFdtVariableGuid,\r
+           EFI_VARIABLE_RUNTIME_ACCESS |\r
+           EFI_VARIABLE_NON_VOLATILE   |\r
+           EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+           0,\r
+           NULL\r
+           );\r
+    ASSERT_EFI_ERROR (Status);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Try to load FDT from the new EFI Device Path\r
+  //\r
+\r
+  //\r
+  // Load the FDT given its device path.\r
+  // This operation may fail if the device path is not supported.\r
+  //\r
+  FdtBlobBase = 0;\r
+  NumPages    = 0;\r
+  Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
+  FreePool (FdtDevicePath);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT_LOAD_FDT;\r
+  }\r
+\r
+  // Check the FDT header is valid. We only make this check in DEBUG mode in\r
+  // case the FDT header change on production device and this ASSERT() becomes\r
+  // not valid.\r
+  ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
+\r
+  //\r
+  // Ensure the Size of the Device Tree is smaller than the size of the read file\r
+  //\r
+  ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
+\r
+  //\r
+  // Store the FDT as Runtime Service Data to prevent the Kernel from\r
+  // overwritting its data.\r
+  //\r
+  NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
+  Status = gBS->AllocatePages (\r
+                  AllocateAnyPages, EfiRuntimeServicesData,\r
+                  NumPages, &FdtConfigurationTableBase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT_LOAD_FDT;\r
+  }\r
+  gBS->CopyMem (\r
+    (VOID*)(UINTN)FdtConfigurationTableBase,\r
+    (VOID*)(UINTN)FdtBlobBase,\r
+    FdtBlobSize\r
+    );\r
+\r
+  //\r
+  // Install the FDT into the Configuration Table\r
+  //\r
+  Status = gBS->InstallConfigurationTable (\r
+                  &gFdtTableGuid,\r
+                  (VOID*)(UINTN)FdtConfigurationTableBase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
+  }\r
+\r
+EXIT_LOAD_FDT:\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");\r
+  }\r
+\r
+  if (FdtBlobBase != 0) {\r
+    gBS->FreePages (FdtBlobBase, NumPages);\r
+  }\r
+\r
+EXIT:\r
+  if (Status == EFI_ABORTED) {\r
+    Print (L"\n");\r
+  }\r
+\r
+  if (SupportedBootDevice != NULL) {\r
+    FreePool (SupportedBootDevice);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Set boot timeout\r
 \r
 /**\r
   Set boot timeout\r
 \r
@@ -880,6 +1026,7 @@ struct BOOT_MANAGER_ENTRY {
     { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
     { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
     { L"Reorder Boot Device Entries", BootMenuReorderBootOptions },\r
     { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
     { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
     { L"Reorder Boot Device Entries", BootMenuReorderBootOptions },\r
+    { L"Update FDT path", UpdateFdtPath },\r
     { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
 };\r
 \r
     { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
 };\r
 \r