From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:400c:c09::229; helo=mail-wm0-x229.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-wm0-x229.google.com (mail-wm0-x229.google.com [IPv6:2a00:1450:400c:c09::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 9D36020347134 for ; Mon, 20 Nov 2017 03:33:13 -0800 (PST) Received: by mail-wm0-x229.google.com with SMTP id v186so17956780wma.2 for ; Mon, 20 Nov 2017 03:37:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=n4Fk1PGKDteCjO04GLJ8ByaaSegow5Zh66ChqlmjwX4=; b=Fux628us6iNG28vyLsJRC7hQzc6p2Vo7s0bVlTCd5TIpls3nSRDz5HXe2LDhvYakDo eFSbLJR575kGH8YR3EH4ceIPUZUWxV4hLuWPLkQbtrdEE4QcC/iRWavTUXhURehTwATi v8Z2Nvm52D8SZuZ7nQxaMDyetsTVyDk+kkmz0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=n4Fk1PGKDteCjO04GLJ8ByaaSegow5Zh66ChqlmjwX4=; b=B2T3YSF2HkXra+O9gQEk3jWbL7JDQL0bqabzHa3HhyuyfzenkegRn/i0CjVgxVgUCT fr+wnezF2xEnPzzjKclbYJ1MTpReLEuqk2cW5LUgWH8LRCz4PNTTvpqvMgaci60Jy4r4 NFHxKp+p63okj9rxgUumWueviGDkyNLJrtYmjxTbjqfIY7CPk695U+TboEpS9bCCZM+n cLeH25xYR/13o5VEdNrJM4BdAPzfBfGTupVoguXpO8Xb+1PDRT4+caTM4uKn21cVHXXZ sk7FhmHzRo9QbAgBEMG5rzesyoZi8w8q5RpUL3uCSAMGKcl6ottEv6XqNeR8Z1M2Y/7x aW/A== X-Gm-Message-State: AJaThX5GOCclq6ADCg4VjrAzxtgj3NUr/hTG1yiO1KF0t8YEe+yC4BnB ZYxvi+1T5HxLHU4SvBqDz+HPrtGSIfQ= X-Google-Smtp-Source: AGs4zMYwBEh7+Euedea9hCG9ktPiB6rDhkBar53NA/xy6GQjtoJNJiMHgid5DV1GW+wFW7rFoV85jQ== X-Received: by 10.28.96.195 with SMTP id u186mr6885986wmb.121.1511177844357; Mon, 20 Nov 2017 03:37:24 -0800 (PST) Received: from localhost.localdomain ([154.145.25.106]) by smtp.gmail.com with ESMTPSA id d4sm14760181wmh.35.2017.11.20.03.37.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Nov 2017 03:37:23 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org Cc: leif.lindholm@linaro.org, Ard Biesheuvel Date: Mon, 20 Nov 2017 11:37:12 +0000 Message-Id: <20171120113714.21856-3-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171120113714.21856-1-ard.biesheuvel@linaro.org> References: <20171120113714.21856-1-ard.biesheuvel@linaro.org> Subject: [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2 X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Nov 2017 11:33:14 -0000 Import FdtPlatformDxe from EmbeddedPkg into Platform/ARM, given that it is not used anywhere else, nor should it be. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel --- Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c | 461 +++++++++++++++++++ Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h | 174 ++++++++ Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec | 31 ++ Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf | 65 +++ Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni | 109 +++++ Platform/ARM/Drivers/FdtPlatformDxe/README.txt | 72 +++ Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c | 279 ++++++++++++ Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c | 468 ++++++++++++++++++++ 8 files changed, 1659 insertions(+) diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c new file mode 100644 index 000000000000..b4be2a078991 --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c @@ -0,0 +1,461 @@ +/** @file + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + 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" + +#include +#include +#include + +#include + +// +// Internal variables +// + +STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = { + L"setfdt", // Name of the command + ShellDynCmdSetFdtHandler, // Handler + ShellDynCmdSetFdtGetHelp // GetHelp +}; + +STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolDumpFdt = { + L"dumpfdt", // Name of the command + ShellDynCmdDumpFdtHandler, // Handler + ShellDynCmdDumpFdtGetHelp // GetHelp +}; + +STATIC CONST EFI_GUID mFdtPlatformDxeHiiGuid = { + 0x8afa7610, 0x62b1, 0x46aa, + {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c} + }; + +EFI_HANDLE mFdtPlatformDxeHiiHandle; + +/** + Install the FDT specified by its device path in text form. + + @param[in] TextDevicePath Device path of the FDT to install in text form + + @retval EFI_SUCCESS The FDT was installed. + @retval EFI_NOT_FOUND Failed to locate a protocol or a file. + @retval EFI_INVALID_PARAMETER Invalid device path. + @retval EFI_UNSUPPORTED Device path not supported. + @retval EFI_OUT_OF_RESOURCES An allocation failed. +**/ +STATIC +EFI_STATUS +InstallFdt ( + IN CONST CHAR16* TextDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; + EFI_DEVICE_PATH *DevicePath; + EFI_PHYSICAL_ADDRESS FdtBlobBase; + UINTN FdtBlobSize; + UINTN NumPages; + EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase; + + Status = gBS->LocateProtocol ( + &gEfiDevicePathFromTextProtocolGuid, + NULL, + (VOID **)&EfiDevicePathFromTextProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n")); + return Status; + } + + DevicePath = (EFI_DEVICE_PATH*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (TextDevicePath); + if (DevicePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Load the FDT given its device path. + // This operation may fail if the device path is not supported. + // + FdtBlobBase = 0; + NumPages = 0; + Status = BdsLoadImage (DevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // Ensure that the FDT header is valid and that the Size of the Device Tree + // is smaller than the size of the read file + // + if (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) != 0 || + (UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) > FdtBlobSize) { + DEBUG ((EFI_D_ERROR, "InstallFdt() - loaded FDT binary image seems corrupt\n")); + Status = EFI_LOAD_ERROR; + goto Error; + } + + // + // Store the FDT as Runtime Service Data to prevent the Kernel from + // overwritting its data. + // + NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize); + Status = gBS->AllocatePages ( + AllocateAnyPages, EfiRuntimeServicesData, + NumPages, &FdtConfigurationTableBase + ); + if (EFI_ERROR (Status)) { + goto Error; + } + CopyMem ( + (VOID*)(UINTN)FdtConfigurationTableBase, + (VOID*)(UINTN)FdtBlobBase, + FdtBlobSize + ); + + // + // Install the FDT into the Configuration Table + // + Status = gBS->InstallConfigurationTable ( + &gFdtTableGuid, + (VOID*)(UINTN)FdtConfigurationTableBase + ); + if (EFI_ERROR (Status)) { + gBS->FreePages (FdtConfigurationTableBase, NumPages); + } + +Error: + if (FdtBlobBase != 0) { + gBS->FreePages (FdtBlobBase, NumPages); + } + FreePool (DevicePath); + + return Status; +} + +/** + Main entry point of the FDT platform driver. + + @param[in] ImageHandle The firmware allocated handle for the present driver + UEFI image. + @param[in] *SystemTable A pointer to the EFI System table. + + @retval EFI_SUCCESS The driver was initialized. + @retval EFI_OUT_OF_RESOURCES The "End of DXE" event could not be allocated or + there was not enough memory in pool to install + the Shell Dynamic Command protocol. + @retval EFI_LOAD_ERROR Unable to add the HII package. + +**/ +EFI_STATUS +FdtPlatformEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + // + // Install the Device Tree from its expected location + // + Status = RunFdtInstallation (NULL); + + if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) { + // + // Register the strings for the user interface in the HII Database. + // This shows the way to the multi-language support, even if + // only the English language is actually supported. The strings to register + // are stored in the "ShellSetFdtStrings[]" array. This array is + // built by the building process from the "*.uni" file associated to + // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build + // folder under your package's DEBUG folder and you will find the array + // defined in a xxxStrDefs.h file. + // + mFdtPlatformDxeHiiHandle = HiiAddPackages ( + &mFdtPlatformDxeHiiGuid, + ImageHandle, + FdtPlatformDxeStrings, + NULL + ); + } + + // + // If the development features are enabled, install the dynamic shell + // command "setfdt" to be able to define a device path for the FDT + // that has precedence over the device paths defined by + // "PcdFdtDevicePaths". + // + + if (FeaturePcdGet (PcdOverridePlatformFdt)) { + if (mFdtPlatformDxeHiiHandle != NULL) { + // We install dynamic EFI command on separate handles as we cannot register + // more than one protocol of the same protocol interface on the same handle. + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiShellDynamicCommandProtocolGuid, + &mShellDynCmdProtocolSetFdt, + NULL + ); + if (EFI_ERROR (Status)) { + HiiRemovePackages (mFdtPlatformDxeHiiHandle); + } + } else { + Status = EFI_LOAD_ERROR; + } + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_WARN, + "Unable to install \"setfdt\" EFI Shell command - %r \n", + Status + )); + } + } + + if (FeaturePcdGet (PcdDumpFdtShellCommand)) { + if (mFdtPlatformDxeHiiHandle != NULL) { + // We install dynamic EFI command on separate handles as we cannot register + // more than one protocol of the same protocol interface on the same handle. + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiShellDynamicCommandProtocolGuid, + &mShellDynCmdProtocolDumpFdt, + NULL + ); + if (EFI_ERROR (Status)) { + HiiRemovePackages (mFdtPlatformDxeHiiHandle); + } + } else { + Status = EFI_LOAD_ERROR; + } + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_WARN, + "Unable to install \"dumpfdt\" EFI Shell command - %r \n", + Status + )); + } + } + + return Status; +} + +/** + Run the FDT installation process. + + Loop in priority order over the device paths from which the FDT has + been asked to be retrieved for. For each device path, try to install + the FDT. Stop as soon as an installation succeeds. + + @param[in] SuccessfullDevicePath If not NULL, address where to store the + pointer to the text device path from + which the FDT was successfully retrieved. + Not used if the FDT installation failed. + The returned address is the address of + an allocated buffer that has to be + freed by the caller. + + @retval EFI_SUCCESS The FDT was installed. + @retval EFI_NOT_FOUND Failed to locate a protocol or a file. + @retval EFI_INVALID_PARAMETER Invalid device path. + @retval EFI_UNSUPPORTED Device path not supported. + @retval EFI_OUT_OF_RESOURCES An allocation failed. + +**/ +EFI_STATUS +RunFdtInstallation ( + OUT CHAR16 **SuccessfullDevicePath + ) +{ + EFI_STATUS Status; + UINTN DataSize; + CHAR16 *TextDevicePath; + CHAR16 *TextDevicePathStart; + CHAR16 *TextDevicePathSeparator; + UINTN TextDevicePathLen; + + TextDevicePath = NULL; + // + // For development purpose, if enabled through the "PcdOverridePlatformFdt" + // feature PCD, try first to install the FDT specified by the device path in + // text form stored in the "Fdt" UEFI variable. + // + 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) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + Status = gRT->GetVariable ( + L"Fdt", + &gFdtVariableGuid, + NULL, + &DataSize, + TextDevicePath + ); + if (EFI_ERROR (Status)) { + FreePool (TextDevicePath); + goto Error; + } + + Status = InstallFdt (TextDevicePath); + if (!EFI_ERROR (Status)) { + DEBUG (( + EFI_D_WARN, + "Installation of the FDT using the device path <%s> completed.\n", + TextDevicePath + )); + goto Done; + } + DEBUG (( + EFI_D_ERROR, + "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n", + Status + )); + FreePool (TextDevicePath); + } + } + + // + // Loop over the device path list provided by "PcdFdtDevicePaths". The device + // paths are in text form and separated by a semi-colon. + // + + Status = EFI_NOT_FOUND; + for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths); + *TextDevicePathStart != L'\0' ; ) { + TextDevicePathSeparator = StrStr (TextDevicePathStart, L";"); + + // + // Last device path of the list + // + if (TextDevicePathSeparator == NULL) { + TextDevicePathLen = StrLen (TextDevicePathStart); + } else { + TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart); + } + + TextDevicePath = AllocateCopyPool ( + (TextDevicePathLen + 1) * sizeof (CHAR16), + TextDevicePathStart + ); + if (TextDevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + TextDevicePath[TextDevicePathLen] = L'\0'; + + Status = InstallFdt (TextDevicePath); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n", + TextDevicePath + )); + goto Done; + } + + DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n", + TextDevicePath, Status + )); + FreePool (TextDevicePath); + + if (TextDevicePathSeparator == NULL) { + goto Error; + } + TextDevicePathStart = TextDevicePathSeparator + 1; + } + +Error: +Done: + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status)); + return Status; + } + + if (SuccessfullDevicePath != NULL) { + *SuccessfullDevicePath = TextDevicePath; + } else { + FreePool (TextDevicePath); + } + + return EFI_SUCCESS; +} + +/** + Transcode one of the EFI return code used by the model into an EFI Shell return code. + + @param[in] Status EFI return code. + + @return Transcoded EFI Shell return code. + +**/ +SHELL_STATUS +EfiCodeToShellCode ( + IN EFI_STATUS Status + ) +{ + SHELL_STATUS ShellStatus; + + switch (Status) { + case EFI_SUCCESS : + ShellStatus = SHELL_SUCCESS; + break; + + case EFI_INVALID_PARAMETER : + ShellStatus = SHELL_INVALID_PARAMETER; + break; + + case EFI_UNSUPPORTED : + ShellStatus = SHELL_UNSUPPORTED; + break; + + case EFI_DEVICE_ERROR : + ShellStatus = SHELL_DEVICE_ERROR; + break; + + case EFI_WRITE_PROTECTED : + case EFI_SECURITY_VIOLATION : + ShellStatus = SHELL_ACCESS_DENIED; + break; + + case EFI_OUT_OF_RESOURCES : + ShellStatus = SHELL_OUT_OF_RESOURCES; + break; + + case EFI_NOT_FOUND : + ShellStatus = SHELL_NOT_FOUND; + break; + + default : + ShellStatus = SHELL_ABORTED; + } + + return ShellStatus; +} diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h new file mode 100644 index 000000000000..a631f2847bf5 --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h @@ -0,0 +1,174 @@ +/** @file + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + 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. + +**/ + +#ifndef __FDT_PLATFORM_DXE_H__ +#define __FDT_PLATFORM_DXE_H__ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +extern EFI_HANDLE mFdtPlatformDxeHiiHandle; + +/** + Transcode one of the EFI return code used by the model into an EFI Shell return code. + + @param[in] Status EFI return code. + + @return Transcoded EFI Shell return code. + +**/ +SHELL_STATUS +EfiCodeToShellCode ( + IN EFI_STATUS Status + ); + +/** + Run the FDT installation process. + + Loop in priority order over the device paths from which the FDT has + been asked to be retrieved for. For each device path, try to install + the FDT. Stop as soon as an installation succeeds. + + @param[in] SuccessfullDevicePath If not NULL, address where to store the + pointer to the text device path from + which the FDT was successfully retrieved. + Not used if the FDT installation failed. + The returned address is the address of + an allocated buffer that has to be + freed by the caller. + + @retval EFI_SUCCESS The FDT was installed. + @retval EFI_NOT_FOUND Failed to locate a protocol or a file. + @retval EFI_INVALID_PARAMETER Invalid device path. + @retval EFI_UNSUPPORTED Device path not supported. + @retval EFI_OUT_OF_RESOURCES An allocation failed. + +**/ +EFI_STATUS +RunFdtInstallation ( + OUT CHAR16 **SuccessfullDevicePath + ); + +/** + 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 + ); + +/** + 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 is the shell command "dumpfdt" 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_NOT_FOUND Failed to locate the Device Tree into the EFI Configuration Table + @return SHELL_OUT_OF_RESOURCES A memory allocation failed. + +**/ +SHELL_STATUS +EFIAPI +ShellDynCmdDumpFdtHandler ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN EFI_SHELL_PROTOCOL *Shell + ); + +/** + This is the shell command "dumpfdt" help handler function. This + function returns the formatted help for the "dumpfdt" 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 +ShellDynCmdDumpFdtGetHelp ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN CONST CHAR8 *Language + ); + +#endif /* __FDT_PLATFORM_DXE_H__ */ diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec new file mode 100644 index 000000000000..3faced589504 --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec @@ -0,0 +1,31 @@ +#/** @file +# +# Copyright (c) 2011-2017, ARM Limited. All rights reserved. +# +# 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. +# +#**/ + +[Defines] + DEC_SPECIFICATION = 0x0001001A + PACKAGE_NAME = FdtPlatformDxe + PACKAGE_GUID = ed22c1e5-71cb-48d6-a9d8-c20f8d6b909f + PACKAGE_VERSION = 0.1 + +[Guids] + gFdtPlatformDxeTokenSpaceGuid = { 0xbfcaa0af, 0xedd4, 0x4ce7, { 0xbd, 0xb3, 0x39, 0x15, 0x07, 0x28, 0x65, 0x77 } } + +[PcdsFeatureFlag.common] + # Enable the development specific features + gFdtPlatformDxeTokenSpaceGuid.PcdOverridePlatformFdt|TRUE|BOOLEAN|0x00000001 + # Add 'dumpfdt' EFI Shell command + gFdtPlatformDxeTokenSpaceGuid.PcdDumpFdtShellCommand|TRUE|BOOLEAN|0x00000002 + +[PcdsFixedAtBuild.common, PcdsDynamic.common] + gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths|L""|VOID*|0x00000055 diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf new file mode 100644 index 000000000000..f9a5aee3596e --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf @@ -0,0 +1,65 @@ +#/** @file +# +# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# +# 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. +# +#**/ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = FdtPlatformDxe + MODULE_UNI_FILE = FdtPlatformDxe.uni + FILE_GUID = 4bd726b2-d1c8-4e98-ba08-2bc2ab251daf + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = FdtPlatformEntryPoint + +[Sources.common] + FdtPlatform.c + FdtPlatformDxe.uni + ShellDumpFdt.c + ShellSetFdt.c + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseMemoryLib + BdsLib + DebugLib + DxeServicesTableLib + FdtLib + HiiLib + ShellLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + +[Protocols] + gEfiDevicePathFromTextProtocolGuid + gEfiDevicePathToTextProtocolGuid + gEfiShellDynamicCommandProtocolGuid + +[Guids] + gEfiEndOfDxeEventGroupGuid + gFdtTableGuid + gFdtVariableGuid + +[FeaturePcd] + gFdtPlatformDxeTokenSpaceGuid.PcdDumpFdtShellCommand + gFdtPlatformDxeTokenSpaceGuid.PcdOverridePlatformFdt + +[Pcd] + gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni new file mode 100644 index 000000000000..f8bde834841d --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni @@ -0,0 +1,109 @@ +// *++ +// +// Copyright (c) 2014, ARM Ltd. All rights reserved.
+// +// 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. +// +// +// Module Name: +// +// FdtPlatformDxe +// +// Abstract: +// +// String definitions for the EFI Shell 'setfdt' command +// +// Revision History: +// +// --*/ + +/=# + +#langdef en-US "English" + +#string STR_SETFDT_INSTALLING #language en-US "Installing the FDT ...\r\n" +#string STR_SETFDT_INSTALL_SUCCEEDED #language en-US "Installation of\r\n'%s'\r\ncompleted.\r\n" + +#string STR_SETFDT_UPDATING #language en-US "Updating the FDT device path ...\r\n" +#string STR_SETFDT_UPDATE_SUCCEEDED #language en-US "Update of the FDT device path '%s' completed.\r\n" +#string STR_SETFDT_UPDATE_DELETED #language en-US "The UEFI variable "Fdt" was deleted.\r\n" + +#string STR_SETFDT_INVALID_DEVICE_PATH #language en-US "Invalid device path.\r\n" +#string STR_SETFDT_INVALID_PATH #language en-US "The EFI Shell or device file path '%s' is invalid.\r\n" +#string STR_SETFDT_ERROR #language en-US "Error - %r.\r\n" +#string STR_SETFDT_DEVICE_PATH_LIST #language en-US "FDT device paths :\r\n" +#string STR_SETFDT_DEVICE_PATH #language en-US "'%s'\r\n" + +#string STR_GET_HELP_SETFDT #language en-US "" +".TH setfdt 0 "Define and/or install a new Flat Device Tree (FDT) for the platform."\r\n" +".SH NAME\r\n" +"Define and/or re-install a Flat Device Tree (FDT)\r\n" +".SH SYNOPSIS\r\n" +"setfdt [-i] [fdt_path]\r\n" +".SH OPTIONS\r\n" +"-i run the FDT installation process\r\n" +"file_path EFI Shell file path or device path to a FDT\r\n" +"\r\n" +".SH DESCRIPTION\r\n" +"NOTES:\r\n" +"1. If a valid EFI Shell file path is passed to the command, then the\r\n" +" command translates the EFI Shell file path into a device path in the\r\n" +" text form and saves it in the non volatile UEFI variable "Fdt". If\r\n" +" the path to the FDT is a device path in the text form, it is saved as\r\n" +" it is in the non volatile UEFI variable "Fdt". The next time the FDT\r\n" +" installation process is run, it will first try to install the FDT from\r\n" +" the device path specified by the UEFI variable "Fdt".\r\n" +" \r\n +"2. If the option -i is passed to the command, then the FDT installation\r\n" +" process is run. If a path to the FDT is passed to the command as well,\r\n" +" the update of the "Fdt" UEFI variable is done first before to launch\r\n" +" the FDT installation process.\r\n" +" \r\n +".SH RETURNVALUES\r\n" +"SHELL_SUCCESS Operation(s) completed.\r\n" +"SHELL_ABORTED Operation aborted.\r\n" +"SHELL_INVALID_PARAMETER Invalid argument(s).\r\n" +"SHELL_NOT_FOUND Failed to locate a protocol or a file.\r\n" +"SHELL_UNSUPPORTED Device path not supported.\r\n" +"SHELL_OUT_OF_RESOURCES A memory allocation failed.\r\n" +"SHELL_DEVICE ERROR Hardware failure.\r\n" +"SHELL_ACCESS_DENIED Access to the Fdt UEFI variable for modification denied.\r\n" +".SH EXAMPLES\r\n" +"EXAMPLES:\r\n" +"1. Relaunch the FDT installation process :\r\n" +" Shell> setfdt -i\r\n" +" \r\n" +"2. Set the EFI Shell file path 'fs0:\>fdt.dtb' to be the default path\r\n" +" to the FDT :\r\n" +" Shell> setfdt fs0:fdt.dtb\r\n" +" \r\n" +"3. Set a TFTP device path to be the default path to the FDT :\r\n" +" Shell> setfdt MAC(0002f700570b,0x1)/IPv4(192.168.1.1)/fdt.dtb\r\n" +" where . 00:02:f7:00:57:0b is the MAC address of the network\r\n" +" interface card to be used. The 'ifconfig -l' EFI Shell\r\n" +" command allows to get the MAC address of the network\r\n" +" interface cards.\r\n" +" . 192.168.1.1 is the address of the TFTP server.\r\n" +" . fdt.dtb is the file path to the FDT file on the server.\r\n" +"4. Display the FDT device paths from the highest to the lowest\r\n" +" priority :\r\n" +" Shell> setfdt\r\n" +"5. Delete the "Fdt" UEFI variable :\r\n" +" Shell> setfdt ""\r\n" +"\r\n" + +#string STR_GET_HELP_DUMPFDT #language en-US "" +".TH dumpfdt 0 "Dump installed Flat Device Tree (FDT) of the platform."\r\n" +".SH NAME\r\n" +"Dump current Flat Device Tree (FDT)\r\n" +".SH SYNOPSIS\r\n" +"dumpfdt\r\n" +"\r\n" +".SH DESCRIPTION\r\n" +"\r\n" diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/README.txt b/Platform/ARM/Drivers/FdtPlatformDxe/README.txt new file mode 100644 index 000000000000..5f052d9a63aa --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/README.txt @@ -0,0 +1,72 @@ +/** @file + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + 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. + +**/ + +The purpose of the FdtPlatformDxe UEFI driver is to install the Flat Device +Tree (FDT) of the platform the UEFI frimware is running on into the UEFI +Configuration Table. The FDT is identified within the UEFI Configuration +Table by the "gFdtTableGuid" GUID defined in "EmbeddedPkg.dec". + +Once installed, an UEFI application or OS boot loader can get from the UEFI +Configuration Table the FDT of the platform from the "gFdtTableGuid" GUID. + +The installation is done after each boot at the end of the DXE phase, +just before the BDS phase. It is done at the end of the DXE phase to be sure +that all drivers have been dispatched. That way, all UEFI protocols that may +be needed to retrieve the FDT can be made available. It is done before the BDS +phase to be able to provide the FDT during that phase. + +The present driver tries to retrieve the FDT from the device paths defined in the +"gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths" PCD. The "PcdFdtDevicePaths" +PCD contains a list a device paths. The device paths are in the text form and +separated by semi-colons. The present driver tries the device paths in the order +it finds them in the "PcdFdtDevicePaths" PCD as long as he did not install +succesfully a FDT. + +The "PcdFdtDevicePaths" PCD is a dynamic PCD that can be modified during the +DXE phase. This allows for exemple to select the right FDT when a binary is +intended to run on several platforms and/or variants of a platform. + +If the driver manages to download a FDT from one of the device paths mentioned +above then it installs it in the UEFI Configuration table and the run over the +device paths is stopped. + +For development purposes only, if the feature PCD "gFdtPlatformDxeTokenSpaceGuid. +PcdOverridePlatformFdt" is equal to TRUE, then before to try to install the +FDT from the device paths listed in the "PcdFdtDevicePaths" PCD, the present +driver tries to install it using the device path defined by the UEFI variable +"Fdt". If the variable does not exist or the installation using the device path +defined by the UEFI variable fails then the installation proceeds as described +above. + +Furthermore and again for development purposes only, if the feature PCD +"PcdOverridePlatformFdt" is equal to TRUE, the current driver provides the EFI +Shell command "setfdt" to define the location of the FDT by the mean of an EFI +Shell file path (like "fs2:\boot\fdt.dtb") or a device path. + +If the path passed in to the command is a valid EFI Shell file path, the +command translates it into the corresponding device path and stores that +device path in the "Fdt" UEFI variable asking for the variable to be non +volatile. + +If the path passed in to the command is not recognised as a valid EFI +Shell device path, the command handles it as device path and stored +in the "Fdt" UEFI variable as it is. + +Finally, the "-i" option of the "setfdt" command allows to trigger the FDT +installation process. The installation process is completed when the command +returns. The command can be invoked with the "-i" option only and in that +case the "Fdt" UEFI variable is not updated and the command just runs the +FDT installation process. If the command is invoked with the "-i" option and +an EFI Shell file path then first the "Fdt" UEFI variable is updated accordingly +and then the FDT installation process is run. diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c b/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c new file mode 100644 index 000000000000..c7dc8985685b --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c @@ -0,0 +1,279 @@ +/** @file + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + 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" + +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#define PALIGN(p, a) ((void *)(ALIGN ((unsigned long)(p), (a)))) +#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) + +STATIC +UINTN +IsPrintableString ( + IN CONST VOID* data, + IN UINTN len + ) +{ + CONST CHAR8 *s = data; + CONST CHAR8 *ss; + + // Zero length is not + if (len == 0) { + return 0; + } + + // Must terminate with zero + if (s[len - 1] != '\0') { + return 0; + } + + ss = s; + while (*s/* && isprint (*s)*/) { + s++; + } + + // Not zero, or not done yet + if (*s != '\0' || (s + 1 - ss) < len) { + return 0; + } + + return 1; +} + +STATIC +VOID +PrintData ( + IN CONST CHAR8* data, + IN UINTN len + ) +{ + UINTN i; + CONST CHAR8 *p = data; + + // No data, don't print + if (len == 0) + return; + + if (IsPrintableString (data, len)) { + Print (L" = \"%a\"", (const char *)data); + } else if ((len % 4) == 0) { + Print (L" = <"); + for (i = 0; i < len; i += 4) { + Print (L"0x%08x%a", fdt32_to_cpu (GET_CELL (p)), i < (len - 4) ? " " : ""); + } + Print (L">"); + } else { + Print (L" = ["); + for (i = 0; i < len; i++) + Print (L"%02x%a", *p++, i < len - 1 ? " " : ""); + Print (L"]"); + } +} + +STATIC +VOID +DumpFdt ( + IN VOID* FdtBlob + ) +{ + struct fdt_header *bph; + UINT32 off_dt; + UINT32 off_str; + CONST CHAR8* p_struct; + CONST CHAR8* p_strings; + CONST CHAR8* p; + CONST CHAR8* s; + CONST CHAR8* t; + UINT32 tag; + UINTN sz; + UINTN depth; + UINTN shift; + UINT32 version; + + { + // Can 'memreserve' be printed by below code? + INTN num = fdt_num_mem_rsv (FdtBlob); + INTN i, err; + UINT64 addr = 0, size = 0; + + for (i = 0; i < num; i++) { + err = fdt_get_mem_rsv (FdtBlob, i, &addr, &size); + if (err) { + DEBUG ((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i)); + } + else { + Print (L"/memreserve/ \t0x%lx \t0x%lx;\n", addr, size); + } + } + } + + depth = 0; + shift = 4; + + bph = FdtBlob; + off_dt = fdt32_to_cpu (bph->off_dt_struct); + off_str = fdt32_to_cpu (bph->off_dt_strings); + p_struct = (CONST CHAR8*)FdtBlob + off_dt; + p_strings = (CONST CHAR8*)FdtBlob + off_str; + version = fdt32_to_cpu (bph->version); + + p = p_struct; + while ((tag = fdt32_to_cpu (GET_CELL (p))) != FDT_END) { + if (tag == FDT_BEGIN_NODE) { + s = p; + p = PALIGN (p + AsciiStrLen (s) + 1, 4); + + if (*s == '\0') + s = "/"; + + Print (L"%*s%a {\n", depth * shift, L" ", s); + + depth++; + continue; + } + + if (tag == FDT_END_NODE) { + depth--; + + Print (L"%*s};\n", depth * shift, L" "); + continue; + } + + if (tag == FDT_NOP) { + Print (L"%*s// [NOP]\n", depth * shift, L" "); + continue; + } + + if (tag != FDT_PROP) { + Print (L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag); + break; + } + sz = fdt32_to_cpu (GET_CELL (p)); + s = p_strings + fdt32_to_cpu (GET_CELL (p)); + if (version < 16 && sz >= 8) + p = PALIGN (p, 8); + t = p; + + p = PALIGN (p + sz, 4); + + Print (L"%*s%a", depth * shift, L" ", s); + PrintData (t, sz); + Print (L";\n"); + } +} + +/** + This is the shell command "dumpfdt" 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_NOT_FOUND Failed to locate the Device Tree into the EFI Configuration Table + @return SHELL_OUT_OF_RESOURCES A memory allocation failed. + +**/ +SHELL_STATUS +EFIAPI +ShellDynCmdDumpFdtHandler ( + 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; + VOID *FdtBlob; + + ShellStatus = SHELL_SUCCESS; + + // + // 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 = EfiGetSystemConfigurationTable (&gFdtTableGuid, &FdtBlob); + if (EFI_ERROR (Status)) { + Print (L"ERROR: Did not find the Fdt Blob.\n"); + return EfiCodeToShellCode (Status); + } + + DumpFdt (FdtBlob); + + gBS->UninstallMultipleProtocolInterfaces ( + gImageHandle, + &gEfiShellProtocolGuid, Shell, + &gEfiShellParametersProtocolGuid, ShellParameters, + NULL + ); + + return ShellStatus; +} + +/** + This is the shell command "dumpfdt" help handler function. This + function returns the formatted help for the "dumpfdt" 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 +ShellDynCmdDumpFdtGetHelp ( + 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_DUMPFDT), + Language + ); +} diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c b/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c new file mode 100644 index 000000000000..9be23c845593 --- /dev/null +++ b/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c @@ -0,0 +1,468 @@ +/** @file + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + 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 + ); +} -- 2.11.0