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