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 (
68 &gEfiLoadFile2ProtocolGuid
,
72 if (EFI_ERROR (Status
)) {
77 // Check whether the existing instance is one that we installed during
78 // a previous invocation.
80 if (Handle
== mInitrdLoadFile2Handle
) {
91 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
92 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
93 IN BOOLEAN BootPolicy
,
94 IN OUT UINTN
*BufferSize
,
95 OUT VOID
*Buffer OPTIONAL
99 return EFI_UNSUPPORTED
;
102 if ((BufferSize
== NULL
) || !IsDevicePathValid (FilePath
, 0)) {
103 return EFI_INVALID_PARAMETER
;
106 if ((FilePath
->Type
!= END_DEVICE_PATH_TYPE
) ||
107 (FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
) ||
108 (mInitrdFileSize
== 0))
110 return EFI_NOT_FOUND
;
113 if ((Buffer
== NULL
) || (*BufferSize
< mInitrdFileSize
)) {
114 *BufferSize
= mInitrdFileSize
;
115 return EFI_BUFFER_TOO_SMALL
;
118 ASSERT (mInitrdFileAddress
!= 0);
120 gBS
->CopyMem (Buffer
, (VOID
*)(UINTN
)mInitrdFileAddress
, mInitrdFileSize
);
121 *BufferSize
= mInitrdFileSize
;
125 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
131 UninstallLoadFile2Protocol (
137 if (mInitrdLoadFile2Handle
!= NULL
) {
138 Status
= gBS
->UninstallMultipleProtocolInterfaces (
139 mInitrdLoadFile2Handle
,
140 &gEfiDevicePathProtocolGuid
,
142 &gEfiLoadFile2ProtocolGuid
,
146 if (!EFI_ERROR (Status
)) {
147 mInitrdLoadFile2Handle
= NULL
;
162 if (mInitrdFileSize
!= 0) {
163 gBS
->FreePages (mInitrdFileAddress
, EFI_SIZE_TO_PAGES (mInitrdFileSize
));
171 IN SHELL_FILE_HANDLE FileHandle
178 Status
= gEfiShellProtocol
->GetFileSize (FileHandle
, &FileSize
);
179 if (EFI_ERROR (Status
)) {
183 if ((FileSize
== 0) || (FileSize
> MAX_UINTN
)) {
184 return EFI_UNSUPPORTED
;
187 Status
= gBS
->AllocatePages (
190 EFI_SIZE_TO_PAGES ((UINTN
)FileSize
),
193 if (EFI_ERROR (Status
)) {
197 ReadSize
= (UINTN
)FileSize
;
198 Status
= gEfiShellProtocol
->ReadFile (
201 (VOID
*)(UINTN
)mInitrdFileAddress
203 if (EFI_ERROR (Status
) || (ReadSize
< FileSize
)) {
206 "%a: failed to read initrd file - %r 0x%lx 0x%lx\n",
215 if (mInitrdLoadFile2Handle
== NULL
) {
216 Status
= gBS
->InstallMultipleProtocolInterfaces (
217 &mInitrdLoadFile2Handle
,
218 &gEfiDevicePathProtocolGuid
,
220 &gEfiLoadFile2ProtocolGuid
,
224 ASSERT_EFI_ERROR (Status
);
227 mInitrdFileSize
= (UINTN
)FileSize
;
231 gBS
->FreePages (mInitrdFileAddress
, EFI_SIZE_TO_PAGES ((UINTN
)FileSize
));
236 Function for 'initrd' command.
238 @param[in] ImageHandle Handle to the Image (NULL if Internal).
239 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
245 IN EFI_HANDLE ImageHandle
,
246 IN EFI_SYSTEM_TABLE
*SystemTable
251 CHAR16
*ProblemParam
;
254 SHELL_STATUS ShellStatus
;
255 SHELL_FILE_HANDLE FileHandle
;
258 ShellStatus
= SHELL_SUCCESS
;
260 Status
= ShellInitialize ();
261 ASSERT_EFI_ERROR (Status
);
264 // parse the command line
266 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
267 if (EFI_ERROR (Status
)) {
268 if ((Status
== EFI_VOLUME_CORRUPTED
) && (ProblemParam
!= NULL
)) {
273 STRING_TOKEN (STR_GEN_PROBLEM
),
274 mLinuxInitrdShellCommandHiiHandle
,
278 FreePool (ProblemParam
);
279 ShellStatus
= SHELL_INVALID_PARAMETER
;
283 } else if (IsOtherInitrdDevicePathAlreadyInstalled ()) {
288 STRING_TOKEN (STR_GEN_ALREADY_INSTALLED
),
289 mLinuxInitrdShellCommandHiiHandle
,
292 ShellStatus
= SHELL_UNSUPPORTED
;
294 if (ShellCommandLineGetCount (Package
) > 2) {
299 STRING_TOKEN (STR_GEN_TOO_MANY
),
300 mLinuxInitrdShellCommandHiiHandle
,
303 ShellStatus
= SHELL_INVALID_PARAMETER
;
304 } else if (ShellCommandLineGetCount (Package
) < 2) {
305 if (ShellCommandLineGetFlag (Package
, L
"-u")) {
307 UninstallLoadFile2Protocol ();
313 STRING_TOKEN (STR_GEN_TOO_FEW
),
314 mLinuxInitrdShellCommandHiiHandle
,
317 ShellStatus
= SHELL_INVALID_PARAMETER
;
320 Param
= ShellCommandLineGetRawValue (Package
, 1);
321 ASSERT (Param
!= NULL
);
323 Filename
= ShellFindFilePath (Param
);
324 if (Filename
== NULL
) {
329 STRING_TOKEN (STR_GEN_FIND_FAIL
),
330 mLinuxInitrdShellCommandHiiHandle
,
334 ShellStatus
= SHELL_NOT_FOUND
;
336 Status
= ShellOpenFileByName (
342 if (!EFI_ERROR (Status
)) {
344 Status
= CacheInitrdFile (FileHandle
);
345 ShellCloseFile (&FileHandle
);
348 if (EFI_ERROR (Status
)) {
353 STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
),
354 mLinuxInitrdShellCommandHiiHandle
,
358 ShellStatus
= SHELL_NOT_FOUND
;
370 This is the shell command handler function pointer callback type. This
371 function handles the command when it is invoked in the shell.
373 @param[in] This The instance of the
374 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
375 @param[in] SystemTable The pointer to the system table.
376 @param[in] ShellParameters The parameters associated with the command.
377 @param[in] Shell The instance of the shell protocol used in
378 the context of processing this command.
380 @return EFI_SUCCESS the operation was successful
381 @return other the operation failed.
385 LinuxInitrdCommandHandler (
386 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
387 IN EFI_SYSTEM_TABLE
*SystemTable
,
388 IN EFI_SHELL_PARAMETERS_PROTOCOL
*ShellParameters
,
389 IN EFI_SHELL_PROTOCOL
*Shell
392 gEfiShellParametersProtocol
= ShellParameters
;
393 gEfiShellProtocol
= Shell
;
395 return RunInitrd (gImageHandle
, SystemTable
);
399 This is the command help handler function pointer callback type. This
400 function is responsible for displaying help information for the associated
403 @param[in] This The instance of the
404 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
405 @param[in] Language The pointer to the language string to use.
407 @return string Pool allocated help string, must be freed
414 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
415 IN CONST CHAR8
*Language
418 return HiiGetString (
419 mLinuxInitrdShellCommandHiiHandle
,
420 STRING_TOKEN (STR_GET_HELP_INITRD
),
425 STATIC EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mLinuxInitrdDynamicCommand
= {
427 LinuxInitrdCommandHandler
,
432 Retrieve HII package list from ImageHandle and publish to HII database.
434 @param ImageHandle The image handle of the process.
440 InitializeHiiPackage (
441 EFI_HANDLE ImageHandle
445 EFI_HII_PACKAGE_LIST_HEADER
*PackageList
;
446 EFI_HII_HANDLE HiiHandle
;
449 // Retrieve HII package list from ImageHandle
451 Status
= gBS
->OpenProtocol (
453 &gEfiHiiPackageListProtocolGuid
,
454 (VOID
**)&PackageList
,
457 EFI_OPEN_PROTOCOL_GET_PROTOCOL
459 ASSERT_EFI_ERROR (Status
);
460 if (EFI_ERROR (Status
)) {
465 // Publish HII package list to HII Database.
467 Status
= gHiiDatabase
->NewPackageList (
473 ASSERT_EFI_ERROR (Status
);
474 if (EFI_ERROR (Status
)) {
482 Entry point of Linux Initrd dynamic UEFI Shell command.
484 Produce the DynamicCommand protocol to handle "initrd" command.
486 @param ImageHandle The image handle of the process.
487 @param SystemTable The EFI System Table pointer.
489 @retval EFI_SUCCESS Initrd command is executed successfully.
490 @retval EFI_ABORTED HII package was failed to initialize.
491 @retval others Other errors when executing Initrd command.
495 LinuxInitrdDynamicShellCommandEntryPoint (
496 IN EFI_HANDLE ImageHandle
,
497 IN EFI_SYSTEM_TABLE
*SystemTable
502 mLinuxInitrdShellCommandHiiHandle
= InitializeHiiPackage (ImageHandle
);
503 if (mLinuxInitrdShellCommandHiiHandle
== NULL
) {
507 Status
= gBS
->InstallProtocolInterface (
509 &gEfiShellDynamicCommandProtocolGuid
,
510 EFI_NATIVE_INTERFACE
,
511 &mLinuxInitrdDynamicCommand
513 ASSERT_EFI_ERROR (Status
);
518 Unload the dynamic UEFI Shell command.
520 @param ImageHandle The image handle of the process.
522 @retval EFI_SUCCESS The image is unloaded.
523 @retval Others Failed to unload the image.
527 LinuxInitrdDynamicShellCommandUnload (
528 IN EFI_HANDLE ImageHandle
535 Status
= UninstallLoadFile2Protocol ();
536 if (EFI_ERROR (Status
)) {
540 Status
= gBS
->UninstallProtocolInterface (
542 &gEfiShellDynamicCommandProtocolGuid
,
543 &mLinuxInitrdDynamicCommand
545 if (EFI_ERROR (Status
)) {
549 HiiRemovePackages (mLinuxInitrdShellCommandHiiHandle
);