]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/QemuRamfbDxe/QemuRamfb.c
IntelFsp2Pkg/SplitFspBin.py: Support rebasing 1.x binary.
[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
29 UINT64 Address;\r
30 UINT32 FourCC;\r
31 UINT32 Flags;\r
32 UINT32 Width;\r
33 UINT32 Height;\r
34 UINT32 Stride;\r
35} RAMFB_CONFIG;\r
36#pragma pack ()\r
37\r
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
43\r
44STATIC EFI_GRAPHICS_OUTPUT_MODE_INFORMATION mQemuRamfbModeInfo[] = {\r
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
60STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE mQemuRamfbMode = {\r
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
79 if (Info == NULL || SizeOfInfo == NULL ||\r
80 ModeNumber >= mQemuRamfbMode.MaxMode) {\r
81 return EFI_INVALID_PARAMETER;\r
82 }\r
83 ModeInfo = &mQemuRamfbModeInfo[ModeNumber];\r
84\r
85 *Info = AllocateCopyPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),\r
86 ModeInfo);\r
87 if (*Info == NULL) {\r
88 return EFI_OUT_OF_RESOURCES;\r
89 }\r
90 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
91\r
92 return EFI_SUCCESS;\r
93}\r
94\r
95STATIC\r
96EFI_STATUS\r
97EFIAPI\r
98QemuRamfbGraphicsOutputSetMode (\r
99 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
100 IN UINT32 ModeNumber\r
101 )\r
102{\r
103 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo;\r
104 RAMFB_CONFIG Config;\r
105 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;\r
106 RETURN_STATUS Status;\r
107\r
108 if (ModeNumber >= mQemuRamfbMode.MaxMode) {\r
109 return EFI_UNSUPPORTED;\r
110 }\r
111 ModeInfo = &mQemuRamfbModeInfo[ModeNumber];\r
112\r
113 DEBUG ((DEBUG_INFO, "Ramfb: SetMode %u (%ux%u)\n", ModeNumber,\r
114 ModeInfo->HorizontalResolution, ModeInfo->VerticalResolution));\r
115\r
116 Config.Address = SwapBytes64 (mQemuRamfbMode.FrameBufferBase);\r
117 Config.FourCC = SwapBytes32 (RAMFB_FORMAT);\r
118 Config.Flags = SwapBytes32 (0);\r
119 Config.Width = SwapBytes32 (ModeInfo->HorizontalResolution);\r
120 Config.Height = SwapBytes32 (ModeInfo->VerticalResolution);\r
121 Config.Stride = SwapBytes32 (ModeInfo->HorizontalResolution * RAMFB_BPP);\r
122\r
123 Status = FrameBufferBltConfigure (\r
124 (VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase,\r
125 ModeInfo,\r
126 mQemuRamfbFrameBufferBltConfigure,\r
127 &mQemuRamfbFrameBufferBltConfigureSize\r
128 );\r
129\r
130 if (Status == RETURN_BUFFER_TOO_SMALL) {\r
131 if (mQemuRamfbFrameBufferBltConfigure != NULL) {\r
132 FreePool (mQemuRamfbFrameBufferBltConfigure);\r
133 }\r
134 mQemuRamfbFrameBufferBltConfigure =\r
135 AllocatePool (mQemuRamfbFrameBufferBltConfigureSize);\r
136 if (mQemuRamfbFrameBufferBltConfigure == NULL) {\r
137 mQemuRamfbFrameBufferBltConfigureSize = 0;\r
138 return EFI_OUT_OF_RESOURCES;\r
139 }\r
140\r
141 Status = FrameBufferBltConfigure (\r
142 (VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase,\r
143 ModeInfo,\r
144 mQemuRamfbFrameBufferBltConfigure,\r
145 &mQemuRamfbFrameBufferBltConfigureSize\r
146 );\r
147 }\r
148 if (RETURN_ERROR (Status)) {\r
149 ASSERT (Status == RETURN_UNSUPPORTED);\r
150 return Status;\r
151 }\r
152\r
153 mQemuRamfbMode.Mode = ModeNumber;\r
154 mQemuRamfbMode.Info = ModeInfo;\r
155\r
156 QemuFwCfgSelectItem (mRamfbFwCfgItem);\r
157 QemuFwCfgWriteBytes (sizeof (Config), &Config);\r
158\r
159 //\r
160 // clear screen\r
161 //\r
162 ZeroMem (&Black, sizeof (Black));\r
163 Status = FrameBufferBlt (\r
164 mQemuRamfbFrameBufferBltConfigure,\r
165 &Black,\r
166 EfiBltVideoFill,\r
167 0, // SourceX -- ignored\r
168 0, // SourceY -- ignored\r
169 0, // DestinationX\r
170 0, // DestinationY\r
171 ModeInfo->HorizontalResolution, // Width\r
172 ModeInfo->VerticalResolution, // Height\r
173 0 // Delta -- ignored\r
174 );\r
175 if (RETURN_ERROR (Status)) {\r
176 DEBUG ((DEBUG_WARN, "%a: clearing the screen failed: %r\n",\r
177 __FUNCTION__, Status));\r
178 }\r
179\r
180 return EFI_SUCCESS;\r
181}\r
182\r
183STATIC\r
184EFI_STATUS\r
185EFIAPI\r
186QemuRamfbGraphicsOutputBlt (\r
187 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
188 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL\r
189 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,\r
190 IN UINTN SourceX,\r
191 IN UINTN SourceY,\r
192 IN UINTN DestinationX,\r
193 IN UINTN DestinationY,\r
194 IN UINTN Width,\r
195 IN UINTN Height,\r
196 IN UINTN Delta\r
197 )\r
198{\r
199 return FrameBufferBlt (\r
200 mQemuRamfbFrameBufferBltConfigure,\r
201 BltBuffer,\r
202 BltOperation,\r
203 SourceX,\r
204 SourceY,\r
205 DestinationX,\r
206 DestinationY,\r
207 Width,\r
208 Height,\r
209 Delta\r
210 );\r
211}\r
212\r
213STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL mQemuRamfbGraphicsOutput = {\r
214 QemuRamfbGraphicsOutputQueryMode,\r
215 QemuRamfbGraphicsOutputSetMode,\r
216 QemuRamfbGraphicsOutputBlt,\r
217 &mQemuRamfbMode,\r
218};\r
219\r
220EFI_STATUS\r
221EFIAPI\r
222InitializeQemuRamfb (\r
223 IN EFI_HANDLE ImageHandle,\r
224 IN EFI_SYSTEM_TABLE *SystemTable\r
225 )\r
226{\r
227 EFI_DEVICE_PATH_PROTOCOL *RamfbDevicePath;\r
228 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
229 VOID *DevicePath;\r
230 VENDOR_DEVICE_PATH VendorDeviceNode;\r
231 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;\r
232 EFI_STATUS Status;\r
233 EFI_PHYSICAL_ADDRESS FbBase;\r
234 UINTN FbSize, MaxFbSize, Pages;\r
235 UINTN FwCfgSize;\r
236 UINTN Index;\r
237\r
238 if (!QemuFwCfgIsAvailable ()) {\r
239 DEBUG ((DEBUG_INFO, "Ramfb: no FwCfg\n"));\r
240 return EFI_NOT_FOUND;\r
241 }\r
242\r
243 Status = QemuFwCfgFindFile ("etc/ramfb", &mRamfbFwCfgItem, &FwCfgSize);\r
244 if (EFI_ERROR (Status)) {\r
245 return EFI_NOT_FOUND;\r
246 }\r
247 if (FwCfgSize != sizeof (RAMFB_CONFIG)) {\r
248 DEBUG ((DEBUG_ERROR, "Ramfb: FwCfg size mismatch (expected %lu, got %lu)\n",\r
249 (UINT64)sizeof (RAMFB_CONFIG), (UINT64)FwCfgSize));\r
250 return EFI_PROTOCOL_ERROR;\r
251 }\r
252\r
253 MaxFbSize = 0;\r
254 for (Index = 0; Index < ARRAY_SIZE (mQemuRamfbModeInfo); Index++) {\r
255 mQemuRamfbModeInfo[Index].PixelsPerScanLine =\r
256 mQemuRamfbModeInfo[Index].HorizontalResolution;\r
257 mQemuRamfbModeInfo[Index].PixelFormat =\r
258 PixelBlueGreenRedReserved8BitPerColor;\r
259 FbSize = RAMFB_BPP *\r
260 mQemuRamfbModeInfo[Index].HorizontalResolution *\r
261 mQemuRamfbModeInfo[Index].VerticalResolution;\r
262 if (MaxFbSize < FbSize) {\r
263 MaxFbSize = FbSize;\r
264 }\r
265 DEBUG ((DEBUG_INFO, "Ramfb: Mode %lu: %ux%u, %lu kB\n", (UINT64)Index,\r
266 mQemuRamfbModeInfo[Index].HorizontalResolution,\r
267 mQemuRamfbModeInfo[Index].VerticalResolution,\r
268 (UINT64)(FbSize / 1024)));\r
269 }\r
270\r
271 Pages = EFI_SIZE_TO_PAGES (MaxFbSize);\r
272 MaxFbSize = EFI_PAGES_TO_SIZE (Pages);\r
273 FbBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (Pages);\r
274 if (FbBase == 0) {\r
275 DEBUG ((DEBUG_ERROR, "Ramfb: memory allocation failed\n"));\r
276 return EFI_OUT_OF_RESOURCES;\r
277 }\r
278 DEBUG ((DEBUG_INFO, "Ramfb: Framebuffer at 0x%lx, %lu kB, %lu pages\n",\r
279 (UINT64)FbBase, (UINT64)(MaxFbSize / 1024), (UINT64)Pages));\r
280 mQemuRamfbMode.FrameBufferSize = MaxFbSize;\r
281 mQemuRamfbMode.FrameBufferBase = FbBase;\r
282\r
283 //\r
284 // 800 x 600\r
285 //\r
286 QemuRamfbGraphicsOutputSetMode (&mQemuRamfbGraphicsOutput, 1);\r
287\r
288 //\r
289 // ramfb vendor devpath\r
290 //\r
291 VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;\r
292 VendorDeviceNode.Header.SubType = HW_VENDOR_DP;\r
293 CopyGuid (&VendorDeviceNode.Guid, &gQemuRamfbGuid);\r
294 SetDevicePathNodeLength (&VendorDeviceNode.Header,\r
295 sizeof (VENDOR_DEVICE_PATH));\r
296\r
297 RamfbDevicePath = AppendDevicePathNode (NULL,\r
298 (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode);\r
299 if (RamfbDevicePath == NULL) {\r
300 Status = EFI_OUT_OF_RESOURCES;\r
301 goto FreeFramebuffer;\r
302 }\r
303\r
304 Status = gBS->InstallMultipleProtocolInterfaces (\r
305 &mRamfbHandle,\r
306 &gEfiDevicePathProtocolGuid,\r
307 RamfbDevicePath,\r
308 NULL\r
309 );\r
310 if (EFI_ERROR (Status)) {\r
311 DEBUG ((DEBUG_ERROR, "Ramfb: install Ramfb Vendor DevicePath failed: %r\n",\r
312 Status));\r
313 goto FreeRamfbDevicePath;\r
314 }\r
315\r
316 //\r
317 // gop devpath + protocol\r
318 //\r
319 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
320 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
321 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (\r
322 1, // DeviceIdScheme\r
323 0, // HeadId\r
324 0, // NonVgaOutput\r
325 1, // BiosCanDetect\r
326 0, // VendorInfo\r
327 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, // Type\r
328 0, // Port\r
329 0 // Index\r
330 );\r
331 SetDevicePathNodeLength (&AcpiDeviceNode.Header,\r
332 sizeof (ACPI_ADR_DEVICE_PATH));\r
333\r
334 GopDevicePath = AppendDevicePathNode (RamfbDevicePath,\r
335 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode);\r
336 if (GopDevicePath == NULL) {\r
337 Status = EFI_OUT_OF_RESOURCES;\r
338 goto FreeRamfbHandle;\r
339 }\r
340\r
341 Status = gBS->InstallMultipleProtocolInterfaces (\r
342 &mGopHandle,\r
343 &gEfiDevicePathProtocolGuid,\r
344 GopDevicePath,\r
345 &gEfiGraphicsOutputProtocolGuid,\r
346 &mQemuRamfbGraphicsOutput,\r
347 NULL\r
348 );\r
349 if (EFI_ERROR (Status)) {\r
350 DEBUG ((DEBUG_ERROR, "Ramfb: install GOP DevicePath failed: %r\n",\r
351 Status));\r
352 goto FreeGopDevicePath;\r
353 }\r
354\r
355 Status = gBS->OpenProtocol (\r
356 mRamfbHandle,\r
357 &gEfiDevicePathProtocolGuid,\r
358 &DevicePath,\r
359 gImageHandle,\r
360 mGopHandle,\r
361 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
362 );\r
363 if (EFI_ERROR (Status)) {\r
364 DEBUG ((DEBUG_ERROR, "Ramfb: OpenProtocol failed: %r\n", Status));\r
365 goto FreeGopHandle;\r
366 }\r
367\r
368 return EFI_SUCCESS;\r
369\r
370FreeGopHandle:\r
371 gBS->UninstallMultipleProtocolInterfaces (\r
372 mGopHandle,\r
373 &gEfiDevicePathProtocolGuid,\r
374 GopDevicePath,\r
375 &gEfiGraphicsOutputProtocolGuid,\r
376 &mQemuRamfbGraphicsOutput,\r
377 NULL\r
378 );\r
379FreeGopDevicePath:\r
380 FreePool (GopDevicePath);\r
381FreeRamfbHandle:\r
382 gBS->UninstallMultipleProtocolInterfaces (\r
383 mRamfbHandle,\r
384 &gEfiDevicePathProtocolGuid,\r
385 RamfbDevicePath,\r
386 NULL\r
387 );\r
388FreeRamfbDevicePath:\r
389 FreePool (RamfbDevicePath);\r
390FreeFramebuffer:\r
391 FreePages ((VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase, Pages);\r
392 return Status;\r
393}\r