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
{
31 typedef struct RAMFBCfg RAMFBCfg
;
35 uint32_t width
, height
;
39 static void ramfb_unmap_display_surface(pixman_image_t
*image
, void *unused
)
41 void *data
= pixman_image_get_data(image
);
42 uint32_t size
= pixman_image_get_stride(image
) *
43 pixman_image_get_height(image
);
44 cpu_physical_memory_unmap(data
, size
, 0, 0);
47 static DisplaySurface
*ramfb_create_display_surface(int width
, int height
,
48 pixman_format_code_t format
,
49 hwaddr stride
, hwaddr addr
)
51 DisplaySurface
*surface
;
52 hwaddr size
, mapsize
, linesize
;
55 if (width
< 16 || width
> VBE_DISPI_MAX_XRES
||
56 height
< 16 || height
> VBE_DISPI_MAX_YRES
||
57 format
== 0 /* unknown format */)
60 linesize
= width
* PIXMAN_FORMAT_BPP(format
) / 8;
65 mapsize
= size
= stride
* (height
- 1) + linesize
;
66 data
= cpu_physical_memory_map(addr
, &mapsize
, false);
67 if (size
!= mapsize
) {
68 cpu_physical_memory_unmap(data
, mapsize
, 0, 0);
72 surface
= qemu_create_displaysurface_from(width
, height
,
73 format
, stride
, data
);
74 pixman_image_set_destroy_function(surface
->image
,
75 ramfb_unmap_display_surface
, NULL
);
80 static void ramfb_fw_cfg_write(void *dev
, off_t offset
, size_t len
)
83 DisplaySurface
*surface
;
84 uint32_t fourcc
, format
, width
, height
;
87 width
= be32_to_cpu(s
->cfg
.width
);
88 height
= be32_to_cpu(s
->cfg
.height
);
89 stride
= be32_to_cpu(s
->cfg
.stride
);
90 fourcc
= be32_to_cpu(s
->cfg
.fourcc
);
91 addr
= be64_to_cpu(s
->cfg
.addr
);
92 format
= qemu_drm_format_to_pixman(fourcc
);
94 surface
= ramfb_create_display_surface(width
, height
,
95 format
, stride
, addr
);
102 qemu_free_displaysurface(s
->ds
);
106 void ramfb_display_update(QemuConsole
*con
, RAMFBState
*s
)
108 if (!s
->width
|| !s
->height
) {
113 dpy_gfx_replace_surface(con
, s
->ds
);
117 /* simple full screen update */
118 dpy_gfx_update_full(con
);
121 static int ramfb_post_load(void *opaque
, int version_id
)
123 ramfb_fw_cfg_write(opaque
, 0, 0);
127 const VMStateDescription ramfb_vmstate
= {
130 .minimum_version_id
= 1,
131 .post_load
= ramfb_post_load
,
132 .fields
= (const VMStateField
[]) {
133 VMSTATE_BUFFER_UNSAFE(cfg
, RAMFBState
, 0, sizeof(RAMFBCfg
)),
134 VMSTATE_END_OF_LIST()
138 RAMFBState
*ramfb_setup(Error
**errp
)
140 FWCfgState
*fw_cfg
= fw_cfg_find();
143 if (!fw_cfg
|| !fw_cfg
->dma_enabled
) {
144 error_setg(errp
, "ramfb device requires fw_cfg with DMA");
148 s
= g_new0(RAMFBState
, 1);
150 rom_add_vga("vgabios-ramfb.bin");
151 fw_cfg_add_file_callback(fw_cfg
, "etc/ramfb",
152 NULL
, ramfb_fw_cfg_write
, s
,
153 &s
->cfg
, sizeof(s
->cfg
), false);