*\r
**/\r
\r
+#include <Library/ArmSmcLib.h>\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
UINTN shift;\r
UINT32 version;\r
\r
+ {\r
+ // Can 'memreserve' be printed by below code?\r
+ INTN num = fdt_num_mem_rsv(FdtBlob);\r
+ INTN i, err;\r
+ UINT64 addr = 0,size = 0;\r
+\r
+ for (i = 0; i < num; i++) {\r
+ err = fdt_get_mem_rsv(FdtBlob, i, &addr, &size);\r
+ if (err) {\r
+ DEBUG((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));\r
+ }\r
+ else {\r
+ Print(L"/memreserve/ \t0x%lx \t0x%lx;\n",addr,size);\r
+ }\r
+ }\r
+ }\r
+\r
depth = 0;\r
shift = 4;\r
\r
}\r
}\r
\r
+STATIC\r
+BOOLEAN\r
+IsLinuxReservedRegion (\r
+ IN EFI_MEMORY_TYPE MemoryType\r
+ )\r
+{\r
+ switch(MemoryType) {\r
+ case EfiRuntimeServicesCode:\r
+ case EfiRuntimeServicesData:\r
+ case EfiUnusableMemory:\r
+ case EfiACPIReclaimMemory:\r
+ case EfiACPIMemoryNVS:\r
+ return TRUE;\r
+ default:\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+\r
typedef struct {\r
UINTN Base;\r
UINTN Size;\r
INTN cpu_node;\r
INTN lenp;\r
CONST VOID* BootArg;\r
+ CONST VOID* Method;\r
EFI_PHYSICAL_ADDRESS InitrdImageStart;\r
EFI_PHYSICAL_ADDRESS InitrdImageEnd;\r
FdtRegion Region;\r
UINT32 ClusterId;\r
UINT32 CoreId;\r
UINT64 CpuReleaseAddr;\r
+ UINTN MemoryMapSize;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+ UINTN MapKey;\r
+ UINTN DescriptorSize;\r
+ UINT32 DescriptorVersion;\r
+ UINTN Pages;\r
+ BOOLEAN PsciSmcSupported;\r
+ UINTN Rx;\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
+ //TODO: Replace ARM magic number\r
+ if (Rx == 0x40524d48) {\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
\r
err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase));\r
if (err != 0) {\r
}\r
DEBUG_CODE_END();\r
\r
+ //\r
// Set Linux CmdLine\r
+ //\r
if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) {\r
err = fdt_setprop(fdt, node, "bootargs", CommandLineArguments, AsciiStrSize(CommandLineArguments));\r
if (err) {\r
}\r
}\r
\r
+ //\r
// Set Linux Initrd\r
+ //\r
if (InitrdImageSize != 0) {\r
InitrdImageStart = cpu_to_fdt64 (InitrdImage);\r
err = fdt_setprop(fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof(EFI_PHYSICAL_ADDRESS));\r
}\r
}\r
\r
+ //\r
// Set Physical memory setup if does not exist\r
+ //\r
node = fdt_subnode_offset(fdt, 0, "memory");\r
if (node < 0) {\r
// The 'memory' node does not exist, create it\r
}\r
}\r
\r
+ //\r
+ // Add the memory regions reserved by the UEFI Firmware\r
+ //\r
+\r
+ // Retrieve the UEFI Memory Map\r
+ MemoryMap = NULL;\r
+ MemoryMapSize = 0;\r
+ Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;\r
+ MemoryMap = AllocatePages (Pages);\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
+ if (err != 0) {\r
+ Print(L"Warning: Fail to add 'memreserve' (err:%d)\n", err);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
// Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms\r
+ //\r
for (Index=0; Index < gST->NumberOfTableEntries; Index++) {\r
// Check for correct GUID type\r
if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
fdt_setprop(fdt, cpu_node, "reg", &Index, sizeof(Index));\r
}\r
\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 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
+ // 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
+ }\r
+ } else {\r
+ Print(L"Warning: Unsupported enable-method type for CPU[%d] : %a\n", Index, (CHAR8 *)Method);\r
+ }\r
}\r
}\r
break;\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_NEW_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
+ }\r
+ }\r
+ }\r
+\r
DEBUG_CODE_BEGIN();\r
//DebugDumpFdt (fdt);\r
DEBUG_CODE_END();\r