2 Generic implementation of QemuLoadImageLib library class interface.
4 Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Guid/QemuKernelLoaderFsMedia.h>
13 #include <Library/DebugLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/PrintLib.h>
16 #include <Library/QemuFwCfgLib.h>
17 #include <Library/QemuLoadImageLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Protocol/DevicePath.h>
20 #include <Protocol/LoadedImage.h>
24 EFI_DEVICE_PATH_PROTOCOL FilePathHeader
;
25 CHAR16 FilePath
[ARRAY_SIZE (L
"kernel")];
26 } KERNEL_FILE_DEVPATH
;
29 VENDOR_DEVICE_PATH VenMediaNode
;
30 KERNEL_FILE_DEVPATH FileNode
;
31 EFI_DEVICE_PATH_PROTOCOL EndNode
;
32 } KERNEL_VENMEDIA_FILE_DEVPATH
;
35 STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath
= {
38 MEDIA_DEVICE_PATH
, MEDIA_VENDOR_DP
,
39 { sizeof (VENDOR_DEVICE_PATH
) }
41 QEMU_KERNEL_LOADER_FS_MEDIA_GUID
44 MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
,
45 { sizeof (KERNEL_FILE_DEVPATH
) }
49 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
50 { sizeof (EFI_DEVICE_PATH_PROTOCOL
) }
55 Download the kernel, the initial ramdisk, and the kernel command line from
56 QEMU's fw_cfg. The kernel will be instructed via its command line to load
57 the initrd from the same Simple FileSystem where the kernel was loaded from.
59 @param[out] ImageHandle The image handle that was allocated for
62 @retval EFI_SUCCESS The image was loaded successfully.
63 @retval EFI_NOT_FOUND Kernel image was not found.
64 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
65 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
66 @retval EFI_ACCESS_DENIED The underlying LoadImage boot service call
67 returned EFI_SECURITY_VIOLATION, and the image
70 @return Error codes from any of the underlying
76 OUT EFI_HANDLE
*ImageHandle
80 EFI_HANDLE KernelImageHandle
;
81 EFI_LOADED_IMAGE_PROTOCOL
*KernelLoadedImage
;
82 UINTN CommandLineSize
;
87 // Load the image. This should call back into the QEMU EFI loader file system.
89 Status
= gBS
->LoadImage (
90 FALSE
, // BootPolicy: exact match required
91 gImageHandle
, // ParentImageHandle
92 (EFI_DEVICE_PATH_PROTOCOL
*)&mKernelDevicePath
,
101 case EFI_SECURITY_VIOLATION
:
103 // In this case, the image was loaded but failed to authenticate.
105 Status
= EFI_ACCESS_DENIED
;
109 DEBUG ((DEBUG_ERROR
, "%a: LoadImage(): %r\n", __FUNCTION__
, Status
));
114 // Construct the kernel command line.
116 Status
= gBS
->OpenProtocol (
118 &gEfiLoadedImageProtocolGuid
,
119 (VOID
**)&KernelLoadedImage
,
120 gImageHandle
, // AgentHandle
121 NULL
, // ControllerHandle
122 EFI_OPEN_PROTOCOL_GET_PROTOCOL
124 ASSERT_EFI_ERROR (Status
);
126 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize
);
127 CommandLineSize
= (UINTN
)QemuFwCfgRead32 ();
129 if (CommandLineSize
== 0) {
130 KernelLoadedImage
->LoadOptionsSize
= 0;
132 CommandLine
= AllocatePool (CommandLineSize
);
133 if (CommandLine
== NULL
) {
134 Status
= EFI_OUT_OF_RESOURCES
;
138 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData
);
139 QemuFwCfgReadBytes (CommandLineSize
, CommandLine
);
142 // Verify NUL-termination of the command line.
144 if (CommandLine
[CommandLineSize
- 1] != '\0') {
145 DEBUG ((DEBUG_ERROR
, "%a: kernel command line is not NUL-terminated\n",
147 Status
= EFI_PROTOCOL_ERROR
;
148 goto FreeCommandLine
;
152 // Drop the terminating NUL, convert to UTF-16.
154 KernelLoadedImage
->LoadOptionsSize
= (UINT32
)((CommandLineSize
- 1) * 2);
157 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize
);
158 InitrdSize
= (UINTN
)QemuFwCfgRead32 ();
160 if (InitrdSize
> 0) {
162 // Append ' initrd=initrd' in UTF-16.
164 KernelLoadedImage
->LoadOptionsSize
+= sizeof (L
" initrd=initrd") - 2;
167 if (KernelLoadedImage
->LoadOptionsSize
== 0) {
168 KernelLoadedImage
->LoadOptions
= NULL
;
171 // NUL-terminate in UTF-16.
173 KernelLoadedImage
->LoadOptionsSize
+= 2;
175 KernelLoadedImage
->LoadOptions
= AllocatePool (
176 KernelLoadedImage
->LoadOptionsSize
);
177 if (KernelLoadedImage
->LoadOptions
== NULL
) {
178 KernelLoadedImage
->LoadOptionsSize
= 0;
179 Status
= EFI_OUT_OF_RESOURCES
;
180 goto FreeCommandLine
;
183 UnicodeSPrintAsciiFormat (
184 KernelLoadedImage
->LoadOptions
,
185 KernelLoadedImage
->LoadOptionsSize
,
187 (CommandLineSize
== 0) ? "" : CommandLine
,
188 (InitrdSize
== 0) ? "" : " initrd=initrd"
190 DEBUG ((DEBUG_INFO
, "%a: command line: \"%s\"\n", __FUNCTION__
,
191 (CHAR16
*)KernelLoadedImage
->LoadOptions
));
194 *ImageHandle
= KernelImageHandle
;
198 if (CommandLineSize
> 0) {
199 FreePool (CommandLine
);
202 gBS
->UnloadImage (KernelImageHandle
);
208 Transfer control to a kernel image loaded with QemuLoadKernelImage ()
210 @param[in,out] ImageHandle Handle of image to be started. May assume a
211 different value on return if the image was
214 @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle
215 or the image has already been initialized with
217 @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the
218 image should not be started.
220 @return Error codes returned by the started image
224 QemuStartKernelImage (
225 IN OUT EFI_HANDLE
*ImageHandle
228 return gBS
->StartImage (
230 NULL
, // ExitDataSize
236 Unloads an image loaded with QemuLoadKernelImage ().
238 @param ImageHandle Handle that identifies the image to be
241 @retval EFI_SUCCESS The image has been unloaded.
242 @retval EFI_UNSUPPORTED The image has been started, and does not
244 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
246 @return Exit code from the image's unload function.
250 QemuUnloadKernelImage (
251 IN EFI_HANDLE ImageHandle
254 EFI_LOADED_IMAGE_PROTOCOL
*KernelLoadedImage
;
257 Status
= gBS
->OpenProtocol (
259 &gEfiLoadedImageProtocolGuid
,
260 (VOID
**)&KernelLoadedImage
,
261 gImageHandle
, // AgentHandle
262 NULL
, // ControllerHandle
263 EFI_OPEN_PROTOCOL_GET_PROTOCOL
265 if (EFI_ERROR (Status
)) {
266 return EFI_INVALID_PARAMETER
;
269 if (KernelLoadedImage
->LoadOptions
!= NULL
) {
270 FreePool (KernelLoadedImage
->LoadOptions
);
271 KernelLoadedImage
->LoadOptions
= NULL
;
273 KernelLoadedImage
->LoadOptionsSize
= 0;
275 return gBS
->UnloadImage (ImageHandle
);