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