]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c
EmbeddedPkg/FdtPlatformDxe: 'setfdt' command, display the successful device path
[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
14#include <Uefi.h>\r
15\r
16#include <Library/UefiLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/UefiRuntimeServicesTableLib.h>\r
20#include <Library/PcdLib.h>\r
21#include <Library/DevicePathLib.h>\r
22#include <Library/MemoryAllocationLib.h>\r
3c1e53ce 23#include <Library/HiiLib.h>\r
158497a0 24#include <Library/BdsLib.h>\r
3c1e53ce 25#include <Library/ShellLib.h>\r
158497a0 26\r
3c1e53ce 27#include <Protocol/DevicePathToText.h>\r
158497a0
RC
28#include <Protocol/DevicePathFromText.h>\r
29#include <Protocol/DevicePath.h>\r
3c1e53ce
RC
30#include <Protocol/EfiShell.h>\r
31#include <Protocol/EfiShellDynamicCommand.h>\r
158497a0 32\r
158497a0
RC
33#include <Guid/Fdt.h>\r
34\r
35#include <libfdt.h>\r
36\r
37//\r
38// Internal types\r
39//\r
3c1e53ce 40\r
3c1e53ce
RC
41STATIC SHELL_STATUS EFIAPI ShellDynCmdSetFdtHandler (\r
42 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,\r
43 IN EFI_SYSTEM_TABLE *SystemTable,\r
44 IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,\r
45 IN EFI_SHELL_PROTOCOL *Shell\r
46 );\r
47\r
48STATIC CHAR16* EFIAPI ShellDynCmdSetFdtGetHelp (\r
49 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,\r
50 IN CONST CHAR8 *Language\r
51 );\r
52\r
4589ffaa
RC
53STATIC VOID DisplayFdtDevicePaths (\r
54 VOID\r
55 );\r
56\r
3c1e53ce
RC
57STATIC SHELL_STATUS UpdateFdtTextDevicePath (\r
58 IN EFI_SHELL_PROTOCOL *Shell,\r
59 IN CONST CHAR16 *FilePath\r
60 );\r
61\r
62STATIC SHELL_STATUS EfiCodeToShellCode (\r
63 IN EFI_STATUS Status\r
64 );\r
65\r
66//\r
67// Internal variables\r
68//\r
69\r
70STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = {\r
71 L"setfdt", // Name of the command\r
72 ShellDynCmdSetFdtHandler, // Handler\r
73 ShellDynCmdSetFdtGetHelp // GetHelp\r
74};\r
75\r
76STATIC CONST EFI_GUID mFdtPlatformDxeHiiGuid = {\r
77 0x8afa7610, 0x62b1, 0x46aa,\r
78 {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}\r
79 };\r
80STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
81 {L"-i", TypeFlag },\r
82 {NULL , TypeMax }\r
83};\r
84\r
85STATIC EFI_HANDLE mFdtPlatformDxeHiiHandle;\r
86\r
cd66c5a2
OM
87/**\r
88 Install the FDT specified by its device path in text form.\r
89\r
90 @param[in] TextDevicePath Device path of the FDT to install in text form\r
91\r
92 @retval EFI_SUCCESS The FDT was installed.\r
93 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.\r
94 @retval EFI_INVALID_PARAMETER Invalid device path.\r
95 @retval EFI_UNSUPPORTED Device path not supported.\r
96 @retval EFI_OUT_OF_RESOURCES An allocation failed.\r
97**/\r
98STATIC\r
99EFI_STATUS\r
100InstallFdt (\r
101 IN CONST CHAR16* TextDevicePath\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
106 EFI_DEVICE_PATH *DevicePath;\r
107 EFI_PHYSICAL_ADDRESS FdtBlobBase;\r
108 UINTN FdtBlobSize;\r
109 UINTN NumPages;\r
110 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;\r
111\r
112 Status = gBS->LocateProtocol (\r
113 &gEfiDevicePathFromTextProtocolGuid,\r
114 NULL,\r
115 (VOID **)&EfiDevicePathFromTextProtocol\r
116 );\r
117 if (EFI_ERROR (Status)) {\r
118 DEBUG ((EFI_D_ERROR, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n"));\r
119 return Status;\r
120 }\r
121\r
122 DevicePath = (EFI_DEVICE_PATH*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (TextDevicePath);\r
123 if (DevicePath == NULL) {\r
124 return EFI_INVALID_PARAMETER;\r
125 }\r
126\r
127 //\r
128 // Load the FDT given its device path.\r
129 // This operation may fail if the device path is not supported.\r
130 //\r
131 FdtBlobBase = 0;\r
132 NumPages = 0;\r
133 Status = BdsLoadImage (DevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
134 if (EFI_ERROR (Status)) {\r
135 goto Error;\r
136 }\r
137\r
138 // Check the FDT header is valid. We only make this check in DEBUG mode in\r
139 // case the FDT header change on production device and this ASSERT() becomes\r
140 // not valid.\r
141 ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
142\r
143 //\r
144 // Ensure the Size of the Device Tree is smaller than the size of the read file\r
145 //\r
146 ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
147\r
148 //\r
149 // Store the FDT as Runtime Service Data to prevent the Kernel from\r
150 // overwritting its data.\r
151 //\r
152 NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
153 Status = gBS->AllocatePages (\r
154 AllocateAnyPages, EfiRuntimeServicesData,\r
155 NumPages, &FdtConfigurationTableBase\r
156 );\r
157 if (EFI_ERROR (Status)) {\r
158 goto Error;\r
159 }\r
160 CopyMem (\r
161 (VOID*)(UINTN)FdtConfigurationTableBase,\r
162 (VOID*)(UINTN)FdtBlobBase,\r
163 FdtBlobSize\r
164 );\r
165\r
166 //\r
167 // Install the FDT into the Configuration Table\r
168 //\r
169 Status = gBS->InstallConfigurationTable (\r
170 &gFdtTableGuid,\r
171 (VOID*)(UINTN)FdtConfigurationTableBase\r
172 );\r
173 if (EFI_ERROR (Status)) {\r
174 gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
175 }\r
176\r
177Error:\r
178 if (FdtBlobBase != 0) {\r
179 gBS->FreePages (FdtBlobBase, NumPages);\r
180 }\r
181 FreePool (DevicePath);\r
182\r
183 return Status;\r
184}\r
185\r
158497a0
RC
186/**\r
187 Main entry point of the FDT platform driver.\r
188\r
189 @param[in] ImageHandle The firmware allocated handle for the present driver\r
190 UEFI image.\r
191 @param[in] *SystemTable A pointer to the EFI System table.\r
192\r
193 @retval EFI_SUCCESS The driver was initialized.\r
3c1e53ce
RC
194 @retval EFI_OUT_OF_RESOURCES The "End of DXE" event could not be allocated or\r
195 there was not enough memory in pool to install\r
196 the Shell Dynamic Command protocol.\r
197 @retval EFI_LOAD_ERROR Unable to add the HII package.\r
158497a0
RC
198\r
199**/\r
200EFI_STATUS\r
201FdtPlatformEntryPoint (\r
202 IN EFI_HANDLE ImageHandle,\r
203 IN EFI_SYSTEM_TABLE *SystemTable\r
204 )\r
205{\r
206 EFI_STATUS Status;\r
158497a0
RC
207\r
208 //\r
cd66c5a2 209 // Install the Device Tree from its expected location\r
158497a0 210 //\r
cd66c5a2 211 Status = RunFdtInstallation (NULL);\r
3c1e53ce
RC
212 if (EFI_ERROR (Status)) {\r
213 return Status;\r
214 }\r
215\r
216 //\r
217 // If the development features are enabled, install the dynamic shell\r
218 // command "setfdt" to be able to define a device path for the FDT\r
219 // that has precedence over the device paths defined by\r
220 // "PcdFdtDevicePaths".\r
221 //\r
222\r
223 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
224 //\r
225 // Register the strings for the user interface in the HII Database.\r
226 // This shows the way to the multi-language support, even if\r
227 // only the English language is actually supported. The strings to register\r
228 // are stored in the "FdtPlatformDxeStrings[]" array. This array is\r
229 // built by the building process from the "*.uni" file associated to\r
230 // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build\r
231 // folder under your package's DEBUG folder and you will find the array\r
232 // defined in a xxxStrDefs.h file.\r
233 //\r
234 mFdtPlatformDxeHiiHandle = HiiAddPackages (\r
235 &mFdtPlatformDxeHiiGuid,\r
236 ImageHandle,\r
237 FdtPlatformDxeStrings,\r
238 NULL\r
239 );\r
240\r
241 if (mFdtPlatformDxeHiiHandle != NULL) {\r
242 Status = gBS->InstallMultipleProtocolInterfaces (\r
243 &ImageHandle,\r
244 &gEfiShellDynamicCommandProtocolGuid,\r
245 &mShellDynCmdProtocolSetFdt,\r
246 NULL\r
247 );\r
248 if (EFI_ERROR (Status)) {\r
249 HiiRemovePackages (mFdtPlatformDxeHiiHandle);\r
250 }\r
251 } else {\r
252 Status = EFI_LOAD_ERROR;\r
253 }\r
254 if (EFI_ERROR (Status)) {\r
255 DEBUG ((\r
256 EFI_D_WARN,\r
257 "Unable to install \"setfdt\" EFI Shell command - %r \n",\r
258 Status\r
259 ));\r
260 }\r
261 }\r
262\r
158497a0
RC
263 return Status;\r
264}\r
265\r
158497a0
RC
266/**\r
267 Run the FDT installation process.\r
268\r
269 Loop in priority order over the device paths from which the FDT has\r
270 been asked to be retrieved for. For each device path, try to install\r
271 the FDT. Stop as soon as an installation succeeds.\r
272\r
01674025
RC
273 @param[in] SuccessfullDevicePath If not NULL, address where to store the\r
274 pointer to the text device path from\r
275 which the FDT was successfully retrieved.\r
276 Not used if the FDT installation failed.\r
277 The returned address is the address of\r
278 an allocated buffer that has to be\r
279 freed by the caller.\r
280\r
158497a0
RC
281 @retval EFI_SUCCESS The FDT was installed.\r
282 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.\r
283 @retval EFI_INVALID_PARAMETER Invalid device path.\r
284 @retval EFI_UNSUPPORTED Device path not supported.\r
285 @retval EFI_OUT_OF_RESOURCES An allocation failed.\r
286\r
287**/\r
288STATIC\r
289EFI_STATUS\r
290RunFdtInstallation (\r
01674025 291 OUT CHAR16 **SuccessfullDevicePath\r
158497a0
RC
292 )\r
293{\r
294 EFI_STATUS Status;\r
295 UINTN DataSize;\r
01674025 296 CHAR16 *TextDevicePath;\r
158497a0
RC
297 CHAR16 *TextDevicePathStart;\r
298 CHAR16 *TextDevicePathSeparator;\r
299 UINTN TextDevicePathLen;\r
158497a0 300\r
01674025 301 TextDevicePath = NULL;\r
158497a0
RC
302 //\r
303 // For development purpose, if enabled through the "PcdOverridePlatformFdt"\r
304 // feature PCD, try first to install the FDT specified by the device path in\r
305 // text form stored in the "Fdt" UEFI variable.\r
306 //\r
307 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
158497a0
RC
308 DataSize = 0;\r
309 Status = gRT->GetVariable (\r
310 L"Fdt",\r
311 &gFdtVariableGuid,\r
312 NULL,\r
313 &DataSize,\r
01674025 314 NULL\r
158497a0
RC
315 );\r
316\r
317 //\r
318 // Keep going only if the "Fdt" variable is defined.\r
319 //\r
320\r
321 if (Status == EFI_BUFFER_TOO_SMALL) {\r
01674025
RC
322 TextDevicePath = AllocatePool (DataSize);\r
323 if (TextDevicePath == NULL) {\r
158497a0 324 Status = EFI_OUT_OF_RESOURCES;\r
01674025 325 goto Error;\r
158497a0
RC
326 }\r
327\r
01674025
RC
328 Status = gRT->GetVariable (\r
329 L"Fdt",\r
330 &gFdtVariableGuid,\r
331 NULL,\r
332 &DataSize,\r
333 TextDevicePath\r
334 );\r
158497a0 335 if (EFI_ERROR (Status)) {\r
01674025
RC
336 FreePool (TextDevicePath);\r
337 goto Error;\r
338 }\r
339\r
340 Status = InstallFdt (TextDevicePath);\r
341 if (!EFI_ERROR (Status)) {\r
158497a0 342 DEBUG ((\r
01674025
RC
343 EFI_D_WARN,\r
344 "Installation of the FDT using the device path <%s> completed.\n",\r
345 TextDevicePath\r
158497a0 346 ));\r
01674025 347 goto Done;\r
158497a0 348 }\r
01674025
RC
349 DEBUG ((\r
350 EFI_D_ERROR,\r
351 "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",\r
352 Status\r
353 ));\r
354 FreePool (TextDevicePath);\r
158497a0
RC
355 }\r
356 }\r
357\r
358 //\r
359 // Loop over the device path list provided by "PcdFdtDevicePaths". The device\r
360 // paths are in text form and separated by a semi-colon.\r
361 //\r
362\r
01674025 363 Status = EFI_NOT_FOUND;\r
158497a0
RC
364 for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);\r
365 *TextDevicePathStart != L'\0' ; ) {\r
366 TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");\r
367\r
368 //\r
369 // Last device path of the list\r
370 //\r
371 if (TextDevicePathSeparator == NULL) {\r
01674025 372 TextDevicePathLen = StrLen (TextDevicePathStart);\r
158497a0
RC
373 } else {\r
374 TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);\r
158497a0
RC
375 }\r
376\r
01674025
RC
377 TextDevicePath = AllocateCopyPool (\r
378 (TextDevicePathLen + 1) * sizeof (CHAR16),\r
379 TextDevicePathStart\r
380 );\r
381 if (TextDevicePath == NULL) {\r
382 Status = EFI_OUT_OF_RESOURCES;\r
383 goto Error;\r
384 }\r
385 TextDevicePath[TextDevicePathLen] = L'\0';\r
386\r
158497a0 387 Status = InstallFdt (TextDevicePath);\r
01674025 388 if (!EFI_ERROR (Status)) {\r
158497a0
RC
389 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",\r
390 TextDevicePath\r
391 ));\r
01674025 392 goto Done;\r
158497a0
RC
393 }\r
394\r
01674025
RC
395 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",\r
396 TextDevicePath, Status\r
397 ));\r
398 FreePool (TextDevicePath);\r
399\r
158497a0 400 if (TextDevicePathSeparator == NULL) {\r
01674025 401 goto Error;\r
158497a0 402 }\r
01674025 403 TextDevicePathStart = TextDevicePathSeparator + 1;\r
158497a0
RC
404 }\r
405\r
01674025
RC
406Error:\r
407Done:\r
408\r
158497a0
RC
409 if (EFI_ERROR (Status)) {\r
410 DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));\r
01674025 411 return Status;\r
158497a0
RC
412 }\r
413\r
01674025
RC
414 if (SuccessfullDevicePath != NULL) {\r
415 *SuccessfullDevicePath = TextDevicePath;\r
416 } else {\r
417 FreePool (TextDevicePath);\r
418 }\r
419\r
420 return EFI_SUCCESS;\r
158497a0
RC
421}\r
422\r
158497a0
RC
423/**\r
424 This is the shell command "setfdt" handler function. This function handles\r
425 the command when it is invoked in the shell.\r
426\r
427 @param[in] This The instance of the\r
428 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.\r
429 @param[in] SystemTable The pointer to the UEFI system table.\r
430 @param[in] ShellParameters The parameters associated with the command.\r
431 @param[in] Shell The instance of the shell protocol used in the\r
432 context of processing this command.\r
433\r
434 @return SHELL_SUCCESS The operation was successful.\r
435 @return SHELL_ABORTED Operation aborted due to internal error.\r
436 @return SHELL_INVALID_PARAMETER The parameters of the command are not valid.\r
437 @return SHELL_INVALID_PARAMETER The EFI Shell file path is not valid.\r
438 @return SHELL_NOT_FOUND Failed to locate a protocol or a file.\r
439 @return SHELL_UNSUPPORTED Device path not supported.\r
440 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.\r
441 @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.\r
442 @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.\r
443 @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.\r
444 @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.\r
445\r
446**/\r
447STATIC\r
448SHELL_STATUS\r
449EFIAPI\r
450ShellDynCmdSetFdtHandler (\r
451 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,\r
452 IN EFI_SYSTEM_TABLE *SystemTable,\r
453 IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,\r
454 IN EFI_SHELL_PROTOCOL *Shell\r
455 )\r
456{\r
457 SHELL_STATUS ShellStatus;\r
458 EFI_STATUS Status;\r
459 LIST_ENTRY *ParamPackage;\r
460 BOOLEAN FilePath;\r
461 CONST CHAR16 *ValueStr;\r
01674025 462 CHAR16 *TextDevicePath;\r
158497a0
RC
463\r
464 ShellStatus = SHELL_SUCCESS;\r
465 ParamPackage = NULL;\r
466 FilePath = FALSE;\r
467\r
468 //\r
469 // Install the Shell and Shell Parameters Protocols on the driver\r
470 // image. This is necessary for the initialisation of the Shell\r
471 // Library to succeed in the next step.\r
472 //\r
473 Status = gBS->InstallMultipleProtocolInterfaces (\r
474 &gImageHandle,\r
475 &gEfiShellProtocolGuid, Shell,\r
476 &gEfiShellParametersProtocolGuid, ShellParameters,\r
477 NULL\r
478 );\r
479 if (EFI_ERROR (Status)) {\r
480 return SHELL_ABORTED;\r
481 }\r
482\r
483 //\r
484 // Initialise the Shell Library as we are going to use it.\r
485 // Assert that the return code is EFI_SUCCESS as it should.\r
486 // To anticipate any change is the codes returned by\r
487 // ShellInitialize(), leave in case of error.\r
488 //\r
489 Status = ShellInitialize ();\r
490 if (EFI_ERROR (Status)) {\r
491 ASSERT_EFI_ERROR (Status);\r
492 return SHELL_ABORTED;\r
493 }\r
494\r
495 Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);\r
496 if (!EFI_ERROR (Status)) {\r
497 switch (ShellCommandLineGetCount (ParamPackage)) {\r
498 case 1:\r
499 //\r
4589ffaa 500 // Case "setfdt" or "setfdt -i"\r
158497a0
RC
501 //\r
502 if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) {\r
4589ffaa 503 DisplayFdtDevicePaths ();\r
158497a0
RC
504 }\r
505 break;\r
506\r
507 case 2:\r
508 //\r
509 // Case "setfdt file_path" or\r
510 // "setfdt -i file_path" or\r
511 // "setfdt file_path -i"\r
512 //\r
513 FilePath = TRUE;\r
514 break;\r
515\r
516 default:\r
517 Status = EFI_INVALID_PARAMETER;\r
518 }\r
519 }\r
520 if (EFI_ERROR (Status)) {\r
521 ShellStatus = EfiCodeToShellCode (Status);\r
522 ShellPrintHiiEx (\r
523 -1, -1, NULL,\r
524 STRING_TOKEN (STR_SETFDT_ERROR),\r
525 mFdtPlatformDxeHiiHandle,\r
526 Status\r
527 );\r
528 goto Error;\r
529 }\r
530\r
531 //\r
532 // Update the preferred device path for the FDT if asked for.\r
533 //\r
534 if (FilePath) {\r
535 ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);\r
536 ShellPrintHiiEx (\r
537 -1, -1, NULL,\r
538 STRING_TOKEN (STR_SETFDT_UPDATING),\r
539 mFdtPlatformDxeHiiHandle\r
540 );\r
541 ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr);\r
542 if (ShellStatus != SHELL_SUCCESS) {\r
543 goto Error;\r
544 }\r
545 }\r
546\r
547 //\r
548 // Run the FDT installation process if asked for.\r
549 //\r
550 if (ShellCommandLineGetFlag (ParamPackage, L"-i")) {\r
551 ShellPrintHiiEx (\r
552 -1, -1, NULL,\r
553 STRING_TOKEN (STR_SETFDT_INSTALLING),\r
554 mFdtPlatformDxeHiiHandle\r
555 );\r
01674025 556 Status = RunFdtInstallation (&TextDevicePath);\r
158497a0
RC
557 ShellStatus = EfiCodeToShellCode (Status);\r
558 if (!EFI_ERROR (Status)) {\r
559 ShellPrintHiiEx (\r
560 -1, -1, NULL,\r
561 STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED),\r
01674025
RC
562 mFdtPlatformDxeHiiHandle,\r
563 TextDevicePath\r
158497a0 564 );\r
01674025 565 FreePool (TextDevicePath);\r
158497a0
RC
566 } else {\r
567 if (Status == EFI_INVALID_PARAMETER) {\r
568 ShellPrintHiiEx (\r
569 -1, -1, NULL,\r
570 STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH),\r
571 mFdtPlatformDxeHiiHandle\r
572 );\r
573 } else {\r
574 ShellPrintHiiEx (\r
575 -1, -1, NULL,\r
576 STRING_TOKEN (STR_SETFDT_ERROR),\r
577 mFdtPlatformDxeHiiHandle,\r
578 Status\r
579 );\r
580 }\r
4589ffaa 581 DisplayFdtDevicePaths ();\r
158497a0
RC
582 }\r
583 }\r
584\r
585Error:\r
158497a0
RC
586 gBS->UninstallMultipleProtocolInterfaces (\r
587 gImageHandle,\r
588 &gEfiShellProtocolGuid, Shell,\r
589 &gEfiShellParametersProtocolGuid, ShellParameters,\r
590 NULL\r
591 );\r
592 ShellCommandLineFreeVarList (ParamPackage);\r
593\r
594 return ShellStatus;\r
595}\r
596\r
597/**\r
598 This is the shell command "setfdt" help handler function. This\r
599 function returns the formatted help for the "setfdt" command.\r
600 The format matchs that in Appendix B of the revision 2.1 of the\r
601 UEFI Shell Specification.\r
602\r
603 @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.\r
604 @param[in] Language The pointer to the language string to use.\r
605\r
606 @return CHAR16* Pool allocated help string, must be freed by caller.\r
607**/\r
608STATIC\r
609CHAR16*\r
610EFIAPI\r
611ShellDynCmdSetFdtGetHelp (\r
612 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,\r
613 IN CONST CHAR8 *Language\r
614 )\r
615{\r
616 //\r
617 // This allocates memory. The caller has to free the allocated memory.\r
618 //\r
619 return HiiGetString (\r
620 mFdtPlatformDxeHiiHandle,\r
621 STRING_TOKEN (STR_GET_HELP_SETFDT),\r
622 Language\r
623 );\r
624}\r
625\r
4589ffaa
RC
626/**\r
627 Display FDT device paths.\r
628\r
629 Display in text form the device paths used to install the FDT from the\r
630 highest to the lowest priority.\r
631\r
632**/\r
633STATIC\r
634VOID\r
635DisplayFdtDevicePaths (\r
636 VOID\r
637 )\r
638{\r
639 EFI_STATUS Status;\r
640 UINTN DataSize;\r
641 CHAR16 *TextDevicePath;\r
642 CHAR16 *TextDevicePaths;\r
643 CHAR16 *TextDevicePathSeparator;\r
644\r
645 ShellPrintHiiEx (\r
646 -1, -1, NULL,\r
647 STRING_TOKEN (STR_SETFDT_DEVICE_PATH_LIST),\r
648 mFdtPlatformDxeHiiHandle\r
649 );\r
650\r
651 if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
652 DataSize = 0;\r
653 Status = gRT->GetVariable (\r
654 L"Fdt",\r
655 &gFdtVariableGuid,\r
656 NULL,\r
657 &DataSize,\r
658 NULL\r
659 );\r
660\r
661 //\r
662 // Keep going only if the "Fdt" variable is defined.\r
663 //\r
664\r
665 if (Status == EFI_BUFFER_TOO_SMALL) {\r
666 TextDevicePath = AllocatePool (DataSize);\r
667 if (TextDevicePath == NULL) {\r
668 return;\r
669 }\r
670\r
671 Status = gRT->GetVariable (\r
672 L"Fdt",\r
673 &gFdtVariableGuid,\r
674 NULL,\r
675 &DataSize,\r
676 TextDevicePath\r
677 );\r
678 if (!EFI_ERROR (Status)) {\r
679 ShellPrintHiiEx (\r
680 -1, -1, NULL,\r
681 STRING_TOKEN (STR_SETFDT_DEVICE_PATH),\r
682 mFdtPlatformDxeHiiHandle,\r
683 TextDevicePath\r
684 );\r
685 }\r
686\r
687 FreePool (TextDevicePath);\r
688 }\r
689 }\r
690\r
691 //\r
692 // Loop over the device path list provided by "PcdFdtDevicePaths". The device\r
693 // paths are in text form and separated by a semi-colon.\r
694 //\r
695\r
696 TextDevicePaths = AllocateCopyPool (\r
697 StrSize ((CHAR16*)PcdGetPtr (PcdFdtDevicePaths)),\r
698 (CHAR16*)PcdGetPtr (PcdFdtDevicePaths)\r
699 );\r
700 if (TextDevicePaths == NULL) {\r
701 return;\r
702 }\r
703\r
704 for (TextDevicePath = TextDevicePaths;\r
705 *TextDevicePath != L'\0' ; ) {\r
706 TextDevicePathSeparator = StrStr (TextDevicePath, L";");\r
707\r
708 if (TextDevicePathSeparator != NULL) {\r
709 *TextDevicePathSeparator = L'\0';\r
710 }\r
711\r
712 ShellPrintHiiEx (\r
713 -1, -1, NULL,\r
714 STRING_TOKEN (STR_SETFDT_DEVICE_PATH),\r
715 mFdtPlatformDxeHiiHandle,\r
716 TextDevicePath\r
717 );\r
718\r
719 if (TextDevicePathSeparator == NULL) {\r
720 break;\r
721 }\r
722 TextDevicePath = TextDevicePathSeparator + 1;\r
723 }\r
724\r
725 FreePool (TextDevicePaths);\r
726\r
727}\r
728\r
158497a0
RC
729/**\r
730 Update the text device path stored in the "Fdt" UEFI variable given\r
731 an EFI Shell file path or a text device path.\r
732\r
733 This function is a subroutine of the ShellDynCmdSetFdtHandler() function\r
734 to make its code easier to read.\r
735\r
736 @param[in] Shell The instance of the shell protocol used in the\r
737 context of processing the "setfdt" command.\r
738 @param[in] FilePath EFI Shell path or the device path to the FDT file.\r
739\r
740 @return SHELL_SUCCESS The text device path was succesfully updated.\r
741 @return SHELL_INVALID_PARAMETER The Shell file path is not valid.\r
742 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.\r
743 @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.\r
744 @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.\r
745 @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.\r
746 @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.\r
747 @return SHELL_NOT_FOUND Device path to text protocol not found.\r
748 @return SHELL_ABORTED Operation aborted.\r
749\r
750**/\r
751STATIC\r
752SHELL_STATUS\r
753UpdateFdtTextDevicePath (\r
754 IN EFI_SHELL_PROTOCOL *Shell,\r
755 IN CONST CHAR16 *FilePath\r
756 )\r
757{\r
758 EFI_STATUS Status;\r
759 EFI_DEVICE_PATH *DevicePath;\r
760 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *EfiDevicePathToTextProtocol;\r
761 CHAR16 *TextDevicePath;\r
762 CHAR16 *FdtVariableValue;\r
763 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
764 SHELL_STATUS ShellStatus;\r
765\r
766 ASSERT (FilePath != NULL);\r
bbd6a161 767 DevicePath = NULL;\r
158497a0
RC
768 TextDevicePath = NULL;\r
769 FdtVariableValue = NULL;\r
770\r
bbd6a161
RC
771 if (*FilePath != L'\0') {\r
772 DevicePath = Shell->GetDevicePathFromFilePath (FilePath);\r
773 if (DevicePath != NULL) {\r
774 Status = gBS->LocateProtocol (\r
775 &gEfiDevicePathToTextProtocolGuid,\r
776 NULL,\r
777 (VOID **)&EfiDevicePathToTextProtocol\r
778 );\r
779 if (EFI_ERROR (Status)) {\r
780 goto Error;\r
781 }\r
158497a0 782\r
bbd6a161
RC
783 TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText (\r
784 DevicePath,\r
785 FALSE,\r
786 FALSE\r
787 );\r
788 if (TextDevicePath == NULL) {\r
789 Status = EFI_OUT_OF_RESOURCES;\r
790 goto Error;\r
791 }\r
792 FdtVariableValue = TextDevicePath;\r
793 } else {\r
794 //\r
795 // Try to convert back the EFI Device Path String into a EFI device Path\r
796 // to ensure the format is valid\r
797 //\r
798 Status = gBS->LocateProtocol (\r
799 &gEfiDevicePathFromTextProtocolGuid,\r
800 NULL,\r
801 (VOID **)&EfiDevicePathFromTextProtocol\r
802 );\r
803 if (EFI_ERROR (Status)) {\r
804 goto Error;\r
805 }\r
158497a0 806\r
bbd6a161
RC
807 DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (\r
808 FilePath\r
809 );\r
810 if (DevicePath == NULL) {\r
811 Status = EFI_INVALID_PARAMETER;\r
812 goto Error;\r
813 }\r
814 FdtVariableValue = (CHAR16*)FilePath;\r
158497a0 815 }\r
158497a0
RC
816 }\r
817\r
818 Status = gRT->SetVariable (\r
819 (CHAR16*)L"Fdt",\r
820 &gFdtVariableGuid,\r
821 EFI_VARIABLE_RUNTIME_ACCESS |\r
822 EFI_VARIABLE_NON_VOLATILE |\r
823 EFI_VARIABLE_BOOTSERVICE_ACCESS ,\r
bbd6a161
RC
824 (FdtVariableValue != NULL) ?\r
825 StrSize (FdtVariableValue) : 0,\r
158497a0
RC
826 FdtVariableValue\r
827 );\r
828\r
829Error:\r
830 ShellStatus = EfiCodeToShellCode (Status);\r
831 if (!EFI_ERROR (Status)) {\r
bbd6a161
RC
832 if (FdtVariableValue != NULL) {\r
833 ShellPrintHiiEx (\r
834 -1, -1, NULL,\r
835 STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED),\r
836 mFdtPlatformDxeHiiHandle,\r
837 FdtVariableValue\r
838 );\r
839 } else {\r
840 ShellPrintHiiEx (\r
841 -1, -1, NULL,\r
842 STRING_TOKEN (STR_SETFDT_UPDATE_DELETED),\r
01674025 843 mFdtPlatformDxeHiiHandle\r
bbd6a161
RC
844 );\r
845 }\r
158497a0
RC
846 } else {\r
847 if (Status == EFI_INVALID_PARAMETER) {\r
848 ShellPrintHiiEx (\r
849 -1, -1, NULL,\r
850 STRING_TOKEN (STR_SETFDT_INVALID_PATH),\r
851 mFdtPlatformDxeHiiHandle,\r
852 FilePath\r
853 );\r
854 } else {\r
855 ShellPrintHiiEx (\r
856 -1, -1, NULL,\r
857 STRING_TOKEN (STR_SETFDT_ERROR),\r
858 mFdtPlatformDxeHiiHandle,\r
859 Status\r
860 );\r
861 }\r
862 }\r
863\r
864 if (DevicePath != NULL) {\r
865 FreePool (DevicePath);\r
866 }\r
867 if (TextDevicePath != NULL) {\r
868 FreePool (TextDevicePath);\r
869 }\r
870\r
871 return ShellStatus;\r
872}\r
873\r
874/**\r
875 Transcode one of the EFI return code used by the model into an EFI Shell return code.\r
876\r
877 @param[in] Status EFI return code.\r
878\r
879 @return Transcoded EFI Shell return code.\r
880\r
881**/\r
882STATIC\r
883SHELL_STATUS\r
884EfiCodeToShellCode (\r
885 IN EFI_STATUS Status\r
886 )\r
887{\r
888 SHELL_STATUS ShellStatus;\r
889\r
890 switch (Status) {\r
891 case EFI_SUCCESS :\r
892 ShellStatus = SHELL_SUCCESS;\r
893 break;\r
894\r
895 case EFI_INVALID_PARAMETER :\r
896 ShellStatus = SHELL_INVALID_PARAMETER;\r
897 break;\r
898\r
899 case EFI_UNSUPPORTED :\r
900 ShellStatus = SHELL_UNSUPPORTED;\r
901 break;\r
902\r
903 case EFI_DEVICE_ERROR :\r
904 ShellStatus = SHELL_DEVICE_ERROR;\r
905 break;\r
906\r
907 case EFI_WRITE_PROTECTED :\r
908 case EFI_SECURITY_VIOLATION :\r
909 ShellStatus = SHELL_ACCESS_DENIED;\r
910 break;\r
911\r
912 case EFI_OUT_OF_RESOURCES :\r
913 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
914 break;\r
915\r
916 case EFI_NOT_FOUND :\r
917 ShellStatus = SHELL_NOT_FOUND;\r
918 break;\r
919\r
920 default :\r
921 ShellStatus = SHELL_ABORTED;\r
922 }\r
923\r
924 return ShellStatus;\r
925}\r