]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c
EmbeddedPkg/FdtPlatformDxe: Introduce EFI Shell command 'dumfdt'
[mirror_edk2.git] / EmbeddedPkg / Drivers / FdtPlatformDxe / FdtPlatform.c
CommitLineData
158497a0
RC
1/** @file\r
2\r
3 Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>\r
4\r
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
12\r
13**/\r
158497a0 14\r
3d7f1060
OM
15#include "FdtPlatform.h"\r
16\r
158497a0
RC
17#include <Library/PcdLib.h>\r
18#include <Library/DevicePathLib.h>\r
158497a0
RC
19#include <Library/BdsLib.h>\r
20\r
158497a0 21#include <Protocol/DevicePath.h>\r
158497a0 22\r
3c1e53ce
RC
23//\r
24// Internal variables\r
25//\r
26\r
27STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = {\r
28 L"setfdt", // Name of the command\r
29 ShellDynCmdSetFdtHandler, // Handler\r
30 ShellDynCmdSetFdtGetHelp // GetHelp\r
31};\r
32\r
b0866ad3
OM
33STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolDumpFdt = {\r
34 L"dumpfdt", // Name of the command\r
35 ShellDynCmdDumpFdtHandler, // Handler\r
36 ShellDynCmdDumpFdtGetHelp // GetHelp\r
37};\r
38\r
3c1e53ce
RC
39STATIC CONST EFI_GUID mFdtPlatformDxeHiiGuid = {\r
40 0x8afa7610, 0x62b1, 0x46aa,\r
41 {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}\r
42 };\r
3c1e53ce 43\r
3d7f1060 44EFI_HANDLE mFdtPlatformDxeHiiHandle;\r
3c1e53ce 45\r
cd66c5a2
OM
46/**\r
47 Install the FDT specified by its device path in text form.\r
48\r
49 @param[in] TextDevicePath Device path of the FDT to install in text form\r
50\r
51 @retval EFI_SUCCESS The FDT was installed.\r
52 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.\r
53 @retval EFI_INVALID_PARAMETER Invalid device path.\r
54 @retval EFI_UNSUPPORTED Device path not supported.\r
55 @retval EFI_OUT_OF_RESOURCES An allocation failed.\r
56**/\r
57STATIC\r
58EFI_STATUS\r
59InstallFdt (\r
60 IN CONST CHAR16* TextDevicePath\r
61 )\r
62{\r
63 EFI_STATUS Status;\r
64 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
65 EFI_DEVICE_PATH *DevicePath;\r
66 EFI_PHYSICAL_ADDRESS FdtBlobBase;\r
67 UINTN FdtBlobSize;\r
68 UINTN NumPages;\r
69 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;\r
70\r
71 Status = gBS->LocateProtocol (\r
72 &gEfiDevicePathFromTextProtocolGuid,\r
73 NULL,\r
74 (VOID **)&EfiDevicePathFromTextProtocol\r
75 );\r
76 if (EFI_ERROR (Status)) {\r
77 DEBUG ((EFI_D_ERROR, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n"));\r
78 return Status;\r
79 }\r
80\r
81 DevicePath = (EFI_DEVICE_PATH*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (TextDevicePath);\r
82 if (DevicePath == NULL) {\r
83 return EFI_INVALID_PARAMETER;\r
84 }\r
85\r
86 //\r
87 // Load the FDT given its device path.\r
88 // This operation may fail if the device path is not supported.\r
89 //\r
90 FdtBlobBase = 0;\r
91 NumPages = 0;\r
92 Status = BdsLoadImage (DevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
93 if (EFI_ERROR (Status)) {\r
94 goto Error;\r
95 }\r
96\r
97 // Check the FDT header is valid. We only make this check in DEBUG mode in\r
98 // case the FDT header change on production device and this ASSERT() becomes\r
99 // not valid.\r
100 ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
101\r
102 //\r
103 // Ensure the Size of the Device Tree is smaller than the size of the read file\r
104 //\r
105 ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
106\r
107 //\r
108 // Store the FDT as Runtime Service Data to prevent the Kernel from\r
109 // overwritting its data.\r
110 //\r
111 NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
112 Status = gBS->AllocatePages (\r
113 AllocateAnyPages, EfiRuntimeServicesData,\r
114 NumPages, &FdtConfigurationTableBase\r
115 );\r
116 if (EFI_ERROR (Status)) {\r
117 goto Error;\r
118 }\r
119 CopyMem (\r
120 (VOID*)(UINTN)FdtConfigurationTableBase,\r
121 (VOID*)(UINTN)FdtBlobBase,\r
122 FdtBlobSize\r
123 );\r
124\r
125 //\r
126 // Install the FDT into the Configuration Table\r
127 //\r
128 Status = gBS->InstallConfigurationTable (\r
129 &gFdtTableGuid,\r
130 (VOID*)(UINTN)FdtConfigurationTableBase\r
131 );\r
132 if (EFI_ERROR (Status)) {\r
133 gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
134 }\r
135\r
136Error:\r
137 if (FdtBlobBase != 0) {\r
138 gBS->FreePages (FdtBlobBase, NumPages);\r
139 }\r
140 FreePool (DevicePath);\r
141\r
142 return Status;\r
143}\r
144\r
158497a0
RC
145/**\r
146 Main entry point of the FDT platform driver.\r
147\r
148 @param[in] ImageHandle The firmware allocated handle for the present driver\r
149 UEFI image.\r
150 @param[in] *SystemTable A pointer to the EFI System table.\r
151\r
152 @retval EFI_SUCCESS The driver was initialized.\r
3c1e53ce
RC
153 @retval EFI_OUT_OF_RESOURCES The "End of DXE" event could not be allocated or\r
154 there was not enough memory in pool to install\r
155 the Shell Dynamic Command protocol.\r
156 @retval EFI_LOAD_ERROR Unable to add the HII package.\r
158497a0
RC
157\r
158**/\r
159EFI_STATUS\r
160FdtPlatformEntryPoint (\r
161 IN EFI_HANDLE ImageHandle,\r
162 IN EFI_SYSTEM_TABLE *SystemTable\r
163 )\r
164{\r
165 EFI_STATUS Status;\r
b0866ad3 166 EFI_HANDLE Handle;\r
158497a0
RC
167\r
168 //\r
cd66c5a2 169 // Install the Device Tree from its expected location\r
158497a0 170 //\r
cd66c5a2 171 Status = RunFdtInstallation (NULL);\r
3c1e53ce
RC
172 if (EFI_ERROR (Status)) {\r
173 return Status;\r
174 }\r
175\r
b0866ad3 176 if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
3c1e53ce
RC
177 //\r
178 // Register the strings for the user interface in the HII Database.\r
179 // This shows the way to the multi-language support, even if\r
180 // only the English language is actually supported. The strings to register\r
3d7f1060 181 // are stored in the "ShellSetFdtStrings[]" array. This array is\r
3c1e53ce
RC
182 // built by the building process from the "*.uni" file associated to\r
183 // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build\r
184 // folder under your package's DEBUG folder and you will find the array\r
185 // defined in a xxxStrDefs.h file.\r
186 //\r
187 mFdtPlatformDxeHiiHandle = HiiAddPackages (\r
188 &mFdtPlatformDxeHiiGuid,\r
189 ImageHandle,\r
190 FdtPlatformDxeStrings,\r
191 NULL\r
192 );\r
b0866ad3
OM
193 }\r
194\r
195 //\r
196 // If the development features are enabled, install the dynamic shell\r
197 // command "setfdt" to be able to define a device path for the FDT\r
198 // that has precedence over the device paths defined by\r
199 // "PcdFdtDevicePaths".\r
200 //\r
3c1e53ce 201\r
b0866ad3 202 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
3c1e53ce 203 if (mFdtPlatformDxeHiiHandle != NULL) {\r
b0866ad3
OM
204 // We install dynamic EFI command on separate handles as we cannot register\r
205 // more than one protocol of the same protocol interface on the same handle.\r
206 Handle = NULL;\r
3c1e53ce 207 Status = gBS->InstallMultipleProtocolInterfaces (\r
b0866ad3 208 &Handle,\r
3c1e53ce
RC
209 &gEfiShellDynamicCommandProtocolGuid,\r
210 &mShellDynCmdProtocolSetFdt,\r
211 NULL\r
212 );\r
213 if (EFI_ERROR (Status)) {\r
214 HiiRemovePackages (mFdtPlatformDxeHiiHandle);\r
215 }\r
216 } else {\r
217 Status = EFI_LOAD_ERROR;\r
218 }\r
219 if (EFI_ERROR (Status)) {\r
220 DEBUG ((\r
221 EFI_D_WARN,\r
222 "Unable to install \"setfdt\" EFI Shell command - %r \n",\r
223 Status\r
224 ));\r
225 }\r
226 }\r
227\r
b0866ad3
OM
228 if (FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
229 if (mFdtPlatformDxeHiiHandle != NULL) {\r
230 // We install dynamic EFI command on separate handles as we cannot register\r
231 // more than one protocol of the same protocol interface on the same handle.\r
232 Handle = NULL;\r
233 Status = gBS->InstallMultipleProtocolInterfaces (\r
234 &Handle,\r
235 &gEfiShellDynamicCommandProtocolGuid,\r
236 &mShellDynCmdProtocolDumpFdt,\r
237 NULL\r
238 );\r
239 if (EFI_ERROR (Status)) {\r
240 HiiRemovePackages (mFdtPlatformDxeHiiHandle);\r
241 }\r
242 } else {\r
243 Status = EFI_LOAD_ERROR;\r
244 }\r
245 if (EFI_ERROR (Status)) {\r
246 DEBUG ((\r
247 EFI_D_WARN,\r
248 "Unable to install \"dumpfdt\" EFI Shell command - %r \n",\r
249 Status\r
250 ));\r
251 }\r
252 }\r
253\r
158497a0
RC
254 return Status;\r
255}\r
256\r
158497a0
RC
257/**\r
258 Run the FDT installation process.\r
259\r
260 Loop in priority order over the device paths from which the FDT has\r
261 been asked to be retrieved for. For each device path, try to install\r
262 the FDT. Stop as soon as an installation succeeds.\r
263\r
01674025
RC
264 @param[in] SuccessfullDevicePath If not NULL, address where to store the\r
265 pointer to the text device path from\r
266 which the FDT was successfully retrieved.\r
267 Not used if the FDT installation failed.\r
268 The returned address is the address of\r
269 an allocated buffer that has to be\r
270 freed by the caller.\r
271\r
158497a0
RC
272 @retval EFI_SUCCESS The FDT was installed.\r
273 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.\r
274 @retval EFI_INVALID_PARAMETER Invalid device path.\r
275 @retval EFI_UNSUPPORTED Device path not supported.\r
276 @retval EFI_OUT_OF_RESOURCES An allocation failed.\r
277\r
278**/\r
158497a0
RC
279EFI_STATUS\r
280RunFdtInstallation (\r
01674025 281 OUT CHAR16 **SuccessfullDevicePath\r
158497a0
RC
282 )\r
283{\r
284 EFI_STATUS Status;\r
285 UINTN DataSize;\r
01674025 286 CHAR16 *TextDevicePath;\r
158497a0
RC
287 CHAR16 *TextDevicePathStart;\r
288 CHAR16 *TextDevicePathSeparator;\r
289 UINTN TextDevicePathLen;\r
158497a0 290\r
01674025 291 TextDevicePath = NULL;\r
158497a0
RC
292 //\r
293 // For development purpose, if enabled through the "PcdOverridePlatformFdt"\r
294 // feature PCD, try first to install the FDT specified by the device path in\r
295 // text form stored in the "Fdt" UEFI variable.\r
296 //\r
297 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
158497a0
RC
298 DataSize = 0;\r
299 Status = gRT->GetVariable (\r
300 L"Fdt",\r
301 &gFdtVariableGuid,\r
302 NULL,\r
303 &DataSize,\r
01674025 304 NULL\r
158497a0
RC
305 );\r
306\r
307 //\r
308 // Keep going only if the "Fdt" variable is defined.\r
309 //\r
310\r
311 if (Status == EFI_BUFFER_TOO_SMALL) {\r
01674025
RC
312 TextDevicePath = AllocatePool (DataSize);\r
313 if (TextDevicePath == NULL) {\r
158497a0 314 Status = EFI_OUT_OF_RESOURCES;\r
01674025 315 goto Error;\r
158497a0
RC
316 }\r
317\r
01674025
RC
318 Status = gRT->GetVariable (\r
319 L"Fdt",\r
320 &gFdtVariableGuid,\r
321 NULL,\r
322 &DataSize,\r
323 TextDevicePath\r
324 );\r
158497a0 325 if (EFI_ERROR (Status)) {\r
01674025
RC
326 FreePool (TextDevicePath);\r
327 goto Error;\r
328 }\r
329\r
330 Status = InstallFdt (TextDevicePath);\r
331 if (!EFI_ERROR (Status)) {\r
158497a0 332 DEBUG ((\r
01674025
RC
333 EFI_D_WARN,\r
334 "Installation of the FDT using the device path <%s> completed.\n",\r
335 TextDevicePath\r
158497a0 336 ));\r
01674025 337 goto Done;\r
158497a0 338 }\r
01674025
RC
339 DEBUG ((\r
340 EFI_D_ERROR,\r
341 "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",\r
342 Status\r
343 ));\r
344 FreePool (TextDevicePath);\r
158497a0
RC
345 }\r
346 }\r
347\r
348 //\r
349 // Loop over the device path list provided by "PcdFdtDevicePaths". The device\r
350 // paths are in text form and separated by a semi-colon.\r
351 //\r
352\r
01674025 353 Status = EFI_NOT_FOUND;\r
158497a0
RC
354 for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);\r
355 *TextDevicePathStart != L'\0' ; ) {\r
356 TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");\r
357\r
358 //\r
359 // Last device path of the list\r
360 //\r
361 if (TextDevicePathSeparator == NULL) {\r
01674025 362 TextDevicePathLen = StrLen (TextDevicePathStart);\r
158497a0
RC
363 } else {\r
364 TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);\r
158497a0
RC
365 }\r
366\r
01674025
RC
367 TextDevicePath = AllocateCopyPool (\r
368 (TextDevicePathLen + 1) * sizeof (CHAR16),\r
369 TextDevicePathStart\r
370 );\r
371 if (TextDevicePath == NULL) {\r
372 Status = EFI_OUT_OF_RESOURCES;\r
373 goto Error;\r
374 }\r
375 TextDevicePath[TextDevicePathLen] = L'\0';\r
376\r
158497a0 377 Status = InstallFdt (TextDevicePath);\r
01674025 378 if (!EFI_ERROR (Status)) {\r
158497a0
RC
379 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",\r
380 TextDevicePath\r
381 ));\r
01674025 382 goto Done;\r
158497a0
RC
383 }\r
384\r
01674025
RC
385 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",\r
386 TextDevicePath, Status\r
387 ));\r
388 FreePool (TextDevicePath);\r
389\r
158497a0 390 if (TextDevicePathSeparator == NULL) {\r
01674025 391 goto Error;\r
158497a0 392 }\r
01674025 393 TextDevicePathStart = TextDevicePathSeparator + 1;\r
158497a0
RC
394 }\r
395\r
01674025
RC
396Error:\r
397Done:\r
398\r
158497a0
RC
399 if (EFI_ERROR (Status)) {\r
400 DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));\r
01674025 401 return Status;\r
158497a0
RC
402 }\r
403\r
01674025
RC
404 if (SuccessfullDevicePath != NULL) {\r
405 *SuccessfullDevicePath = TextDevicePath;\r
406 } else {\r
407 FreePool (TextDevicePath);\r
408 }\r
409\r
410 return EFI_SUCCESS;\r
158497a0
RC
411}\r
412\r
158497a0
RC
413/**\r
414 Transcode one of the EFI return code used by the model into an EFI Shell return code.\r
415\r
416 @param[in] Status EFI return code.\r
417\r
418 @return Transcoded EFI Shell return code.\r
419\r
420**/\r
158497a0
RC
421SHELL_STATUS\r
422EfiCodeToShellCode (\r
423 IN EFI_STATUS Status\r
424 )\r
425{\r
426 SHELL_STATUS ShellStatus;\r
427\r
428 switch (Status) {\r
429 case EFI_SUCCESS :\r
430 ShellStatus = SHELL_SUCCESS;\r
431 break;\r
432\r
433 case EFI_INVALID_PARAMETER :\r
434 ShellStatus = SHELL_INVALID_PARAMETER;\r
435 break;\r
436\r
437 case EFI_UNSUPPORTED :\r
438 ShellStatus = SHELL_UNSUPPORTED;\r
439 break;\r
440\r
441 case EFI_DEVICE_ERROR :\r
442 ShellStatus = SHELL_DEVICE_ERROR;\r
443 break;\r
444\r
445 case EFI_WRITE_PROTECTED :\r
446 case EFI_SECURITY_VIOLATION :\r
447 ShellStatus = SHELL_ACCESS_DENIED;\r
448 break;\r
449\r
450 case EFI_OUT_OF_RESOURCES :\r
451 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
452 break;\r
453\r
454 case EFI_NOT_FOUND :\r
455 ShellStatus = SHELL_NOT_FOUND;\r
456 break;\r
457\r
458 default :\r
459 ShellStatus = SHELL_ABORTED;\r
460 }\r
461\r
462 return ShellStatus;\r
463}\r