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