2 Provides 'initrd' dynamic UEFI shell command to load a Linux initrd
3 via its GUIDed vendor media path
5 Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/DebugLib.h>
13 #include <Library/DevicePathLib.h>
14 #include <Library/HiiLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/ShellLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiHiiServicesLib.h>
20 #include <Guid/LinuxEfiInitrdMedia.h>
22 #include <Protocol/DevicePath.h>
23 #include <Protocol/HiiPackageList.h>
24 #include <Protocol/LoadFile2.h>
25 #include <Protocol/ShellDynamicCommand.h>
29 VENDOR_DEVICE_PATH VenMediaNode
;
30 EFI_DEVICE_PATH_PROTOCOL EndNode
;
31 } SINGLE_NODE_VENDOR_MEDIA_DEVPATH
;
34 STATIC EFI_HII_HANDLE mLinuxInitrdShellCommandHiiHandle
;
35 STATIC EFI_PHYSICAL_ADDRESS mInitrdFileAddress
;
36 STATIC UINTN mInitrdFileSize
;
37 STATIC EFI_HANDLE mInitrdLoadFile2Handle
;
39 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
44 STATIC CONST SINGLE_NODE_VENDOR_MEDIA_DEVPATH mInitrdDevicePath
= {
47 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
) }
49 LINUX_EFI_INITRD_MEDIA_GUID
51 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
52 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
58 IsOtherInitrdDevicePathAlreadyInstalled (
63 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
66 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)&mInitrdDevicePath
;
67 Status
= gBS
->LocateDevicePath (&gEfiLoadFile2ProtocolGuid
, &DevicePath
,
69 if (EFI_ERROR (Status
)) {
74 // Check whether the existing instance is one that we installed during
75 // a previous invocation.
77 if (Handle
== mInitrdLoadFile2Handle
) {
87 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
88 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
89 IN BOOLEAN BootPolicy
,
90 IN OUT UINTN
*BufferSize
,
91 OUT VOID
*Buffer OPTIONAL
95 return EFI_UNSUPPORTED
;
98 if (BufferSize
== NULL
|| !IsDevicePathValid (FilePath
, 0)) {
99 return EFI_INVALID_PARAMETER
;
102 if (FilePath
->Type
!= END_DEVICE_PATH_TYPE
||
103 FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
||
104 mInitrdFileSize
== 0) {
105 return EFI_NOT_FOUND
;
108 if (Buffer
== NULL
|| *BufferSize
< mInitrdFileSize
) {
109 *BufferSize
= mInitrdFileSize
;
110 return EFI_BUFFER_TOO_SMALL
;
113 ASSERT (mInitrdFileAddress
!= 0);
115 gBS
->CopyMem (Buffer
, (VOID
*)(UINTN
)mInitrdFileAddress
, mInitrdFileSize
);
116 *BufferSize
= mInitrdFileSize
;
120 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
126 UninstallLoadFile2Protocol (
132 if (mInitrdLoadFile2Handle
!= NULL
) {
133 Status
= gBS
->UninstallMultipleProtocolInterfaces (mInitrdLoadFile2Handle
,
134 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
135 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
137 if (!EFI_ERROR (Status
)) {
138 mInitrdLoadFile2Handle
= NULL
;
150 if (mInitrdFileSize
!= 0) {
151 gBS
->FreePages (mInitrdFileAddress
, EFI_SIZE_TO_PAGES (mInitrdFileSize
));
159 IN SHELL_FILE_HANDLE FileHandle
166 Status
= gEfiShellProtocol
->GetFileSize (FileHandle
, &FileSize
);
167 if (EFI_ERROR (Status
)) {
171 if (FileSize
== 0 || FileSize
> MAX_UINTN
) {
172 return EFI_UNSUPPORTED
;
175 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiLoaderData
,
176 EFI_SIZE_TO_PAGES ((UINTN
)FileSize
), &mInitrdFileAddress
);
177 if (EFI_ERROR (Status
)) {
181 ReadSize
= (UINTN
)FileSize
;
182 Status
= gEfiShellProtocol
->ReadFile (FileHandle
, &ReadSize
,
183 (VOID
*)(UINTN
)mInitrdFileAddress
);
184 if (EFI_ERROR (Status
) || ReadSize
< FileSize
) {
185 DEBUG ((DEBUG_WARN
, "%a: failed to read initrd file - %r 0x%lx 0x%lx\n",
186 __FUNCTION__
, Status
, (UINT64
)ReadSize
, FileSize
));
190 if (mInitrdLoadFile2Handle
== NULL
) {
191 Status
= gBS
->InstallMultipleProtocolInterfaces (&mInitrdLoadFile2Handle
,
192 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
193 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
195 ASSERT_EFI_ERROR (Status
);
198 mInitrdFileSize
= FileSize
;
202 gBS
->FreePages (mInitrdFileAddress
, EFI_SIZE_TO_PAGES ((UINTN
)FileSize
));
207 Function for 'initrd' command.
209 @param[in] ImageHandle Handle to the Image (NULL if Internal).
210 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
216 IN EFI_HANDLE ImageHandle
,
217 IN EFI_SYSTEM_TABLE
*SystemTable
222 CHAR16
*ProblemParam
;
225 SHELL_STATUS ShellStatus
;
226 SHELL_FILE_HANDLE FileHandle
;
229 ShellStatus
= SHELL_SUCCESS
;
231 Status
= ShellInitialize ();
232 ASSERT_EFI_ERROR (Status
);
235 // parse the command line
237 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
238 if (EFI_ERROR (Status
)) {
239 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
240 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
),
241 mLinuxInitrdShellCommandHiiHandle
, L
"initrd", ProblemParam
);
242 FreePool (ProblemParam
);
243 ShellStatus
= SHELL_INVALID_PARAMETER
;
247 } else if (IsOtherInitrdDevicePathAlreadyInstalled ()) {
248 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_ALREADY_INSTALLED
),
249 mLinuxInitrdShellCommandHiiHandle
, L
"initrd");
250 ShellStatus
= SHELL_UNSUPPORTED
;
252 if (ShellCommandLineGetCount (Package
) > 2) {
253 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
),
254 mLinuxInitrdShellCommandHiiHandle
, L
"initrd");
255 ShellStatus
= SHELL_INVALID_PARAMETER
;
256 } else if (ShellCommandLineGetCount (Package
) < 2) {
257 if (ShellCommandLineGetFlag (Package
, L
"-u")) {
259 UninstallLoadFile2Protocol ();
261 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
),
262 mLinuxInitrdShellCommandHiiHandle
, L
"initrd");
263 ShellStatus
= SHELL_INVALID_PARAMETER
;
266 Param
= ShellCommandLineGetRawValue (Package
, 1);
267 ASSERT (Param
!= NULL
);
269 Filename
= ShellFindFilePath (Param
);
270 if (Filename
== NULL
) {
271 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FIND_FAIL
),
272 mLinuxInitrdShellCommandHiiHandle
, L
"initrd", Param
);
273 ShellStatus
= SHELL_NOT_FOUND
;
275 Status
= ShellOpenFileByName (Filename
, &FileHandle
,
276 EFI_FILE_MODE_READ
, 0);
277 if (!EFI_ERROR (Status
)) {
279 Status
= CacheInitrdFile (FileHandle
);
280 ShellCloseFile (&FileHandle
);
282 if (EFI_ERROR (Status
)) {
283 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
),
284 mLinuxInitrdShellCommandHiiHandle
, L
"initrd", Param
);
285 ShellStatus
= SHELL_NOT_FOUND
;
296 This is the shell command handler function pointer callback type. This
297 function handles the command when it is invoked in the shell.
299 @param[in] This The instance of the
300 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
301 @param[in] SystemTable The pointer to the system table.
302 @param[in] ShellParameters The parameters associated with the command.
303 @param[in] Shell The instance of the shell protocol used in
304 the context of processing this command.
306 @return EFI_SUCCESS the operation was successful
307 @return other the operation failed.
311 LinuxInitrdCommandHandler (
312 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
313 IN EFI_SYSTEM_TABLE
*SystemTable
,
314 IN EFI_SHELL_PARAMETERS_PROTOCOL
*ShellParameters
,
315 IN EFI_SHELL_PROTOCOL
*Shell
318 gEfiShellParametersProtocol
= ShellParameters
;
319 gEfiShellProtocol
= Shell
;
321 return RunInitrd (gImageHandle
, SystemTable
);
325 This is the command help handler function pointer callback type. This
326 function is responsible for displaying help information for the associated
329 @param[in] This The instance of the
330 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
331 @param[in] Language The pointer to the language string to use.
333 @return string Pool allocated help string, must be freed
340 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
341 IN CONST CHAR8
*Language
344 return HiiGetString (mLinuxInitrdShellCommandHiiHandle
,
345 STRING_TOKEN (STR_GET_HELP_INITRD
), Language
);
348 STATIC EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mLinuxInitrdDynamicCommand
= {
350 LinuxInitrdCommandHandler
,
355 Retrieve HII package list from ImageHandle and publish to HII database.
357 @param ImageHandle The image handle of the process.
363 InitializeHiiPackage (
364 EFI_HANDLE ImageHandle
368 EFI_HII_PACKAGE_LIST_HEADER
*PackageList
;
369 EFI_HII_HANDLE HiiHandle
;
372 // Retrieve HII package list from ImageHandle
374 Status
= gBS
->OpenProtocol (ImageHandle
, &gEfiHiiPackageListProtocolGuid
,
375 (VOID
**)&PackageList
, ImageHandle
, NULL
,
376 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
377 ASSERT_EFI_ERROR (Status
);
378 if (EFI_ERROR (Status
)) {
383 // Publish HII package list to HII Database.
385 Status
= gHiiDatabase
->NewPackageList (gHiiDatabase
, PackageList
, NULL
,
387 ASSERT_EFI_ERROR (Status
);
388 if (EFI_ERROR (Status
)) {
395 Entry point of Linux Initrd dynamic UEFI Shell command.
397 Produce the DynamicCommand protocol to handle "initrd" command.
399 @param ImageHandle The image handle of the process.
400 @param SystemTable The EFI System Table pointer.
402 @retval EFI_SUCCESS Initrd command is executed successfully.
403 @retval EFI_ABORTED HII package was failed to initialize.
404 @retval others Other errors when executing Initrd command.
408 LinuxInitrdDynamicShellCommandEntryPoint (
409 IN EFI_HANDLE ImageHandle
,
410 IN EFI_SYSTEM_TABLE
*SystemTable
415 mLinuxInitrdShellCommandHiiHandle
= InitializeHiiPackage (ImageHandle
);
416 if (mLinuxInitrdShellCommandHiiHandle
== NULL
) {
420 Status
= gBS
->InstallProtocolInterface (&ImageHandle
,
421 &gEfiShellDynamicCommandProtocolGuid
,
422 EFI_NATIVE_INTERFACE
,
423 &mLinuxInitrdDynamicCommand
);
424 ASSERT_EFI_ERROR (Status
);
429 Unload the dynamic UEFI Shell command.
431 @param ImageHandle The image handle of the process.
433 @retval EFI_SUCCESS The image is unloaded.
434 @retval Others Failed to unload the image.
438 LinuxInitrdDynamicShellCommandUnload (
439 IN EFI_HANDLE ImageHandle
446 Status
= UninstallLoadFile2Protocol ();
447 if (EFI_ERROR (Status
)) {
451 Status
= gBS
->UninstallProtocolInterface (ImageHandle
,
452 &gEfiShellDynamicCommandProtocolGuid
,
453 &mLinuxInitrdDynamicCommand
);
454 if (EFI_ERROR (Status
)) {
458 HiiRemovePackages (mLinuxInitrdShellCommandHiiHandle
);