--- /dev/null
+/** @file\r
+ X86 specific implementation of QemuLoadImageLib library class interface\r
+ with support for loading mixed mode images and non-EFI stub images\r
+\r
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/QemuKernelLoaderFsMedia.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/LoadLinuxLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/QemuFwCfgLib.h>\r
+#include <Library/QemuLoadImageLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/OvmfLoadedX86LinuxKernel.h>\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+ EFI_DEVICE_PATH_PROTOCOL FilePathHeader;\r
+ CHAR16 FilePath[ARRAY_SIZE (L"kernel")];\r
+} KERNEL_FILE_DEVPATH;\r
+\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH VenMediaNode;\r
+ KERNEL_FILE_DEVPATH FileNode;\r
+ EFI_DEVICE_PATH_PROTOCOL EndNode;\r
+} KERNEL_VENMEDIA_FILE_DEVPATH;\r
+#pragma pack ()\r
+\r
+STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {\r
+ {\r
+ {\r
+ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,\r
+ { sizeof (VENDOR_DEVICE_PATH) }\r
+ },\r
+ QEMU_KERNEL_LOADER_FS_MEDIA_GUID\r
+ }, {\r
+ {\r
+ MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,\r
+ { sizeof (KERNEL_FILE_DEVPATH) }\r
+ },\r
+ L"kernel",\r
+ }, {\r
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL) }\r
+ }\r
+};\r
+\r
+STATIC\r
+VOID\r
+FreeLegacyImage (\r
+ IN OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage\r
+ )\r
+{\r
+ if (LoadedImage->SetupBuf != NULL) {\r
+ FreePages (LoadedImage->SetupBuf,\r
+ EFI_SIZE_TO_PAGES (LoadedImage->SetupSize));\r
+ }\r
+ if (LoadedImage->KernelBuf != NULL) {\r
+ FreePages (LoadedImage->KernelBuf,\r
+ EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize));\r
+ }\r
+ if (LoadedImage->CommandLine != NULL) {\r
+ FreePages (LoadedImage->CommandLine,\r
+ EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize));\r
+ }\r
+ if (LoadedImage->InitrdData != NULL) {\r
+ FreePages (LoadedImage->InitrdData,\r
+ EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize));\r
+ }\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+QemuLoadLegacyImage (\r
+ OUT EFI_HANDLE *ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN KernelSize;\r
+ UINTN SetupSize;\r
+ OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);\r
+ KernelSize = (UINTN)QemuFwCfgRead32 ();\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);\r
+ SetupSize = (UINTN)QemuFwCfgRead32 ();\r
+\r
+ if (KernelSize == 0 || SetupSize == 0) {\r
+ DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n"));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ LoadedImage = AllocateZeroPool (sizeof (*LoadedImage));\r
+ if (LoadedImage == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ LoadedImage->SetupSize = SetupSize;\r
+ LoadedImage->SetupBuf = LoadLinuxAllocateKernelSetupPages (\r
+ EFI_SIZE_TO_PAGES (LoadedImage->SetupSize));\r
+ if (LoadedImage->SetupBuf == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FreeImageDesc;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "Setup size: 0x%x\n", (UINT32)LoadedImage->SetupSize));\r
+ DEBUG ((DEBUG_INFO, "Reading kernel setup image ..."));\r
+ QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);\r
+ QemuFwCfgReadBytes (LoadedImage->SetupSize, LoadedImage->SetupBuf);\r
+ DEBUG ((DEBUG_INFO, " [done]\n"));\r
+\r
+ Status = LoadLinuxCheckKernelSetup (LoadedImage->SetupBuf,\r
+ LoadedImage->SetupSize);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeImage;\r
+ }\r
+\r
+ Status = LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeImage;\r
+ }\r
+\r
+ LoadedImage->KernelInitialSize = LoadLinuxGetKernelSize (\r
+ LoadedImage->SetupBuf, KernelSize);\r
+ if (LoadedImage->KernelInitialSize == 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto FreeImage;\r
+ }\r
+\r
+ LoadedImage->KernelBuf = LoadLinuxAllocateKernelPages (\r
+ LoadedImage->SetupBuf,\r
+ EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)\r
+ );\r
+ if (LoadedImage->KernelBuf == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FreeImage;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "Kernel size: 0x%x\n", (UINT32)KernelSize));\r
+ DEBUG ((DEBUG_INFO, "Reading kernel image ..."));\r
+ QemuFwCfgSelectItem (QemuFwCfgItemKernelData);\r
+ QemuFwCfgReadBytes (KernelSize, LoadedImage->KernelBuf);\r
+ DEBUG ((DEBUG_INFO, " [done]\n"));\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);\r
+ LoadedImage->CommandLineSize = (UINTN)QemuFwCfgRead32 ();\r
+\r
+ if (LoadedImage->CommandLineSize > 0) {\r
+ LoadedImage->CommandLine = LoadLinuxAllocateCommandLinePages (\r
+ EFI_SIZE_TO_PAGES (\r
+ LoadedImage->CommandLineSize));\r
+ QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);\r
+ QemuFwCfgReadBytes (LoadedImage->CommandLineSize, LoadedImage->CommandLine);\r
+ }\r
+\r
+ Status = LoadLinuxSetCommandLine (LoadedImage->SetupBuf,\r
+ LoadedImage->CommandLine);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeImage;\r
+ }\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);\r
+ LoadedImage->InitrdSize = (UINTN)QemuFwCfgRead32 ();\r
+\r
+ if (LoadedImage->InitrdSize > 0) {\r
+ LoadedImage->InitrdData = LoadLinuxAllocateInitrdPages (\r
+ LoadedImage->SetupBuf,\r
+ EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize));\r
+ DEBUG ((DEBUG_INFO, "Initrd size: 0x%x\n",\r
+ (UINT32)LoadedImage->InitrdSize));\r
+ DEBUG ((DEBUG_INFO, "Reading initrd image ..."));\r
+ QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);\r
+ QemuFwCfgReadBytes (LoadedImage->InitrdSize, LoadedImage->InitrdData);\r
+ DEBUG ((DEBUG_INFO, " [done]\n"));\r
+ }\r
+\r
+ Status = LoadLinuxSetInitrd (LoadedImage->SetupBuf, LoadedImage->InitrdData,\r
+ LoadedImage->InitrdSize);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeImage;\r
+ }\r
+\r
+ *ImageHandle = NULL;\r
+ Status = gBS->InstallProtocolInterface (ImageHandle,\r
+ &gOvmfLoadedX86LinuxKernelProtocolGuid, EFI_NATIVE_INTERFACE,\r
+ LoadedImage);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeImage;\r
+ }\r
+ return EFI_SUCCESS;\r
+\r
+FreeImage:\r
+ FreeLegacyImage (LoadedImage);\r
+FreeImageDesc:\r
+ FreePool (LoadedImage);\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+QemuStartLegacyImage (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
+ &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
+ (VOID **)&LoadedImage,\r
+ gImageHandle, // AgentHandle\r
+ NULL, // ControllerHandle\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return LoadLinux (LoadedImage->KernelBuf, LoadedImage->SetupBuf);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+QemuUnloadLegacyImage (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
+ &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
+ (VOID **)&LoadedImage,\r
+ gImageHandle, // AgentHandle\r
+ NULL, // ControllerHandle\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = gBS->UninstallProtocolInterface (ImageHandle,\r
+ &gOvmfLoadedX86LinuxKernelProtocolGuid, LoadedImage);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ FreeLegacyImage (LoadedImage);\r
+ FreePool (LoadedImage);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Download the kernel, the initial ramdisk, and the kernel command line from\r
+ QEMU's fw_cfg. The kernel will be instructed via its command line to load\r
+ the initrd from the same Simple FileSystem where the kernel was loaded from.\r
+\r
+ @param[out] ImageHandle The image handle that was allocated for\r
+ loading the image\r
+\r
+ @retval EFI_SUCCESS The image was loaded successfully.\r
+ @retval EFI_NOT_FOUND Kernel image was not found.\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
+ @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.\r
+\r
+ @return Error codes from any of the underlying\r
+ functions.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QemuLoadKernelImage (\r
+ OUT EFI_HANDLE *ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE KernelImageHandle;\r
+ EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
+ UINTN CommandLineSize;\r
+ CHAR8 *CommandLine;\r
+ UINTN InitrdSize;\r
+\r
+ //\r
+ // Load the image. This should call back into the QEMU EFI loader file system.\r
+ //\r
+ Status = gBS->LoadImage (\r
+ FALSE, // BootPolicy: exact match required\r
+ gImageHandle, // ParentImageHandle\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,\r
+ NULL, // SourceBuffer\r
+ 0, // SourceSize\r
+ &KernelImageHandle\r
+ );\r
+ switch (Status) {\r
+ case EFI_SUCCESS:\r
+ break;\r
+\r
+ case EFI_NOT_FOUND:\r
+ //\r
+ // The image does not exist - no -kernel image was supplied via the\r
+ // command line so no point in invoking the legacy fallback\r
+ //\r
+ return EFI_NOT_FOUND;\r
+\r
+ case EFI_SECURITY_VIOLATION:\r
+ //\r
+ // We are running with UEFI secure boot enabled, and the image failed to\r
+ // authenticate. For compatibility reasons, we fall back to the legacy\r
+ // loader in this case. Since the image has been loaded, we need to unload\r
+ // it before proceeding\r
+ //\r
+ gBS->UnloadImage (KernelImageHandle);\r
+ //\r
+ // Fall through\r
+ //\r
+ case EFI_UNSUPPORTED:\r
+ //\r
+ // The image is not natively supported or cross-type supported. Let's try\r
+ // loading it using the loader that parses the bzImage metadata directly.\r
+ //\r
+ Status = QemuLoadLegacyImage (&KernelImageHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: QemuLoadLegacyImage(): %r\n", __FUNCTION__,\r
+ Status));\r
+ return Status;\r
+ }\r
+ *ImageHandle = KernelImageHandle;\r
+ return EFI_SUCCESS;\r
+\r
+ default:\r
+ DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Construct the kernel command line.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ KernelImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&KernelLoadedImage,\r
+ gImageHandle, // AgentHandle\r
+ NULL, // ControllerHandle\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);\r
+ CommandLineSize = (UINTN)QemuFwCfgRead32 ();\r
+\r
+ if (CommandLineSize == 0) {\r
+ KernelLoadedImage->LoadOptionsSize = 0;\r
+ } else {\r
+ CommandLine = AllocatePool (CommandLineSize);\r
+ if (CommandLine == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto UnloadImage;\r
+ }\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);\r
+ QemuFwCfgReadBytes (CommandLineSize, CommandLine);\r
+\r
+ //\r
+ // Verify NUL-termination of the command line.\r
+ //\r
+ if (CommandLine[CommandLineSize - 1] != '\0') {\r
+ DEBUG ((DEBUG_ERROR, "%a: kernel command line is not NUL-terminated\n",\r
+ __FUNCTION__));\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ goto FreeCommandLine;\r
+ }\r
+\r
+ //\r
+ // Drop the terminating NUL, convert to UTF-16.\r
+ //\r
+ KernelLoadedImage->LoadOptionsSize = (CommandLineSize - 1) * 2;\r
+ }\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);\r
+ InitrdSize = (UINTN)QemuFwCfgRead32 ();\r
+\r
+ if (InitrdSize > 0) {\r
+ //\r
+ // Append ' initrd=initrd' in UTF-16.\r
+ //\r
+ KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;\r
+ }\r
+\r
+ if (KernelLoadedImage->LoadOptionsSize == 0) {\r
+ KernelLoadedImage->LoadOptions = NULL;\r
+ } else {\r
+ //\r
+ // NUL-terminate in UTF-16.\r
+ //\r
+ KernelLoadedImage->LoadOptionsSize += 2;\r
+\r
+ KernelLoadedImage->LoadOptions = AllocatePool (\r
+ KernelLoadedImage->LoadOptionsSize);\r
+ if (KernelLoadedImage->LoadOptions == NULL) {\r
+ KernelLoadedImage->LoadOptionsSize = 0;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FreeCommandLine;\r
+ }\r
+\r
+ UnicodeSPrintAsciiFormat (\r
+ KernelLoadedImage->LoadOptions,\r
+ KernelLoadedImage->LoadOptionsSize,\r
+ "%a%a",\r
+ (CommandLineSize == 0) ? "" : CommandLine,\r
+ (InitrdSize == 0) ? "" : " initrd=initrd"\r
+ );\r
+ DEBUG ((DEBUG_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,\r
+ (CHAR16 *)KernelLoadedImage->LoadOptions));\r
+ }\r
+\r
+ *ImageHandle = KernelImageHandle;\r
+ return EFI_SUCCESS;\r
+\r
+FreeCommandLine:\r
+ if (CommandLineSize > 0) {\r
+ FreePool (CommandLine);\r
+ }\r
+UnloadImage:\r
+ gBS->UnloadImage (KernelImageHandle);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Transfer control to a kernel image loaded with QemuLoadKernelImage ()\r
+\r
+ @param[in,out] ImageHandle Handle of image to be started. May assume a\r
+ different value on return if the image was\r
+ reloaded.\r
+\r
+ @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle\r
+ or the image has already been initialized with\r
+ StartImage\r
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the\r
+ image should not be started.\r
+\r
+ @return Error codes returned by the started image\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QemuStartKernelImage (\r
+ IN OUT EFI_HANDLE *ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;\r
+ EFI_HANDLE KernelImageHandle;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ *ImageHandle,\r
+ &gOvmfLoadedX86LinuxKernelProtocolGuid,\r
+ (VOID **)&LoadedImage,\r
+ gImageHandle, // AgentHandle\r
+ NULL, // ControllerHandle\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return QemuStartLegacyImage (*ImageHandle);\r
+ }\r
+\r
+ Status = gBS->StartImage (\r
+ *ImageHandle,\r
+ NULL, // ExitDataSize\r
+ NULL // ExitData\r
+ );\r
+#ifdef MDE_CPU_IA32\r
+ if (Status == EFI_UNSUPPORTED) {\r
+ //\r
+ // On IA32, EFI_UNSUPPORTED means that the image's machine type is X64 while\r
+ // we are expecting a IA32 one, and the StartImage () boot service is unable\r
+ // to handle it, either because the image does not have the special .compat\r
+ // PE/COFF section that Linux specifies for mixed mode capable images, or\r
+ // because we are running without the support code for that. So load the\r
+ // image again, using the legacy loader, and unload the normally loaded\r
+ // image before starting the legacy one.\r
+ //\r
+ Status = QemuLoadLegacyImage (&KernelImageHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Note: no change to (*ImageHandle), the caller will release it.\r
+ //\r
+ return Status;\r
+ }\r
+ //\r
+ // Swap in the legacy-loaded image.\r
+ //\r
+ QemuUnloadKernelImage (*ImageHandle);\r
+ *ImageHandle = KernelImageHandle;\r
+ return QemuStartLegacyImage (KernelImageHandle);\r
+ }\r
+#endif\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Unloads an image loaded with QemuLoadKernelImage ().\r
+\r
+ @param ImageHandle Handle that identifies the image to be\r
+ unloaded.\r
+\r
+ @retval EFI_SUCCESS The image has been unloaded.\r
+ @retval EFI_UNSUPPORTED The image has been started, and does not\r
+ support unload.\r
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.\r
+\r
+ @return Exit code from the image's unload function.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QemuUnloadKernelImage (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&KernelLoadedImage,\r
+ gImageHandle, // AgentHandle\r
+ NULL, // ControllerHandle\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (Status == EFI_UNSUPPORTED) {\r
+ //\r
+ // The handle exists but does not have an instance of the standard loaded\r
+ // image protocol installed on it. Attempt to unload it as a legacy image\r
+ // instead.\r
+ //\r
+ return QemuUnloadLegacyImage (ImageHandle);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // We are unloading a normal, non-legacy loaded image, either on behalf of\r
+ // an external caller, or called from QemuStartKernelImage() on IA32, while\r
+ // switching from the normal to the legacy method to load and start a X64\r
+ // image.\r
+ //\r
+ if (KernelLoadedImage->LoadOptions != NULL) {\r
+ FreePool (KernelLoadedImage->LoadOptions);\r
+ KernelLoadedImage->LoadOptions = NULL;\r
+ }\r
+ KernelLoadedImage->LoadOptionsSize = 0;\r
+\r
+ return gBS->UnloadImage (ImageHandle);\r
+}\r