]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/BdsLib/BdsLinuxFdt.c
ArmPkg/BdsLib: Added support for FDT alignment through PcdArmLinuxFdtAlignment
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsLinuxFdt.c
CommitLineData
0a6653bc 1/** @file\r
2*\r
7e91decd 3* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
0a6653bc 4*\r
7e91decd 5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
0a6653bc 12*\r
13**/\r
14\r
bc87b507 15#include <Library/ArmSmcLib.h>\r
0a6653bc 16#include <Library/PcdLib.h>\r
17#include <libfdt.h>\r
18\r
bc87b507 19#include <IndustryStandard/ArmSmc.h>\r
20\r
0a6653bc 21#include "BdsInternal.h"\r
22#include "BdsLinuxLoader.h"\r
23\r
24#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))\r
25#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))\r
26#define GET_CELL(p) (p += 4, *((const UINT32 *)(p-4)))\r
27\r
28STATIC\r
29UINTN\r
30IsPrintableString (\r
31 IN CONST VOID* data,\r
32 IN UINTN len\r
33 )\r
34{\r
35 CONST CHAR8 *s = data;\r
36 CONST CHAR8 *ss;\r
37\r
38 // Zero length is not\r
39 if (len == 0) {\r
40 return 0;\r
41 }\r
42\r
43 // Must terminate with zero\r
44 if (s[len - 1] != '\0') {\r
45 return 0;\r
46 }\r
47\r
48 ss = s;\r
49 while (*s/* && isprint(*s)*/) {\r
50 s++;\r
51 }\r
52\r
53 // Not zero, or not done yet\r
54 if (*s != '\0' || (s + 1 - ss) < len) {\r
55 return 0;\r
56 }\r
57\r
58 return 1;\r
59}\r
60\r
61STATIC\r
62VOID\r
63PrintData (\r
64 IN CONST CHAR8* data,\r
65 IN UINTN len\r
66 )\r
67{\r
68 UINTN i;\r
69 CONST CHAR8 *p = data;\r
70\r
71 // No data, don't print\r
72 if (len == 0)\r
73 return;\r
74\r
75 if (IsPrintableString (data, len)) {\r
76 Print(L" = \"%a\"", (const char *)data);\r
77 } else if ((len % 4) == 0) {\r
78 Print(L" = <");\r
79 for (i = 0; i < len; i += 4) {\r
80 Print(L"0x%08x%a", fdt32_to_cpu(GET_CELL(p)),i < (len - 4) ? " " : "");\r
81 }\r
82 Print(L">");\r
83 } else {\r
84 Print(L" = [");\r
85 for (i = 0; i < len; i++)\r
86 Print(L"%02x%a", *p++, i < len - 1 ? " " : "");\r
87 Print(L"]");\r
88 }\r
89}\r
90\r
91VOID\r
92DebugDumpFdt (\r
93 IN VOID* FdtBlob\r
94 )\r
95{\r
96 struct fdt_header *bph;\r
97 UINT32 off_dt;\r
98 UINT32 off_str;\r
99 CONST CHAR8* p_struct;\r
100 CONST CHAR8* p_strings;\r
101 CONST CHAR8* p;\r
102 CONST CHAR8* s;\r
103 CONST CHAR8* t;\r
104 UINT32 tag;\r
105 UINTN sz;\r
106 UINTN depth;\r
107 UINTN shift;\r
108 UINT32 version;\r
109\r
a01e042d 110 {\r
111 // Can 'memreserve' be printed by below code?\r
112 INTN num = fdt_num_mem_rsv(FdtBlob);\r
113 INTN i, err;\r
114 UINT64 addr = 0,size = 0;\r
115\r
116 for (i = 0; i < num; i++) {\r
117 err = fdt_get_mem_rsv(FdtBlob, i, &addr, &size);\r
118 if (err) {\r
119 DEBUG((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));\r
120 }\r
121 else {\r
122 Print(L"/memreserve/ \t0x%lx \t0x%lx;\n",addr,size);\r
123 }\r
124 }\r
125 }\r
126\r
0a6653bc 127 depth = 0;\r
128 shift = 4;\r
129\r
130 bph = FdtBlob;\r
131 off_dt = fdt32_to_cpu(bph->off_dt_struct);\r
132 off_str = fdt32_to_cpu(bph->off_dt_strings);\r
133 p_struct = (CONST CHAR8*)FdtBlob + off_dt;\r
134 p_strings = (CONST CHAR8*)FdtBlob + off_str;\r
135 version = fdt32_to_cpu(bph->version);\r
136\r
137 p = p_struct;\r
138 while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {\r
139 if (tag == FDT_BEGIN_NODE) {\r
140 s = p;\r
141 p = PALIGN(p + AsciiStrLen (s) + 1, 4);\r
142\r
143 if (*s == '\0')\r
144 s = "/";\r
145\r
146 Print(L"%*s%a {\n", depth * shift, L" ", s);\r
147\r
148 depth++;\r
149 continue;\r
150 }\r
151\r
152 if (tag == FDT_END_NODE) {\r
153 depth--;\r
154\r
155 Print(L"%*s};\n", depth * shift, L" ");\r
156 continue;\r
157 }\r
158\r
159 if (tag == FDT_NOP) {\r
160 Print(L"%*s// [NOP]\n", depth * shift, L" ");\r
161 continue;\r
162 }\r
163\r
164 if (tag != FDT_PROP) {\r
165 Print(L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);\r
166 break;\r
167 }\r
168 sz = fdt32_to_cpu(GET_CELL(p));\r
169 s = p_strings + fdt32_to_cpu(GET_CELL(p));\r
170 if (version < 16 && sz >= 8)\r
171 p = PALIGN(p, 8);\r
172 t = p;\r
173\r
174 p = PALIGN(p + sz, 4);\r
175\r
176 Print(L"%*s%a", depth * shift, L" ", s);\r
177 PrintData(t, sz);\r
178 Print(L";\n");\r
179 }\r
180}\r
181\r
a01e042d 182STATIC\r
183BOOLEAN\r
184IsLinuxReservedRegion (\r
185 IN EFI_MEMORY_TYPE MemoryType\r
186 )\r
187{\r
188 switch(MemoryType) {\r
189 case EfiRuntimeServicesCode:\r
190 case EfiRuntimeServicesData:\r
191 case EfiUnusableMemory:\r
192 case EfiACPIReclaimMemory:\r
193 case EfiACPIMemoryNVS:\r
194 return TRUE;\r
195 default:\r
196 return FALSE;\r
197 }\r
198}\r
199\r
200\r
0a6653bc 201typedef struct {\r
202 UINTN Base;\r
203 UINTN Size;\r
204} FdtRegion;\r
205\r
206EFI_STATUS\r
207PrepareFdt (\r
208 IN CONST CHAR8* CommandLineArguments,\r
209 IN EFI_PHYSICAL_ADDRESS InitrdImage,\r
210 IN UINTN InitrdImageSize,\r
211 IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,\r
c63626b7 212 IN OUT UINTN *FdtBlobSize\r
0a6653bc 213 )\r
214{\r
215 EFI_STATUS Status;\r
216 EFI_PHYSICAL_ADDRESS NewFdtBlobBase;\r
387653a4 217 EFI_PHYSICAL_ADDRESS NewFdtBlobAllocation;\r
0a6653bc 218 UINTN NewFdtBlobSize;\r
387653a4 219 UINT32 FdtAlignment;\r
0a6653bc 220 VOID* fdt;\r
221 INTN err;\r
222 INTN node;\r
223 INTN cpu_node;\r
224 INTN lenp;\r
225 CONST VOID* BootArg;\r
bc87b507 226 CONST VOID* Method;\r
0a6653bc 227 EFI_PHYSICAL_ADDRESS InitrdImageStart;\r
228 EFI_PHYSICAL_ADDRESS InitrdImageEnd;\r
229 FdtRegion Region;\r
230 UINTN Index;\r
231 CHAR8 Name[10];\r
232 LIST_ENTRY ResourceList;\r
233 BDS_SYSTEM_MEMORY_RESOURCE *Resource;\r
234 ARM_PROCESSOR_TABLE *ArmProcessorTable;\r
235 ARM_CORE_INFO *ArmCoreInfoTable;\r
236 UINT32 MpId;\r
237 UINT32 ClusterId;\r
238 UINT32 CoreId;\r
239 UINT64 CpuReleaseAddr;\r
a01e042d 240 UINTN MemoryMapSize;\r
241 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
242 UINTN MapKey;\r
243 UINTN DescriptorSize;\r
244 UINT32 DescriptorVersion;\r
245 UINTN Pages;\r
bc87b507 246 BOOLEAN PsciSmcSupported;\r
247 UINTN Rx;\r
7e91decd 248 UINTN OriginalFdtSize;\r
3809e6e0 249 BOOLEAN CpusNodeExist;\r
bc87b507 250\r
251 //\r
252 // Ensure the Power State Coordination Interface (PSCI) SMCs are there if supported\r
253 //\r
254 PsciSmcSupported = FALSE;\r
255 if (FeaturePcdGet (PcdArmPsciSupport) == TRUE) {\r
256 // Check the SMC response to the Presence SMC\r
257 Rx = ARM_SMC_ID_PRESENCE;\r
258 ArmCallSmc (&Rx);\r
259 if (Rx == 1) {\r
260 // Check the SMC UID\r
261 Rx = ARM_SMC_ID_UID;\r
262 ArmCallSmc (&Rx);\r
263 if (Rx == ARM_TRUSTZONE_UID_4LETTERID) {\r
264 Rx = ARM_SMC_ID_UID + 1;\r
265 ArmCallSmc (&Rx);\r
1a7b6d9e 266 if (Rx == ARM_TRUSTZONE_ARM_UID) {\r
bc87b507 267 PsciSmcSupported = TRUE;\r
268 }\r
269 }\r
270 if (PsciSmcSupported == FALSE) {\r
271 DEBUG((EFI_D_ERROR,"Warning: The Power State Coordination Interface (PSCI) is not supported"\r
272 "by your platform Trusted Firmware.\n"));\r
273 }\r
274 }\r
275 }\r
0a6653bc 276\r
7e91decd 277 //\r
278 // Sanity checks on the original FDT blob.\r
279 //\r
0a6653bc 280 err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase));\r
281 if (err != 0) {\r
282 Print (L"ERROR: Device Tree header not valid (err:%d)\n", err);\r
283 return EFI_INVALID_PARAMETER;\r
284 }\r
285\r
7e91decd 286 // The original FDT blob might have been loaded partially.\r
287 // Check that it is not the case.\r
288 OriginalFdtSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));\r
289 if (OriginalFdtSize > *FdtBlobSize) {\r
290 Print (L"ERROR: Incomplete FDT. Only %d/%d bytes have been loaded.\n",\r
291 *FdtBlobSize, OriginalFdtSize);\r
292 return EFI_INVALID_PARAMETER;\r
293 }\r
294\r
0a6653bc 295 //\r
296 // Allocate memory for the new FDT\r
297 //\r
7e91decd 298 NewFdtBlobSize = OriginalFdtSize + FDT_ADDITIONAL_ENTRIES_SIZE;\r
0a6653bc 299\r
387653a4 300 // If FDT load address needs to be aligned, allocate more space.\r
301 FdtAlignment = PcdGet32 (PcdArmLinuxFdtAlignment);\r
302 if (FdtAlignment != 0) {\r
303 NewFdtBlobSize += FdtAlignment;\r
304 }\r
305\r
0a6653bc 306 // Try below a watermark address\r
307 Status = EFI_NOT_FOUND;\r
387653a4 308 if (PcdGet32 (PcdArmLinuxFdtMaxOffset) != 0) {\r
0a6653bc 309 NewFdtBlobBase = LINUX_FDT_MAX_OFFSET;\r
310 Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);\r
311 if (EFI_ERROR(Status)) {\r
312 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
313 }\r
314 }\r
315\r
316 // Try anywhere there is available space\r
317 if (EFI_ERROR(Status)) {\r
318 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);\r
319 if (EFI_ERROR(Status)) {\r
320 ASSERT_EFI_ERROR(Status);\r
a90e3279 321 goto FAIL_ALLOCATE_NEW_FDT;\r
0a6653bc 322 } else {\r
323 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
324 }\r
325 }\r
326\r
387653a4 327 NewFdtBlobAllocation = NewFdtBlobBase;\r
328 if (FdtAlignment != 0) {\r
329 NewFdtBlobBase = ALIGN (NewFdtBlobBase, FdtAlignment);\r
330 }\r
331\r
0a6653bc 332 // Load the Original FDT tree into the new region\r
333 fdt = (VOID*)(UINTN)NewFdtBlobBase;\r
334 err = fdt_open_into((VOID*)(UINTN)(*FdtBlobBase), fdt, NewFdtBlobSize);\r
335 if (err) {\r
336 DEBUG((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror(err)));\r
337 Status = EFI_INVALID_PARAMETER;\r
338 goto FAIL_NEW_FDT;\r
339 }\r
340\r
341 DEBUG_CODE_BEGIN();\r
342 //DebugDumpFdt (fdt);\r
343 DEBUG_CODE_END();\r
344\r
345 node = fdt_subnode_offset(fdt, 0, "chosen");\r
346 if (node < 0) {\r
347 // The 'chosen' node does not exist, create it\r
348 node = fdt_add_subnode(fdt, 0, "chosen");\r
349 if (node < 0) {\r
350 DEBUG((EFI_D_ERROR,"Error on finding 'chosen' node\n"));\r
351 Status = EFI_INVALID_PARAMETER;\r
352 goto FAIL_NEW_FDT;\r
353 }\r
354 }\r
355\r
356 DEBUG_CODE_BEGIN();\r
357 BootArg = fdt_getprop(fdt, node, "bootargs", &lenp);\r
358 if (BootArg != NULL) {\r
359 DEBUG((EFI_D_ERROR,"BootArg: %a\n",BootArg));\r
360 }\r
361 DEBUG_CODE_END();\r
362\r
a01e042d 363 //\r
0a6653bc 364 // Set Linux CmdLine\r
a01e042d 365 //\r
0a6653bc 366 if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) {\r
367 err = fdt_setprop(fdt, node, "bootargs", CommandLineArguments, AsciiStrSize(CommandLineArguments));\r
368 if (err) {\r
369 DEBUG((EFI_D_ERROR,"Fail to set new 'bootarg' (err:%d)\n",err));\r
370 }\r
371 }\r
372\r
a01e042d 373 //\r
0a6653bc 374 // Set Linux Initrd\r
a01e042d 375 //\r
0a6653bc 376 if (InitrdImageSize != 0) {\r
377 InitrdImageStart = cpu_to_fdt64 (InitrdImage);\r
378 err = fdt_setprop(fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof(EFI_PHYSICAL_ADDRESS));\r
379 if (err) {\r
380 DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err));\r
381 }\r
382 InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize);\r
383 err = fdt_setprop(fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof(EFI_PHYSICAL_ADDRESS));\r
384 if (err) {\r
385 DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err));\r
386 }\r
387 }\r
388\r
a01e042d 389 //\r
0a6653bc 390 // Set Physical memory setup if does not exist\r
a01e042d 391 //\r
0a6653bc 392 node = fdt_subnode_offset(fdt, 0, "memory");\r
393 if (node < 0) {\r
394 // The 'memory' node does not exist, create it\r
395 node = fdt_add_subnode(fdt, 0, "memory");\r
396 if (node >= 0) {\r
397 fdt_setprop_string(fdt, node, "name", "memory");\r
398 fdt_setprop_string(fdt, node, "device_type", "memory");\r
7e91decd 399\r
0a6653bc 400 GetSystemMemoryResources (&ResourceList);\r
401 Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink;\r
7e91decd 402\r
0a6653bc 403 if (sizeof(UINTN) == sizeof(UINT32)) {\r
404 Region.Base = cpu_to_fdt32((UINTN)Resource->PhysicalStart);\r
405 Region.Size = cpu_to_fdt32((UINTN)Resource->ResourceLength);\r
406 } else {\r
407 Region.Base = cpu_to_fdt64((UINTN)Resource->PhysicalStart);\r
408 Region.Size = cpu_to_fdt64((UINTN)Resource->ResourceLength);\r
409 }\r
410\r
411 err = fdt_setprop(fdt, node, "reg", &Region, sizeof(Region));\r
412 if (err) {\r
413 DEBUG((EFI_D_ERROR,"Fail to set new 'memory region' (err:%d)\n",err));\r
414 }\r
415 }\r
416 }\r
417\r
a01e042d 418 //\r
419 // Add the memory regions reserved by the UEFI Firmware\r
420 //\r
421\r
422 // Retrieve the UEFI Memory Map\r
423 MemoryMap = NULL;\r
424 MemoryMapSize = 0;\r
425 Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
426 if (Status == EFI_BUFFER_TOO_SMALL) {\r
427 Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;\r
428 MemoryMap = AllocatePages (Pages);\r
429 Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);\r
430 }\r
431\r
432 // Go through the list and add the reserved region to the Device Tree\r
433 if (!EFI_ERROR(Status)) {\r
434 for (Index = 0; Index < (MemoryMapSize / sizeof(EFI_MEMORY_DESCRIPTOR)); Index++) {\r
435 if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMap[Index].Type)) {\r
436 DEBUG((DEBUG_VERBOSE, "Reserved region of type %d [0x%X, 0x%X]\n",\r
437 MemoryMap[Index].Type,\r
438 (UINTN)MemoryMap[Index].PhysicalStart,\r
439 (UINTN)(MemoryMap[Index].PhysicalStart + MemoryMap[Index].NumberOfPages * EFI_PAGE_SIZE)));\r
440 err = fdt_add_mem_rsv(fdt, MemoryMap[Index].PhysicalStart, MemoryMap[Index].NumberOfPages * EFI_PAGE_SIZE);\r
441 if (err != 0) {\r
442 Print(L"Warning: Fail to add 'memreserve' (err:%d)\n", err);\r
443 }\r
444 }\r
445 }\r
446 }\r
447\r
448 //\r
0a6653bc 449 // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms\r
a01e042d 450 //\r
0a6653bc 451 for (Index=0; Index < gST->NumberOfTableEntries; Index++) {\r
452 // Check for correct GUID type\r
453 if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
454 MpId = ArmReadMpidr ();\r
455 ClusterId = GET_CLUSTER_ID(MpId);\r
456 CoreId = GET_CORE_ID(MpId);\r
457\r
458 node = fdt_subnode_offset(fdt, 0, "cpus");\r
459 if (node < 0) {\r
460 // Create the /cpus node\r
461 node = fdt_add_subnode(fdt, 0, "cpus");\r
462 fdt_setprop_string(fdt, node, "name", "cpus");\r
463 fdt_setprop_cell(fdt, node, "#address-cells", 1);\r
464 fdt_setprop_cell(fdt, node, "#size-cells", 0);\r
3809e6e0 465 CpusNodeExist = FALSE;\r
466 } else {\r
467 CpusNodeExist = TRUE;\r
0a6653bc 468 }\r
469\r
470 // Get pointer to ARM processor table\r
471 ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable;\r
472 ArmCoreInfoTable = ArmProcessorTable->ArmCpus;\r
473\r
474 for (Index = 0; Index < ArmProcessorTable->NumberOfEntries; Index++) {\r
475 AsciiSPrint (Name, 10, "cpu@%d", Index);\r
3809e6e0 476\r
477 // If the 'cpus' node did not exist then creates the 'cpu' nodes. In case 'cpus' node\r
478 // is provided in the original FDT then we do not add any 'cpu' node.\r
479 if (!CpusNodeExist) {\r
0a6653bc 480 cpu_node = fdt_add_subnode(fdt, node, Name);\r
481 fdt_setprop_string(fdt, cpu_node, "device-type", "cpu");\r
482 fdt_setprop(fdt, cpu_node, "reg", &Index, sizeof(Index));\r
3809e6e0 483 } else {\r
484 cpu_node = fdt_subnode_offset(fdt, node, Name);\r
0a6653bc 485 }\r
486\r
bc87b507 487 // If Power State Coordination Interface (PSCI) is not supported then it is expected the secondary\r
39f58c9b 488 // cores are spinning waiting for the Operating System to release them\r
3809e6e0 489 if ((PsciSmcSupported == FALSE) && (cpu_node >= 0)) {\r
39f58c9b 490 // We as the bootloader are responsible for either creating or updating\r
491 // these entries. Do not trust the entries in the DT. We only know about\r
492 // 'spin-table' type. Do not try to update other types if defined.\r
bc87b507 493 Method = fdt_getprop(fdt, cpu_node, "enable-method", &lenp);\r
39f58c9b 494 if ( (Method == NULL) || (!AsciiStrCmp((CHAR8 *)Method, "spin-table")) ) {\r
bc87b507 495 fdt_setprop_string(fdt, cpu_node, "enable-method", "spin-table");\r
496 CpuReleaseAddr = cpu_to_fdt64(ArmCoreInfoTable[Index].MailboxSetAddress);\r
497 fdt_setprop(fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof(CpuReleaseAddr));\r
498\r
499 // If it is not the primary core than the cpu should be disabled\r
500 if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) {\r
501 fdt_setprop_string(fdt, cpu_node, "status", "disabled");\r
502 }\r
39f58c9b 503 } else {\r
504 Print(L"Warning: Unsupported enable-method type for CPU[%d] : %a\n", Index, (CHAR8 *)Method);\r
bc87b507 505 }\r
0a6653bc 506 }\r
507 }\r
508 break;\r
509 }\r
510 }\r
511\r
bc87b507 512 // If the Power State Coordination Interface is supported then we signal it in the Device Tree\r
513 if (PsciSmcSupported == TRUE) {\r
514 // Before to create it we check if the node is not already defined in the Device Tree\r
515 node = fdt_subnode_offset(fdt, 0, "psci");\r
516 if (node < 0) {\r
517 // The 'psci' node does not exist, create it\r
518 node = fdt_add_subnode(fdt, 0, "psci");\r
519 if (node < 0) {\r
520 DEBUG((EFI_D_ERROR,"Error on creating 'psci' node\n"));\r
521 Status = EFI_INVALID_PARAMETER;\r
522 goto FAIL_NEW_FDT;\r
523 } else {\r
524 fdt_setprop_string(fdt, node, "compatible", "arm,psci");\r
525 fdt_setprop_string(fdt, node, "method", "smc");\r
526 fdt_setprop_cell(fdt, node, "cpu_suspend", ARM_SMC_ARM_CPU_SUSPEND);\r
527 fdt_setprop_cell(fdt, node, "cpu_off", ARM_SMC_ARM_CPU_OFF);\r
528 fdt_setprop_cell(fdt, node, "cpu_on", ARM_SMC_ARM_CPU_ON);\r
529 fdt_setprop_cell(fdt, node, "cpu_migrate", ARM_SMC_ARM_MIGRATE);\r
530 }\r
531 }\r
532 }\r
533\r
0a6653bc 534 DEBUG_CODE_BEGIN();\r
535 //DebugDumpFdt (fdt);\r
536 DEBUG_CODE_END();\r
537\r
a90e3279 538 // If we succeeded to generate the new Device Tree then free the old Device Tree\r
539 gBS->FreePages (*FdtBlobBase, EFI_SIZE_TO_PAGES (*FdtBlobSize));\r
540\r
0a6653bc 541 *FdtBlobBase = NewFdtBlobBase;\r
542 *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));\r
543 return EFI_SUCCESS;\r
544\r
545FAIL_NEW_FDT:\r
387653a4 546 gBS->FreePages (NewFdtBlobAllocation, EFI_SIZE_TO_PAGES (NewFdtBlobSize));\r
a90e3279 547\r
548FAIL_ALLOCATE_NEW_FDT:\r
549 *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));\r
0a6653bc 550 // Return success even if we failed to update the FDT blob. The original one is still valid.\r
551 return EFI_SUCCESS;\r
552}\r
553\r
554\r