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.
13 #include "qemu/osdep.h"
14 #include "qapi/error.h"
15 #include "qemu/option.h"
16 #include "hw/loader.h"
17 #include "hw/display/ramfb.h"
18 #include "ui/console.h"
19 #include "sysemu/sysemu.h"
21 struct QEMU_PACKED RAMFBCfg
{
32 uint32_t width
, height
;
33 uint32_t starting_width
, starting_height
;
38 static void ramfb_unmap_display_surface(pixman_image_t
*image
, void *unused
)
40 void *data
= pixman_image_get_data(image
);
41 uint32_t size
= pixman_image_get_stride(image
) *
42 pixman_image_get_height(image
);
43 cpu_physical_memory_unmap(data
, size
, 0, 0);
46 static DisplaySurface
*ramfb_create_display_surface(int width
, int height
,
47 pixman_format_code_t format
,
48 int linesize
, uint64_t addr
)
50 DisplaySurface
*surface
;
55 linesize
= width
* PIXMAN_FORMAT_BPP(format
) / 8;
58 size
= (hwaddr
)linesize
* height
;
59 data
= cpu_physical_memory_map(addr
, &size
, 0);
60 if (size
!= (hwaddr
)linesize
* height
) {
61 cpu_physical_memory_unmap(data
, size
, 0, 0);
65 surface
= qemu_create_displaysurface_from(width
, height
,
66 format
, linesize
, data
);
67 pixman_image_set_destroy_function(surface
->image
,
68 ramfb_unmap_display_surface
, NULL
);
73 static void ramfb_fw_cfg_write(void *dev
, off_t offset
, size_t len
)
76 uint32_t fourcc
, format
, width
, height
;
79 width
= be32_to_cpu(s
->cfg
.width
);
80 height
= be32_to_cpu(s
->cfg
.height
);
81 stride
= be32_to_cpu(s
->cfg
.stride
);
82 fourcc
= be32_to_cpu(s
->cfg
.fourcc
);
83 addr
= be64_to_cpu(s
->cfg
.addr
);
84 format
= qemu_drm_format_to_pixman(fourcc
);
86 fprintf(stderr
, "%s: %dx%d @ 0x%" PRIx64
"\n", __func__
,
89 fprintf(stderr
, "%s: resolution locked, change rejected\n", __func__
);
95 s
->ds
= ramfb_create_display_surface(s
->width
, s
->height
,
96 format
, stride
, addr
);
99 void ramfb_display_update(QemuConsole
*con
, RAMFBState
*s
)
101 if (!s
->width
|| !s
->height
) {
106 dpy_gfx_replace_surface(con
, s
->ds
);
110 /* simple full screen update */
111 dpy_gfx_update_full(con
);
114 static void ramfb_reset(void *opaque
)
116 RAMFBState
*s
= (RAMFBState
*)opaque
;
118 memset(&s
->cfg
, 0, sizeof(s
->cfg
));
119 s
->cfg
.width
= s
->starting_width
;
120 s
->cfg
.height
= s
->starting_height
;
123 RAMFBState
*ramfb_setup(DeviceState
* dev
, Error
**errp
)
125 FWCfgState
*fw_cfg
= fw_cfg_find();
128 if (!fw_cfg
|| !fw_cfg
->dma_enabled
) {
129 error_setg(errp
, "ramfb device requires fw_cfg with DMA");
133 s
= g_new0(RAMFBState
, 1);
135 const char *s_fb_width
= qemu_opt_get(dev
->opts
, "xres");
136 const char *s_fb_height
= qemu_opt_get(dev
->opts
, "yres");
138 s
->cfg
.width
= atoi(s_fb_width
);
139 s
->starting_width
= s
->cfg
.width
;
142 s
->cfg
.height
= atoi(s_fb_height
);
143 s
->starting_height
= s
->cfg
.height
;
147 rom_add_vga("vgabios-ramfb.bin");
148 fw_cfg_add_file_callback(fw_cfg
, "etc/ramfb",
149 NULL
, ramfb_fw_cfg_write
, s
,
150 &s
->cfg
, sizeof(s
->cfg
), false);
151 qemu_register_reset(ramfb_reset
, s
);