+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