]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
OvmfPkg/GenericQemuLoadImageLib: Fix VS2019 UINT32 conversion error
[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
109 DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));\r
110 return Status;\r
111 }\r
112\r
113 //\r
114 // Construct the kernel command line.\r
115 //\r
116 Status = gBS->OpenProtocol (\r
117 KernelImageHandle,\r
118 &gEfiLoadedImageProtocolGuid,\r
119 (VOID **)&KernelLoadedImage,\r
120 gImageHandle, // AgentHandle\r
121 NULL, // ControllerHandle\r
122 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
123 );\r
124 ASSERT_EFI_ERROR (Status);\r
125\r
126 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);\r
127 CommandLineSize = (UINTN)QemuFwCfgRead32 ();\r
128\r
129 if (CommandLineSize == 0) {\r
130 KernelLoadedImage->LoadOptionsSize = 0;\r
131 } else {\r
132 CommandLine = AllocatePool (CommandLineSize);\r
133 if (CommandLine == NULL) {\r
134 Status = EFI_OUT_OF_RESOURCES;\r
135 goto UnloadImage;\r
136 }\r
137\r
138 QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);\r
139 QemuFwCfgReadBytes (CommandLineSize, CommandLine);\r
140\r
141 //\r
142 // Verify NUL-termination of the command line.\r
143 //\r
144 if (CommandLine[CommandLineSize - 1] != '\0') {\r
145 DEBUG ((DEBUG_ERROR, "%a: kernel command line is not NUL-terminated\n",\r
146 __FUNCTION__));\r
147 Status = EFI_PROTOCOL_ERROR;\r
148 goto FreeCommandLine;\r
149 }\r
150\r
151 //\r
152 // Drop the terminating NUL, convert to UTF-16.\r
153 //\r
3000c296 154 KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);\r
ddd2be6b
AB
155 }\r
156\r
157 QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);\r
158 InitrdSize = (UINTN)QemuFwCfgRead32 ();\r
159\r
160 if (InitrdSize > 0) {\r
161 //\r
162 // Append ' initrd=initrd' in UTF-16.\r
163 //\r
164 KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;\r
165 }\r
166\r
167 if (KernelLoadedImage->LoadOptionsSize == 0) {\r
168 KernelLoadedImage->LoadOptions = NULL;\r
169 } else {\r
170 //\r
171 // NUL-terminate in UTF-16.\r
172 //\r
173 KernelLoadedImage->LoadOptionsSize += 2;\r
174\r
175 KernelLoadedImage->LoadOptions = AllocatePool (\r
176 KernelLoadedImage->LoadOptionsSize);\r
177 if (KernelLoadedImage->LoadOptions == NULL) {\r
178 KernelLoadedImage->LoadOptionsSize = 0;\r
179 Status = EFI_OUT_OF_RESOURCES;\r
180 goto FreeCommandLine;\r
181 }\r
182\r
183 UnicodeSPrintAsciiFormat (\r
184 KernelLoadedImage->LoadOptions,\r
185 KernelLoadedImage->LoadOptionsSize,\r
186 "%a%a",\r
187 (CommandLineSize == 0) ? "" : CommandLine,\r
188 (InitrdSize == 0) ? "" : " initrd=initrd"\r
189 );\r
190 DEBUG ((DEBUG_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,\r
191 (CHAR16 *)KernelLoadedImage->LoadOptions));\r
192 }\r
193\r
194 *ImageHandle = KernelImageHandle;\r
195 return EFI_SUCCESS;\r
196\r
197FreeCommandLine:\r
198 if (CommandLineSize > 0) {\r
199 FreePool (CommandLine);\r
200 }\r
201UnloadImage:\r
202 gBS->UnloadImage (KernelImageHandle);\r
203\r
204 return Status;\r
205}\r
206\r
207/**\r
208 Transfer control to a kernel image loaded with QemuLoadKernelImage ()\r
209\r
210 @param[in,out] ImageHandle Handle of image to be started. May assume a\r
211 different value on return if the image was\r
212 reloaded.\r
213\r
214 @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle\r
215 or the image has already been initialized with\r
216 StartImage\r
217 @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the\r
218 image should not be started.\r
219\r
220 @return Error codes returned by the started image\r
221**/\r
222EFI_STATUS\r
223EFIAPI\r
224QemuStartKernelImage (\r
225 IN OUT EFI_HANDLE *ImageHandle\r
226 )\r
227{\r
228 return gBS->StartImage (\r
229 *ImageHandle,\r
230 NULL, // ExitDataSize\r
231 NULL // ExitData\r
232 );\r
233}\r
234\r
235/**\r
236 Unloads an image loaded with QemuLoadKernelImage ().\r
237\r
238 @param ImageHandle Handle that identifies the image to be\r
239 unloaded.\r
240\r
241 @retval EFI_SUCCESS The image has been unloaded.\r
242 @retval EFI_UNSUPPORTED The image has been started, and does not\r
243 support unload.\r
244 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.\r
245\r
246 @return Exit code from the image's unload function.\r
247**/\r
248EFI_STATUS\r
249EFIAPI\r
250QemuUnloadKernelImage (\r
251 IN EFI_HANDLE ImageHandle\r
252 )\r
253{\r
254 EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
255 EFI_STATUS Status;\r
256\r
257 Status = gBS->OpenProtocol (\r
258 ImageHandle,\r
259 &gEfiLoadedImageProtocolGuid,\r
260 (VOID **)&KernelLoadedImage,\r
261 gImageHandle, // AgentHandle\r
262 NULL, // ControllerHandle\r
263 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
264 );\r
265 if (EFI_ERROR (Status)) {\r
266 return EFI_INVALID_PARAMETER;\r
267 }\r
268\r
269 if (KernelLoadedImage->LoadOptions != NULL) {\r
270 FreePool (KernelLoadedImage->LoadOptions);\r
271 KernelLoadedImage->LoadOptions = NULL;\r
272 }\r
273 KernelLoadedImage->LoadOptionsSize = 0;\r
274\r
275 return gBS->UnloadImage (ImageHandle);\r
276}\r