/** @file\r
*\r
-* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+* Copyright (c) 2011-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
#include <Library/PcdLib.h>\r
#include <libfdt.h>\r
\r
-#include <IndustryStandard/ArmSmc.h>\r
-\r
#include "BdsInternal.h"\r
#include "BdsLinuxLoader.h"\r
\r
#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
+STATIC\r
UINTN\r
cpu_to_fdtn (UINTN x) {\r
if (sizeof (UINTN) == sizeof (UINT32)) {\r
case EfiUnusableMemory:\r
case EfiACPIReclaimMemory:\r
case EfiACPIMemoryNVS:\r
+ case EfiReservedMemoryType:\r
return TRUE;\r
default:\r
return FALSE;\r
}\r
}\r
\r
-\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
EFI_STATUS Status;\r
INTN Error;\r
- UINT32 FdtAlignment;\r
+ UINT64 FdtAlignment;\r
\r
*RelocatedFdtSize = OriginalFdtSize + FDT_ADDITIONAL_ENTRIES_SIZE;\r
\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 OriginalFdtSize;\r
BOOLEAN CpusNodeExist;\r
UINTN CoreMpId;\r
- UINTN Smc;\r
\r
NewFdtBlobAllocation = 0;\r
\r
goto FAIL_RELOCATE_FDT;\r
}\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
- 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
fdt = (VOID*)(UINTN)NewFdtBlobBase;\r
\r
node = fdt_subnode_offset (fdt, 0, "chosen");\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
- 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 = 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%lX, 0x%lX]\n",\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
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) && (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
- Method = fdt_getprop(fdt, cpu_node, "enable-method", &lenp);\r
- if ( (Method == NULL) || (!AsciiStrCmp((CHAR8 *)Method, "spin-table")) ) {\r
- fdt_setprop_string(fdt, cpu_node, "enable-method", "spin-table");\r
- CpuReleaseAddr = cpu_to_fdt64(ArmCoreInfoTable[Index].MailboxSetAddress);\r
- fdt_setprop(fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof(CpuReleaseAddr));\r
-\r
- // If it is not the primary core than the cpu should be disabled\r
- if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) {\r
- fdt_setprop_string(fdt, cpu_node, "status", "disabled");\r
+ if (cpu_node >= 0) {\r
+ Method = fdt_getprop (fdt, cpu_node, "enable-method", &lenp);\r
+ // We only care when 'enable-method' == 'spin-table'. If the enable-method is not defined\r
+ // or defined as 'psci' then we ignore its properties.\r
+ if ((Method != NULL) && (AsciiStrCmp ((CHAR8 *)Method, "spin-table") == 0)) {\r
+ // There are two cases;\r
+ // - UEFI firmware parked the secondary cores and/or UEFI firmware is aware of the CPU\r
+ // release addresses (PcdArmLinuxSpinTable == TRUE)\r
+ // - the parking of the secondary cores has been managed before starting UEFI and/or UEFI\r
+ // does not anything about the CPU release addresses - in this case we do nothing\r
+ if (FeaturePcdGet (PcdArmLinuxSpinTable)) {\r
+ CpuReleaseAddr = cpu_to_fdt64 (ArmCoreInfoTable[Index].MailboxSetAddress);\r
+ fdt_setprop (fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof(CpuReleaseAddr));\r
+\r
+ // If it is not the primary core than the cpu should be disabled\r
+ if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) {\r
+ fdt_setprop_string(fdt, cpu_node, "status", "disabled");\r
+ }\r
}\r
- } else {\r
- Print(L"Warning: Unsupported enable-method type for CPU[%d] : %a\n", Index, (CHAR8 *)Method);\r
}\r
}\r
}\r
}\r
}\r
\r
- // If the Power State Coordination Interface is supported then we signal it in the Device Tree\r
- if (PsciSmcSupported == TRUE) {\r
- // Before to create it we check if the node is not already defined in the Device Tree\r
- node = fdt_subnode_offset(fdt, 0, "psci");\r
- if (node < 0) {\r
- // The 'psci' node does not exist, create it\r
- node = fdt_add_subnode(fdt, 0, "psci");\r
- if (node < 0) {\r
- DEBUG((EFI_D_ERROR,"Error on creating 'psci' node\n"));\r
- Status = EFI_INVALID_PARAMETER;\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
-\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
-\r
DEBUG_CODE_BEGIN();\r
//DebugDumpFdt (fdt);\r
DEBUG_CODE_END();\r
// If we succeeded to generate the new Device Tree then free the old Device Tree\r
gBS->FreePages (*FdtBlobBase, EFI_SIZE_TO_PAGES (*FdtBlobSize));\r
\r
+ // Update the real size of the Device Tree\r
+ fdt_pack ((VOID*)(UINTN)(NewFdtBlobBase));\r
+\r
*FdtBlobBase = NewFdtBlobBase;\r
*FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));\r
return EFI_SUCCESS;\r