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 ((Status
== EFI_NOT_FOUND
? DEBUG_INFO
: DEBUG_ERROR
,
110 "%a: LoadImage(): %r\n", __FUNCTION__
, Status
));
115 // Construct the kernel command line.
117 Status
= gBS
->OpenProtocol (
119 &gEfiLoadedImageProtocolGuid
,
120 (VOID
**)&KernelLoadedImage
,
121 gImageHandle
, // AgentHandle
122 NULL
, // ControllerHandle
123 EFI_OPEN_PROTOCOL_GET_PROTOCOL
125 ASSERT_EFI_ERROR (Status
);
127 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize
);
128 CommandLineSize
= (UINTN
)QemuFwCfgRead32 ();
130 if (CommandLineSize
== 0) {
131 KernelLoadedImage
->LoadOptionsSize
= 0;
133 CommandLine
= AllocatePool (CommandLineSize
);
134 if (CommandLine
== NULL
) {
135 Status
= EFI_OUT_OF_RESOURCES
;
139 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData
);
140 QemuFwCfgReadBytes (CommandLineSize
, CommandLine
);
143 // Verify NUL-termination of the command line.
145 if (CommandLine
[CommandLineSize
- 1] != '\0') {
146 DEBUG ((DEBUG_ERROR
, "%a: kernel command line is not NUL-terminated\n",
148 Status
= EFI_PROTOCOL_ERROR
;
149 goto FreeCommandLine
;
153 // Drop the terminating NUL, convert to UTF-16.
155 KernelLoadedImage
->LoadOptionsSize
= (UINT32
)((CommandLineSize
- 1) * 2);
158 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize
);
159 InitrdSize
= (UINTN
)QemuFwCfgRead32 ();
161 if (InitrdSize
> 0) {
163 // Append ' initrd=initrd' in UTF-16.
165 KernelLoadedImage
->LoadOptionsSize
+= sizeof (L
" initrd=initrd") - 2;
168 if (KernelLoadedImage
->LoadOptionsSize
== 0) {
169 KernelLoadedImage
->LoadOptions
= NULL
;
172 // NUL-terminate in UTF-16.
174 KernelLoadedImage
->LoadOptionsSize
+= 2;
176 KernelLoadedImage
->LoadOptions
= AllocatePool (
177 KernelLoadedImage
->LoadOptionsSize
);
178 if (KernelLoadedImage
->LoadOptions
== NULL
) {
179 KernelLoadedImage
->LoadOptionsSize
= 0;
180 Status
= EFI_OUT_OF_RESOURCES
;
181 goto FreeCommandLine
;
184 UnicodeSPrintAsciiFormat (
185 KernelLoadedImage
->LoadOptions
,
186 KernelLoadedImage
->LoadOptionsSize
,
188 (CommandLineSize
== 0) ? "" : CommandLine
,
189 (InitrdSize
== 0) ? "" : " initrd=initrd"
191 DEBUG ((DEBUG_INFO
, "%a: command line: \"%s\"\n", __FUNCTION__
,
192 (CHAR16
*)KernelLoadedImage
->LoadOptions
));
195 *ImageHandle
= KernelImageHandle
;
199 if (CommandLineSize
> 0) {
200 FreePool (CommandLine
);
203 gBS
->UnloadImage (KernelImageHandle
);
209 Transfer control to a kernel image loaded with QemuLoadKernelImage ()
211 @param[in,out] ImageHandle Handle of image to be started. May assume a
212 different value on return if the image was
215 @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle
216 or the image has already been initialized with
218 @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the
219 image should not be started.
221 @return Error codes returned by the started image
225 QemuStartKernelImage (
226 IN OUT EFI_HANDLE
*ImageHandle
229 return gBS
->StartImage (
231 NULL
, // ExitDataSize
237 Unloads an image loaded with QemuLoadKernelImage ().
239 @param ImageHandle Handle that identifies the image to be
242 @retval EFI_SUCCESS The image has been unloaded.
243 @retval EFI_UNSUPPORTED The image has been started, and does not
245 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
247 @return Exit code from the image's unload function.
251 QemuUnloadKernelImage (
252 IN EFI_HANDLE ImageHandle
255 EFI_LOADED_IMAGE_PROTOCOL
*KernelLoadedImage
;
258 Status
= gBS
->OpenProtocol (
260 &gEfiLoadedImageProtocolGuid
,
261 (VOID
**)&KernelLoadedImage
,
262 gImageHandle
, // AgentHandle
263 NULL
, // ControllerHandle
264 EFI_OPEN_PROTOCOL_GET_PROTOCOL
266 if (EFI_ERROR (Status
)) {
267 return EFI_INVALID_PARAMETER
;
270 if (KernelLoadedImage
->LoadOptions
!= NULL
) {
271 FreePool (KernelLoadedImage
->LoadOptions
);
272 KernelLoadedImage
->LoadOptions
= NULL
;
274 KernelLoadedImage
->LoadOptionsSize
= 0;
276 return gBS
->UnloadImage (ImageHandle
);