xref: /qemu/hw/display/ramfb.c (revision 17e9aa3f)
1 /*
2  * early boot framebuffer in guest ram
3  * configured using fw_cfg
4  *
5  * Copyright Red Hat, Inc. 2017
6  *
7  * Author:
8  *     Gerd Hoffmann <kraxel@redhat.com>
9  *
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.
12  */
13 #include "qemu/osdep.h"
14 #include "qapi/error.h"
15 #include "hw/loader.h"
16 #include "hw/display/ramfb.h"
17 #include "ui/console.h"
18 #include "sysemu/sysemu.h"
19 
20 struct QEMU_PACKED RAMFBCfg {
21     uint64_t addr;
22     uint32_t fourcc;
23     uint32_t flags;
24     uint32_t width;
25     uint32_t height;
26     uint32_t stride;
27 };
28 
29 struct RAMFBState {
30     DisplaySurface *ds;
31     uint32_t width, height;
32     struct RAMFBCfg cfg;
33 };
34 
35 static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
36 {
37     RAMFBState *s = dev;
38     void *framebuffer;
39     uint32_t fourcc, format;
40     hwaddr stride, addr, length;
41 
42     s->width  = be32_to_cpu(s->cfg.width);
43     s->height = be32_to_cpu(s->cfg.height);
44     stride    = be32_to_cpu(s->cfg.stride);
45     fourcc    = be32_to_cpu(s->cfg.fourcc);
46     addr      = be64_to_cpu(s->cfg.addr);
47     length    = stride * s->height;
48     format    = qemu_drm_format_to_pixman(fourcc);
49 
50     fprintf(stderr, "%s: %dx%d @ 0x%" PRIx64 "\n", __func__,
51             s->width, s->height, addr);
52     framebuffer = address_space_map(&address_space_memory,
53                                     addr, &length, false,
54                                     MEMTXATTRS_UNSPECIFIED);
55     if (!framebuffer || length < stride * s->height) {
56         s->width = 0;
57         s->height = 0;
58         return;
59     }
60     s->ds = qemu_create_displaysurface_from(s->width, s->height,
61                                             format, stride, framebuffer);
62 }
63 
64 void ramfb_display_update(QemuConsole *con, RAMFBState *s)
65 {
66     if (!s->width || !s->height) {
67         return;
68     }
69 
70     if (s->ds) {
71         dpy_gfx_replace_surface(con, s->ds);
72         s->ds = NULL;
73     }
74 
75     /* simple full screen update */
76     dpy_gfx_update_full(con);
77 }
78 
79 RAMFBState *ramfb_setup(Error **errp)
80 {
81     FWCfgState *fw_cfg = fw_cfg_find();
82     RAMFBState *s;
83 
84     if (!fw_cfg || !fw_cfg->dma_enabled) {
85         error_setg(errp, "ramfb device requires fw_cfg with DMA");
86         return NULL;
87     }
88 
89     s = g_new0(RAMFBState, 1);
90 
91     fw_cfg_add_file_callback(fw_cfg, "etc/ramfb",
92                              NULL, ramfb_fw_cfg_write, s,
93                              &s->cfg, sizeof(s->cfg), false);
94     return s;
95 }
96