VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.c@ 93492

Last change on this file since 93492 was 85718, checked in by vboxsync, 5 years ago

Devices/EFI: Merge edk-stable202005 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 12.7 KB
Line 
1/** @file
2 Provides 'initrd' dynamic UEFI shell command to load a Linux initrd
3 via its GUIDed vendor media path
4
5 Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8**/
9
10#include <Uefi.h>
11
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>
19
20#include <Guid/LinuxEfiInitrdMedia.h>
21
22#include <Protocol/DevicePath.h>
23#include <Protocol/HiiPackageList.h>
24#include <Protocol/LoadFile2.h>
25#include <Protocol/ShellDynamicCommand.h>
26
27#pragma pack (1)
28typedef struct {
29 VENDOR_DEVICE_PATH VenMediaNode;
30 EFI_DEVICE_PATH_PROTOCOL EndNode;
31} SINGLE_NODE_VENDOR_MEDIA_DEVPATH;
32#pragma pack ()
33
34STATIC EFI_HII_HANDLE mLinuxInitrdShellCommandHiiHandle;
35STATIC EFI_PHYSICAL_ADDRESS mInitrdFileAddress;
36STATIC UINTN mInitrdFileSize;
37STATIC EFI_HANDLE mInitrdLoadFile2Handle;
38
39STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
40 {L"-u", TypeFlag},
41 {NULL, TypeMax}
42 };
43
44STATIC CONST SINGLE_NODE_VENDOR_MEDIA_DEVPATH mInitrdDevicePath = {
45 {
46 {
47 MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH) }
48 },
49 LINUX_EFI_INITRD_MEDIA_GUID
50 }, {
51 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
52 { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
53 }
54};
55
56STATIC
57BOOLEAN
58IsOtherInitrdDevicePathAlreadyInstalled (
59 VOID
60 )
61{
62 EFI_STATUS Status;
63 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
64 EFI_HANDLE Handle;
65
66 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&mInitrdDevicePath;
67 Status = gBS->LocateDevicePath (&gEfiLoadFile2ProtocolGuid, &DevicePath,
68 &Handle);
69 if (EFI_ERROR (Status)) {
70 return FALSE;
71 }
72
73 //
74 // Check whether the existing instance is one that we installed during
75 // a previous invocation.
76 //
77 if (Handle == mInitrdLoadFile2Handle) {
78 return FALSE;
79 }
80 return TRUE;
81}
82
83STATIC
84EFI_STATUS
85EFIAPI
86InitrdLoadFile2 (
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
92 )
93{
94 if (BootPolicy) {
95 return EFI_UNSUPPORTED;
96 }
97
98 if (BufferSize == NULL || !IsDevicePathValid (FilePath, 0)) {
99 return EFI_INVALID_PARAMETER;
100 }
101
102 if (FilePath->Type != END_DEVICE_PATH_TYPE ||
103 FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ||
104 mInitrdFileSize == 0) {
105 return EFI_NOT_FOUND;
106 }
107
108 if (Buffer == NULL || *BufferSize < mInitrdFileSize) {
109 *BufferSize = mInitrdFileSize;
110 return EFI_BUFFER_TOO_SMALL;
111 }
112
113 ASSERT (mInitrdFileAddress != 0);
114
115 gBS->CopyMem (Buffer, (VOID *)(UINTN)mInitrdFileAddress, mInitrdFileSize);
116 *BufferSize = mInitrdFileSize;
117 return EFI_SUCCESS;
118}
119
120STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = {
121 InitrdLoadFile2,
122};
123
124STATIC
125EFI_STATUS
126UninstallLoadFile2Protocol (
127 VOID
128 )
129{
130 EFI_STATUS Status;
131
132 if (mInitrdLoadFile2Handle != NULL) {
133 Status = gBS->UninstallMultipleProtocolInterfaces (mInitrdLoadFile2Handle,
134 &gEfiDevicePathProtocolGuid, &mInitrdDevicePath,
135 &gEfiLoadFile2ProtocolGuid, &mInitrdLoadFile2,
136 NULL);
137 if (!EFI_ERROR (Status)) {
138 mInitrdLoadFile2Handle = NULL;
139 }
140 return Status;
141 }
142 return EFI_SUCCESS;
143}
144
145STATIC
146VOID
147FreeInitrdFile (
148 VOID
149 )
150{
151 if (mInitrdFileSize != 0) {
152 gBS->FreePages (mInitrdFileAddress, EFI_SIZE_TO_PAGES (mInitrdFileSize));
153 mInitrdFileSize = 0;
154 }
155}
156
157STATIC
158EFI_STATUS
159CacheInitrdFile (
160 IN SHELL_FILE_HANDLE FileHandle
161 )
162{
163 EFI_STATUS Status;
164 UINT64 FileSize;
165 UINTN ReadSize;
166
167 Status = gEfiShellProtocol->GetFileSize (FileHandle, &FileSize);
168 if (EFI_ERROR (Status)) {
169 return Status;
170 }
171
172 if (FileSize == 0 || FileSize > MAX_UINTN) {
173 return EFI_UNSUPPORTED;
174 }
175
176 Status = gBS->AllocatePages (AllocateAnyPages, EfiLoaderData,
177 EFI_SIZE_TO_PAGES ((UINTN)FileSize), &mInitrdFileAddress);
178 if (EFI_ERROR (Status)) {
179 return Status;
180 }
181
182 ReadSize = (UINTN)FileSize;
183 Status = gEfiShellProtocol->ReadFile (FileHandle, &ReadSize,
184 (VOID *)(UINTN)mInitrdFileAddress);
185 if (EFI_ERROR (Status) || ReadSize < FileSize) {
186 DEBUG ((DEBUG_WARN, "%a: failed to read initrd file - %r 0x%lx 0x%lx\n",
187 __FUNCTION__, Status, (UINT64)ReadSize, FileSize));
188 goto FreeMemory;
189 }
190
191 if (mInitrdLoadFile2Handle == NULL) {
192 Status = gBS->InstallMultipleProtocolInterfaces (&mInitrdLoadFile2Handle,
193 &gEfiDevicePathProtocolGuid, &mInitrdDevicePath,
194 &gEfiLoadFile2ProtocolGuid, &mInitrdLoadFile2,
195 NULL);
196 ASSERT_EFI_ERROR (Status);
197 }
198
199 mInitrdFileSize = (UINTN)FileSize;
200 return EFI_SUCCESS;
201
202FreeMemory:
203 gBS->FreePages (mInitrdFileAddress, EFI_SIZE_TO_PAGES ((UINTN)FileSize));
204 return Status;
205}
206
207/**
208 Function for 'initrd' command.
209
210 @param[in] ImageHandle Handle to the Image (NULL if Internal).
211 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
212**/
213STATIC
214SHELL_STATUS
215EFIAPI
216RunInitrd (
217 IN EFI_HANDLE ImageHandle,
218 IN EFI_SYSTEM_TABLE *SystemTable
219 )
220{
221 EFI_STATUS Status;
222 LIST_ENTRY *Package;
223 CHAR16 *ProblemParam;
224 CONST CHAR16 *Param;
225 CHAR16 *Filename;
226 SHELL_STATUS ShellStatus;
227 SHELL_FILE_HANDLE FileHandle;
228
229 ProblemParam = NULL;
230 ShellStatus = SHELL_SUCCESS;
231
232 Status = ShellInitialize ();
233 ASSERT_EFI_ERROR (Status);
234
235 //
236 // parse the command line
237 //
238 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
239 if (EFI_ERROR (Status)) {
240 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
241 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM),
242 mLinuxInitrdShellCommandHiiHandle, L"initrd", ProblemParam);
243 FreePool (ProblemParam);
244 ShellStatus = SHELL_INVALID_PARAMETER;
245 } else {
246 ASSERT(FALSE);
247 }
248 } else if (IsOtherInitrdDevicePathAlreadyInstalled ()) {
249 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ALREADY_INSTALLED),
250 mLinuxInitrdShellCommandHiiHandle, L"initrd");
251 ShellStatus = SHELL_UNSUPPORTED;
252 } else {
253 if (ShellCommandLineGetCount (Package) > 2) {
254 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY),
255 mLinuxInitrdShellCommandHiiHandle, L"initrd");
256 ShellStatus = SHELL_INVALID_PARAMETER;
257 } else if (ShellCommandLineGetCount (Package) < 2) {
258 if (ShellCommandLineGetFlag (Package, L"-u")) {
259 FreeInitrdFile ();
260 UninstallLoadFile2Protocol ();
261 } else {
262 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW),
263 mLinuxInitrdShellCommandHiiHandle, L"initrd");
264 ShellStatus = SHELL_INVALID_PARAMETER;
265 }
266 } else {
267 Param = ShellCommandLineGetRawValue (Package, 1);
268 ASSERT (Param != NULL);
269
270 Filename = ShellFindFilePath (Param);
271 if (Filename == NULL) {
272 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL),
273 mLinuxInitrdShellCommandHiiHandle, L"initrd", Param);
274 ShellStatus = SHELL_NOT_FOUND;
275 } else {
276 Status = ShellOpenFileByName (Filename, &FileHandle,
277 EFI_FILE_MODE_READ, 0);
278 if (!EFI_ERROR (Status)) {
279 FreeInitrdFile ();
280 Status = CacheInitrdFile (FileHandle);
281 ShellCloseFile (&FileHandle);
282 }
283 if (EFI_ERROR (Status)) {
284 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL),
285 mLinuxInitrdShellCommandHiiHandle, L"initrd", Param);
286 ShellStatus = SHELL_NOT_FOUND;
287 }
288 FreePool (Filename);
289 }
290 }
291 }
292 return ShellStatus;
293}
294
295
296/**
297 This is the shell command handler function pointer callback type. This
298 function handles the command when it is invoked in the shell.
299
300 @param[in] This The instance of the
301 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
302 @param[in] SystemTable The pointer to the system table.
303 @param[in] ShellParameters The parameters associated with the command.
304 @param[in] Shell The instance of the shell protocol used in
305 the context of processing this command.
306
307 @return EFI_SUCCESS the operation was successful
308 @return other the operation failed.
309**/
310SHELL_STATUS
311EFIAPI
312LinuxInitrdCommandHandler (
313 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
314 IN EFI_SYSTEM_TABLE *SystemTable,
315 IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
316 IN EFI_SHELL_PROTOCOL *Shell
317 )
318{
319 gEfiShellParametersProtocol = ShellParameters;
320 gEfiShellProtocol = Shell;
321
322 return RunInitrd (gImageHandle, SystemTable);
323}
324
325/**
326 This is the command help handler function pointer callback type. This
327 function is responsible for displaying help information for the associated
328 command.
329
330 @param[in] This The instance of the
331 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
332 @param[in] Language The pointer to the language string to use.
333
334 @return string Pool allocated help string, must be freed
335 by caller
336**/
337STATIC
338CHAR16 *
339EFIAPI
340LinuxInitrdGetHelp (
341 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
342 IN CONST CHAR8 *Language
343 )
344{
345 return HiiGetString (mLinuxInitrdShellCommandHiiHandle,
346 STRING_TOKEN (STR_GET_HELP_INITRD), Language);
347}
348
349STATIC EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mLinuxInitrdDynamicCommand = {
350 L"initrd",
351 LinuxInitrdCommandHandler,
352 LinuxInitrdGetHelp
353};
354
355/**
356 Retrieve HII package list from ImageHandle and publish to HII database.
357
358 @param ImageHandle The image handle of the process.
359
360 @return HII handle.
361**/
362STATIC
363EFI_HII_HANDLE
364InitializeHiiPackage (
365 EFI_HANDLE ImageHandle
366 )
367{
368 EFI_STATUS Status;
369 EFI_HII_PACKAGE_LIST_HEADER *PackageList;
370 EFI_HII_HANDLE HiiHandle;
371
372 //
373 // Retrieve HII package list from ImageHandle
374 //
375 Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid,
376 (VOID **)&PackageList, ImageHandle, NULL,
377 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
378 ASSERT_EFI_ERROR (Status);
379 if (EFI_ERROR (Status)) {
380 return NULL;
381 }
382
383 //
384 // Publish HII package list to HII Database.
385 //
386 Status = gHiiDatabase->NewPackageList (gHiiDatabase, PackageList, NULL,
387 &HiiHandle);
388 ASSERT_EFI_ERROR (Status);
389 if (EFI_ERROR (Status)) {
390 return NULL;
391 }
392 return HiiHandle;
393}
394
395/**
396 Entry point of Linux Initrd dynamic UEFI Shell command.
397
398 Produce the DynamicCommand protocol to handle "initrd" command.
399
400 @param ImageHandle The image handle of the process.
401 @param SystemTable The EFI System Table pointer.
402
403 @retval EFI_SUCCESS Initrd command is executed successfully.
404 @retval EFI_ABORTED HII package was failed to initialize.
405 @retval others Other errors when executing Initrd command.
406**/
407EFI_STATUS
408EFIAPI
409LinuxInitrdDynamicShellCommandEntryPoint (
410 IN EFI_HANDLE ImageHandle,
411 IN EFI_SYSTEM_TABLE *SystemTable
412 )
413{
414 EFI_STATUS Status;
415
416 mLinuxInitrdShellCommandHiiHandle = InitializeHiiPackage (ImageHandle);
417 if (mLinuxInitrdShellCommandHiiHandle == NULL) {
418 return EFI_ABORTED;
419 }
420
421 Status = gBS->InstallProtocolInterface (&ImageHandle,
422 &gEfiShellDynamicCommandProtocolGuid,
423 EFI_NATIVE_INTERFACE,
424 &mLinuxInitrdDynamicCommand);
425 ASSERT_EFI_ERROR (Status);
426 return Status;
427}
428
429/**
430 Unload the dynamic UEFI Shell command.
431
432 @param ImageHandle The image handle of the process.
433
434 @retval EFI_SUCCESS The image is unloaded.
435 @retval Others Failed to unload the image.
436**/
437EFI_STATUS
438EFIAPI
439LinuxInitrdDynamicShellCommandUnload (
440 IN EFI_HANDLE ImageHandle
441)
442{
443 EFI_STATUS Status;
444
445 FreeInitrdFile ();
446
447 Status = UninstallLoadFile2Protocol ();
448 if (EFI_ERROR (Status)) {
449 return Status;
450 }
451
452 Status = gBS->UninstallProtocolInterface (ImageHandle,
453 &gEfiShellDynamicCommandProtocolGuid,
454 &mLinuxInitrdDynamicCommand);
455 if (EFI_ERROR (Status)) {
456 return Status;
457 }
458
459 HiiRemovePackages (mLinuxInitrdShellCommandHiiHandle);
460 return EFI_SUCCESS;
461}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette