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