Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> Reviewed-by: Ronald Cron <Ronald.Cron@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17302 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			469 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			469 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
 | 
						|
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#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
 | 
						|
                );
 | 
						|
}
 |