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