2 * early boot framebuffer in guest ram
3 * configured using fw_cfg
5 * Copyright Red Hat, Inc. 2017
8 * Gerd Hoffmann <kraxel@redhat.com>
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qapi/error.h"
16 #include "hw/loader.h"
17 #include "hw/display/ramfb.h"
18 #include "hw/display/bochs-vbe.h" /* for limits */
19 #include "ui/console.h"
20 #include "sysemu/reset.h"
22 struct QEMU_PACKED RAMFBCfg
{
33 uint32_t width
, height
;
37 static void ramfb_unmap_display_surface(pixman_image_t
*image
, void *unused
)
39 void *data
= pixman_image_get_data(image
);
40 uint32_t size
= pixman_image_get_stride(image
) *
41 pixman_image_get_height(image
);
42 cpu_physical_memory_unmap(data
, size
, 0, 0);
45 static DisplaySurface
*ramfb_create_display_surface(int width
, int height
,
46 pixman_format_code_t format
,
47 hwaddr stride
, hwaddr addr
)
49 DisplaySurface
*surface
;
50 hwaddr size
, mapsize
, linesize
;
53 if (width
< 16 || width
> VBE_DISPI_MAX_XRES
||
54 height
< 16 || height
> VBE_DISPI_MAX_YRES
||
55 format
== 0 /* unknown format */)
58 linesize
= width
* PIXMAN_FORMAT_BPP(format
) / 8;
63 mapsize
= size
= stride
* (height
- 1) + linesize
;
64 data
= cpu_physical_memory_map(addr
, &mapsize
, false);
65 if (size
!= mapsize
) {
66 cpu_physical_memory_unmap(data
, mapsize
, 0, 0);
70 surface
= qemu_create_displaysurface_from(width
, height
,
71 format
, stride
, data
);
72 pixman_image_set_destroy_function(surface
->image
,
73 ramfb_unmap_display_surface
, NULL
);
78 static void ramfb_fw_cfg_write(void *dev
, off_t offset
, size_t len
)
81 DisplaySurface
*surface
;
82 uint32_t fourcc
, format
, width
, height
;
85 width
= be32_to_cpu(s
->cfg
.width
);
86 height
= be32_to_cpu(s
->cfg
.height
);
87 stride
= be32_to_cpu(s
->cfg
.stride
);
88 fourcc
= be32_to_cpu(s
->cfg
.fourcc
);
89 addr
= be64_to_cpu(s
->cfg
.addr
);
90 format
= qemu_drm_format_to_pixman(fourcc
);
92 surface
= ramfb_create_display_surface(width
, height
,
93 format
, stride
, addr
);
103 void ramfb_display_update(QemuConsole
*con
, RAMFBState
*s
)
105 if (!s
->width
|| !s
->height
) {
110 dpy_gfx_replace_surface(con
, s
->ds
);
114 /* simple full screen update */
115 dpy_gfx_update_full(con
);
118 RAMFBState
*ramfb_setup(Error
**errp
)
120 FWCfgState
*fw_cfg
= fw_cfg_find();
123 if (!fw_cfg
|| !fw_cfg
->dma_enabled
) {
124 error_setg(errp
, "ramfb device requires fw_cfg with DMA");
128 s
= g_new0(RAMFBState
, 1);
130 rom_add_vga("vgabios-ramfb.bin");
131 fw_cfg_add_file_callback(fw_cfg
, "etc/ramfb",
132 NULL
, ramfb_fw_cfg_write
, s
,
133 &s
->cfg
, sizeof(s
->cfg
), false);