/** @file Copyright (c) 2015, ARM Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "FdtPlatform.h" STATIC CONST SHELL_PARAM_ITEM ParamList[] = { {L"-i", TypeFlag }, {NULL , TypeMax } }; /** Display FDT device paths. Display in text form the device paths used to install the FDT from the highest to the lowest priority. **/ STATIC VOID DisplayFdtDevicePaths ( VOID ) { EFI_STATUS Status; UINTN DataSize; CHAR16 *TextDevicePath; CHAR16 *TextDevicePaths; CHAR16 *TextDevicePathSeparator; ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_DEVICE_PATH_LIST), mFdtPlatformDxeHiiHandle ); if (FeaturePcdGet (PcdOverridePlatformFdt)) { DataSize = 0; Status = gRT->GetVariable ( L"Fdt", &gFdtVariableGuid, NULL, &DataSize, NULL ); // // Keep going only if the "Fdt" variable is defined. // if (Status == EFI_BUFFER_TOO_SMALL) { TextDevicePath = AllocatePool (DataSize); if (TextDevicePath == NULL) { return; } Status = gRT->GetVariable ( L"Fdt", &gFdtVariableGuid, NULL, &DataSize, TextDevicePath ); if (!EFI_ERROR (Status)) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_DEVICE_PATH), mFdtPlatformDxeHiiHandle, TextDevicePath ); } FreePool (TextDevicePath); } } // // Loop over the device path list provided by "PcdFdtDevicePaths". The device // paths are in text form and separated by a semi-colon. // TextDevicePaths = AllocateCopyPool ( StrSize ((CHAR16*)PcdGetPtr (PcdFdtDevicePaths)), (CHAR16*)PcdGetPtr (PcdFdtDevicePaths) ); if (TextDevicePaths == NULL) { return; } for (TextDevicePath = TextDevicePaths; *TextDevicePath != L'\0' ; ) { TextDevicePathSeparator = StrStr (TextDevicePath, L";"); if (TextDevicePathSeparator != NULL) { *TextDevicePathSeparator = L'\0'; } ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_DEVICE_PATH), mFdtPlatformDxeHiiHandle, TextDevicePath ); if (TextDevicePathSeparator == NULL) { break; } TextDevicePath = TextDevicePathSeparator + 1; } FreePool (TextDevicePaths); } /** Update the text device path stored in the "Fdt" UEFI variable given an EFI Shell file path or a text device path. This function is a subroutine of the ShellDynCmdSetFdtHandler() function to make its code easier to read. @param[in] Shell The instance of the shell protocol used in the context of processing the "setfdt" command. @param[in] FilePath EFI Shell path or the device path to the FDT file. @return SHELL_SUCCESS The text device path was succesfully updated. @return SHELL_INVALID_PARAMETER The Shell file path is not valid. @return SHELL_OUT_OF_RESOURCES A memory allocation failed. @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure. @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only. @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted. @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation. @return SHELL_NOT_FOUND Device path to text protocol not found. @return SHELL_ABORTED Operation aborted. **/ STATIC SHELL_STATUS UpdateFdtTextDevicePath ( IN EFI_SHELL_PROTOCOL *Shell, IN CONST CHAR16 *FilePath ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *EfiDevicePathToTextProtocol; CHAR16 *TextDevicePath; CHAR16 *FdtVariableValue; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; SHELL_STATUS ShellStatus; ASSERT (FilePath != NULL); DevicePath = NULL; TextDevicePath = NULL; FdtVariableValue = NULL; if (*FilePath != L'\0') { DevicePath = Shell->GetDevicePathFromFilePath (FilePath); if (DevicePath != NULL) { Status = gBS->LocateProtocol ( &gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&EfiDevicePathToTextProtocol ); if (EFI_ERROR (Status)) { goto Error; } TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText ( DevicePath, FALSE, FALSE ); if (TextDevicePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } FdtVariableValue = TextDevicePath; } else { // // Try to convert back the EFI Device Path String into a EFI device Path // to ensure the format is valid // Status = gBS->LocateProtocol ( &gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol ); if (EFI_ERROR (Status)) { goto Error; } DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ( FilePath ); if (DevicePath == NULL) { Status = EFI_INVALID_PARAMETER; goto Error; } FdtVariableValue = (CHAR16*)FilePath; } } Status = gRT->SetVariable ( (CHAR16*)L"Fdt", &gFdtVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS , (FdtVariableValue != NULL) ? StrSize (FdtVariableValue) : 0, FdtVariableValue ); Error: ShellStatus = EfiCodeToShellCode (Status); if (!EFI_ERROR (Status)) { if (FdtVariableValue != NULL) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED), mFdtPlatformDxeHiiHandle, FdtVariableValue ); } else { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_UPDATE_DELETED), mFdtPlatformDxeHiiHandle ); } } else { if (Status == EFI_INVALID_PARAMETER) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_INVALID_PATH), mFdtPlatformDxeHiiHandle, FilePath ); } else { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_ERROR), mFdtPlatformDxeHiiHandle, Status ); } } if (DevicePath != NULL) { FreePool (DevicePath); } if (TextDevicePath != NULL) { FreePool (TextDevicePath); } return ShellStatus; } /** This is the shell command "setfdt" handler function. This function handles the command when it is invoked in the shell. @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. @param[in] SystemTable The pointer to the UEFI system table. @param[in] ShellParameters The parameters associated with the command. @param[in] Shell The instance of the shell protocol used in the context of processing this command. @return SHELL_SUCCESS The operation was successful. @return SHELL_ABORTED Operation aborted due to internal error. @return SHELL_INVALID_PARAMETER The parameters of the command are not valid. @return SHELL_INVALID_PARAMETER The EFI Shell file path is not valid. @return SHELL_NOT_FOUND Failed to locate a protocol or a file. @return SHELL_UNSUPPORTED Device path not supported. @return SHELL_OUT_OF_RESOURCES A memory allocation failed. @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure. @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only. @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted. @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation. **/ SHELL_STATUS EFIAPI ShellDynCmdSetFdtHandler ( IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, IN EFI_SYSTEM_TABLE *SystemTable, IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, IN EFI_SHELL_PROTOCOL *Shell ) { SHELL_STATUS ShellStatus; EFI_STATUS Status; LIST_ENTRY *ParamPackage; BOOLEAN FilePath; CONST CHAR16 *ValueStr; CHAR16 *TextDevicePath; ShellStatus = SHELL_SUCCESS; ParamPackage = NULL; FilePath = FALSE; // // Install the Shell and Shell Parameters Protocols on the driver // image. This is necessary for the initialisation of the Shell // Library to succeed in the next step. // Status = gBS->InstallMultipleProtocolInterfaces ( &gImageHandle, &gEfiShellProtocolGuid, Shell, &gEfiShellParametersProtocolGuid, ShellParameters, NULL ); if (EFI_ERROR (Status)) { return SHELL_ABORTED; } // // Initialise the Shell Library as we are going to use it. // Assert that the return code is EFI_SUCCESS as it should. // To anticipate any change is the codes returned by // ShellInitialize(), leave in case of error. // Status = ShellInitialize (); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return SHELL_ABORTED; } Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE); if (!EFI_ERROR (Status)) { switch (ShellCommandLineGetCount (ParamPackage)) { case 1: // // Case "setfdt" or "setfdt -i" // if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) { DisplayFdtDevicePaths (); } break; case 2: // // Case "setfdt file_path" or // "setfdt -i file_path" or // "setfdt file_path -i" // FilePath = TRUE; break; default: Status = EFI_INVALID_PARAMETER; } } if (EFI_ERROR (Status)) { ShellStatus = EfiCodeToShellCode (Status); ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_ERROR), mFdtPlatformDxeHiiHandle, Status ); goto Error; } // // Update the preferred device path for the FDT if asked for. // if (FilePath) { ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1); ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_UPDATING), mFdtPlatformDxeHiiHandle ); ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr); if (ShellStatus != SHELL_SUCCESS) { goto Error; } } // // Run the FDT installation process if asked for. // if (ShellCommandLineGetFlag (ParamPackage, L"-i")) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_INSTALLING), mFdtPlatformDxeHiiHandle ); Status = RunFdtInstallation (&TextDevicePath); ShellStatus = EfiCodeToShellCode (Status); if (!EFI_ERROR (Status)) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED), mFdtPlatformDxeHiiHandle, TextDevicePath ); FreePool (TextDevicePath); } else { if (Status == EFI_INVALID_PARAMETER) { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH), mFdtPlatformDxeHiiHandle ); } else { ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_SETFDT_ERROR), mFdtPlatformDxeHiiHandle, Status ); } DisplayFdtDevicePaths (); } } Error: gBS->UninstallMultipleProtocolInterfaces ( gImageHandle, &gEfiShellProtocolGuid, Shell, &gEfiShellParametersProtocolGuid, ShellParameters, NULL ); ShellCommandLineFreeVarList (ParamPackage); return ShellStatus; } /** This is the shell command "setfdt" help handler function. This function returns the formatted help for the "setfdt" command. The format matchs that in Appendix B of the revision 2.1 of the UEFI Shell Specification. @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL. @param[in] Language The pointer to the language string to use. @return CHAR16* Pool allocated help string, must be freed by caller. **/ CHAR16* EFIAPI ShellDynCmdSetFdtGetHelp ( IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, IN CONST CHAR8 *Language ) { // // This allocates memory. The caller has to free the allocated memory. // return HiiGetString ( mFdtPlatformDxeHiiHandle, STRING_TOKEN (STR_GET_HELP_SETFDT), Language ); }