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