2 This driver is a implementation of the Graphics Output Protocol
3 for the QEMU ramfb device.
5 Copyright (c) 2018, Red Hat Inc.
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Protocol/GraphicsOutput.h>
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>
22 #include <Guid/QemuRamfb.h>
24 #define RAMFB_FORMAT 0x34325258 /* DRM_FORMAT_XRGB8888 */
28 typedef struct RAMFB_CONFIG
{
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
;
44 STATIC EFI_GRAPHICS_OUTPUT_MODE_INFORMATION mQemuRamfbModeInfo
[] = {
47 640, // HorizontalResolution
48 480, // VerticalResolution
51 800, // HorizontalResolution
52 600, // VerticalResolution
55 1024, // HorizontalResolution
56 768, // VerticalResolution
60 STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE mQemuRamfbMode
= {
61 ARRAY_SIZE (mQemuRamfbModeInfo
), // MaxMode
63 mQemuRamfbModeInfo
, // Info
64 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
), // SizeOfInfo
70 QemuRamfbGraphicsOutputQueryMode (
71 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
73 OUT UINTN
*SizeOfInfo
,
74 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
**Info
77 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*ModeInfo
;
79 if ((Info
== NULL
) || (SizeOfInfo
== NULL
) ||
80 (ModeNumber
>= mQemuRamfbMode
.MaxMode
))
82 return EFI_INVALID_PARAMETER
;
85 ModeInfo
= &mQemuRamfbModeInfo
[ModeNumber
];
87 *Info
= AllocateCopyPool (
88 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
),
92 return EFI_OUT_OF_RESOURCES
;
95 *SizeOfInfo
= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
103 QemuRamfbGraphicsOutputSetMode (
104 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
108 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*ModeInfo
;
110 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black
;
111 RETURN_STATUS Status
;
113 if (ModeNumber
>= mQemuRamfbMode
.MaxMode
) {
114 return EFI_UNSUPPORTED
;
117 ModeInfo
= &mQemuRamfbModeInfo
[ModeNumber
];
121 "Ramfb: SetMode %u (%ux%u)\n",
123 ModeInfo
->HorizontalResolution
,
124 ModeInfo
->VerticalResolution
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
);
134 Status
= FrameBufferBltConfigure (
135 (VOID
*)(UINTN
)mQemuRamfbMode
.FrameBufferBase
,
137 mQemuRamfbFrameBufferBltConfigure
,
138 &mQemuRamfbFrameBufferBltConfigureSize
141 if (Status
== RETURN_BUFFER_TOO_SMALL
) {
142 if (mQemuRamfbFrameBufferBltConfigure
!= NULL
) {
143 FreePool (mQemuRamfbFrameBufferBltConfigure
);
146 mQemuRamfbFrameBufferBltConfigure
=
147 AllocatePool (mQemuRamfbFrameBufferBltConfigureSize
);
148 if (mQemuRamfbFrameBufferBltConfigure
== NULL
) {
149 mQemuRamfbFrameBufferBltConfigureSize
= 0;
150 return EFI_OUT_OF_RESOURCES
;
153 Status
= FrameBufferBltConfigure (
154 (VOID
*)(UINTN
)mQemuRamfbMode
.FrameBufferBase
,
156 mQemuRamfbFrameBufferBltConfigure
,
157 &mQemuRamfbFrameBufferBltConfigureSize
161 if (RETURN_ERROR (Status
)) {
162 ASSERT (Status
== RETURN_UNSUPPORTED
);
166 mQemuRamfbMode
.Mode
= ModeNumber
;
167 mQemuRamfbMode
.Info
= ModeInfo
;
169 QemuFwCfgSelectItem (mRamfbFwCfgItem
);
170 QemuFwCfgWriteBytes (sizeof (Config
), &Config
);
175 ZeroMem (&Black
, sizeof (Black
));
176 Status
= FrameBufferBlt (
177 mQemuRamfbFrameBufferBltConfigure
,
180 0, // SourceX -- ignored
181 0, // SourceY -- ignored
184 ModeInfo
->HorizontalResolution
, // Width
185 ModeInfo
->VerticalResolution
, // Height
186 0 // Delta -- ignored
188 if (RETURN_ERROR (Status
)) {
191 "%a: clearing the screen failed: %r\n",
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
,
209 IN UINTN DestinationX
,
210 IN UINTN DestinationY
,
216 return FrameBufferBlt (
217 mQemuRamfbFrameBufferBltConfigure
,
230 STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL mQemuRamfbGraphicsOutput
= {
231 QemuRamfbGraphicsOutputQueryMode
,
232 QemuRamfbGraphicsOutputSetMode
,
233 QemuRamfbGraphicsOutputBlt
,
239 InitializeQemuRamfb (
240 IN EFI_HANDLE ImageHandle
,
241 IN EFI_SYSTEM_TABLE
*SystemTable
244 EFI_DEVICE_PATH_PROTOCOL
*RamfbDevicePath
;
245 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
247 VENDOR_DEVICE_PATH VendorDeviceNode
;
248 ACPI_ADR_DEVICE_PATH AcpiDeviceNode
;
250 EFI_PHYSICAL_ADDRESS FbBase
;
251 UINTN FbSize
, MaxFbSize
, Pages
;
255 if (!QemuFwCfgIsAvailable ()) {
256 DEBUG ((DEBUG_INFO
, "Ramfb: no FwCfg\n"));
257 return EFI_NOT_FOUND
;
260 Status
= QemuFwCfgFindFile ("etc/ramfb", &mRamfbFwCfgItem
, &FwCfgSize
);
261 if (EFI_ERROR (Status
)) {
262 return EFI_NOT_FOUND
;
265 if (FwCfgSize
!= sizeof (RAMFB_CONFIG
)) {
268 "Ramfb: FwCfg size mismatch (expected %lu, got %lu)\n",
269 (UINT64
)sizeof (RAMFB_CONFIG
),
272 return EFI_PROTOCOL_ERROR
;
276 for (Index
= 0; Index
< ARRAY_SIZE (mQemuRamfbModeInfo
); Index
++) {
277 mQemuRamfbModeInfo
[Index
].PixelsPerScanLine
=
278 mQemuRamfbModeInfo
[Index
].HorizontalResolution
;
279 mQemuRamfbModeInfo
[Index
].PixelFormat
=
280 PixelBlueGreenRedReserved8BitPerColor
;
282 mQemuRamfbModeInfo
[Index
].HorizontalResolution
*
283 mQemuRamfbModeInfo
[Index
].VerticalResolution
;
284 if (MaxFbSize
< FbSize
) {
290 "Ramfb: Mode %lu: %ux%u, %lu kB\n",
292 mQemuRamfbModeInfo
[Index
].HorizontalResolution
,
293 mQemuRamfbModeInfo
[Index
].VerticalResolution
,
294 (UINT64
)(FbSize
/ 1024)
298 Pages
= EFI_SIZE_TO_PAGES (MaxFbSize
);
299 MaxFbSize
= EFI_PAGES_TO_SIZE (Pages
);
300 FbBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateReservedPages (Pages
);
302 DEBUG ((DEBUG_ERROR
, "Ramfb: memory allocation failed\n"));
303 return EFI_OUT_OF_RESOURCES
;
308 "Ramfb: Framebuffer at 0x%lx, %lu kB, %lu pages\n",
310 (UINT64
)(MaxFbSize
/ 1024),
313 mQemuRamfbMode
.FrameBufferSize
= MaxFbSize
;
314 mQemuRamfbMode
.FrameBufferBase
= FbBase
;
319 QemuRamfbGraphicsOutputSetMode (&mQemuRamfbGraphicsOutput
, 1);
322 // ramfb vendor devpath
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
)
332 RamfbDevicePath
= AppendDevicePathNode (
334 (EFI_DEVICE_PATH_PROTOCOL
*)&VendorDeviceNode
336 if (RamfbDevicePath
== NULL
) {
337 Status
= EFI_OUT_OF_RESOURCES
;
338 goto FreeFramebuffer
;
341 Status
= gBS
->InstallMultipleProtocolInterfaces (
343 &gEfiDevicePathProtocolGuid
,
347 if (EFI_ERROR (Status
)) {
350 "Ramfb: install Ramfb Vendor DevicePath failed: %r\n",
353 goto FreeRamfbDevicePath
;
357 // gop devpath + protocol
359 AcpiDeviceNode
.Header
.Type
= ACPI_DEVICE_PATH
;
360 AcpiDeviceNode
.Header
.SubType
= ACPI_ADR_DP
;
361 AcpiDeviceNode
.ADR
= ACPI_DISPLAY_ADR (
367 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL
, // Type
371 SetDevicePathNodeLength (
372 &AcpiDeviceNode
.Header
,
373 sizeof (ACPI_ADR_DEVICE_PATH
)
376 GopDevicePath
= AppendDevicePathNode (
378 (EFI_DEVICE_PATH_PROTOCOL
*)&AcpiDeviceNode
380 if (GopDevicePath
== NULL
) {
381 Status
= EFI_OUT_OF_RESOURCES
;
382 goto FreeRamfbHandle
;
385 Status
= gBS
->InstallMultipleProtocolInterfaces (
387 &gEfiDevicePathProtocolGuid
,
389 &gEfiGraphicsOutputProtocolGuid
,
390 &mQemuRamfbGraphicsOutput
,
393 if (EFI_ERROR (Status
)) {
396 "Ramfb: install GOP DevicePath failed: %r\n",
399 goto FreeGopDevicePath
;
402 Status
= gBS
->OpenProtocol (
404 &gEfiDevicePathProtocolGuid
,
408 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
410 if (EFI_ERROR (Status
)) {
411 DEBUG ((DEBUG_ERROR
, "Ramfb: OpenProtocol failed: %r\n", Status
));
418 gBS
->UninstallMultipleProtocolInterfaces (
420 &gEfiDevicePathProtocolGuid
,
422 &gEfiGraphicsOutputProtocolGuid
,
423 &mQemuRamfbGraphicsOutput
,
427 FreePool (GopDevicePath
);
429 gBS
->UninstallMultipleProtocolInterfaces (
431 &gEfiDevicePathProtocolGuid
,
436 FreePool (RamfbDevicePath
);
438 FreePages ((VOID
*)(UINTN
)mQemuRamfbMode
.FrameBufferBase
, Pages
);