EmbeddedPkg: import Lan91x Ethernet controller driver
[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 173\r
b0866ad3 174 if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
3c1e53ce
RC
175 //\r
176 // Register the strings for the user interface in the HII Database.\r
177 // This shows the way to the multi-language support, even if\r
178 // only the English language is actually supported. The strings to register\r
3d7f1060 179 // are stored in the "ShellSetFdtStrings[]" array. This array is\r
3c1e53ce
RC
180 // built by the building process from the "*.uni" file associated to\r
181 // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build\r
182 // folder under your package's DEBUG folder and you will find the array\r
183 // defined in a xxxStrDefs.h file.\r
184 //\r
185 mFdtPlatformDxeHiiHandle = HiiAddPackages (\r
186 &mFdtPlatformDxeHiiGuid,\r
187 ImageHandle,\r
188 FdtPlatformDxeStrings,\r
189 NULL\r
190 );\r
b0866ad3
OM
191 }\r
192\r
193 //\r
194 // If the development features are enabled, install the dynamic shell\r
195 // command "setfdt" to be able to define a device path for the FDT\r
196 // that has precedence over the device paths defined by\r
197 // "PcdFdtDevicePaths".\r
198 //\r
3c1e53ce 199\r
b0866ad3 200 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
3c1e53ce 201 if (mFdtPlatformDxeHiiHandle != NULL) {\r
b0866ad3
OM
202 // We install dynamic EFI command on separate handles as we cannot register\r
203 // more than one protocol of the same protocol interface on the same handle.\r
204 Handle = NULL;\r
3c1e53ce 205 Status = gBS->InstallMultipleProtocolInterfaces (\r
b0866ad3 206 &Handle,\r
3c1e53ce
RC
207 &gEfiShellDynamicCommandProtocolGuid,\r
208 &mShellDynCmdProtocolSetFdt,\r
209 NULL\r
210 );\r
211 if (EFI_ERROR (Status)) {\r
212 HiiRemovePackages (mFdtPlatformDxeHiiHandle);\r
213 }\r
214 } else {\r
215 Status = EFI_LOAD_ERROR;\r
216 }\r
217 if (EFI_ERROR (Status)) {\r
218 DEBUG ((\r
219 EFI_D_WARN,\r
220 "Unable to install \"setfdt\" EFI Shell command - %r \n",\r
221 Status\r
222 ));\r
223 }\r
224 }\r
225\r
b0866ad3
OM
226 if (FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
227 if (mFdtPlatformDxeHiiHandle != NULL) {\r
228 // We install dynamic EFI command on separate handles as we cannot register\r
229 // more than one protocol of the same protocol interface on the same handle.\r
230 Handle = NULL;\r
231 Status = gBS->InstallMultipleProtocolInterfaces (\r
232 &Handle,\r
233 &gEfiShellDynamicCommandProtocolGuid,\r
234 &mShellDynCmdProtocolDumpFdt,\r
235 NULL\r
236 );\r
237 if (EFI_ERROR (Status)) {\r
238 HiiRemovePackages (mFdtPlatformDxeHiiHandle);\r
239 }\r
240 } else {\r
241 Status = EFI_LOAD_ERROR;\r
242 }\r
243 if (EFI_ERROR (Status)) {\r
244 DEBUG ((\r
245 EFI_D_WARN,\r
246 "Unable to install \"dumpfdt\" EFI Shell command - %r \n",\r
247 Status\r
248 ));\r
249 }\r
250 }\r
251\r
158497a0
RC
252 return Status;\r
253}\r
254\r
158497a0
RC
255/**\r
256 Run the FDT installation process.\r
257\r
258 Loop in priority order over the device paths from which the FDT has\r
259 been asked to be retrieved for. For each device path, try to install\r
260 the FDT. Stop as soon as an installation succeeds.\r
261\r
01674025
RC
262 @param[in] SuccessfullDevicePath If not NULL, address where to store the\r
263 pointer to the text device path from\r
264 which the FDT was successfully retrieved.\r
265 Not used if the FDT installation failed.\r
266 The returned address is the address of\r
267 an allocated buffer that has to be\r
268 freed by the caller.\r
269\r
158497a0
RC
270 @retval EFI_SUCCESS The FDT was installed.\r
271 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.\r
272 @retval EFI_INVALID_PARAMETER Invalid device path.\r
273 @retval EFI_UNSUPPORTED Device path not supported.\r
274 @retval EFI_OUT_OF_RESOURCES An allocation failed.\r
275\r
276**/\r
158497a0
RC
277EFI_STATUS\r
278RunFdtInstallation (\r
01674025 279 OUT CHAR16 **SuccessfullDevicePath\r
158497a0
RC
280 )\r
281{\r
282 EFI_STATUS Status;\r
283 UINTN DataSize;\r
01674025 284 CHAR16 *TextDevicePath;\r
158497a0
RC
285 CHAR16 *TextDevicePathStart;\r
286 CHAR16 *TextDevicePathSeparator;\r
287 UINTN TextDevicePathLen;\r
158497a0 288\r
01674025 289 TextDevicePath = NULL;\r
158497a0
RC
290 //\r
291 // For development purpose, if enabled through the "PcdOverridePlatformFdt"\r
292 // feature PCD, try first to install the FDT specified by the device path in\r
293 // text form stored in the "Fdt" UEFI variable.\r
294 //\r
295 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
158497a0
RC
296 DataSize = 0;\r
297 Status = gRT->GetVariable (\r
298 L"Fdt",\r
299 &gFdtVariableGuid,\r
300 NULL,\r
301 &DataSize,\r
01674025 302 NULL\r
158497a0
RC
303 );\r
304\r
305 //\r
306 // Keep going only if the "Fdt" variable is defined.\r
307 //\r
308\r
309 if (Status == EFI_BUFFER_TOO_SMALL) {\r
01674025
RC
310 TextDevicePath = AllocatePool (DataSize);\r
311 if (TextDevicePath == NULL) {\r
158497a0 312 Status = EFI_OUT_OF_RESOURCES;\r
01674025 313 goto Error;\r
158497a0
RC
314 }\r
315\r
01674025
RC
316 Status = gRT->GetVariable (\r
317 L"Fdt",\r
318 &gFdtVariableGuid,\r
319 NULL,\r
320 &DataSize,\r
321 TextDevicePath\r
322 );\r
158497a0 323 if (EFI_ERROR (Status)) {\r
01674025
RC
324 FreePool (TextDevicePath);\r
325 goto Error;\r
326 }\r
327\r
328 Status = InstallFdt (TextDevicePath);\r
329 if (!EFI_ERROR (Status)) {\r
158497a0 330 DEBUG ((\r
01674025
RC
331 EFI_D_WARN,\r
332 "Installation of the FDT using the device path <%s> completed.\n",\r
333 TextDevicePath\r
158497a0 334 ));\r
01674025 335 goto Done;\r
158497a0 336 }\r
01674025
RC
337 DEBUG ((\r
338 EFI_D_ERROR,\r
339 "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",\r
340 Status\r
341 ));\r
342 FreePool (TextDevicePath);\r
158497a0
RC
343 }\r
344 }\r
345\r
346 //\r
347 // Loop over the device path list provided by "PcdFdtDevicePaths". The device\r
348 // paths are in text form and separated by a semi-colon.\r
349 //\r
350\r
01674025 351 Status = EFI_NOT_FOUND;\r
158497a0
RC
352 for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);\r
353 *TextDevicePathStart != L'\0' ; ) {\r
354 TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");\r
355\r
356 //\r
357 // Last device path of the list\r
358 //\r
359 if (TextDevicePathSeparator == NULL) {\r
01674025 360 TextDevicePathLen = StrLen (TextDevicePathStart);\r
158497a0
RC
361 } else {\r
362 TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);\r
158497a0
RC
363 }\r
364\r
01674025
RC
365 TextDevicePath = AllocateCopyPool (\r
366 (TextDevicePathLen + 1) * sizeof (CHAR16),\r
367 TextDevicePathStart\r
368 );\r
369 if (TextDevicePath == NULL) {\r
370 Status = EFI_OUT_OF_RESOURCES;\r
371 goto Error;\r
372 }\r
373 TextDevicePath[TextDevicePathLen] = L'\0';\r
374\r
158497a0 375 Status = InstallFdt (TextDevicePath);\r
01674025 376 if (!EFI_ERROR (Status)) {\r
158497a0
RC
377 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",\r
378 TextDevicePath\r
379 ));\r
01674025 380 goto Done;\r
158497a0
RC
381 }\r
382\r
01674025
RC
383 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",\r
384 TextDevicePath, Status\r
385 ));\r
386 FreePool (TextDevicePath);\r
387\r
158497a0 388 if (TextDevicePathSeparator == NULL) {\r
01674025 389 goto Error;\r
158497a0 390 }\r
01674025 391 TextDevicePathStart = TextDevicePathSeparator + 1;\r
158497a0
RC
392 }\r
393\r
01674025
RC
394Error:\r
395Done:\r
396\r
158497a0
RC
397 if (EFI_ERROR (Status)) {\r
398 DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));\r
01674025 399 return Status;\r
158497a0
RC
400 }\r
401\r
01674025
RC
402 if (SuccessfullDevicePath != NULL) {\r
403 *SuccessfullDevicePath = TextDevicePath;\r
404 } else {\r
405 FreePool (TextDevicePath);\r
406 }\r
407\r
408 return EFI_SUCCESS;\r
158497a0
RC
409}\r
410\r
158497a0
RC
411/**\r
412 Transcode one of the EFI return code used by the model into an EFI Shell return code.\r
413\r
414 @param[in] Status EFI return code.\r
415\r
416 @return Transcoded EFI Shell return code.\r
417\r
418**/\r
158497a0
RC
419SHELL_STATUS\r
420EfiCodeToShellCode (\r
421 IN EFI_STATUS Status\r
422 )\r
423{\r
424 SHELL_STATUS ShellStatus;\r
425\r
426 switch (Status) {\r
427 case EFI_SUCCESS :\r
428 ShellStatus = SHELL_SUCCESS;\r
429 break;\r
430\r
431 case EFI_INVALID_PARAMETER :\r
432 ShellStatus = SHELL_INVALID_PARAMETER;\r
433 break;\r
434\r
435 case EFI_UNSUPPORTED :\r
436 ShellStatus = SHELL_UNSUPPORTED;\r
437 break;\r
438\r
439 case EFI_DEVICE_ERROR :\r
440 ShellStatus = SHELL_DEVICE_ERROR;\r
441 break;\r
442\r
443 case EFI_WRITE_PROTECTED :\r
444 case EFI_SECURITY_VIOLATION :\r
445 ShellStatus = SHELL_ACCESS_DENIED;\r
446 break;\r
447\r
448 case EFI_OUT_OF_RESOURCES :\r
449 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
450 break;\r
451\r
452 case EFI_NOT_FOUND :\r
453 ShellStatus = SHELL_NOT_FOUND;\r
454 break;\r
455\r
456 default :\r
457 ShellStatus = SHELL_ABORTED;\r
458 }\r
459\r
460 return ShellStatus;\r
461}\r