]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
OvmfPkg/GenericQemuLoadImageLib: log "Not Found" at INFO level
[mirror_edk2.git] / OvmfPkg / Library / GenericQemuLoadImageLib / GenericQemuLoadImageLib.c
CommitLineData
ddd2be6b
AB
1/** @file\r
2 Generic implementation of QemuLoadImageLib library class interface.\r
3\r
4 Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7**/\r
8\r
9#include <Uefi.h>\r
10\r
11#include <Base.h>\r
12#include <Guid/QemuKernelLoaderFsMedia.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/MemoryAllocationLib.h>\r
15#include <Library/PrintLib.h>\r
16#include <Library/QemuFwCfgLib.h>\r
17#include <Library/QemuLoadImageLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Protocol/DevicePath.h>\r
20#include <Protocol/LoadedImage.h>\r
21\r
22#pragma pack (1)\r
23typedef struct {\r
24 EFI_DEVICE_PATH_PROTOCOL FilePathHeader;\r
25 CHAR16 FilePath[ARRAY_SIZE (L"kernel")];\r
26} KERNEL_FILE_DEVPATH;\r
27\r
28typedef struct {\r
29 VENDOR_DEVICE_PATH VenMediaNode;\r
30 KERNEL_FILE_DEVPATH FileNode;\r
31 EFI_DEVICE_PATH_PROTOCOL EndNode;\r
32} KERNEL_VENMEDIA_FILE_DEVPATH;\r
33#pragma pack ()\r
34\r
35STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {\r
36 {\r
37 {\r
38 MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,\r
39 { sizeof (VENDOR_DEVICE_PATH) }\r
40 },\r
41 QEMU_KERNEL_LOADER_FS_MEDIA_GUID\r
42 }, {\r
43 {\r
44 MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,\r
45 { sizeof (KERNEL_FILE_DEVPATH) }\r
46 },\r
47 L"kernel",\r
48 }, {\r
49 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
50 { sizeof (EFI_DEVICE_PATH_PROTOCOL) }\r
51 }\r
52};\r
53\r
54/**\r
55 Download the kernel, the initial ramdisk, and the kernel command line from\r
56 QEMU's fw_cfg. The kernel will be instructed via its command line to load\r
57 the initrd from the same Simple FileSystem where the kernel was loaded from.\r
58\r
59 @param[out] ImageHandle The image handle that was allocated for\r
60 loading the image\r
61\r
62 @retval EFI_SUCCESS The image was loaded successfully.\r
63 @retval EFI_NOT_FOUND Kernel image was not found.\r
64 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
65 @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.\r
66 @retval EFI_ACCESS_DENIED The underlying LoadImage boot service call\r
67 returned EFI_SECURITY_VIOLATION, and the image\r
68 was unloaded again.\r
69\r
70 @return Error codes from any of the underlying\r
71 functions.\r
72**/\r
73EFI_STATUS\r
74EFIAPI\r
75QemuLoadKernelImage (\r
76 OUT EFI_HANDLE *ImageHandle\r
77 )\r
78{\r
79 EFI_STATUS Status;\r
80 EFI_HANDLE KernelImageHandle;\r
81 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
82 UINTN CommandLineSize;\r
83 CHAR8 *CommandLine;\r
84 UINTN InitrdSize;\r
85\r
86 //\r
87 // Load the image. This should call back into the QEMU EFI loader file system.\r
88 //\r
89 Status = gBS->LoadImage (\r
90 FALSE, // BootPolicy: exact match required\r
91 gImageHandle, // ParentImageHandle\r
92 (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,\r
93 NULL, // SourceBuffer\r
94 0, // SourceSize\r
95 &KernelImageHandle\r
96 );\r
97 switch (Status) {\r
98 case EFI_SUCCESS:\r
99 break;\r
100\r
101 case EFI_SECURITY_VIOLATION:\r
102 //\r
103 // In this case, the image was loaded but failed to authenticate.\r
104 //\r
105 Status = EFI_ACCESS_DENIED;\r
106 goto UnloadImage;\r
107\r
108 default:\r
14c7ed8b
LE
109 DEBUG ((Status == EFI_NOT_FOUND ? DEBUG_INFO : DEBUG_ERROR,\r
110 "%a: LoadImage(): %r\n", __FUNCTION__, Status));\r
ddd2be6b
AB
111 return Status;\r
112 }\r
113\r
114 //\r
115 // Construct the kernel command line.\r
116 //\r
117 Status = gBS->OpenProtocol (\r
118 KernelImageHandle,\r
119 &gEfiLoadedImageProtocolGuid,\r
120 (VOID **)&KernelLoadedImage,\r
121 gImageHandle, // AgentHandle\r
122 NULL, // ControllerHandle\r
123 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
124 );\r
125 ASSERT_EFI_ERROR (Status);\r
126\r
127 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);\r
128 CommandLineSize = (UINTN)QemuFwCfgRead32 ();\r
129\r
130 if (CommandLineSize == 0) {\r
131 KernelLoadedImage->LoadOptionsSize = 0;\r
132 } else {\r
133 CommandLine = AllocatePool (CommandLineSize);\r
134 if (CommandLine == NULL) {\r
135 Status = EFI_OUT_OF_RESOURCES;\r
136 goto UnloadImage;\r
137 }\r
138\r
139 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);\r
140 QemuFwCfgReadBytes (CommandLineSize, CommandLine);\r
141\r
142 //\r
143 // Verify NUL-termination of the command line.\r
144 //\r
145 if (CommandLine[CommandLineSize - 1] != '\0') {\r
146 DEBUG ((DEBUG_ERROR, "%a: kernel command line is not NUL-terminated\n",\r
147 __FUNCTION__));\r
148 Status = EFI_PROTOCOL_ERROR;\r
149 goto FreeCommandLine;\r
150 }\r
151\r
152 //\r
153 // Drop the terminating NUL, convert to UTF-16.\r
154 //\r
3000c296 155 KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);\r
ddd2be6b
AB
156 }\r
157\r
158 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);\r
159 InitrdSize = (UINTN)QemuFwCfgRead32 ();\r
160\r
161 if (InitrdSize > 0) {\r
162 //\r
163 // Append ' initrd=initrd' in UTF-16.\r
164 //\r
165 KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;\r
166 }\r
167\r
168 if (KernelLoadedImage->LoadOptionsSize == 0) {\r
169 KernelLoadedImage->LoadOptions = NULL;\r
170 } else {\r
171 //\r
172 // NUL-terminate in UTF-16.\r
173 //\r
174 KernelLoadedImage->LoadOptionsSize += 2;\r
175\r
176 KernelLoadedImage->LoadOptions = AllocatePool (\r
177 KernelLoadedImage->LoadOptionsSize);\r
178 if (KernelLoadedImage->LoadOptions == NULL) {\r
179 KernelLoadedImage->LoadOptionsSize = 0;\r
180 Status = EFI_OUT_OF_RESOURCES;\r
181 goto FreeCommandLine;\r
182 }\r
183\r
184 UnicodeSPrintAsciiFormat (\r
185 KernelLoadedImage->LoadOptions,\r
186 KernelLoadedImage->LoadOptionsSize,\r
187 "%a%a",\r
188 (CommandLineSize == 0) ? "" : CommandLine,\r
189 (InitrdSize == 0) ? "" : " initrd=initrd"\r
190 );\r
191 DEBUG ((DEBUG_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,\r
192 (CHAR16 *)KernelLoadedImage->LoadOptions));\r
193 }\r
194\r
195 *ImageHandle = KernelImageHandle;\r
196 return EFI_SUCCESS;\r
197\r
198FreeCommandLine:\r
199 if (CommandLineSize > 0) {\r
200 FreePool (CommandLine);\r
201 }\r
202UnloadImage:\r
203 gBS->UnloadImage (KernelImageHandle);\r
204\r
205 return Status;\r
206}\r
207\r
208/**\r
209 Transfer control to a kernel image loaded with QemuLoadKernelImage ()\r
210\r
211 @param[in,out] ImageHandle Handle of image to be started. May assume a\r
212 different value on return if the image was\r
213 reloaded.\r
214\r
215 @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle\r
216 or the image has already been initialized with\r
217 StartImage\r
218 @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the\r
219 image should not be started.\r
220\r
221 @return Error codes returned by the started image\r
222**/\r
223EFI_STATUS\r
224EFIAPI\r
225QemuStartKernelImage (\r
226 IN OUT EFI_HANDLE *ImageHandle\r
227 )\r
228{\r
229 return gBS->StartImage (\r
230 *ImageHandle,\r
231 NULL, // ExitDataSize\r
232 NULL // ExitData\r
233 );\r
234}\r
235\r
236/**\r
237 Unloads an image loaded with QemuLoadKernelImage ().\r
238\r
239 @param ImageHandle Handle that identifies the image to be\r
240 unloaded.\r
241\r
242 @retval EFI_SUCCESS The image has been unloaded.\r
243 @retval EFI_UNSUPPORTED The image has been started, and does not\r
244 support unload.\r
245 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.\r
246\r
247 @return Exit code from the image's unload function.\r
248**/\r
249EFI_STATUS\r
250EFIAPI\r
251QemuUnloadKernelImage (\r
252 IN EFI_HANDLE ImageHandle\r
253 )\r
254{\r
255 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
256 EFI_STATUS Status;\r
257\r
258 Status = gBS->OpenProtocol (\r
259 ImageHandle,\r
260 &gEfiLoadedImageProtocolGuid,\r
261 (VOID **)&KernelLoadedImage,\r
262 gImageHandle, // AgentHandle\r
263 NULL, // ControllerHandle\r
264 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
265 );\r
266 if (EFI_ERROR (Status)) {\r
267 return EFI_INVALID_PARAMETER;\r
268 }\r
269\r
270 if (KernelLoadedImage->LoadOptions != NULL) {\r
271 FreePool (KernelLoadedImage->LoadOptions);\r
272 KernelLoadedImage->LoadOptions = NULL;\r
273 }\r
274 KernelLoadedImage->LoadOptionsSize = 0;\r
275\r
276 return gBS->UnloadImage (ImageHandle);\r
277}\r