]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c
EmbeddedPkg: do not ASSERT() on valid external input
[mirror_edk2.git] / EmbeddedPkg / Drivers / FdtPlatformDxe / FdtPlatform.c
... / ...
CommitLineData
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
14\r
15#include "FdtPlatform.h"\r
16\r
17#include <Library/PcdLib.h>\r
18#include <Library/DevicePathLib.h>\r
19#include <Library/BdsLib.h>\r
20\r
21#include <Protocol/DevicePath.h>\r
22\r
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
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
39STATIC CONST EFI_GUID mFdtPlatformDxeHiiGuid = {\r
40 0x8afa7610, 0x62b1, 0x46aa,\r
41 {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}\r
42 };\r
43\r
44EFI_HANDLE mFdtPlatformDxeHiiHandle;\r
45\r
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 //\r
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
100 //\r
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
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
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
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
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
167 EFI_HANDLE Handle;\r
168\r
169 //\r
170 // Install the Device Tree from its expected location\r
171 //\r
172 Status = RunFdtInstallation (NULL);\r
173 if (EFI_ERROR (Status)) {\r
174 return Status;\r
175 }\r
176\r
177 if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
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
182 // are stored in the "ShellSetFdtStrings[]" array. This array is\r
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
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
202\r
203 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
204 if (mFdtPlatformDxeHiiHandle != NULL) {\r
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
208 Status = gBS->InstallMultipleProtocolInterfaces (\r
209 &Handle,\r
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
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
255 return Status;\r
256}\r
257\r
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
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
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
280EFI_STATUS\r
281RunFdtInstallation (\r
282 OUT CHAR16 **SuccessfullDevicePath\r
283 )\r
284{\r
285 EFI_STATUS Status;\r
286 UINTN DataSize;\r
287 CHAR16 *TextDevicePath;\r
288 CHAR16 *TextDevicePathStart;\r
289 CHAR16 *TextDevicePathSeparator;\r
290 UINTN TextDevicePathLen;\r
291\r
292 TextDevicePath = NULL;\r
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
299 DataSize = 0;\r
300 Status = gRT->GetVariable (\r
301 L"Fdt",\r
302 &gFdtVariableGuid,\r
303 NULL,\r
304 &DataSize,\r
305 NULL\r
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
313 TextDevicePath = AllocatePool (DataSize);\r
314 if (TextDevicePath == NULL) {\r
315 Status = EFI_OUT_OF_RESOURCES;\r
316 goto Error;\r
317 }\r
318\r
319 Status = gRT->GetVariable (\r
320 L"Fdt",\r
321 &gFdtVariableGuid,\r
322 NULL,\r
323 &DataSize,\r
324 TextDevicePath\r
325 );\r
326 if (EFI_ERROR (Status)) {\r
327 FreePool (TextDevicePath);\r
328 goto Error;\r
329 }\r
330\r
331 Status = InstallFdt (TextDevicePath);\r
332 if (!EFI_ERROR (Status)) {\r
333 DEBUG ((\r
334 EFI_D_WARN,\r
335 "Installation of the FDT using the device path <%s> completed.\n",\r
336 TextDevicePath\r
337 ));\r
338 goto Done;\r
339 }\r
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
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
354 Status = EFI_NOT_FOUND;\r
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
363 TextDevicePathLen = StrLen (TextDevicePathStart);\r
364 } else {\r
365 TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);\r
366 }\r
367\r
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
378 Status = InstallFdt (TextDevicePath);\r
379 if (!EFI_ERROR (Status)) {\r
380 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",\r
381 TextDevicePath\r
382 ));\r
383 goto Done;\r
384 }\r
385\r
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
391 if (TextDevicePathSeparator == NULL) {\r
392 goto Error;\r
393 }\r
394 TextDevicePathStart = TextDevicePathSeparator + 1;\r
395 }\r
396\r
397Error:\r
398Done:\r
399\r
400 if (EFI_ERROR (Status)) {\r
401 DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));\r
402 return Status;\r
403 }\r
404\r
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
412}\r
413\r
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
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