3 Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
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
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.
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>
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>
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
48 STATIC CHAR16
* EFIAPI
ShellDynCmdSetFdtGetHelp (
49 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
50 IN CONST CHAR8
*Language
53 STATIC SHELL_STATUS
UpdateFdtTextDevicePath (
54 IN EFI_SHELL_PROTOCOL
*Shell
,
55 IN CONST CHAR16
*FilePath
58 STATIC SHELL_STATUS
EfiCodeToShellCode (
66 STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt
= {
67 L
"setfdt", // Name of the command
68 ShellDynCmdSetFdtHandler
, // Handler
69 ShellDynCmdSetFdtGetHelp
// GetHelp
72 STATIC CONST EFI_GUID mFdtPlatformDxeHiiGuid
= {
73 0x8afa7610, 0x62b1, 0x46aa,
74 {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}
76 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
81 STATIC EFI_HANDLE mFdtPlatformDxeHiiHandle
;
84 Install the FDT specified by its device path in text form.
86 @param[in] TextDevicePath Device path of the FDT to install in text form
88 @retval EFI_SUCCESS The FDT was installed.
89 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.
90 @retval EFI_INVALID_PARAMETER Invalid device path.
91 @retval EFI_UNSUPPORTED Device path not supported.
92 @retval EFI_OUT_OF_RESOURCES An allocation failed.
97 IN CONST CHAR16
* TextDevicePath
101 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
102 EFI_DEVICE_PATH
*DevicePath
;
103 EFI_PHYSICAL_ADDRESS FdtBlobBase
;
106 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase
;
108 Status
= gBS
->LocateProtocol (
109 &gEfiDevicePathFromTextProtocolGuid
,
111 (VOID
**)&EfiDevicePathFromTextProtocol
113 if (EFI_ERROR (Status
)) {
114 DEBUG ((EFI_D_ERROR
, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n"));
118 DevicePath
= (EFI_DEVICE_PATH
*)EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (TextDevicePath
);
119 if (DevicePath
== NULL
) {
120 return EFI_INVALID_PARAMETER
;
124 // Load the FDT given its device path.
125 // This operation may fail if the device path is not supported.
129 Status
= BdsLoadImage (DevicePath
, AllocateAnyPages
, &FdtBlobBase
, &FdtBlobSize
);
130 if (EFI_ERROR (Status
)) {
134 // Check the FDT header is valid. We only make this check in DEBUG mode in
135 // case the FDT header change on production device and this ASSERT() becomes
137 ASSERT (fdt_check_header ((VOID
*)(UINTN
)FdtBlobBase
) == 0);
140 // Ensure the Size of the Device Tree is smaller than the size of the read file
142 ASSERT ((UINTN
)fdt_totalsize ((VOID
*)(UINTN
)FdtBlobBase
) <= FdtBlobSize
);
145 // Store the FDT as Runtime Service Data to prevent the Kernel from
146 // overwritting its data.
148 NumPages
= EFI_SIZE_TO_PAGES (FdtBlobSize
);
149 Status
= gBS
->AllocatePages (
150 AllocateAnyPages
, EfiRuntimeServicesData
,
151 NumPages
, &FdtConfigurationTableBase
153 if (EFI_ERROR (Status
)) {
157 (VOID
*)(UINTN
)FdtConfigurationTableBase
,
158 (VOID
*)(UINTN
)FdtBlobBase
,
163 // Install the FDT into the Configuration Table
165 Status
= gBS
->InstallConfigurationTable (
167 (VOID
*)(UINTN
)FdtConfigurationTableBase
169 if (EFI_ERROR (Status
)) {
170 gBS
->FreePages (FdtConfigurationTableBase
, NumPages
);
174 if (FdtBlobBase
!= 0) {
175 gBS
->FreePages (FdtBlobBase
, NumPages
);
177 FreePool (DevicePath
);
183 Main entry point of the FDT platform driver.
185 @param[in] ImageHandle The firmware allocated handle for the present driver
187 @param[in] *SystemTable A pointer to the EFI System table.
189 @retval EFI_SUCCESS The driver was initialized.
190 @retval EFI_OUT_OF_RESOURCES The "End of DXE" event could not be allocated or
191 there was not enough memory in pool to install
192 the Shell Dynamic Command protocol.
193 @retval EFI_LOAD_ERROR Unable to add the HII package.
197 FdtPlatformEntryPoint (
198 IN EFI_HANDLE ImageHandle
,
199 IN EFI_SYSTEM_TABLE
*SystemTable
205 // Install the Device Tree from its expected location
207 Status
= RunFdtInstallation (NULL
);
208 if (EFI_ERROR (Status
)) {
213 // If the development features are enabled, install the dynamic shell
214 // command "setfdt" to be able to define a device path for the FDT
215 // that has precedence over the device paths defined by
216 // "PcdFdtDevicePaths".
219 if (FeaturePcdGet (PcdOverridePlatformFdt
)) {
221 // Register the strings for the user interface in the HII Database.
222 // This shows the way to the multi-language support, even if
223 // only the English language is actually supported. The strings to register
224 // are stored in the "FdtPlatformDxeStrings[]" array. This array is
225 // built by the building process from the "*.uni" file associated to
226 // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build
227 // folder under your package's DEBUG folder and you will find the array
228 // defined in a xxxStrDefs.h file.
230 mFdtPlatformDxeHiiHandle
= HiiAddPackages (
231 &mFdtPlatformDxeHiiGuid
,
233 FdtPlatformDxeStrings
,
237 if (mFdtPlatformDxeHiiHandle
!= NULL
) {
238 Status
= gBS
->InstallMultipleProtocolInterfaces (
240 &gEfiShellDynamicCommandProtocolGuid
,
241 &mShellDynCmdProtocolSetFdt
,
244 if (EFI_ERROR (Status
)) {
245 HiiRemovePackages (mFdtPlatformDxeHiiHandle
);
248 Status
= EFI_LOAD_ERROR
;
250 if (EFI_ERROR (Status
)) {
253 "Unable to install \"setfdt\" EFI Shell command - %r \n",
263 Run the FDT installation process.
265 Loop in priority order over the device paths from which the FDT has
266 been asked to be retrieved for. For each device path, try to install
267 the FDT. Stop as soon as an installation succeeds.
269 @retval EFI_SUCCESS The FDT was installed.
270 @retval EFI_NOT_FOUND Failed to locate a protocol or a file.
271 @retval EFI_INVALID_PARAMETER Invalid device path.
272 @retval EFI_UNSUPPORTED Device path not supported.
273 @retval EFI_OUT_OF_RESOURCES An allocation failed.
285 CHAR16
*TextDevicePathStart
;
286 CHAR16
*TextDevicePathSeparator
;
287 UINTN TextDevicePathLen
;
288 CHAR16
*TextDevicePath
;
291 // For development purpose, if enabled through the "PcdOverridePlatformFdt"
292 // feature PCD, try first to install the FDT specified by the device path in
293 // text form stored in the "Fdt" UEFI variable.
295 if (FeaturePcdGet (PcdOverridePlatformFdt
)) {
298 Status
= gRT
->GetVariable (
307 // Keep going only if the "Fdt" variable is defined.
310 if (Status
== EFI_BUFFER_TOO_SMALL
) {
311 Data
= AllocatePool (DataSize
);
313 Status
= EFI_OUT_OF_RESOURCES
;
315 Status
= gRT
->GetVariable (
322 if (!EFI_ERROR (Status
)) {
323 Status
= InstallFdt ((CHAR16
*)Data
);
324 if (!EFI_ERROR (Status
)) {
327 "Installation of the FDT using the device path <%s> completed.\n",
335 if (EFI_ERROR (Status
)) {
338 "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",
348 // Loop over the device path list provided by "PcdFdtDevicePaths". The device
349 // paths are in text form and separated by a semi-colon.
352 Status
= EFI_SUCCESS
;
353 for (TextDevicePathStart
= (CHAR16
*)PcdGetPtr (PcdFdtDevicePaths
);
354 *TextDevicePathStart
!= L
'\0' ; ) {
355 TextDevicePathSeparator
= StrStr (TextDevicePathStart
, L
";");
358 // Last device path of the list
360 if (TextDevicePathSeparator
== NULL
) {
361 TextDevicePath
= TextDevicePathStart
;
363 TextDevicePathLen
= (UINTN
)(TextDevicePathSeparator
- TextDevicePathStart
);
364 TextDevicePath
= AllocateCopyPool (
365 (TextDevicePathLen
+ 1) * sizeof (CHAR16
),
368 if (TextDevicePath
== NULL
) {
369 Status
= EFI_OUT_OF_RESOURCES
;
370 DEBUG ((EFI_D_ERROR
, "Memory allocation error during FDT installation process.\n"));
373 TextDevicePath
[TextDevicePathLen
] = L
'\0';
376 Status
= InstallFdt (TextDevicePath
);
377 if (EFI_ERROR (Status
)) {
378 DEBUG ((EFI_D_WARN
, "Installation of the FDT using the device path <%s> failed - %r.\n",
379 TextDevicePath
, Status
382 DEBUG ((EFI_D_WARN
, "Installation of the FDT using the device path <%s> completed.\n",
387 if (TextDevicePathSeparator
== NULL
) {
390 FreePool (TextDevicePath
);
391 if (!EFI_ERROR (Status
)) {
394 TextDevicePathStart
= TextDevicePathSeparator
+ 1;
398 if (EFI_ERROR (Status
)) {
399 DEBUG ((EFI_D_ERROR
, "Failed to install the FDT - %r.\n", Status
));
406 This is the shell command "setfdt" handler function. This function handles
407 the command when it is invoked in the shell.
409 @param[in] This The instance of the
410 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
411 @param[in] SystemTable The pointer to the UEFI system table.
412 @param[in] ShellParameters The parameters associated with the command.
413 @param[in] Shell The instance of the shell protocol used in the
414 context of processing this command.
416 @return SHELL_SUCCESS The operation was successful.
417 @return SHELL_ABORTED Operation aborted due to internal error.
418 @return SHELL_INVALID_PARAMETER The parameters of the command are not valid.
419 @return SHELL_INVALID_PARAMETER The EFI Shell file path is not valid.
420 @return SHELL_NOT_FOUND Failed to locate a protocol or a file.
421 @return SHELL_UNSUPPORTED Device path not supported.
422 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
423 @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
424 @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
425 @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
426 @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
432 ShellDynCmdSetFdtHandler (
433 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
434 IN EFI_SYSTEM_TABLE
*SystemTable
,
435 IN EFI_SHELL_PARAMETERS_PROTOCOL
*ShellParameters
,
436 IN EFI_SHELL_PROTOCOL
*Shell
439 SHELL_STATUS ShellStatus
;
441 LIST_ENTRY
*ParamPackage
;
443 CONST CHAR16
*ValueStr
;
445 ShellStatus
= SHELL_SUCCESS
;
450 // Install the Shell and Shell Parameters Protocols on the driver
451 // image. This is necessary for the initialisation of the Shell
452 // Library to succeed in the next step.
454 Status
= gBS
->InstallMultipleProtocolInterfaces (
456 &gEfiShellProtocolGuid
, Shell
,
457 &gEfiShellParametersProtocolGuid
, ShellParameters
,
460 if (EFI_ERROR (Status
)) {
461 return SHELL_ABORTED
;
465 // Initialise the Shell Library as we are going to use it.
466 // Assert that the return code is EFI_SUCCESS as it should.
467 // To anticipate any change is the codes returned by
468 // ShellInitialize(), leave in case of error.
470 Status
= ShellInitialize ();
471 if (EFI_ERROR (Status
)) {
472 ASSERT_EFI_ERROR (Status
);
473 return SHELL_ABORTED
;
476 Status
= ShellCommandLineParse (ParamList
, &ParamPackage
, NULL
, TRUE
);
477 if (!EFI_ERROR (Status
)) {
478 switch (ShellCommandLineGetCount (ParamPackage
)) {
483 if (!ShellCommandLineGetFlag (ParamPackage
, L
"-i")) {
484 Status
= EFI_INVALID_PARAMETER
;
490 // Case "setfdt file_path" or
491 // "setfdt -i file_path" or
492 // "setfdt file_path -i"
498 Status
= EFI_INVALID_PARAMETER
;
501 if (EFI_ERROR (Status
)) {
502 ShellStatus
= EfiCodeToShellCode (Status
);
505 STRING_TOKEN (STR_SETFDT_ERROR
),
506 mFdtPlatformDxeHiiHandle
,
513 // Update the preferred device path for the FDT if asked for.
516 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
519 STRING_TOKEN (STR_SETFDT_UPDATING
),
520 mFdtPlatformDxeHiiHandle
522 ShellStatus
= UpdateFdtTextDevicePath (Shell
, ValueStr
);
523 if (ShellStatus
!= SHELL_SUCCESS
) {
529 // Run the FDT installation process if asked for.
531 if (ShellCommandLineGetFlag (ParamPackage
, L
"-i")) {
534 STRING_TOKEN (STR_SETFDT_INSTALLING
),
535 mFdtPlatformDxeHiiHandle
537 Status
= RunFdtInstallation ();
538 ShellStatus
= EfiCodeToShellCode (Status
);
539 if (!EFI_ERROR (Status
)) {
542 STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED
),
543 mFdtPlatformDxeHiiHandle
546 if (Status
== EFI_INVALID_PARAMETER
) {
549 STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH
),
550 mFdtPlatformDxeHiiHandle
555 STRING_TOKEN (STR_SETFDT_ERROR
),
556 mFdtPlatformDxeHiiHandle
,
564 gBS
->UninstallMultipleProtocolInterfaces (
566 &gEfiShellProtocolGuid
, Shell
,
567 &gEfiShellParametersProtocolGuid
, ShellParameters
,
570 ShellCommandLineFreeVarList (ParamPackage
);
576 This is the shell command "setfdt" help handler function. This
577 function returns the formatted help for the "setfdt" command.
578 The format matchs that in Appendix B of the revision 2.1 of the
579 UEFI Shell Specification.
581 @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
582 @param[in] Language The pointer to the language string to use.
584 @return CHAR16* Pool allocated help string, must be freed by caller.
589 ShellDynCmdSetFdtGetHelp (
590 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
591 IN CONST CHAR8
*Language
595 // This allocates memory. The caller has to free the allocated memory.
597 return HiiGetString (
598 mFdtPlatformDxeHiiHandle
,
599 STRING_TOKEN (STR_GET_HELP_SETFDT
),
605 Update the text device path stored in the "Fdt" UEFI variable given
606 an EFI Shell file path or a text device path.
608 This function is a subroutine of the ShellDynCmdSetFdtHandler() function
609 to make its code easier to read.
611 @param[in] Shell The instance of the shell protocol used in the
612 context of processing the "setfdt" command.
613 @param[in] FilePath EFI Shell path or the device path to the FDT file.
615 @return SHELL_SUCCESS The text device path was succesfully updated.
616 @return SHELL_INVALID_PARAMETER The Shell file path is not valid.
617 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
618 @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
619 @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
620 @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
621 @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
622 @return SHELL_NOT_FOUND Device path to text protocol not found.
623 @return SHELL_ABORTED Operation aborted.
628 UpdateFdtTextDevicePath (
629 IN EFI_SHELL_PROTOCOL
*Shell
,
630 IN CONST CHAR16
*FilePath
634 EFI_DEVICE_PATH
*DevicePath
;
635 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
*EfiDevicePathToTextProtocol
;
636 CHAR16
*TextDevicePath
;
637 CHAR16
*FdtVariableValue
;
638 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
639 SHELL_STATUS ShellStatus
;
641 ASSERT (FilePath
!= NULL
);
642 TextDevicePath
= NULL
;
643 FdtVariableValue
= NULL
;
645 DevicePath
= Shell
->GetDevicePathFromFilePath (FilePath
);
646 if (DevicePath
!= NULL
) {
647 Status
= gBS
->LocateProtocol (
648 &gEfiDevicePathToTextProtocolGuid
,
650 (VOID
**)&EfiDevicePathToTextProtocol
652 if (EFI_ERROR (Status
)) {
656 TextDevicePath
= EfiDevicePathToTextProtocol
->ConvertDevicePathToText (
661 if (TextDevicePath
== NULL
) {
662 Status
= EFI_OUT_OF_RESOURCES
;
665 FdtVariableValue
= TextDevicePath
;
668 // Try to convert back the EFI Device Path String into a EFI device Path
669 // to ensure the format is valid
671 Status
= gBS
->LocateProtocol (
672 &gEfiDevicePathFromTextProtocolGuid
,
674 (VOID
**)&EfiDevicePathFromTextProtocol
676 if (EFI_ERROR (Status
)) {
680 DevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (
683 if (DevicePath
== NULL
) {
684 Status
= EFI_INVALID_PARAMETER
;
687 FdtVariableValue
= (CHAR16
*)FilePath
;
690 Status
= gRT
->SetVariable (
693 EFI_VARIABLE_RUNTIME_ACCESS
|
694 EFI_VARIABLE_NON_VOLATILE
|
695 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
696 StrSize (FdtVariableValue
),
701 ShellStatus
= EfiCodeToShellCode (Status
);
702 if (!EFI_ERROR (Status
)) {
705 STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED
),
706 mFdtPlatformDxeHiiHandle
,
710 if (Status
== EFI_INVALID_PARAMETER
) {
713 STRING_TOKEN (STR_SETFDT_INVALID_PATH
),
714 mFdtPlatformDxeHiiHandle
,
720 STRING_TOKEN (STR_SETFDT_ERROR
),
721 mFdtPlatformDxeHiiHandle
,
727 if (DevicePath
!= NULL
) {
728 FreePool (DevicePath
);
730 if (TextDevicePath
!= NULL
) {
731 FreePool (TextDevicePath
);
738 Transcode one of the EFI return code used by the model into an EFI Shell return code.
740 @param[in] Status EFI return code.
742 @return Transcoded EFI Shell return code.
751 SHELL_STATUS ShellStatus
;
755 ShellStatus
= SHELL_SUCCESS
;
758 case EFI_INVALID_PARAMETER
:
759 ShellStatus
= SHELL_INVALID_PARAMETER
;
762 case EFI_UNSUPPORTED
:
763 ShellStatus
= SHELL_UNSUPPORTED
;
766 case EFI_DEVICE_ERROR
:
767 ShellStatus
= SHELL_DEVICE_ERROR
;
770 case EFI_WRITE_PROTECTED
:
771 case EFI_SECURITY_VIOLATION
:
772 ShellStatus
= SHELL_ACCESS_DENIED
;
775 case EFI_OUT_OF_RESOURCES
:
776 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
780 ShellStatus
= SHELL_NOT_FOUND
;
784 ShellStatus
= SHELL_ABORTED
;