]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c
b5ae8c0bb5bd3a7b4e8ed9da17d8f8289e6262af
[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 @retval EFI_SUCCESS The FDT was installed.
274 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.
275 @retval EFI_INVALID_PARAMETER Invalid device path.
276 @retval EFI_UNSUPPORTED Device path not supported.
277 @retval EFI_OUT_OF_RESOURCES An allocation failed.
278
279 **/
280 STATIC
281 EFI_STATUS
282 RunFdtInstallation (
283 VOID
284 )
285 {
286 EFI_STATUS Status;
287 UINTN DataSize;
288 VOID *Data;
289 CHAR16 *TextDevicePathStart;
290 CHAR16 *TextDevicePathSeparator;
291 UINTN TextDevicePathLen;
292 CHAR16 *TextDevicePath;
293
294 //
295 // For development purpose, if enabled through the "PcdOverridePlatformFdt"
296 // feature PCD, try first to install the FDT specified by the device path in
297 // text form stored in the "Fdt" UEFI variable.
298 //
299 if (FeaturePcdGet (PcdOverridePlatformFdt)) {
300 Data = NULL;
301 DataSize = 0;
302 Status = gRT->GetVariable (
303 L"Fdt",
304 &gFdtVariableGuid,
305 NULL,
306 &DataSize,
307 Data
308 );
309
310 //
311 // Keep going only if the "Fdt" variable is defined.
312 //
313
314 if (Status == EFI_BUFFER_TOO_SMALL) {
315 Data = AllocatePool (DataSize);
316 if (Data == NULL) {
317 Status = EFI_OUT_OF_RESOURCES;
318 } else {
319 Status = gRT->GetVariable (
320 L"Fdt",
321 &gFdtVariableGuid,
322 NULL,
323 &DataSize,
324 Data
325 );
326 if (!EFI_ERROR (Status)) {
327 Status = InstallFdt ((CHAR16*)Data);
328 if (!EFI_ERROR (Status)) {
329 DEBUG ((
330 EFI_D_WARN,
331 "Installation of the FDT using the device path <%s> completed.\n",
332 (CHAR16*)Data
333 ));
334 }
335 }
336 FreePool (Data);
337 }
338
339 if (EFI_ERROR (Status)) {
340 DEBUG ((
341 EFI_D_ERROR,
342 "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",
343 Status
344 ));
345 } else {
346 return Status;
347 }
348 }
349 }
350
351 //
352 // Loop over the device path list provided by "PcdFdtDevicePaths". The device
353 // paths are in text form and separated by a semi-colon.
354 //
355
356 Status = EFI_SUCCESS;
357 for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);
358 *TextDevicePathStart != L'\0' ; ) {
359 TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");
360
361 //
362 // Last device path of the list
363 //
364 if (TextDevicePathSeparator == NULL) {
365 TextDevicePath = TextDevicePathStart;
366 } else {
367 TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);
368 TextDevicePath = AllocateCopyPool (
369 (TextDevicePathLen + 1) * sizeof (CHAR16),
370 TextDevicePathStart
371 );
372 if (TextDevicePath == NULL) {
373 Status = EFI_OUT_OF_RESOURCES;
374 DEBUG ((EFI_D_ERROR, "Memory allocation error during FDT installation process.\n"));
375 break;
376 }
377 TextDevicePath[TextDevicePathLen] = L'\0';
378 }
379
380 Status = InstallFdt (TextDevicePath);
381 if (EFI_ERROR (Status)) {
382 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",
383 TextDevicePath, Status
384 ));
385 } else {
386 DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",
387 TextDevicePath
388 ));
389 }
390
391 if (TextDevicePathSeparator == NULL) {
392 break;
393 } else {
394 FreePool (TextDevicePath);
395 if (!EFI_ERROR (Status)) {
396 break;
397 }
398 TextDevicePathStart = TextDevicePathSeparator + 1;
399 }
400 }
401
402 if (EFI_ERROR (Status)) {
403 DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));
404 }
405
406 return Status;
407 }
408
409 /**
410 This is the shell command "setfdt" handler function. This function handles
411 the command when it is invoked in the shell.
412
413 @param[in] This The instance of the
414 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
415 @param[in] SystemTable The pointer to the UEFI system table.
416 @param[in] ShellParameters The parameters associated with the command.
417 @param[in] Shell The instance of the shell protocol used in the
418 context of processing this command.
419
420 @return SHELL_SUCCESS The operation was successful.
421 @return SHELL_ABORTED Operation aborted due to internal error.
422 @return SHELL_INVALID_PARAMETER The parameters of the command are not valid.
423 @return SHELL_INVALID_PARAMETER The EFI Shell file path is not valid.
424 @return SHELL_NOT_FOUND Failed to locate a protocol or a file.
425 @return SHELL_UNSUPPORTED Device path not supported.
426 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
427 @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
428 @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
429 @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
430 @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
431
432 **/
433 STATIC
434 SHELL_STATUS
435 EFIAPI
436 ShellDynCmdSetFdtHandler (
437 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
438 IN EFI_SYSTEM_TABLE *SystemTable,
439 IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
440 IN EFI_SHELL_PROTOCOL *Shell
441 )
442 {
443 SHELL_STATUS ShellStatus;
444 EFI_STATUS Status;
445 LIST_ENTRY *ParamPackage;
446 BOOLEAN FilePath;
447 CONST CHAR16 *ValueStr;
448
449 ShellStatus = SHELL_SUCCESS;
450 ParamPackage = NULL;
451 FilePath = FALSE;
452
453 //
454 // Install the Shell and Shell Parameters Protocols on the driver
455 // image. This is necessary for the initialisation of the Shell
456 // Library to succeed in the next step.
457 //
458 Status = gBS->InstallMultipleProtocolInterfaces (
459 &gImageHandle,
460 &gEfiShellProtocolGuid, Shell,
461 &gEfiShellParametersProtocolGuid, ShellParameters,
462 NULL
463 );
464 if (EFI_ERROR (Status)) {
465 return SHELL_ABORTED;
466 }
467
468 //
469 // Initialise the Shell Library as we are going to use it.
470 // Assert that the return code is EFI_SUCCESS as it should.
471 // To anticipate any change is the codes returned by
472 // ShellInitialize(), leave in case of error.
473 //
474 Status = ShellInitialize ();
475 if (EFI_ERROR (Status)) {
476 ASSERT_EFI_ERROR (Status);
477 return SHELL_ABORTED;
478 }
479
480 Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
481 if (!EFI_ERROR (Status)) {
482 switch (ShellCommandLineGetCount (ParamPackage)) {
483 case 1:
484 //
485 // Case "setfdt" or "setfdt -i"
486 //
487 if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) {
488 DisplayFdtDevicePaths ();
489 }
490 break;
491
492 case 2:
493 //
494 // Case "setfdt file_path" or
495 // "setfdt -i file_path" or
496 // "setfdt file_path -i"
497 //
498 FilePath = TRUE;
499 break;
500
501 default:
502 Status = EFI_INVALID_PARAMETER;
503 }
504 }
505 if (EFI_ERROR (Status)) {
506 ShellStatus = EfiCodeToShellCode (Status);
507 ShellPrintHiiEx (
508 -1, -1, NULL,
509 STRING_TOKEN (STR_SETFDT_ERROR),
510 mFdtPlatformDxeHiiHandle,
511 Status
512 );
513 goto Error;
514 }
515
516 //
517 // Update the preferred device path for the FDT if asked for.
518 //
519 if (FilePath) {
520 ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);
521 ShellPrintHiiEx (
522 -1, -1, NULL,
523 STRING_TOKEN (STR_SETFDT_UPDATING),
524 mFdtPlatformDxeHiiHandle
525 );
526 ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr);
527 if (ShellStatus != SHELL_SUCCESS) {
528 goto Error;
529 }
530 }
531
532 //
533 // Run the FDT installation process if asked for.
534 //
535 if (ShellCommandLineGetFlag (ParamPackage, L"-i")) {
536 ShellPrintHiiEx (
537 -1, -1, NULL,
538 STRING_TOKEN (STR_SETFDT_INSTALLING),
539 mFdtPlatformDxeHiiHandle
540 );
541 Status = RunFdtInstallation ();
542 ShellStatus = EfiCodeToShellCode (Status);
543 if (!EFI_ERROR (Status)) {
544 ShellPrintHiiEx (
545 -1, -1, NULL,
546 STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED),
547 mFdtPlatformDxeHiiHandle
548 );
549 } else {
550 if (Status == EFI_INVALID_PARAMETER) {
551 ShellPrintHiiEx (
552 -1, -1, NULL,
553 STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH),
554 mFdtPlatformDxeHiiHandle
555 );
556 } else {
557 ShellPrintHiiEx (
558 -1, -1, NULL,
559 STRING_TOKEN (STR_SETFDT_ERROR),
560 mFdtPlatformDxeHiiHandle,
561 Status
562 );
563 }
564 DisplayFdtDevicePaths ();
565 }
566 }
567
568 Error:
569 gBS->UninstallMultipleProtocolInterfaces (
570 gImageHandle,
571 &gEfiShellProtocolGuid, Shell,
572 &gEfiShellParametersProtocolGuid, ShellParameters,
573 NULL
574 );
575 ShellCommandLineFreeVarList (ParamPackage);
576
577 return ShellStatus;
578 }
579
580 /**
581 This is the shell command "setfdt" help handler function. This
582 function returns the formatted help for the "setfdt" command.
583 The format matchs that in Appendix B of the revision 2.1 of the
584 UEFI Shell Specification.
585
586 @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
587 @param[in] Language The pointer to the language string to use.
588
589 @return CHAR16* Pool allocated help string, must be freed by caller.
590 **/
591 STATIC
592 CHAR16*
593 EFIAPI
594 ShellDynCmdSetFdtGetHelp (
595 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
596 IN CONST CHAR8 *Language
597 )
598 {
599 //
600 // This allocates memory. The caller has to free the allocated memory.
601 //
602 return HiiGetString (
603 mFdtPlatformDxeHiiHandle,
604 STRING_TOKEN (STR_GET_HELP_SETFDT),
605 Language
606 );
607 }
608
609 /**
610 Display FDT device paths.
611
612 Display in text form the device paths used to install the FDT from the
613 highest to the lowest priority.
614
615 **/
616 STATIC
617 VOID
618 DisplayFdtDevicePaths (
619 VOID
620 )
621 {
622 EFI_STATUS Status;
623 UINTN DataSize;
624 CHAR16 *TextDevicePath;
625 CHAR16 *TextDevicePaths;
626 CHAR16 *TextDevicePathSeparator;
627
628 ShellPrintHiiEx (
629 -1, -1, NULL,
630 STRING_TOKEN (STR_SETFDT_DEVICE_PATH_LIST),
631 mFdtPlatformDxeHiiHandle
632 );
633
634 if (FeaturePcdGet (PcdOverridePlatformFdt)) {
635 DataSize = 0;
636 Status = gRT->GetVariable (
637 L"Fdt",
638 &gFdtVariableGuid,
639 NULL,
640 &DataSize,
641 NULL
642 );
643
644 //
645 // Keep going only if the "Fdt" variable is defined.
646 //
647
648 if (Status == EFI_BUFFER_TOO_SMALL) {
649 TextDevicePath = AllocatePool (DataSize);
650 if (TextDevicePath == NULL) {
651 return;
652 }
653
654 Status = gRT->GetVariable (
655 L"Fdt",
656 &gFdtVariableGuid,
657 NULL,
658 &DataSize,
659 TextDevicePath
660 );
661 if (!EFI_ERROR (Status)) {
662 ShellPrintHiiEx (
663 -1, -1, NULL,
664 STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
665 mFdtPlatformDxeHiiHandle,
666 TextDevicePath
667 );
668 }
669
670 FreePool (TextDevicePath);
671 }
672 }
673
674 //
675 // Loop over the device path list provided by "PcdFdtDevicePaths". The device
676 // paths are in text form and separated by a semi-colon.
677 //
678
679 TextDevicePaths = AllocateCopyPool (
680 StrSize ((CHAR16*)PcdGetPtr (PcdFdtDevicePaths)),
681 (CHAR16*)PcdGetPtr (PcdFdtDevicePaths)
682 );
683 if (TextDevicePaths == NULL) {
684 return;
685 }
686
687 for (TextDevicePath = TextDevicePaths;
688 *TextDevicePath != L'\0' ; ) {
689 TextDevicePathSeparator = StrStr (TextDevicePath, L";");
690
691 if (TextDevicePathSeparator != NULL) {
692 *TextDevicePathSeparator = L'\0';
693 }
694
695 ShellPrintHiiEx (
696 -1, -1, NULL,
697 STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
698 mFdtPlatformDxeHiiHandle,
699 TextDevicePath
700 );
701
702 if (TextDevicePathSeparator == NULL) {
703 break;
704 }
705 TextDevicePath = TextDevicePathSeparator + 1;
706 }
707
708 FreePool (TextDevicePaths);
709
710 }
711
712 /**
713 Update the text device path stored in the "Fdt" UEFI variable given
714 an EFI Shell file path or a text device path.
715
716 This function is a subroutine of the ShellDynCmdSetFdtHandler() function
717 to make its code easier to read.
718
719 @param[in] Shell The instance of the shell protocol used in the
720 context of processing the "setfdt" command.
721 @param[in] FilePath EFI Shell path or the device path to the FDT file.
722
723 @return SHELL_SUCCESS The text device path was succesfully updated.
724 @return SHELL_INVALID_PARAMETER The Shell file path is not valid.
725 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
726 @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
727 @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
728 @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
729 @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
730 @return SHELL_NOT_FOUND Device path to text protocol not found.
731 @return SHELL_ABORTED Operation aborted.
732
733 **/
734 STATIC
735 SHELL_STATUS
736 UpdateFdtTextDevicePath (
737 IN EFI_SHELL_PROTOCOL *Shell,
738 IN CONST CHAR16 *FilePath
739 )
740 {
741 EFI_STATUS Status;
742 EFI_DEVICE_PATH *DevicePath;
743 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *EfiDevicePathToTextProtocol;
744 CHAR16 *TextDevicePath;
745 CHAR16 *FdtVariableValue;
746 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
747 SHELL_STATUS ShellStatus;
748
749 ASSERT (FilePath != NULL);
750 TextDevicePath = NULL;
751 FdtVariableValue = NULL;
752
753 DevicePath = Shell->GetDevicePathFromFilePath (FilePath);
754 if (DevicePath != NULL) {
755 Status = gBS->LocateProtocol (
756 &gEfiDevicePathToTextProtocolGuid,
757 NULL,
758 (VOID **)&EfiDevicePathToTextProtocol
759 );
760 if (EFI_ERROR (Status)) {
761 goto Error;
762 }
763
764 TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText (
765 DevicePath,
766 FALSE,
767 FALSE
768 );
769 if (TextDevicePath == NULL) {
770 Status = EFI_OUT_OF_RESOURCES;
771 goto Error;
772 }
773 FdtVariableValue = TextDevicePath;
774 } else {
775 //
776 // Try to convert back the EFI Device Path String into a EFI device Path
777 // to ensure the format is valid
778 //
779 Status = gBS->LocateProtocol (
780 &gEfiDevicePathFromTextProtocolGuid,
781 NULL,
782 (VOID **)&EfiDevicePathFromTextProtocol
783 );
784 if (EFI_ERROR (Status)) {
785 goto Error;
786 }
787
788 DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
789 FilePath
790 );
791 if (DevicePath == NULL) {
792 Status = EFI_INVALID_PARAMETER;
793 goto Error;
794 }
795 FdtVariableValue = (CHAR16*)FilePath;
796 }
797
798 Status = gRT->SetVariable (
799 (CHAR16*)L"Fdt",
800 &gFdtVariableGuid,
801 EFI_VARIABLE_RUNTIME_ACCESS |
802 EFI_VARIABLE_NON_VOLATILE |
803 EFI_VARIABLE_BOOTSERVICE_ACCESS ,
804 StrSize (FdtVariableValue),
805 FdtVariableValue
806 );
807
808 Error:
809 ShellStatus = EfiCodeToShellCode (Status);
810 if (!EFI_ERROR (Status)) {
811 ShellPrintHiiEx (
812 -1, -1, NULL,
813 STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED),
814 mFdtPlatformDxeHiiHandle,
815 FdtVariableValue
816 );
817 } else {
818 if (Status == EFI_INVALID_PARAMETER) {
819 ShellPrintHiiEx (
820 -1, -1, NULL,
821 STRING_TOKEN (STR_SETFDT_INVALID_PATH),
822 mFdtPlatformDxeHiiHandle,
823 FilePath
824 );
825 } else {
826 ShellPrintHiiEx (
827 -1, -1, NULL,
828 STRING_TOKEN (STR_SETFDT_ERROR),
829 mFdtPlatformDxeHiiHandle,
830 Status
831 );
832 }
833 }
834
835 if (DevicePath != NULL) {
836 FreePool (DevicePath);
837 }
838 if (TextDevicePath != NULL) {
839 FreePool (TextDevicePath);
840 }
841
842 return ShellStatus;
843 }
844
845 /**
846 Transcode one of the EFI return code used by the model into an EFI Shell return code.
847
848 @param[in] Status EFI return code.
849
850 @return Transcoded EFI Shell return code.
851
852 **/
853 STATIC
854 SHELL_STATUS
855 EfiCodeToShellCode (
856 IN EFI_STATUS Status
857 )
858 {
859 SHELL_STATUS ShellStatus;
860
861 switch (Status) {
862 case EFI_SUCCESS :
863 ShellStatus = SHELL_SUCCESS;
864 break;
865
866 case EFI_INVALID_PARAMETER :
867 ShellStatus = SHELL_INVALID_PARAMETER;
868 break;
869
870 case EFI_UNSUPPORTED :
871 ShellStatus = SHELL_UNSUPPORTED;
872 break;
873
874 case EFI_DEVICE_ERROR :
875 ShellStatus = SHELL_DEVICE_ERROR;
876 break;
877
878 case EFI_WRITE_PROTECTED :
879 case EFI_SECURITY_VIOLATION :
880 ShellStatus = SHELL_ACCESS_DENIED;
881 break;
882
883 case EFI_OUT_OF_RESOURCES :
884 ShellStatus = SHELL_OUT_OF_RESOURCES;
885 break;
886
887 case EFI_NOT_FOUND :
888 ShellStatus = SHELL_NOT_FOUND;
889 break;
890
891 default :
892 ShellStatus = SHELL_ABORTED;
893 }
894
895 return ShellStatus;
896 }