TianoCore EDK2 master
Loading...
Searching...
No Matches
X86QemuLoadImageLib.c
Go to the documentation of this file.
1
14#include <Uefi.h>
15
17#include <Library/DebugLib.h>
20#include <Library/PrintLib.h>
24#include <Protocol/DevicePath.h>
27
28#pragma pack (1)
29typedef struct {
30 EFI_DEVICE_PATH_PROTOCOL FilePathHeader;
31 CHAR16 FilePath[ARRAY_SIZE (L"kernel")];
33
34typedef struct {
35 VENDOR_DEVICE_PATH VenMediaNode;
36 KERNEL_FILE_DEVPATH FileNode;
39#pragma pack ()
40
41STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
42 {
43 {
44 MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
45 { sizeof (VENDOR_DEVICE_PATH) }
46 },
47 QEMU_KERNEL_LOADER_FS_MEDIA_GUID
48 }, {
49 {
50 MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,
51 { sizeof (KERNEL_FILE_DEVPATH) }
52 },
53 L"kernel",
54 }, {
55 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
56 { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
57 }
58};
59
61VOID
62FreeLegacyImage (
64 )
65{
66 if (LoadedImage->SetupBuf != NULL) {
67 FreePages (
68 LoadedImage->SetupBuf,
69 EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)
70 );
71 }
72
73 if (LoadedImage->KernelBuf != NULL) {
74 FreePages (
75 LoadedImage->KernelBuf,
76 EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)
77 );
78 }
79
80 if (LoadedImage->CommandLine != NULL) {
81 FreePages (
82 LoadedImage->CommandLine,
83 EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize)
84 );
85 }
86
87 if (LoadedImage->InitrdData != NULL) {
88 FreePages (
89 LoadedImage->InitrdData,
90 EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize)
91 );
92 }
93}
94
97QemuLoadLegacyImage (
98 OUT EFI_HANDLE *ImageHandle
99 )
100{
101 EFI_STATUS Status;
102 UINTN KernelSize;
103 UINTN SetupSize;
104 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
105
106 QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
107 KernelSize = (UINTN)QemuFwCfgRead32 ();
108
109 QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
110 SetupSize = (UINTN)QemuFwCfgRead32 ();
111
112 if ((KernelSize == 0) || (SetupSize == 0)) {
113 DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n"));
114 return EFI_NOT_FOUND;
115 }
116
117 LoadedImage = AllocateZeroPool (sizeof (*LoadedImage));
118 if (LoadedImage == NULL) {
119 return EFI_OUT_OF_RESOURCES;
120 }
121
122 LoadedImage->SetupSize = SetupSize;
123 LoadedImage->SetupBuf = LoadLinuxAllocateKernelSetupPages (
124 EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)
125 );
126 if (LoadedImage->SetupBuf == NULL) {
127 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n"));
128 Status = EFI_OUT_OF_RESOURCES;
129 goto FreeImageDesc;
130 }
131
132 DEBUG ((DEBUG_INFO, "Setup size: 0x%x\n", (UINT32)LoadedImage->SetupSize));
133 DEBUG ((DEBUG_INFO, "Reading kernel setup image ..."));
134 QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
135 QemuFwCfgReadBytes (LoadedImage->SetupSize, LoadedImage->SetupBuf);
136 DEBUG ((DEBUG_INFO, " [done]\n"));
137
139 LoadedImage->SetupBuf,
140 LoadedImage->SetupSize
141 );
142 if (EFI_ERROR (Status)) {
143 goto FreeImage;
144 }
145
146 Status = LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf);
147 if (EFI_ERROR (Status)) {
148 goto FreeImage;
149 }
150
151 LoadedImage->KernelInitialSize = LoadLinuxGetKernelSize (
152 LoadedImage->SetupBuf,
153 KernelSize
154 );
155 if (LoadedImage->KernelInitialSize == 0) {
156 Status = EFI_UNSUPPORTED;
157 goto FreeImage;
158 }
159
160 LoadedImage->KernelBuf = LoadLinuxAllocateKernelPages (
161 LoadedImage->SetupBuf,
162 EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)
163 );
164 if (LoadedImage->KernelBuf == NULL) {
165 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n"));
166 Status = EFI_OUT_OF_RESOURCES;
167 goto FreeImage;
168 }
169
170 DEBUG ((DEBUG_INFO, "Kernel size: 0x%x\n", (UINT32)KernelSize));
171 DEBUG ((DEBUG_INFO, "Reading kernel image ..."));
172 QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
173 QemuFwCfgReadBytes (KernelSize, LoadedImage->KernelBuf);
174 DEBUG ((DEBUG_INFO, " [done]\n"));
175
176 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
177 LoadedImage->CommandLineSize = (UINTN)QemuFwCfgRead32 ();
178
179 if (LoadedImage->CommandLineSize > 0) {
180 LoadedImage->CommandLine = LoadLinuxAllocateCommandLinePages (
182 LoadedImage->CommandLineSize
183 )
184 );
185 if (LoadedImage->CommandLine == NULL) {
186 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel command line!\n"));
187 Status = EFI_OUT_OF_RESOURCES;
188 goto FreeImage;
189 }
190
191 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
192 QemuFwCfgReadBytes (LoadedImage->CommandLineSize, LoadedImage->CommandLine);
193 }
194
195 Status = LoadLinuxSetCommandLine (
196 LoadedImage->SetupBuf,
197 LoadedImage->CommandLine
198 );
199 if (EFI_ERROR (Status)) {
200 goto FreeImage;
201 }
202
203 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
204 LoadedImage->InitrdSize = (UINTN)QemuFwCfgRead32 ();
205
206 if (LoadedImage->InitrdSize > 0) {
207 LoadedImage->InitrdData = LoadLinuxAllocateInitrdPages (
208 LoadedImage->SetupBuf,
209 EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize)
210 );
211 if (LoadedImage->InitrdData == NULL) {
212 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for initrd!\n"));
213 Status = EFI_OUT_OF_RESOURCES;
214 goto FreeImage;
215 }
216
217 DEBUG ((
218 DEBUG_INFO,
219 "Initrd size: 0x%x\n",
220 (UINT32)LoadedImage->InitrdSize
221 ));
222 DEBUG ((DEBUG_INFO, "Reading initrd image ..."));
223 QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);
224 QemuFwCfgReadBytes (LoadedImage->InitrdSize, LoadedImage->InitrdData);
225 DEBUG ((DEBUG_INFO, " [done]\n"));
226 }
227
228 Status = LoadLinuxSetInitrd (
229 LoadedImage->SetupBuf,
230 LoadedImage->InitrdData,
231 LoadedImage->InitrdSize
232 );
233 if (EFI_ERROR (Status)) {
234 goto FreeImage;
235 }
236
237 *ImageHandle = NULL;
238 Status = gBS->InstallProtocolInterface (
239 ImageHandle,
240 &gOvmfLoadedX86LinuxKernelProtocolGuid,
242 LoadedImage
243 );
244 if (EFI_ERROR (Status)) {
245 goto FreeImage;
246 }
247
248 return EFI_SUCCESS;
249
250FreeImage:
251 FreeLegacyImage (LoadedImage);
252FreeImageDesc:
253 FreePool (LoadedImage);
254 return Status;
255}
256
257STATIC
259QemuStartLegacyImage (
260 IN EFI_HANDLE ImageHandle
261 )
262{
263 EFI_STATUS Status;
264 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
265
266 Status = gBS->OpenProtocol (
267 ImageHandle,
268 &gOvmfLoadedX86LinuxKernelProtocolGuid,
269 (VOID **)&LoadedImage,
270 gImageHandle, // AgentHandle
271 NULL, // ControllerHandle
272 EFI_OPEN_PROTOCOL_GET_PROTOCOL
273 );
274 if (EFI_ERROR (Status)) {
275 return EFI_INVALID_PARAMETER;
276 }
277
278 return LoadLinux (LoadedImage->KernelBuf, LoadedImage->SetupBuf);
279}
280
281STATIC
283QemuUnloadLegacyImage (
284 IN EFI_HANDLE ImageHandle
285 )
286{
287 EFI_STATUS Status;
288 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
289
290 Status = gBS->OpenProtocol (
291 ImageHandle,
292 &gOvmfLoadedX86LinuxKernelProtocolGuid,
293 (VOID **)&LoadedImage,
294 gImageHandle, // AgentHandle
295 NULL, // ControllerHandle
296 EFI_OPEN_PROTOCOL_GET_PROTOCOL
297 );
298 if (EFI_ERROR (Status)) {
299 return EFI_INVALID_PARAMETER;
300 }
301
302 Status = gBS->UninstallProtocolInterface (
303 ImageHandle,
304 &gOvmfLoadedX86LinuxKernelProtocolGuid,
305 LoadedImage
306 );
307 ASSERT_EFI_ERROR (Status);
308
309 FreeLegacyImage (LoadedImage);
310 FreePool (LoadedImage);
311 return EFI_SUCCESS;
312}
313
331EFIAPI
333 OUT EFI_HANDLE *ImageHandle
334 )
335{
336 EFI_STATUS Status;
337 EFI_HANDLE KernelImageHandle;
338 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
339 UINTN CommandLineSize;
340 CHAR8 *CommandLine;
341 UINTN InitrdSize;
342
343 //
344 // Redundant assignment to work around GCC48/GCC49 limitations.
345 //
346 CommandLine = NULL;
347
348 //
349 // Load the image. This should call back into the QEMU EFI loader file system.
350 //
351 Status = gBS->LoadImage (
352 FALSE, // BootPolicy: exact match required
353 gImageHandle, // ParentImageHandle
354 (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,
355 NULL, // SourceBuffer
356 0, // SourceSize
357 &KernelImageHandle
358 );
359 switch (Status) {
360 case EFI_SUCCESS:
361 break;
362
363 case EFI_NOT_FOUND:
364 //
365 // The image does not exist - no -kernel image was supplied via the
366 // command line so no point in invoking the legacy fallback
367 //
368 return EFI_NOT_FOUND;
369
370 case EFI_SECURITY_VIOLATION:
371 //
372 // Since the image has been loaded, we need to unload it before proceeding
373 // to the EFI_ACCESS_DENIED case below.
374 //
375 gBS->UnloadImage (KernelImageHandle);
376 //
377 // Fall through
378 //
379 case EFI_ACCESS_DENIED:
380 //
381 // We are running with UEFI secure boot enabled, and the image failed to
382 // authenticate. For compatibility reasons, we fall back to the legacy
383 // loader in this case.
384 //
385 // Fall through
386 //
387 case EFI_UNSUPPORTED:
388 //
389 // The image is not natively supported or cross-type supported. Let's try
390 // loading it using the loader that parses the bzImage metadata directly.
391 //
392 Status = QemuLoadLegacyImage (&KernelImageHandle);
393 if (EFI_ERROR (Status)) {
394 DEBUG ((
395 DEBUG_ERROR,
396 "%a: QemuLoadLegacyImage(): %r\n",
397 __func__,
398 Status
399 ));
400 return Status;
401 }
402
403 *ImageHandle = KernelImageHandle;
404 return EFI_SUCCESS;
405
406 default:
407 DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __func__, Status));
408 return Status;
409 }
410
411 //
412 // Construct the kernel command line.
413 //
414 Status = gBS->OpenProtocol (
415 KernelImageHandle,
416 &gEfiLoadedImageProtocolGuid,
417 (VOID **)&KernelLoadedImage,
418 gImageHandle, // AgentHandle
419 NULL, // ControllerHandle
420 EFI_OPEN_PROTOCOL_GET_PROTOCOL
421 );
422 ASSERT_EFI_ERROR (Status);
423
424 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
425 CommandLineSize = (UINTN)QemuFwCfgRead32 ();
426
427 if (CommandLineSize == 0) {
428 KernelLoadedImage->LoadOptionsSize = 0;
429 } else {
430 CommandLine = AllocatePool (CommandLineSize);
431 if (CommandLine == NULL) {
432 Status = EFI_OUT_OF_RESOURCES;
433 goto UnloadImage;
434 }
435
436 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
437 QemuFwCfgReadBytes (CommandLineSize, CommandLine);
438
439 //
440 // Verify NUL-termination of the command line.
441 //
442 if (CommandLine[CommandLineSize - 1] != '\0') {
443 DEBUG ((
444 DEBUG_ERROR,
445 "%a: kernel command line is not NUL-terminated\n",
446 __func__
447 ));
448 Status = EFI_PROTOCOL_ERROR;
449 goto FreeCommandLine;
450 }
451
452 //
453 // Drop the terminating NUL, convert to UTF-16.
454 //
455 KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);
456 }
457
458 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
459 InitrdSize = (UINTN)QemuFwCfgRead32 ();
460
461 if (InitrdSize > 0) {
462 //
463 // Append ' initrd=initrd' in UTF-16.
464 //
465 KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;
466 }
467
468 if (KernelLoadedImage->LoadOptionsSize == 0) {
469 KernelLoadedImage->LoadOptions = NULL;
470 } else {
471 //
472 // NUL-terminate in UTF-16.
473 //
474 KernelLoadedImage->LoadOptionsSize += 2;
475
476 KernelLoadedImage->LoadOptions = AllocatePool (
477 KernelLoadedImage->LoadOptionsSize
478 );
479 if (KernelLoadedImage->LoadOptions == NULL) {
480 KernelLoadedImage->LoadOptionsSize = 0;
481 Status = EFI_OUT_OF_RESOURCES;
482 goto FreeCommandLine;
483 }
484
486 KernelLoadedImage->LoadOptions,
487 KernelLoadedImage->LoadOptionsSize,
488 "%a%a",
489 (CommandLineSize == 0) ? "" : CommandLine,
490 (InitrdSize == 0) ? "" : " initrd=initrd"
491 );
492 DEBUG ((
493 DEBUG_INFO,
494 "%a: command line: \"%s\"\n",
495 __func__,
496 (CHAR16 *)KernelLoadedImage->LoadOptions
497 ));
498 }
499
500 *ImageHandle = KernelImageHandle;
501 Status = EFI_SUCCESS;
502
503FreeCommandLine:
504 if (CommandLineSize > 0) {
505 FreePool (CommandLine);
506 }
507
508UnloadImage:
509 if (EFI_ERROR (Status)) {
510 gBS->UnloadImage (KernelImageHandle);
511 }
512
513 return Status;
514}
515
532EFIAPI
534 IN OUT EFI_HANDLE *ImageHandle
535 )
536{
537 EFI_STATUS Status;
538 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
539
540 Status = gBS->OpenProtocol (
541 *ImageHandle,
542 &gOvmfLoadedX86LinuxKernelProtocolGuid,
543 (VOID **)&LoadedImage,
544 gImageHandle, // AgentHandle
545 NULL, // ControllerHandle
546 EFI_OPEN_PROTOCOL_GET_PROTOCOL
547 );
548 if (!EFI_ERROR (Status)) {
549 return QemuStartLegacyImage (*ImageHandle);
550 }
551
552 Status = gBS->StartImage (
553 *ImageHandle,
554 NULL, // ExitDataSize
555 NULL // ExitData
556 );
557 #ifdef MDE_CPU_IA32
558 if (Status == EFI_UNSUPPORTED) {
559 EFI_HANDLE KernelImageHandle;
560
561 //
562 // On IA32, EFI_UNSUPPORTED means that the image's machine type is X64 while
563 // we are expecting a IA32 one, and the StartImage () boot service is unable
564 // to handle it, either because the image does not have the special .compat
565 // PE/COFF section that Linux specifies for mixed mode capable images, or
566 // because we are running without the support code for that. So load the
567 // image again, using the legacy loader, and unload the normally loaded
568 // image before starting the legacy one.
569 //
570 Status = QemuLoadLegacyImage (&KernelImageHandle);
571 if (EFI_ERROR (Status)) {
572 //
573 // Note: no change to (*ImageHandle), the caller will release it.
574 //
575 return Status;
576 }
577
578 //
579 // Swap in the legacy-loaded image.
580 //
581 QemuUnloadKernelImage (*ImageHandle);
582 *ImageHandle = KernelImageHandle;
583 return QemuStartLegacyImage (KernelImageHandle);
584 }
585
586 #endif
587 return Status;
588}
589
604EFIAPI
606 IN EFI_HANDLE ImageHandle
607 )
608{
609 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
610 EFI_STATUS Status;
611
612 Status = gBS->OpenProtocol (
613 ImageHandle,
614 &gEfiLoadedImageProtocolGuid,
615 (VOID **)&KernelLoadedImage,
616 gImageHandle, // AgentHandle
617 NULL, // ControllerHandle
618 EFI_OPEN_PROTOCOL_GET_PROTOCOL
619 );
620 if (Status == EFI_UNSUPPORTED) {
621 //
622 // The handle exists but does not have an instance of the standard loaded
623 // image protocol installed on it. Attempt to unload it as a legacy image
624 // instead.
625 //
626 return QemuUnloadLegacyImage (ImageHandle);
627 }
628
629 if (EFI_ERROR (Status)) {
630 return EFI_INVALID_PARAMETER;
631 }
632
633 //
634 // We are unloading a normal, non-legacy loaded image, either on behalf of
635 // an external caller, or called from QemuStartKernelImage() on IA32, while
636 // switching from the normal to the legacy method to load and start a X64
637 // image.
638 //
639 if (KernelLoadedImage->LoadOptions != NULL) {
640 FreePool (KernelLoadedImage->LoadOptions);
641 KernelLoadedImage->LoadOptions = NULL;
642 }
643
644 KernelLoadedImage->LoadOptionsSize = 0;
645
646 return gBS->UnloadImage (ImageHandle);
647}
UINT64 UINTN
#define MEDIA_FILEPATH_DP
Definition: DevicePath.h:1098
#define MEDIA_VENDOR_DP
Media vendor device path subtype.
Definition: DevicePath.h:1093
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI LoadLinuxInitializeKernelSetup(IN VOID *KernelSetup)
Definition: Linux.c:115
VOID *EFIAPI LoadLinuxAllocateCommandLinePages(IN UINTN Pages)
Definition: Linux.c:185
UINTN EFIAPI LoadLinuxGetKernelSize(IN VOID *KernelSetup, IN UINTN KernelSize)
Definition: Linux.c:67
VOID *EFIAPI LoadLinuxAllocateKernelPages(IN VOID *KernelSetup, IN UINTN Pages)
Definition: Linux.c:148
EFI_STATUS EFIAPI LoadLinuxSetCommandLine(IN OUT VOID *KernelSetup, IN CHAR8 *CommandLine)
Definition: Linux.c:392
EFI_STATUS EFIAPI LoadLinux(IN VOID *Kernel, IN OUT VOID *KernelSetup)
Definition: Linux.c:624
EFI_STATUS EFIAPI LoadLinuxCheckKernelSetup(IN VOID *KernelSetup, IN UINTN KernelSetupSize)
Definition: Linux.c:36
VOID *EFIAPI LoadLinuxAllocateKernelSetupPages(IN UINTN Pages)
Definition: Linux.c:92
VOID *EFIAPI LoadLinuxAllocateInitrdPages(IN VOID *KernelSetup, IN UINTN Pages)
Definition: Linux.c:208
EFI_STATUS EFIAPI LoadLinuxSetInitrd(IN OUT VOID *KernelSetup, IN VOID *Initrd, IN UINTN InitrdSize)
Definition: Linux.c:414
UINTN EFIAPI UnicodeSPrintAsciiFormat(OUT CHAR16 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition: PrintLib.c:583
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT32 EFIAPI QemuFwCfgRead32(VOID)
Definition: QemuFwCfgLib.c:205
VOID EFIAPI QemuFwCfgReadBytes(IN UINTN Size, IN VOID *Buffer OPTIONAL)
Definition: QemuFwCfgNull.c:66
VOID EFIAPI QemuFwCfgSelectItem(IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem)
Definition: QemuFwCfgLib.c:33
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_HANDLE gImageHandle
EFI_BOOT_SERVICES * gBS
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
EFI_STATUS EFIAPI QemuLoadKernelImage(OUT EFI_HANDLE *ImageHandle)
EFI_STATUS EFIAPI QemuStartKernelImage(IN OUT EFI_HANDLE *ImageHandle)
EFI_STATUS EFIAPI QemuUnloadKernelImage(IN EFI_HANDLE ImageHandle)
VOID * LoadOptions
A pointer to the image's binary load options.
Definition: LoadedImage.h:62
UINT32 LoadOptionsSize
The size in bytes of LoadOptions.
Definition: LoadedImage.h:61