#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))\r
#define GET_CELL(p) (p += 4, *((const UINT32 *)(p-4)))\r
\r
+STATIC inline\r
+UINTN\r
+cpu_to_fdtn (UINTN x) {\r
+ if (sizeof (UINTN) == sizeof (UINT32)) {\r
+ return cpu_to_fdt32 (x);\r
+ } else {\r
+ return cpu_to_fdt64 (x);\r
+ }\r
+}\r
+\r
+typedef struct {\r
+ UINTN Base;\r
+ UINTN Size;\r
+} FdtRegion;\r
+\r
+\r
STATIC\r
UINTN\r
IsPrintableString (\r
}\r
\r
\r
-typedef struct {\r
- UINTN Base;\r
- UINTN Size;\r
-} FdtRegion;\r
+STATIC\r
+BOOLEAN\r
+IsPsciSmcSupported (\r
+ VOID\r
+ )\r
+{\r
+ BOOLEAN PsciSmcSupported;\r
+ UINTN Rx;\r
+\r
+ PsciSmcSupported = FALSE;\r
+\r
+ // Check the SMC response to the Presence SMC\r
+ Rx = ARM_SMC_ID_PRESENCE;\r
+ ArmCallSmc (&Rx);\r
+ if (Rx == 1) {\r
+ // Check the SMC UID\r
+ Rx = ARM_SMC_ID_UID;\r
+ ArmCallSmc (&Rx);\r
+ if (Rx == ARM_TRUSTZONE_UID_4LETTERID) {\r
+ Rx = ARM_SMC_ID_UID + 1;\r
+ ArmCallSmc (&Rx);\r
+ if (Rx == ARM_TRUSTZONE_ARM_UID) {\r
+ PsciSmcSupported = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return PsciSmcSupported;\r
+}\r
+\r
+\r
+/**\r
+** Relocate the FDT blob to a more appropriate location for the Linux kernel.\r
+** This function will allocate memory for the relocated FDT blob.\r
+**\r
+** @retval EFI_SUCCESS on success.\r
+** @retval EFI_OUT_OF_RESOURCES or EFI_INVALID_PARAMETER on failure.\r
+*/\r
+STATIC\r
+EFI_STATUS\r
+RelocateFdt (\r
+ EFI_PHYSICAL_ADDRESS OriginalFdt,\r
+ UINTN OriginalFdtSize,\r
+ EFI_PHYSICAL_ADDRESS *RelocatedFdt,\r
+ UINTN *RelocatedFdtSize,\r
+ EFI_PHYSICAL_ADDRESS *RelocatedFdtAlloc\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ INTN Error;\r
+ UINT32 FdtAlignment;\r
+\r
+ *RelocatedFdtSize = OriginalFdtSize + FDT_ADDITIONAL_ENTRIES_SIZE;\r
+\r
+ // If FDT load address needs to be aligned, allocate more space.\r
+ FdtAlignment = PcdGet32 (PcdArmLinuxFdtAlignment);\r
+ if (FdtAlignment != 0) {\r
+ *RelocatedFdtSize += FdtAlignment;\r
+ }\r
+\r
+ // Try below a watermark address.\r
+ Status = EFI_NOT_FOUND;\r
+ if (PcdGet32 (PcdArmLinuxFdtMaxOffset) != 0) {\r
+ *RelocatedFdt = LINUX_FDT_MAX_OFFSET;\r
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (*RelocatedFdtSize), RelocatedFdt);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_WARN, "Warning: Failed to load FDT below address 0x%lX (%r). Will try again at a random address anywhere.\n", *RelocatedFdt, Status));\r
+ }\r
+ }\r
+\r
+ // Try anywhere there is available space.\r
+ if (EFI_ERROR (Status)) {\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (*RelocatedFdtSize), RelocatedFdt);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT_EFI_ERROR (Status);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ DEBUG ((EFI_D_WARN, "WARNING: Loaded FDT at random address 0x%lX.\nWARNING: There is a risk of accidental overwriting by other code/data.\n", *RelocatedFdt));\r
+ }\r
+ }\r
+\r
+ *RelocatedFdtAlloc = *RelocatedFdt;\r
+ if (FdtAlignment != 0) {\r
+ *RelocatedFdt = ALIGN (*RelocatedFdt, FdtAlignment);\r
+ }\r
+\r
+ // Load the Original FDT tree into the new region\r
+ Error = fdt_open_into ((VOID*)(UINTN) OriginalFdt,\r
+ (VOID*)(UINTN)(*RelocatedFdt), *RelocatedFdtSize);\r
+ if (Error) {\r
+ DEBUG ((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Error)));\r
+ gBS->FreePages (*RelocatedFdtAlloc, EFI_SIZE_TO_PAGES (*RelocatedFdtSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG_CODE_BEGIN();\r
+ //DebugDumpFdt (fdt);\r
+ DEBUG_CODE_END();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
\r
EFI_STATUS\r
PrepareFdt (\r
{\r
EFI_STATUS Status;\r
EFI_PHYSICAL_ADDRESS NewFdtBlobBase;\r
+ EFI_PHYSICAL_ADDRESS NewFdtBlobAllocation;\r
UINTN NewFdtBlobSize;\r
VOID* fdt;\r
INTN err;\r
INTN node;\r
INTN cpu_node;\r
- INTN lenp;\r
+ INT32 lenp;\r
CONST VOID* BootArg;\r
CONST VOID* Method;\r
EFI_PHYSICAL_ADDRESS InitrdImageStart;\r
UINT64 CpuReleaseAddr;\r
UINTN MemoryMapSize;\r
EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;\r
UINTN MapKey;\r
UINTN DescriptorSize;\r
UINT32 DescriptorVersion;\r
UINTN Pages;\r
BOOLEAN PsciSmcSupported;\r
- UINTN Rx;\r
UINTN OriginalFdtSize;\r
+ BOOLEAN CpusNodeExist;\r
+ UINTN CoreMpId;\r
+ UINTN Smc;\r
\r
- //\r
- // Ensure the Power State Coordination Interface (PSCI) SMCs are there if supported\r
- //\r
- PsciSmcSupported = FALSE;\r
- if (FeaturePcdGet (PcdArmPsciSupport) == TRUE) {\r
- // Check the SMC response to the Presence SMC\r
- Rx = ARM_SMC_ID_PRESENCE;\r
- ArmCallSmc (&Rx);\r
- if (Rx == 1) {\r
- // Check the SMC UID\r
- Rx = ARM_SMC_ID_UID;\r
- ArmCallSmc (&Rx);\r
- if (Rx == ARM_TRUSTZONE_UID_4LETTERID) {\r
- Rx = ARM_SMC_ID_UID + 1;\r
- ArmCallSmc (&Rx);\r
- if (Rx == ARM_TRUSTZONE_ARM_UID) {\r
- PsciSmcSupported = TRUE;\r
- }\r
- }\r
- if (PsciSmcSupported == FALSE) {\r
- DEBUG((EFI_D_ERROR,"Warning: The Power State Coordination Interface (PSCI) is not supported"\r
- "by your platform Trusted Firmware.\n"));\r
- }\r
- }\r
- }\r
+ NewFdtBlobAllocation = 0;\r
\r
//\r
// Sanity checks on the original FDT blob.\r
}\r
\r
//\r
- // Allocate memory for the new FDT\r
+ // Relocate the FDT to its final location.\r
//\r
- NewFdtBlobSize = OriginalFdtSize + FDT_ADDITIONAL_ENTRIES_SIZE;\r
-\r
- // Try below a watermark address\r
- Status = EFI_NOT_FOUND;\r
- if (PcdGet32(PcdArmLinuxFdtMaxOffset) != 0) {\r
- NewFdtBlobBase = LINUX_FDT_MAX_OFFSET;\r
- Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((EFI_D_WARN, "Warning: Failed to load FDT below address 0x%lX (%r). Will try again at a random address anywhere.\n", NewFdtBlobBase, Status));\r
- }\r
+ Status = RelocateFdt (*FdtBlobBase, OriginalFdtSize,\r
+ &NewFdtBlobBase, &NewFdtBlobSize, &NewFdtBlobAllocation);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FAIL_RELOCATE_FDT;\r
}\r
\r
- // Try anywhere there is available space\r
- if (EFI_ERROR(Status)) {\r
- Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);\r
- if (EFI_ERROR(Status)) {\r
- ASSERT_EFI_ERROR(Status);\r
- goto FAIL_ALLOCATE_NEW_FDT;\r
- } else {\r
- DEBUG ((EFI_D_WARN, "WARNING: Loaded FDT at random address 0x%lX.\nWARNING: There is a risk of accidental overwriting by other code/data.\n", NewFdtBlobBase));\r
+ //\r
+ // Ensure the Power State Coordination Interface (PSCI) SMCs are there if supported\r
+ //\r
+ PsciSmcSupported = FALSE;\r
+ if (FeaturePcdGet (PcdArmPsciSupport) == TRUE) {\r
+ PsciSmcSupported = IsPsciSmcSupported();\r
+ if (PsciSmcSupported == FALSE) {\r
+ DEBUG ((EFI_D_ERROR, "Warning: The Power State Coordination Interface (PSCI) is not supported by your platform Trusted Firmware.\n"));\r
}\r
}\r
\r
- // Load the Original FDT tree into the new region\r
fdt = (VOID*)(UINTN)NewFdtBlobBase;\r
- err = fdt_open_into((VOID*)(UINTN)(*FdtBlobBase), fdt, NewFdtBlobSize);\r
- if (err) {\r
- DEBUG((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror(err)));\r
- Status = EFI_INVALID_PARAMETER;\r
- goto FAIL_NEW_FDT;\r
- }\r
\r
- DEBUG_CODE_BEGIN();\r
- //DebugDumpFdt (fdt);\r
- DEBUG_CODE_END();\r
-\r
- node = fdt_subnode_offset(fdt, 0, "chosen");\r
+ node = fdt_subnode_offset (fdt, 0, "chosen");\r
if (node < 0) {\r
// The 'chosen' node does not exist, create it\r
node = fdt_add_subnode(fdt, 0, "chosen");\r
if (node < 0) {\r
DEBUG((EFI_D_ERROR,"Error on finding 'chosen' node\n"));\r
Status = EFI_INVALID_PARAMETER;\r
- goto FAIL_NEW_FDT;\r
+ goto FAIL_COMPLETE_FDT;\r
}\r
}\r
\r
GetSystemMemoryResources (&ResourceList);\r
Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink;\r
\r
- if (sizeof(UINTN) == sizeof(UINT32)) {\r
- Region.Base = cpu_to_fdt32((UINTN)Resource->PhysicalStart);\r
- Region.Size = cpu_to_fdt32((UINTN)Resource->ResourceLength);\r
- } else {\r
- Region.Base = cpu_to_fdt64((UINTN)Resource->PhysicalStart);\r
- Region.Size = cpu_to_fdt64((UINTN)Resource->ResourceLength);\r
- }\r
+ Region.Base = cpu_to_fdtn ((UINTN)Resource->PhysicalStart);\r
+ Region.Size = cpu_to_fdtn ((UINTN)Resource->ResourceLength);\r
\r
err = fdt_setprop(fdt, node, "reg", &Region, sizeof(Region));\r
if (err) {\r
MemoryMapSize = 0;\r
Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ // The UEFI specification advises to allocate more memory for the MemoryMap buffer between successive\r
+ // calls to GetMemoryMap(), since allocation of the new buffer may potentially increase memory map size.\r
Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;\r
MemoryMap = AllocatePages (Pages);\r
+ if (MemoryMap == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FAIL_COMPLETE_FDT;\r
+ }\r
Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
}\r
\r
// Go through the list and add the reserved region to the Device Tree\r
if (!EFI_ERROR(Status)) {\r
- for (Index = 0; Index < (MemoryMapSize / sizeof(EFI_MEMORY_DESCRIPTOR)); Index++) {\r
- if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMap[Index].Type)) {\r
+ MemoryMapPtr = MemoryMap;\r
+ for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {\r
+ if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMapPtr->Type)) {\r
DEBUG((DEBUG_VERBOSE, "Reserved region of type %d [0x%X, 0x%X]\n",\r
- MemoryMap[Index].Type,\r
- (UINTN)MemoryMap[Index].PhysicalStart,\r
- (UINTN)(MemoryMap[Index].PhysicalStart + MemoryMap[Index].NumberOfPages * EFI_PAGE_SIZE)));\r
- err = fdt_add_mem_rsv(fdt, MemoryMap[Index].PhysicalStart, MemoryMap[Index].NumberOfPages * EFI_PAGE_SIZE);\r
+ MemoryMapPtr->Type,\r
+ (UINTN)MemoryMapPtr->PhysicalStart,\r
+ (UINTN)(MemoryMapPtr->PhysicalStart + MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE)));\r
+ err = fdt_add_mem_rsv(fdt, MemoryMapPtr->PhysicalStart, MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE);\r
if (err != 0) {\r
Print(L"Warning: Fail to add 'memreserve' (err:%d)\n", err);\r
}\r
}\r
+ MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR*)((UINTN)MemoryMapPtr + DescriptorSize);\r
}\r
}\r
\r
//\r
- // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms\r
+ // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms.\r
+ //\r
+ // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file\r
+ // in the kernel documentation:\r
+ // Documentation/devicetree/bindings/arm/cpus.txt\r
//\r
for (Index=0; Index < gST->NumberOfTableEntries; Index++) {\r
// Check for correct GUID type\r
// Create the /cpus node\r
node = fdt_add_subnode(fdt, 0, "cpus");\r
fdt_setprop_string(fdt, node, "name", "cpus");\r
- fdt_setprop_cell(fdt, node, "#address-cells", 1);\r
+ fdt_setprop_cell (fdt, node, "#address-cells", sizeof (UINTN) / 4);\r
fdt_setprop_cell(fdt, node, "#size-cells", 0);\r
+ CpusNodeExist = FALSE;\r
+ } else {\r
+ CpusNodeExist = TRUE;\r
}\r
\r
// Get pointer to ARM processor table\r
ArmCoreInfoTable = ArmProcessorTable->ArmCpus;\r
\r
for (Index = 0; Index < ArmProcessorTable->NumberOfEntries; Index++) {\r
- AsciiSPrint (Name, 10, "cpu@%d", Index);\r
- cpu_node = fdt_subnode_offset(fdt, node, Name);\r
- if (cpu_node < 0) {\r
- cpu_node = fdt_add_subnode(fdt, node, Name);\r
- fdt_setprop_string(fdt, cpu_node, "device-type", "cpu");\r
- fdt_setprop(fdt, cpu_node, "reg", &Index, sizeof(Index));\r
+ CoreMpId = (UINTN) GET_MPID (ArmCoreInfoTable[Index].ClusterId,\r
+ ArmCoreInfoTable[Index].CoreId);\r
+ AsciiSPrint (Name, 10, "cpu@%x", CoreMpId);\r
+\r
+ // If the 'cpus' node did not exist then create all the 'cpu' nodes.\r
+ // In case 'cpus' node is provided in the original FDT then we do not add\r
+ // any 'cpu' node.\r
+ if (!CpusNodeExist) {\r
+ cpu_node = fdt_add_subnode (fdt, node, Name);\r
+ if (cpu_node < 0) {\r
+ DEBUG ((EFI_D_ERROR, "Error on creating '%s' node\n", Name));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto FAIL_COMPLETE_FDT;\r
+ }\r
+\r
+ fdt_setprop_string (fdt, cpu_node, "device_type", "cpu");\r
+\r
+ CoreMpId = cpu_to_fdtn (CoreMpId);\r
+ fdt_setprop (fdt, cpu_node, "reg", &CoreMpId, sizeof (CoreMpId));\r
+ if (PsciSmcSupported) {\r
+ fdt_setprop_string (fdt, cpu_node, "enable-method", "psci");\r
+ }\r
+ } else {\r
+ cpu_node = fdt_subnode_offset(fdt, node, Name);\r
}\r
\r
// If Power State Coordination Interface (PSCI) is not supported then it is expected the secondary\r
// cores are spinning waiting for the Operating System to release them\r
- if (PsciSmcSupported == FALSE) {\r
+ if ((PsciSmcSupported == FALSE) && (cpu_node >= 0)) {\r
// We as the bootloader are responsible for either creating or updating\r
// these entries. Do not trust the entries in the DT. We only know about\r
// 'spin-table' type. Do not try to update other types if defined.\r
if (node < 0) {\r
DEBUG((EFI_D_ERROR,"Error on creating 'psci' node\n"));\r
Status = EFI_INVALID_PARAMETER;\r
- goto FAIL_NEW_FDT;\r
+ goto FAIL_COMPLETE_FDT;\r
} else {\r
- fdt_setprop_string(fdt, node, "compatible", "arm,psci");\r
- fdt_setprop_string(fdt, node, "method", "smc");\r
- fdt_setprop_cell(fdt, node, "cpu_suspend", ARM_SMC_ARM_CPU_SUSPEND);\r
- fdt_setprop_cell(fdt, node, "cpu_off", ARM_SMC_ARM_CPU_OFF);\r
- fdt_setprop_cell(fdt, node, "cpu_on", ARM_SMC_ARM_CPU_ON);\r
- fdt_setprop_cell(fdt, node, "cpu_migrate", ARM_SMC_ARM_MIGRATE);\r
+ fdt_setprop_string (fdt, node, "compatible", "arm,psci");\r
+ fdt_setprop_string (fdt, node, "method", "smc");\r
+\r
+ Smc = cpu_to_fdtn (ARM_SMC_ARM_CPU_SUSPEND);\r
+ fdt_setprop (fdt, node, "cpu_suspend", &Smc, sizeof (Smc));\r
+\r
+ Smc = cpu_to_fdtn (ARM_SMC_ARM_CPU_OFF);\r
+ fdt_setprop (fdt, node, "cpu_off", &Smc, sizeof (Smc));\r
+\r
+ Smc = cpu_to_fdtn (ARM_SMC_ARM_CPU_ON);\r
+ fdt_setprop (fdt, node, "cpu_on", &Smc, sizeof (Smc));\r
+\r
+ Smc = cpu_to_fdtn (ARM_SMC_ARM_MIGRATE);\r
+ fdt_setprop (fdt, node, "migrate", &Smc, sizeof (Smc));\r
}\r
}\r
}\r
*FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));\r
return EFI_SUCCESS;\r
\r
-FAIL_NEW_FDT:\r
- gBS->FreePages (NewFdtBlobBase, EFI_SIZE_TO_PAGES (NewFdtBlobSize));\r
+FAIL_COMPLETE_FDT:\r
+ gBS->FreePages (NewFdtBlobAllocation, EFI_SIZE_TO_PAGES (NewFdtBlobSize));\r
\r
-FAIL_ALLOCATE_NEW_FDT:\r
+FAIL_RELOCATE_FDT:\r
*FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));\r
- // Return success even if we failed to update the FDT blob. The original one is still valid.\r
+ // Return success even if we failed to update the FDT blob.\r
+ // The original one is still valid.\r
return EFI_SUCCESS;\r
}\r
-\r
-\r