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
) }
60 IN EFI_LOAD_FILE2_PROTOCOL
*This
,
61 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
62 IN BOOLEAN BootPolicy
,
63 IN OUT UINTN
*BufferSize
,
64 OUT VOID
*Buffer OPTIONAL
68 return EFI_UNSUPPORTED
;
71 if (BufferSize
== NULL
|| !IsDevicePathValid (FilePath
, 0)) {
72 return EFI_INVALID_PARAMETER
;
75 if (FilePath
->Type
!= END_DEVICE_PATH_TYPE
||
76 FilePath
->SubType
!= END_ENTIRE_DEVICE_PATH_SUBTYPE
||
77 mInitrdFileSize
== 0) {
81 if (Buffer
== NULL
|| *BufferSize
< mInitrdFileSize
) {
82 *BufferSize
= mInitrdFileSize
;
83 return EFI_BUFFER_TOO_SMALL
;
86 ASSERT (mInitrdFileAddress
!= 0);
88 gBS
->CopyMem (Buffer
, (VOID
*)(UINTN
)mInitrdFileAddress
, mInitrdFileSize
);
89 *BufferSize
= mInitrdFileSize
;
93 STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2
= {
99 UninstallLoadFile2Protocol (
105 if (mInitrdLoadFile2Handle
!= NULL
) {
106 Status
= gBS
->UninstallMultipleProtocolInterfaces (mInitrdLoadFile2Handle
,
107 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
108 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
110 if (!EFI_ERROR (Status
)) {
111 mInitrdLoadFile2Handle
= NULL
;
123 if (mInitrdFileSize
!= 0) {
124 gBS
->FreePages (mInitrdFileAddress
, EFI_SIZE_TO_PAGES (mInitrdFileSize
));
132 IN SHELL_FILE_HANDLE FileHandle
139 Status
= gEfiShellProtocol
->GetFileSize (FileHandle
, &FileSize
);
140 if (EFI_ERROR (Status
)) {
144 if (FileSize
== 0 || FileSize
> MAX_UINTN
) {
145 return EFI_UNSUPPORTED
;
148 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiLoaderData
,
149 EFI_SIZE_TO_PAGES ((UINTN
)FileSize
), &mInitrdFileAddress
);
150 if (EFI_ERROR (Status
)) {
154 ReadSize
= (UINTN
)FileSize
;
155 Status
= gEfiShellProtocol
->ReadFile (FileHandle
, &ReadSize
,
156 (VOID
*)(UINTN
)mInitrdFileAddress
);
157 if (EFI_ERROR (Status
) || ReadSize
< FileSize
) {
158 DEBUG ((DEBUG_WARN
, "%a: failed to read initrd file - %r 0x%lx 0x%lx\n",
159 __FUNCTION__
, Status
, (UINT64
)ReadSize
, FileSize
));
163 if (mInitrdLoadFile2Handle
== NULL
) {
164 Status
= gBS
->InstallMultipleProtocolInterfaces (&mInitrdLoadFile2Handle
,
165 &gEfiDevicePathProtocolGuid
, &mInitrdDevicePath
,
166 &gEfiLoadFile2ProtocolGuid
, &mInitrdLoadFile2
,
168 ASSERT_EFI_ERROR (Status
);
171 mInitrdFileSize
= FileSize
;
175 gBS
->FreePages (mInitrdFileAddress
, EFI_SIZE_TO_PAGES ((UINTN
)FileSize
));
180 Function for 'initrd' command.
182 @param[in] ImageHandle Handle to the Image (NULL if Internal).
183 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
189 IN EFI_HANDLE ImageHandle
,
190 IN EFI_SYSTEM_TABLE
*SystemTable
195 CHAR16
*ProblemParam
;
198 SHELL_STATUS ShellStatus
;
199 SHELL_FILE_HANDLE FileHandle
;
202 ShellStatus
= SHELL_SUCCESS
;
204 Status
= ShellInitialize ();
205 ASSERT_EFI_ERROR (Status
);
208 // parse the command line
210 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
211 if (EFI_ERROR (Status
)) {
212 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
213 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
),
214 mLinuxInitrdShellCommandHiiHandle
, L
"initrd", ProblemParam
);
215 FreePool (ProblemParam
);
216 ShellStatus
= SHELL_INVALID_PARAMETER
;
221 if (ShellCommandLineGetCount (Package
) > 2) {
222 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
),
223 mLinuxInitrdShellCommandHiiHandle
, L
"initrd");
224 ShellStatus
= SHELL_INVALID_PARAMETER
;
225 } else if (ShellCommandLineGetCount (Package
) < 2) {
226 if (ShellCommandLineGetFlag (Package
, L
"-u")) {
228 UninstallLoadFile2Protocol ();
230 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
),
231 mLinuxInitrdShellCommandHiiHandle
, L
"initrd");
232 ShellStatus
= SHELL_INVALID_PARAMETER
;
235 Param
= ShellCommandLineGetRawValue (Package
, 1);
236 ASSERT (Param
!= NULL
);
238 Filename
= ShellFindFilePath (Param
);
239 if (Filename
== NULL
) {
240 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FIND_FAIL
),
241 mLinuxInitrdShellCommandHiiHandle
, L
"initrd", Param
);
242 ShellStatus
= SHELL_NOT_FOUND
;
244 Status
= ShellOpenFileByName (Filename
, &FileHandle
,
245 EFI_FILE_MODE_READ
, 0);
246 if (!EFI_ERROR (Status
)) {
248 Status
= CacheInitrdFile (FileHandle
);
249 ShellCloseFile (&FileHandle
);
251 if (EFI_ERROR (Status
)) {
252 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
),
253 mLinuxInitrdShellCommandHiiHandle
, L
"initrd", Param
);
254 ShellStatus
= SHELL_NOT_FOUND
;
265 This is the shell command handler function pointer callback type. This
266 function handles the command when it is invoked in the shell.
268 @param[in] This The instance of the
269 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
270 @param[in] SystemTable The pointer to the system table.
271 @param[in] ShellParameters The parameters associated with the command.
272 @param[in] Shell The instance of the shell protocol used in
273 the context of processing this command.
275 @return EFI_SUCCESS the operation was successful
276 @return other the operation failed.
280 LinuxInitrdCommandHandler (
281 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
282 IN EFI_SYSTEM_TABLE
*SystemTable
,
283 IN EFI_SHELL_PARAMETERS_PROTOCOL
*ShellParameters
,
284 IN EFI_SHELL_PROTOCOL
*Shell
287 gEfiShellParametersProtocol
= ShellParameters
;
288 gEfiShellProtocol
= Shell
;
290 return RunInitrd (gImageHandle
, SystemTable
);
294 This is the command help handler function pointer callback type. This
295 function is responsible for displaying help information for the associated
298 @param[in] This The instance of the
299 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
300 @param[in] Language The pointer to the language string to use.
302 @return string Pool allocated help string, must be freed
309 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
310 IN CONST CHAR8
*Language
313 return HiiGetString (mLinuxInitrdShellCommandHiiHandle
,
314 STRING_TOKEN (STR_GET_HELP_INITRD
), Language
);
317 STATIC EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mLinuxInitrdDynamicCommand
= {
319 LinuxInitrdCommandHandler
,
324 Retrieve HII package list from ImageHandle and publish to HII database.
326 @param ImageHandle The image handle of the process.
332 InitializeHiiPackage (
333 EFI_HANDLE ImageHandle
337 EFI_HII_PACKAGE_LIST_HEADER
*PackageList
;
338 EFI_HII_HANDLE HiiHandle
;
341 // Retrieve HII package list from ImageHandle
343 Status
= gBS
->OpenProtocol (ImageHandle
, &gEfiHiiPackageListProtocolGuid
,
344 (VOID
**)&PackageList
, ImageHandle
, NULL
,
345 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
346 ASSERT_EFI_ERROR (Status
);
347 if (EFI_ERROR (Status
)) {
352 // Publish HII package list to HII Database.
354 Status
= gHiiDatabase
->NewPackageList (gHiiDatabase
, PackageList
, NULL
,
356 ASSERT_EFI_ERROR (Status
);
357 if (EFI_ERROR (Status
)) {
364 Entry point of Linux Initrd dynamic UEFI Shell command.
366 Produce the DynamicCommand protocol to handle "initrd" command.
368 @param ImageHandle The image handle of the process.
369 @param SystemTable The EFI System Table pointer.
371 @retval EFI_SUCCESS Initrd command is executed successfully.
372 @retval EFI_ABORTED HII package was failed to initialize.
373 @retval others Other errors when executing Initrd command.
377 LinuxInitrdDynamicShellCommandEntryPoint (
378 IN EFI_HANDLE ImageHandle
,
379 IN EFI_SYSTEM_TABLE
*SystemTable
384 mLinuxInitrdShellCommandHiiHandle
= InitializeHiiPackage (ImageHandle
);
385 if (mLinuxInitrdShellCommandHiiHandle
== NULL
) {
389 Status
= gBS
->InstallProtocolInterface (&ImageHandle
,
390 &gEfiShellDynamicCommandProtocolGuid
,
391 EFI_NATIVE_INTERFACE
,
392 &mLinuxInitrdDynamicCommand
);
393 ASSERT_EFI_ERROR (Status
);
398 Unload the dynamic UEFI Shell command.
400 @param ImageHandle The image handle of the process.
402 @retval EFI_SUCCESS The image is unloaded.
403 @retval Others Failed to unload the image.
407 LinuxInitrdDynamicShellCommandUnload (
408 IN EFI_HANDLE ImageHandle
415 Status
= UninstallLoadFile2Protocol ();
416 if (EFI_ERROR (Status
)) {
420 Status
= gBS
->UninstallProtocolInterface (ImageHandle
,
421 &gEfiShellDynamicCommandProtocolGuid
,
422 &mLinuxInitrdDynamicCommand
);
423 if (EFI_ERROR (Status
)) {
427 HiiRemovePackages (mLinuxInitrdShellCommandHiiHandle
);