]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / X86QemuLoadImageLib / X86QemuLoadImageLib.c
CommitLineData
7c47d890
AB
1/** @file\r
2 X86 specific implementation of QemuLoadImageLib library class interface\r
3 with support for loading mixed mode images and non-EFI stub images\r
4\r
9421f5ab
DM
5 Note that this implementation reads the cmdline (and possibly kernel, setup\r
6 data, and initrd in the legacy boot mode) from fw_cfg directly.\r
7\r
7c47d890
AB
8 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
9 Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>\r
10\r
11 SPDX-License-Identifier: BSD-2-Clause-Patent\r
12**/\r
13\r
14#include <Uefi.h>\r
15\r
16#include <Guid/QemuKernelLoaderFsMedia.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/LoadLinuxLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/PrintLib.h>\r
21#include <Library/QemuFwCfgLib.h>\r
22#include <Library/QemuLoadImageLib.h>\r
23#include <Library/UefiBootServicesTableLib.h>\r
24#include <Protocol/DevicePath.h>\r
25#include <Protocol/LoadedImage.h>\r
26#include <Protocol/OvmfLoadedX86LinuxKernel.h>\r
27\r
28#pragma pack (1)\r
29typedef struct {\r
ac0a286f
MK
30 EFI_DEVICE_PATH_PROTOCOL FilePathHeader;\r
31 CHAR16 FilePath[ARRAY_SIZE (L"kernel")];\r
7c47d890
AB
32} KERNEL_FILE_DEVPATH;\r
33\r
34typedef struct {\r
ac0a286f
MK
35 VENDOR_DEVICE_PATH VenMediaNode;\r
36 KERNEL_FILE_DEVPATH FileNode;\r
37 EFI_DEVICE_PATH_PROTOCOL EndNode;\r
7c47d890
AB
38} KERNEL_VENMEDIA_FILE_DEVPATH;\r
39#pragma pack ()\r
40\r
ac0a286f 41STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {\r
7c47d890
AB
42 {\r
43 {\r
44 MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,\r
ac0a286f 45 { sizeof (VENDOR_DEVICE_PATH) }\r
7c47d890
AB
46 },\r
47 QEMU_KERNEL_LOADER_FS_MEDIA_GUID\r
ac0a286f 48 }, {\r
7c47d890
AB
49 {\r
50 MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,\r
ac0a286f 51 { sizeof (KERNEL_FILE_DEVPATH) }\r
7c47d890
AB
52 },\r
53 L"kernel",\r
ac0a286f 54 }, {\r
7c47d890
AB
55 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
56 { sizeof (EFI_DEVICE_PATH_PROTOCOL) }\r
57 }\r
58};\r
59\r
60STATIC\r
61VOID\r
62FreeLegacyImage (\r
ac0a286f 63 IN OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage\r
7c47d890
AB
64 )\r
65{\r
66 if (LoadedImage->SetupBuf != NULL) {\r
ac0a286f
MK
67 FreePages (\r
68 LoadedImage->SetupBuf,\r
69 EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)\r
70 );\r
7c47d890 71 }\r
ac0a286f 72\r
7c47d890 73 if (LoadedImage->KernelBuf != NULL) {\r
ac0a286f
MK
74 FreePages (\r
75 LoadedImage->KernelBuf,\r
76 EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)\r
77 );\r
7c47d890 78 }\r
ac0a286f 79\r
7c47d890 80 if (LoadedImage->CommandLine != NULL) {\r
ac0a286f
MK
81 FreePages (\r
82 LoadedImage->CommandLine,\r
83 EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize)\r
84 );\r
7c47d890 85 }\r
ac0a286f 86\r
7c47d890 87 if (LoadedImage->InitrdData != NULL) {\r
ac0a286f
MK
88 FreePages (\r
89 LoadedImage->InitrdData,\r
90 EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize)\r
91 );\r
7c47d890
AB
92 }\r
93}\r
94\r
95STATIC\r
96EFI_STATUS\r
97QemuLoadLegacyImage (\r
ac0a286f 98 OUT EFI_HANDLE *ImageHandle\r
7c47d890
AB
99 )\r
100{\r
ac0a286f
MK
101 EFI_STATUS Status;\r
102 UINTN KernelSize;\r
103 UINTN SetupSize;\r
104 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
7c47d890
AB
105\r
106 QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);\r
107 KernelSize = (UINTN)QemuFwCfgRead32 ();\r
108\r
109 QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);\r
110 SetupSize = (UINTN)QemuFwCfgRead32 ();\r
111\r
ac0a286f 112 if ((KernelSize == 0) || (SetupSize == 0)) {\r
7c47d890
AB
113 DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n"));\r
114 return EFI_NOT_FOUND;\r
115 }\r
116\r
117 LoadedImage = AllocateZeroPool (sizeof (*LoadedImage));\r
118 if (LoadedImage == NULL) {\r
119 return EFI_OUT_OF_RESOURCES;\r
120 }\r
121\r
122 LoadedImage->SetupSize = SetupSize;\r
ac0a286f
MK
123 LoadedImage->SetupBuf = LoadLinuxAllocateKernelSetupPages (\r
124 EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)\r
125 );\r
7c47d890
AB
126 if (LoadedImage->SetupBuf == NULL) {\r
127 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n"));\r
128 Status = EFI_OUT_OF_RESOURCES;\r
129 goto FreeImageDesc;\r
130 }\r
131\r
132 DEBUG ((DEBUG_INFO, "Setup size: 0x%x\n", (UINT32)LoadedImage->SetupSize));\r
133 DEBUG ((DEBUG_INFO, "Reading kernel setup image ..."));\r
134 QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);\r
135 QemuFwCfgReadBytes (LoadedImage->SetupSize, LoadedImage->SetupBuf);\r
136 DEBUG ((DEBUG_INFO, " [done]\n"));\r
137\r
ac0a286f
MK
138 Status = LoadLinuxCheckKernelSetup (\r
139 LoadedImage->SetupBuf,\r
140 LoadedImage->SetupSize\r
141 );\r
7c47d890
AB
142 if (EFI_ERROR (Status)) {\r
143 goto FreeImage;\r
144 }\r
145\r
146 Status = LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf);\r
147 if (EFI_ERROR (Status)) {\r
148 goto FreeImage;\r
149 }\r
150\r
151 LoadedImage->KernelInitialSize = LoadLinuxGetKernelSize (\r
ac0a286f
MK
152 LoadedImage->SetupBuf,\r
153 KernelSize\r
154 );\r
7c47d890
AB
155 if (LoadedImage->KernelInitialSize == 0) {\r
156 Status = EFI_UNSUPPORTED;\r
157 goto FreeImage;\r
158 }\r
159\r
160 LoadedImage->KernelBuf = LoadLinuxAllocateKernelPages (\r
161 LoadedImage->SetupBuf,\r
162 EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)\r
163 );\r
164 if (LoadedImage->KernelBuf == NULL) {\r
165 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n"));\r
166 Status = EFI_OUT_OF_RESOURCES;\r
167 goto FreeImage;\r
168 }\r
169\r
170 DEBUG ((DEBUG_INFO, "Kernel size: 0x%x\n", (UINT32)KernelSize));\r
171 DEBUG ((DEBUG_INFO, "Reading kernel image ..."));\r
172 QemuFwCfgSelectItem (QemuFwCfgItemKernelData);\r
173 QemuFwCfgReadBytes (KernelSize, LoadedImage->KernelBuf);\r
174 DEBUG ((DEBUG_INFO, " [done]\n"));\r
175\r
176 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);\r
177 LoadedImage->CommandLineSize = (UINTN)QemuFwCfgRead32 ();\r
178\r
179 if (LoadedImage->CommandLineSize > 0) {\r
180 LoadedImage->CommandLine = LoadLinuxAllocateCommandLinePages (\r
181 EFI_SIZE_TO_PAGES (\r
ac0a286f
MK
182 LoadedImage->CommandLineSize\r
183 )\r
184 );\r
ca318882
MR
185 if (LoadedImage->CommandLine == NULL) {\r
186 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel command line!\n"));\r
187 Status = EFI_OUT_OF_RESOURCES;\r
188 goto FreeImage;\r
189 }\r
ac0a286f 190\r
7c47d890
AB
191 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);\r
192 QemuFwCfgReadBytes (LoadedImage->CommandLineSize, LoadedImage->CommandLine);\r
193 }\r
194\r
ac0a286f
MK
195 Status = LoadLinuxSetCommandLine (\r
196 LoadedImage->SetupBuf,\r
197 LoadedImage->CommandLine\r
198 );\r
7c47d890
AB
199 if (EFI_ERROR (Status)) {\r
200 goto FreeImage;\r
201 }\r
202\r
203 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);\r
204 LoadedImage->InitrdSize = (UINTN)QemuFwCfgRead32 ();\r
205\r
206 if (LoadedImage->InitrdSize > 0) {\r
207 LoadedImage->InitrdData = LoadLinuxAllocateInitrdPages (\r
208 LoadedImage->SetupBuf,\r
ac0a286f
MK
209 EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize)\r
210 );\r
ca318882
MR
211 if (LoadedImage->InitrdData == NULL) {\r
212 DEBUG ((DEBUG_ERROR, "Unable to allocate memory for initrd!\n"));\r
213 Status = EFI_OUT_OF_RESOURCES;\r
214 goto FreeImage;\r
215 }\r
ac0a286f
MK
216\r
217 DEBUG ((\r
218 DEBUG_INFO,\r
219 "Initrd size: 0x%x\n",\r
220 (UINT32)LoadedImage->InitrdSize\r
221 ));\r
7c47d890
AB
222 DEBUG ((DEBUG_INFO, "Reading initrd image ..."));\r
223 QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);\r
224 QemuFwCfgReadBytes (LoadedImage->InitrdSize, LoadedImage->InitrdData);\r
225 DEBUG ((DEBUG_INFO, " [done]\n"));\r
226 }\r
227\r
ac0a286f
MK
228 Status = LoadLinuxSetInitrd (\r
229 LoadedImage->SetupBuf,\r
230 LoadedImage->InitrdData,\r
231 LoadedImage->InitrdSize\r
232 );\r
7c47d890
AB
233 if (EFI_ERROR (Status)) {\r
234 goto FreeImage;\r
235 }\r
236\r
237 *ImageHandle = NULL;\r
ac0a286f
MK
238 Status = gBS->InstallProtocolInterface (\r
239 ImageHandle,\r
240 &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
241 EFI_NATIVE_INTERFACE,\r
242 LoadedImage\r
243 );\r
7c47d890
AB
244 if (EFI_ERROR (Status)) {\r
245 goto FreeImage;\r
246 }\r
ac0a286f 247\r
7c47d890
AB
248 return EFI_SUCCESS;\r
249\r
250FreeImage:\r
251 FreeLegacyImage (LoadedImage);\r
252FreeImageDesc:\r
253 FreePool (LoadedImage);\r
254 return Status;\r
255}\r
256\r
257STATIC\r
258EFI_STATUS\r
259QemuStartLegacyImage (\r
ac0a286f 260 IN EFI_HANDLE ImageHandle\r
7c47d890
AB
261 )\r
262{\r
263 EFI_STATUS Status;\r
264 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
265\r
266 Status = gBS->OpenProtocol (\r
267 ImageHandle,\r
268 &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
269 (VOID **)&LoadedImage,\r
270 gImageHandle, // AgentHandle\r
271 NULL, // ControllerHandle\r
272 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
273 );\r
274 if (EFI_ERROR (Status)) {\r
275 return EFI_INVALID_PARAMETER;\r
276 }\r
277\r
278 return LoadLinux (LoadedImage->KernelBuf, LoadedImage->SetupBuf);\r
279}\r
280\r
281STATIC\r
282EFI_STATUS\r
283QemuUnloadLegacyImage (\r
ac0a286f 284 IN EFI_HANDLE ImageHandle\r
7c47d890
AB
285 )\r
286{\r
287 EFI_STATUS Status;\r
288 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
289\r
290 Status = gBS->OpenProtocol (\r
291 ImageHandle,\r
292 &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
293 (VOID **)&LoadedImage,\r
294 gImageHandle, // AgentHandle\r
295 NULL, // ControllerHandle\r
296 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
297 );\r
298 if (EFI_ERROR (Status)) {\r
299 return EFI_INVALID_PARAMETER;\r
300 }\r
301\r
ac0a286f
MK
302 Status = gBS->UninstallProtocolInterface (\r
303 ImageHandle,\r
304 &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
305 LoadedImage\r
306 );\r
7c47d890
AB
307 ASSERT_EFI_ERROR (Status);\r
308\r
309 FreeLegacyImage (LoadedImage);\r
310 FreePool (LoadedImage);\r
311 return EFI_SUCCESS;\r
312}\r
313\r
314/**\r
315 Download the kernel, the initial ramdisk, and the kernel command line from\r
316 QEMU's fw_cfg. The kernel will be instructed via its command line to load\r
317 the initrd from the same Simple FileSystem where the kernel was loaded from.\r
318\r
319 @param[out] ImageHandle The image handle that was allocated for\r
320 loading the image\r
321\r
322 @retval EFI_SUCCESS The image was loaded successfully.\r
323 @retval EFI_NOT_FOUND Kernel image was not found.\r
324 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
325 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.\r
326\r
327 @return Error codes from any of the underlying\r
328 functions.\r
329**/\r
330EFI_STATUS\r
331EFIAPI\r
332QemuLoadKernelImage (\r
ac0a286f 333 OUT EFI_HANDLE *ImageHandle\r
7c47d890
AB
334 )\r
335{\r
ac0a286f
MK
336 EFI_STATUS Status;\r
337 EFI_HANDLE KernelImageHandle;\r
338 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
339 UINTN CommandLineSize;\r
340 CHAR8 *CommandLine;\r
341 UINTN InitrdSize;\r
7c47d890 342\r
92a1ac40
AB
343 //\r
344 // Redundant assignment to work around GCC48/GCC49 limitations.\r
345 //\r
346 CommandLine = NULL;\r
347\r
7c47d890
AB
348 //\r
349 // Load the image. This should call back into the QEMU EFI loader file system.\r
350 //\r
351 Status = gBS->LoadImage (\r
352 FALSE, // BootPolicy: exact match required\r
353 gImageHandle, // ParentImageHandle\r
354 (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,\r
355 NULL, // SourceBuffer\r
356 0, // SourceSize\r
357 &KernelImageHandle\r
358 );\r
359 switch (Status) {\r
ac0a286f
MK
360 case EFI_SUCCESS:\r
361 break;\r
7c47d890 362\r
ac0a286f
MK
363 case EFI_NOT_FOUND:\r
364 //\r
365 // The image does not exist - no -kernel image was supplied via the\r
366 // command line so no point in invoking the legacy fallback\r
367 //\r
368 return EFI_NOT_FOUND;\r
7c47d890 369\r
ac0a286f
MK
370 case EFI_SECURITY_VIOLATION:\r
371 //\r
372 // Since the image has been loaded, we need to unload it before proceeding\r
373 // to the EFI_ACCESS_DENIED case below.\r
374 //\r
375 gBS->UnloadImage (KernelImageHandle);\r
7c47d890
AB
376 //\r
377 // Fall through\r
378 //\r
ac0a286f 379 case EFI_ACCESS_DENIED:\r
dafce295
LE
380 //\r
381 // We are running with UEFI secure boot enabled, and the image failed to\r
382 // authenticate. For compatibility reasons, we fall back to the legacy\r
383 // loader in this case.\r
384 //\r
385 // Fall through\r
386 //\r
ac0a286f
MK
387 case EFI_UNSUPPORTED:\r
388 //\r
389 // The image is not natively supported or cross-type supported. Let's try\r
390 // loading it using the loader that parses the bzImage metadata directly.\r
391 //\r
392 Status = QemuLoadLegacyImage (&KernelImageHandle);\r
393 if (EFI_ERROR (Status)) {\r
394 DEBUG ((\r
395 DEBUG_ERROR,\r
396 "%a: QemuLoadLegacyImage(): %r\n",\r
397 __FUNCTION__,\r
398 Status\r
399 ));\r
400 return Status;\r
401 }\r
402\r
403 *ImageHandle = KernelImageHandle;\r
404 return EFI_SUCCESS;\r
405\r
406 default:\r
407 DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));\r
7c47d890 408 return Status;\r
7c47d890
AB
409 }\r
410\r
411 //\r
412 // Construct the kernel command line.\r
413 //\r
414 Status = gBS->OpenProtocol (\r
415 KernelImageHandle,\r
416 &gEfiLoadedImageProtocolGuid,\r
417 (VOID **)&KernelLoadedImage,\r
418 gImageHandle, // AgentHandle\r
419 NULL, // ControllerHandle\r
420 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
421 );\r
422 ASSERT_EFI_ERROR (Status);\r
423\r
424 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);\r
425 CommandLineSize = (UINTN)QemuFwCfgRead32 ();\r
426\r
427 if (CommandLineSize == 0) {\r
428 KernelLoadedImage->LoadOptionsSize = 0;\r
429 } else {\r
430 CommandLine = AllocatePool (CommandLineSize);\r
431 if (CommandLine == NULL) {\r
432 Status = EFI_OUT_OF_RESOURCES;\r
433 goto UnloadImage;\r
434 }\r
435\r
436 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);\r
437 QemuFwCfgReadBytes (CommandLineSize, CommandLine);\r
438\r
439 //\r
440 // Verify NUL-termination of the command line.\r
441 //\r
442 if (CommandLine[CommandLineSize - 1] != '\0') {\r
ac0a286f
MK
443 DEBUG ((\r
444 DEBUG_ERROR,\r
445 "%a: kernel command line is not NUL-terminated\n",\r
446 __FUNCTION__\r
447 ));\r
7c47d890
AB
448 Status = EFI_PROTOCOL_ERROR;\r
449 goto FreeCommandLine;\r
450 }\r
451\r
452 //\r
453 // Drop the terminating NUL, convert to UTF-16.\r
454 //\r
ac0a286f 455 KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);\r
7c47d890
AB
456 }\r
457\r
458 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);\r
459 InitrdSize = (UINTN)QemuFwCfgRead32 ();\r
460\r
461 if (InitrdSize > 0) {\r
462 //\r
463 // Append ' initrd=initrd' in UTF-16.\r
464 //\r
465 KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;\r
466 }\r
467\r
468 if (KernelLoadedImage->LoadOptionsSize == 0) {\r
469 KernelLoadedImage->LoadOptions = NULL;\r
470 } else {\r
471 //\r
472 // NUL-terminate in UTF-16.\r
473 //\r
474 KernelLoadedImage->LoadOptionsSize += 2;\r
475\r
476 KernelLoadedImage->LoadOptions = AllocatePool (\r
ac0a286f
MK
477 KernelLoadedImage->LoadOptionsSize\r
478 );\r
7c47d890
AB
479 if (KernelLoadedImage->LoadOptions == NULL) {\r
480 KernelLoadedImage->LoadOptionsSize = 0;\r
ac0a286f 481 Status = EFI_OUT_OF_RESOURCES;\r
7c47d890
AB
482 goto FreeCommandLine;\r
483 }\r
484\r
485 UnicodeSPrintAsciiFormat (\r
486 KernelLoadedImage->LoadOptions,\r
487 KernelLoadedImage->LoadOptionsSize,\r
488 "%a%a",\r
489 (CommandLineSize == 0) ? "" : CommandLine,\r
490 (InitrdSize == 0) ? "" : " initrd=initrd"\r
491 );\r
ac0a286f
MK
492 DEBUG ((\r
493 DEBUG_INFO,\r
494 "%a: command line: \"%s\"\n",\r
495 __FUNCTION__,\r
496 (CHAR16 *)KernelLoadedImage->LoadOptions\r
497 ));\r
7c47d890
AB
498 }\r
499\r
500 *ImageHandle = KernelImageHandle;\r
ac0a286f 501 Status = EFI_SUCCESS;\r
7c47d890
AB
502\r
503FreeCommandLine:\r
504 if (CommandLineSize > 0) {\r
505 FreePool (CommandLine);\r
506 }\r
ac0a286f 507\r
7c47d890 508UnloadImage:\r
93244971
DM
509 if (EFI_ERROR (Status)) {\r
510 gBS->UnloadImage (KernelImageHandle);\r
511 }\r
7c47d890
AB
512\r
513 return Status;\r
514}\r
515\r
516/**\r
517 Transfer control to a kernel image loaded with QemuLoadKernelImage ()\r
518\r
519 @param[in,out] ImageHandle Handle of image to be started. May assume a\r
520 different value on return if the image was\r
521 reloaded.\r
522\r
523 @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle\r
524 or the image has already been initialized with\r
525 StartImage\r
526 @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the\r
527 image should not be started.\r
528\r
529 @return Error codes returned by the started image\r
530**/\r
531EFI_STATUS\r
532EFIAPI\r
533QemuStartKernelImage (\r
ac0a286f 534 IN OUT EFI_HANDLE *ImageHandle\r
7c47d890
AB
535 )\r
536{\r
537 EFI_STATUS Status;\r
538 OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
7c47d890
AB
539\r
540 Status = gBS->OpenProtocol (\r
541 *ImageHandle,\r
542 &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
543 (VOID **)&LoadedImage,\r
544 gImageHandle, // AgentHandle\r
545 NULL, // ControllerHandle\r
546 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
547 );\r
548 if (!EFI_ERROR (Status)) {\r
549 return QemuStartLegacyImage (*ImageHandle);\r
550 }\r
551\r
552 Status = gBS->StartImage (\r
553 *ImageHandle,\r
554 NULL, // ExitDataSize\r
555 NULL // ExitData\r
556 );\r
ac0a286f 557 #ifdef MDE_CPU_IA32\r
7c47d890 558 if (Status == EFI_UNSUPPORTED) {\r
ac0a286f 559 EFI_HANDLE KernelImageHandle;\r
a3e25cc8 560\r
7c47d890
AB
561 //\r
562 // On IA32, EFI_UNSUPPORTED means that the image's machine type is X64 while\r
563 // we are expecting a IA32 one, and the StartImage () boot service is unable\r
564 // to handle it, either because the image does not have the special .compat\r
565 // PE/COFF section that Linux specifies for mixed mode capable images, or\r
566 // because we are running without the support code for that. So load the\r
567 // image again, using the legacy loader, and unload the normally loaded\r
568 // image before starting the legacy one.\r
569 //\r
570 Status = QemuLoadLegacyImage (&KernelImageHandle);\r
571 if (EFI_ERROR (Status)) {\r
572 //\r
573 // Note: no change to (*ImageHandle), the caller will release it.\r
574 //\r
575 return Status;\r
576 }\r
ac0a286f 577\r
7c47d890
AB
578 //\r
579 // Swap in the legacy-loaded image.\r
580 //\r
581 QemuUnloadKernelImage (*ImageHandle);\r
582 *ImageHandle = KernelImageHandle;\r
583 return QemuStartLegacyImage (KernelImageHandle);\r
584 }\r
ac0a286f
MK
585\r
586 #endif\r
7c47d890
AB
587 return Status;\r
588}\r
589\r
590/**\r
591 Unloads an image loaded with QemuLoadKernelImage ().\r
592\r
593 @param ImageHandle Handle that identifies the image to be\r
594 unloaded.\r
595\r
596 @retval EFI_SUCCESS The image has been unloaded.\r
597 @retval EFI_UNSUPPORTED The image has been started, and does not\r
598 support unload.\r
599 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.\r
600\r
601 @return Exit code from the image's unload function.\r
602**/\r
603EFI_STATUS\r
604EFIAPI\r
605QemuUnloadKernelImage (\r
ac0a286f 606 IN EFI_HANDLE ImageHandle\r
7c47d890
AB
607 )\r
608{\r
ac0a286f
MK
609 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
610 EFI_STATUS Status;\r
7c47d890
AB
611\r
612 Status = gBS->OpenProtocol (\r
613 ImageHandle,\r
614 &gEfiLoadedImageProtocolGuid,\r
615 (VOID **)&KernelLoadedImage,\r
616 gImageHandle, // AgentHandle\r
617 NULL, // ControllerHandle\r
618 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
619 );\r
620 if (Status == EFI_UNSUPPORTED) {\r
621 //\r
622 // The handle exists but does not have an instance of the standard loaded\r
623 // image protocol installed on it. Attempt to unload it as a legacy image\r
624 // instead.\r
625 //\r
626 return QemuUnloadLegacyImage (ImageHandle);\r
627 }\r
628\r
629 if (EFI_ERROR (Status)) {\r
630 return EFI_INVALID_PARAMETER;\r
631 }\r
632\r
633 //\r
634 // We are unloading a normal, non-legacy loaded image, either on behalf of\r
635 // an external caller, or called from QemuStartKernelImage() on IA32, while\r
636 // switching from the normal to the legacy method to load and start a X64\r
637 // image.\r
638 //\r
639 if (KernelLoadedImage->LoadOptions != NULL) {\r
640 FreePool (KernelLoadedImage->LoadOptions);\r
641 KernelLoadedImage->LoadOptions = NULL;\r
642 }\r
ac0a286f 643\r
7c47d890
AB
644 KernelLoadedImage->LoadOptionsSize = 0;\r
645\r
646 return gBS->UnloadImage (ImageHandle);\r
647}\r