]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/QemuRamfbDxe/QemuRamfb.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / QemuRamfbDxe / QemuRamfb.c
CommitLineData
1d25ff51
GH
1/** @file\r
2 This driver is a implementation of the Graphics Output Protocol\r
3 for the QEMU ramfb device.\r
4\r
5 Copyright (c) 2018, Red Hat Inc.\r
6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1d25ff51
GH
8\r
9**/\r
10\r
11#include <Protocol/GraphicsOutput.h>\r
12\r
13#include <Library/BaseLib.h>\r
14#include <Library/BaseMemoryLib.h>\r
15#include <Library/DebugLib.h>\r
16#include <Library/DevicePathLib.h>\r
17#include <Library/FrameBufferBltLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/QemuFwCfgLib.h>\r
21\r
22#include <Guid/QemuRamfb.h>\r
23\r
24#define RAMFB_FORMAT 0x34325258 /* DRM_FORMAT_XRGB8888 */\r
25#define RAMFB_BPP 4\r
26\r
27#pragma pack (1)\r
28typedef struct RAMFB_CONFIG {\r
ac0a286f
MK
29 UINT64 Address;\r
30 UINT32 FourCC;\r
31 UINT32 Flags;\r
32 UINT32 Width;\r
33 UINT32 Height;\r
34 UINT32 Stride;\r
1d25ff51
GH
35} RAMFB_CONFIG;\r
36#pragma pack ()\r
37\r
ac0a286f
MK
38STATIC EFI_HANDLE mRamfbHandle;\r
39STATIC EFI_HANDLE mGopHandle;\r
40STATIC FRAME_BUFFER_CONFIGURE *mQemuRamfbFrameBufferBltConfigure;\r
41STATIC UINTN mQemuRamfbFrameBufferBltConfigureSize;\r
42STATIC FIRMWARE_CONFIG_ITEM mRamfbFwCfgItem;\r
1d25ff51 43\r
ac0a286f 44STATIC EFI_GRAPHICS_OUTPUT_MODE_INFORMATION mQemuRamfbModeInfo[] = {\r
1d25ff51
GH
45 {\r
46 0, // Version\r
47 640, // HorizontalResolution\r
48 480, // VerticalResolution\r
49 },{\r
50 0, // Version\r
51 800, // HorizontalResolution\r
52 600, // VerticalResolution\r
53 },{\r
54 0, // Version\r
55 1024, // HorizontalResolution\r
56 768, // VerticalResolution\r
57 }\r
58};\r
59\r
ac0a286f 60STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE mQemuRamfbMode = {\r
1d25ff51
GH
61 ARRAY_SIZE (mQemuRamfbModeInfo), // MaxMode\r
62 0, // Mode\r
63 mQemuRamfbModeInfo, // Info\r
64 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), // SizeOfInfo\r
65};\r
66\r
67STATIC\r
68EFI_STATUS\r
69EFIAPI\r
70QemuRamfbGraphicsOutputQueryMode (\r
71 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
72 IN UINT32 ModeNumber,\r
73 OUT UINTN *SizeOfInfo,\r
74 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info\r
75 )\r
76{\r
77 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo;\r
78\r
ac0a286f
MK
79 if ((Info == NULL) || (SizeOfInfo == NULL) ||\r
80 (ModeNumber >= mQemuRamfbMode.MaxMode))\r
81 {\r
1d25ff51
GH
82 return EFI_INVALID_PARAMETER;\r
83 }\r
ac0a286f 84\r
1d25ff51
GH
85 ModeInfo = &mQemuRamfbModeInfo[ModeNumber];\r
86\r
ac0a286f
MK
87 *Info = AllocateCopyPool (\r
88 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),\r
89 ModeInfo\r
90 );\r
1d25ff51
GH
91 if (*Info == NULL) {\r
92 return EFI_OUT_OF_RESOURCES;\r
93 }\r
ac0a286f 94\r
1d25ff51
GH
95 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
96\r
97 return EFI_SUCCESS;\r
98}\r
99\r
100STATIC\r
101EFI_STATUS\r
102EFIAPI\r
103QemuRamfbGraphicsOutputSetMode (\r
ac0a286f
MK
104 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
105 IN UINT32 ModeNumber\r
1d25ff51
GH
106 )\r
107{\r
108 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo;\r
109 RAMFB_CONFIG Config;\r
110 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;\r
111 RETURN_STATUS Status;\r
112\r
113 if (ModeNumber >= mQemuRamfbMode.MaxMode) {\r
114 return EFI_UNSUPPORTED;\r
115 }\r
ac0a286f 116\r
1d25ff51
GH
117 ModeInfo = &mQemuRamfbModeInfo[ModeNumber];\r
118\r
ac0a286f
MK
119 DEBUG ((\r
120 DEBUG_INFO,\r
121 "Ramfb: SetMode %u (%ux%u)\n",\r
122 ModeNumber,\r
123 ModeInfo->HorizontalResolution,\r
124 ModeInfo->VerticalResolution\r
125 ));\r
1d25ff51
GH
126\r
127 Config.Address = SwapBytes64 (mQemuRamfbMode.FrameBufferBase);\r
128 Config.FourCC = SwapBytes32 (RAMFB_FORMAT);\r
129 Config.Flags = SwapBytes32 (0);\r
130 Config.Width = SwapBytes32 (ModeInfo->HorizontalResolution);\r
131 Config.Height = SwapBytes32 (ModeInfo->VerticalResolution);\r
132 Config.Stride = SwapBytes32 (ModeInfo->HorizontalResolution * RAMFB_BPP);\r
133\r
134 Status = FrameBufferBltConfigure (\r
ac0a286f 135 (VOID *)(UINTN)mQemuRamfbMode.FrameBufferBase,\r
1d25ff51
GH
136 ModeInfo,\r
137 mQemuRamfbFrameBufferBltConfigure,\r
138 &mQemuRamfbFrameBufferBltConfigureSize\r
139 );\r
140\r
141 if (Status == RETURN_BUFFER_TOO_SMALL) {\r
142 if (mQemuRamfbFrameBufferBltConfigure != NULL) {\r
143 FreePool (mQemuRamfbFrameBufferBltConfigure);\r
144 }\r
ac0a286f 145\r
1d25ff51
GH
146 mQemuRamfbFrameBufferBltConfigure =\r
147 AllocatePool (mQemuRamfbFrameBufferBltConfigureSize);\r
148 if (mQemuRamfbFrameBufferBltConfigure == NULL) {\r
149 mQemuRamfbFrameBufferBltConfigureSize = 0;\r
150 return EFI_OUT_OF_RESOURCES;\r
151 }\r
152\r
153 Status = FrameBufferBltConfigure (\r
ac0a286f 154 (VOID *)(UINTN)mQemuRamfbMode.FrameBufferBase,\r
1d25ff51
GH
155 ModeInfo,\r
156 mQemuRamfbFrameBufferBltConfigure,\r
157 &mQemuRamfbFrameBufferBltConfigureSize\r
158 );\r
159 }\r
ac0a286f 160\r
1d25ff51
GH
161 if (RETURN_ERROR (Status)) {\r
162 ASSERT (Status == RETURN_UNSUPPORTED);\r
163 return Status;\r
164 }\r
165\r
166 mQemuRamfbMode.Mode = ModeNumber;\r
167 mQemuRamfbMode.Info = ModeInfo;\r
168\r
169 QemuFwCfgSelectItem (mRamfbFwCfgItem);\r
170 QemuFwCfgWriteBytes (sizeof (Config), &Config);\r
171\r
172 //\r
173 // clear screen\r
174 //\r
175 ZeroMem (&Black, sizeof (Black));\r
176 Status = FrameBufferBlt (\r
177 mQemuRamfbFrameBufferBltConfigure,\r
178 &Black,\r
179 EfiBltVideoFill,\r
180 0, // SourceX -- ignored\r
181 0, // SourceY -- ignored\r
182 0, // DestinationX\r
183 0, // DestinationY\r
184 ModeInfo->HorizontalResolution, // Width\r
185 ModeInfo->VerticalResolution, // Height\r
186 0 // Delta -- ignored\r
187 );\r
188 if (RETURN_ERROR (Status)) {\r
ac0a286f
MK
189 DEBUG ((\r
190 DEBUG_WARN,\r
191 "%a: clearing the screen failed: %r\n",\r
192 __FUNCTION__,\r
193 Status\r
194 ));\r
1d25ff51
GH
195 }\r
196\r
197 return EFI_SUCCESS;\r
198}\r
199\r
200STATIC\r
201EFI_STATUS\r
202EFIAPI\r
203QemuRamfbGraphicsOutputBlt (\r
ac0a286f
MK
204 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
205 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,\r
206 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,\r
207 IN UINTN SourceX,\r
208 IN UINTN SourceY,\r
209 IN UINTN DestinationX,\r
210 IN UINTN DestinationY,\r
211 IN UINTN Width,\r
212 IN UINTN Height,\r
213 IN UINTN Delta\r
1d25ff51
GH
214 )\r
215{\r
216 return FrameBufferBlt (\r
217 mQemuRamfbFrameBufferBltConfigure,\r
218 BltBuffer,\r
219 BltOperation,\r
220 SourceX,\r
221 SourceY,\r
222 DestinationX,\r
223 DestinationY,\r
224 Width,\r
225 Height,\r
226 Delta\r
227 );\r
228}\r
229\r
ac0a286f 230STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL mQemuRamfbGraphicsOutput = {\r
1d25ff51
GH
231 QemuRamfbGraphicsOutputQueryMode,\r
232 QemuRamfbGraphicsOutputSetMode,\r
233 QemuRamfbGraphicsOutputBlt,\r
234 &mQemuRamfbMode,\r
235};\r
236\r
237EFI_STATUS\r
238EFIAPI\r
239InitializeQemuRamfb (\r
ac0a286f
MK
240 IN EFI_HANDLE ImageHandle,\r
241 IN EFI_SYSTEM_TABLE *SystemTable\r
1d25ff51
GH
242 )\r
243{\r
244 EFI_DEVICE_PATH_PROTOCOL *RamfbDevicePath;\r
245 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
246 VOID *DevicePath;\r
247 VENDOR_DEVICE_PATH VendorDeviceNode;\r
248 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;\r
249 EFI_STATUS Status;\r
250 EFI_PHYSICAL_ADDRESS FbBase;\r
251 UINTN FbSize, MaxFbSize, Pages;\r
252 UINTN FwCfgSize;\r
253 UINTN Index;\r
254\r
255 if (!QemuFwCfgIsAvailable ()) {\r
256 DEBUG ((DEBUG_INFO, "Ramfb: no FwCfg\n"));\r
257 return EFI_NOT_FOUND;\r
258 }\r
259\r
260 Status = QemuFwCfgFindFile ("etc/ramfb", &mRamfbFwCfgItem, &FwCfgSize);\r
261 if (EFI_ERROR (Status)) {\r
262 return EFI_NOT_FOUND;\r
263 }\r
ac0a286f 264\r
1d25ff51 265 if (FwCfgSize != sizeof (RAMFB_CONFIG)) {\r
ac0a286f
MK
266 DEBUG ((\r
267 DEBUG_ERROR,\r
268 "Ramfb: FwCfg size mismatch (expected %lu, got %lu)\n",\r
269 (UINT64)sizeof (RAMFB_CONFIG),\r
270 (UINT64)FwCfgSize\r
271 ));\r
1d25ff51
GH
272 return EFI_PROTOCOL_ERROR;\r
273 }\r
274\r
275 MaxFbSize = 0;\r
276 for (Index = 0; Index < ARRAY_SIZE (mQemuRamfbModeInfo); Index++) {\r
277 mQemuRamfbModeInfo[Index].PixelsPerScanLine =\r
278 mQemuRamfbModeInfo[Index].HorizontalResolution;\r
279 mQemuRamfbModeInfo[Index].PixelFormat =\r
280 PixelBlueGreenRedReserved8BitPerColor;\r
281 FbSize = RAMFB_BPP *\r
ac0a286f
MK
282 mQemuRamfbModeInfo[Index].HorizontalResolution *\r
283 mQemuRamfbModeInfo[Index].VerticalResolution;\r
1d25ff51
GH
284 if (MaxFbSize < FbSize) {\r
285 MaxFbSize = FbSize;\r
286 }\r
ac0a286f
MK
287\r
288 DEBUG ((\r
289 DEBUG_INFO,\r
290 "Ramfb: Mode %lu: %ux%u, %lu kB\n",\r
291 (UINT64)Index,\r
1d25ff51
GH
292 mQemuRamfbModeInfo[Index].HorizontalResolution,\r
293 mQemuRamfbModeInfo[Index].VerticalResolution,\r
ac0a286f
MK
294 (UINT64)(FbSize / 1024)\r
295 ));\r
1d25ff51
GH
296 }\r
297\r
ac0a286f 298 Pages = EFI_SIZE_TO_PAGES (MaxFbSize);\r
1d25ff51 299 MaxFbSize = EFI_PAGES_TO_SIZE (Pages);\r
ac0a286f 300 FbBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (Pages);\r
1d25ff51
GH
301 if (FbBase == 0) {\r
302 DEBUG ((DEBUG_ERROR, "Ramfb: memory allocation failed\n"));\r
303 return EFI_OUT_OF_RESOURCES;\r
304 }\r
ac0a286f
MK
305\r
306 DEBUG ((\r
307 DEBUG_INFO,\r
308 "Ramfb: Framebuffer at 0x%lx, %lu kB, %lu pages\n",\r
309 (UINT64)FbBase,\r
310 (UINT64)(MaxFbSize / 1024),\r
311 (UINT64)Pages\r
312 ));\r
1d25ff51
GH
313 mQemuRamfbMode.FrameBufferSize = MaxFbSize;\r
314 mQemuRamfbMode.FrameBufferBase = FbBase;\r
315\r
316 //\r
317 // 800 x 600\r
318 //\r
319 QemuRamfbGraphicsOutputSetMode (&mQemuRamfbGraphicsOutput, 1);\r
320\r
321 //\r
322 // ramfb vendor devpath\r
323 //\r
ac0a286f 324 VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;\r
1d25ff51
GH
325 VendorDeviceNode.Header.SubType = HW_VENDOR_DP;\r
326 CopyGuid (&VendorDeviceNode.Guid, &gQemuRamfbGuid);\r
ac0a286f
MK
327 SetDevicePathNodeLength (\r
328 &VendorDeviceNode.Header,\r
329 sizeof (VENDOR_DEVICE_PATH)\r
330 );\r
1d25ff51 331\r
ac0a286f
MK
332 RamfbDevicePath = AppendDevicePathNode (\r
333 NULL,\r
334 (EFI_DEVICE_PATH_PROTOCOL *)&VendorDeviceNode\r
335 );\r
1d25ff51
GH
336 if (RamfbDevicePath == NULL) {\r
337 Status = EFI_OUT_OF_RESOURCES;\r
338 goto FreeFramebuffer;\r
339 }\r
340\r
341 Status = gBS->InstallMultipleProtocolInterfaces (\r
342 &mRamfbHandle,\r
343 &gEfiDevicePathProtocolGuid,\r
344 RamfbDevicePath,\r
345 NULL\r
346 );\r
347 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
348 DEBUG ((\r
349 DEBUG_ERROR,\r
350 "Ramfb: install Ramfb Vendor DevicePath failed: %r\n",\r
351 Status\r
352 ));\r
1d25ff51
GH
353 goto FreeRamfbDevicePath;\r
354 }\r
355\r
356 //\r
357 // gop devpath + protocol\r
358 //\r
ac0a286f 359 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
1d25ff51 360 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
ac0a286f
MK
361 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (\r
362 1, // DeviceIdScheme\r
363 0, // HeadId\r
364 0, // NonVgaOutput\r
365 1, // BiosCanDetect\r
366 0, // VendorInfo\r
367 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, // Type\r
368 0, // Port\r
369 0 // Index\r
370 );\r
371 SetDevicePathNodeLength (\r
372 &AcpiDeviceNode.Header,\r
373 sizeof (ACPI_ADR_DEVICE_PATH)\r
1d25ff51 374 );\r
1d25ff51 375\r
ac0a286f
MK
376 GopDevicePath = AppendDevicePathNode (\r
377 RamfbDevicePath,\r
378 (EFI_DEVICE_PATH_PROTOCOL *)&AcpiDeviceNode\r
379 );\r
1d25ff51
GH
380 if (GopDevicePath == NULL) {\r
381 Status = EFI_OUT_OF_RESOURCES;\r
382 goto FreeRamfbHandle;\r
383 }\r
384\r
385 Status = gBS->InstallMultipleProtocolInterfaces (\r
386 &mGopHandle,\r
387 &gEfiDevicePathProtocolGuid,\r
388 GopDevicePath,\r
389 &gEfiGraphicsOutputProtocolGuid,\r
390 &mQemuRamfbGraphicsOutput,\r
391 NULL\r
392 );\r
393 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
394 DEBUG ((\r
395 DEBUG_ERROR,\r
396 "Ramfb: install GOP DevicePath failed: %r\n",\r
397 Status\r
398 ));\r
1d25ff51
GH
399 goto FreeGopDevicePath;\r
400 }\r
401\r
402 Status = gBS->OpenProtocol (\r
403 mRamfbHandle,\r
404 &gEfiDevicePathProtocolGuid,\r
405 &DevicePath,\r
406 gImageHandle,\r
407 mGopHandle,\r
408 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
409 );\r
410 if (EFI_ERROR (Status)) {\r
411 DEBUG ((DEBUG_ERROR, "Ramfb: OpenProtocol failed: %r\n", Status));\r
412 goto FreeGopHandle;\r
413 }\r
414\r
415 return EFI_SUCCESS;\r
416\r
417FreeGopHandle:\r
418 gBS->UninstallMultipleProtocolInterfaces (\r
419 mGopHandle,\r
420 &gEfiDevicePathProtocolGuid,\r
421 GopDevicePath,\r
422 &gEfiGraphicsOutputProtocolGuid,\r
423 &mQemuRamfbGraphicsOutput,\r
424 NULL\r
425 );\r
426FreeGopDevicePath:\r
427 FreePool (GopDevicePath);\r
428FreeRamfbHandle:\r
429 gBS->UninstallMultipleProtocolInterfaces (\r
430 mRamfbHandle,\r
431 &gEfiDevicePathProtocolGuid,\r
432 RamfbDevicePath,\r
433 NULL\r
434 );\r
435FreeRamfbDevicePath:\r
436 FreePool (RamfbDevicePath);\r
437FreeFramebuffer:\r
ac0a286f 438 FreePages ((VOID *)(UINTN)mQemuRamfbMode.FrameBufferBase, Pages);\r
1d25ff51
GH
439 return Status;\r
440}\r