diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc index 10037c938eb82..0570eba6ed0c5 100644 --- a/ArmVirtPkg/ArmVirt.dsc.inc +++ b/ArmVirtPkg/ArmVirt.dsc.inc @@ -382,6 +382,7 @@ ShellPkg/Application/Shell/Shell.inf { ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf diff --git a/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.c b/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.c new file mode 100644 index 0000000000000..af5a0a56ea772 --- /dev/null +++ b/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.c @@ -0,0 +1,269 @@ +/** @file + Provides initrd command to load a Linux initrd via its GUIDed vendor media + path + + Copyright (c) 2020, Arm, Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#pragma pack(1) +typedef struct { + VENDOR_DEVICE_PATH VenMediaNode; + EFI_DEVICE_PATH_PROTOCOL EndNode; +} SINGLE_NODE_VENDOR_MEDIA_DEVPATH; +#pragma pack() + +STATIC CONST CHAR16 mFileName[] = L""; +STATIC EFI_HII_HANDLE gLinuxInitrdShellCommandHiiHandle; +STATIC SHELL_FILE_HANDLE mInitrdFileHandle; +STATIC EFI_HANDLE mInitrdLoadFile2Handle; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-u", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Get the filename to get help text from if not using HII. + + @retval The filename. +**/ +STATIC +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameInitrd ( + VOID + ) +{ + return mFileName; +} + +STATIC CONST SINGLE_NODE_VENDOR_MEDIA_DEVPATH mInitrdDevicePath = { + { + { + MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH) } + }, + { + // LINUX_EFI_INITRD_MEDIA_GUID + 0x5568e427, 0x68fc, 0x4f3d, + { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } + } + }, + + { + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL) } + } +}; + +STATIC +EFI_STATUS +EFIAPI +InitrdLoadFile2 ( + IN EFI_LOAD_FILE2_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ) +{ + UINT64 InitrdSize; + EFI_STATUS Status; + + if (BootPolicy) { + return EFI_UNSUPPORTED; + } + + if (BufferSize == NULL || !IsDevicePathValid (FilePath, 0)) { + return EFI_INVALID_PARAMETER; + } + + if (FilePath->Type != END_DEVICE_PATH_TYPE || + FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE || + mInitrdFileHandle == NULL) { + return EFI_NOT_FOUND; + } + + Status = gEfiShellProtocol->GetFileSize (mInitrdFileHandle, &InitrdSize); + ASSERT_EFI_ERROR(Status); + + if (Buffer == NULL || *BufferSize < InitrdSize) { + *BufferSize = InitrdSize; + return EFI_BUFFER_TOO_SMALL; + } + + return gEfiShellProtocol->ReadFile (mInitrdFileHandle, BufferSize, Buffer); +} + +STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = { + InitrdLoadFile2, +}; + +/** + Function for 'initrd' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunInitrd ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + CONST CHAR16 *Filename; + SHELL_STATUS ShellStatus; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + Status = ShellInitialize (); + ASSERT_EFI_ERROR (Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), + gLinuxInitrdShellCommandHiiHandle, L"initrd", ProblemParam); + FreePool (ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount (Package) > 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), + gLinuxInitrdShellCommandHiiHandle, L"initrd"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount (Package) < 2) { + if (ShellCommandLineGetFlag(Package, L"-u")) { + if (mInitrdFileHandle != NULL) { + ShellCloseFile (&mInitrdFileHandle); + mInitrdFileHandle = NULL; + } + if (mInitrdLoadFile2Handle != NULL) { + gBS->UninstallMultipleProtocolInterfaces (mInitrdLoadFile2Handle, + &gEfiDevicePathProtocolGuid, &mInitrdDevicePath, + &gEfiLoadFile2ProtocolGuid, &mInitrdLoadFile2, + NULL); + mInitrdLoadFile2Handle = NULL; + } + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), + gLinuxInitrdShellCommandHiiHandle, L"initrd"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + Param = ShellCommandLineGetRawValue (Package, 1); + ASSERT (Param != NULL); + + Filename = ShellFindFilePath (Param); + if (Filename == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), + gLinuxInitrdShellCommandHiiHandle, L"initrd", Param); + ShellStatus = SHELL_NOT_FOUND; + } else { + if (mInitrdFileHandle != NULL) { + ShellCloseFile (&mInitrdFileHandle); + mInitrdFileHandle = NULL; + } + Status = ShellOpenFileByName (Filename, &mInitrdFileHandle, + EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), + gLinuxInitrdShellCommandHiiHandle, L"initrd", Param); + ShellStatus = SHELL_NOT_FOUND; + } + if (mInitrdLoadFile2Handle == NULL) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mInitrdLoadFile2Handle, + &gEfiDevicePathProtocolGuid, &mInitrdDevicePath, + &gEfiLoadFile2ProtocolGuid, &mInitrdLoadFile2, + NULL); + ASSERT_EFI_ERROR (Status); + } + } + } + } + + return ShellStatus; +} + +/** + Constructor for the 'initrd' UEFI Shell command library + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +LinuxInitrdShellCommandLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gLinuxInitrdShellCommandHiiHandle = HiiAddPackages (&gShellInitrdHiiGuid, + gImageHandle, LinuxInitrdShellCommandLibStrings, NULL); + if (gLinuxInitrdShellCommandHiiHandle == NULL) { + return EFI_DEVICE_ERROR; + } + + ShellCommandRegisterCommandName (L"initrd", ShellCommandRunInitrd, + ShellCommandGetManFileNameInitrd, 0, L"initrd", TRUE, + gLinuxInitrdShellCommandHiiHandle, STRING_TOKEN(STR_GET_HELP_INITRD)); + + return EFI_SUCCESS; +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Always returned. +**/ +EFI_STATUS +EFIAPI +LinuxInitrdShellCommandLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gLinuxInitrdShellCommandHiiHandle != NULL) { + HiiRemovePackages (gLinuxInitrdShellCommandHiiHandle); + } + + if (mInitrdLoadFile2Handle != NULL) { + gBS->UninstallMultipleProtocolInterfaces (mInitrdLoadFile2Handle, + &gEfiDevicePathProtocolGuid, &mInitrdDevicePath, + &gEfiLoadFile2ProtocolGuid, &mInitrdLoadFile2, + NULL); + } + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf b/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf new file mode 100644 index 0000000000000..ed8a0ca85e85b --- /dev/null +++ b/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf @@ -0,0 +1,49 @@ +## @file +# Provides initrd command to load a Linux initrd via its GUIDed vendor media +# path +# +# Copyright (c) 2020, Arm, Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = LinuxInitrdShellCommandLib + FILE_GUID = 2f30da26-f51b-4b6f-85c4-31873c281bca + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = LinuxInitrdShellCommandLibConstructor + DESTRUCTOR = LinuxInitrdShellCommandLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources.common] + LinuxInitrdShellCommandLib.c + LinuxInitrdShellCommandLib.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + DebugLib + DevicePathLib + HiiLib + MemoryAllocationLib + ShellCommandLib + ShellLib + UefiBootServicesTableLib + +[Protocols] + gEfiLoadFile2ProtocolGuid ## SOMETIMES_PRODUCES + +[Guids] + gShellInitrdHiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.uni b/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.uni new file mode 100644 index 0000000000000..d4fe798b1ea2f --- /dev/null +++ b/OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.uni @@ -0,0 +1,37 @@ +// /** +// +// Copyright (c) 2020, Arm, Ltd. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// LinuxInitrdShellCommandLib.uni +// +// Abstract: +// +// String definitions for 'initrd' UEFI Shell command +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments.\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments.\r\n" +#string STR_GEN_FIND_FAIL #language en-US "%H%s%N: File not found - '%H%s%N'\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" + +#string STR_GET_HELP_INITRD #language en-US "" +".TH vol 0 "Registers or unregisters a file as Linux initrd."\r\n" +".SH NAME\r\n" +"Registers or unregisters a file as Linux initrd.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"initrd \r\n" +"initrd -u\r\n" +".SH OPTIONS\r\n" +" \r\n" +" FileName - Specifies a file to register as initrd.\r\n" +" -u - Unregisters any previously registered initrd files.\r\n" diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index d5fee805ef4a1..437b1d2488953 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -86,6 +86,7 @@ gMicrosoftVendorGuid = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b}} gEfiLegacyBiosGuid = {0x2E3044AC, 0x879F, 0x490F, {0x97, 0x60, 0xBB, 0xDF, 0xAF, 0x69, 0x5F, 0x50}} gEfiLegacyDevOrderVariableGuid = {0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52}} + gShellInitrdHiiGuid = {0xeda423e2, 0xf434, 0x4cdd, {0x8d, 0x5d, 0xb5, 0xb0, 0xc7, 0x2c, 0x56, 0xd9}} [Protocols] gVirtioDeviceProtocolGuid = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}} diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 9a60eb8fe2b07..3ffaa9b3388f6 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -817,6 +817,7 @@ ShellPkg/Application/Shell/Shell.inf { ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 1d1480b50b029..691ba204a6ac1 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -830,6 +830,7 @@ ShellPkg/Application/Shell/Shell.inf { ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index c287a436f8ec3..8df5390de132d 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -828,6 +828,7 @@ ShellPkg/Application/Shell/Shell.inf { ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|OvmfPkg/Library/LinuxInitrdShellCommandLib/LinuxInitrdShellCommandLib.inf NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf