]>
Commit | Line | Data |
---|---|---|
995b3017 GH |
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 <[email protected]> | |
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; | |
6b9b3c1e GH |
39 | uint32_t fourcc, format; |
40 | hwaddr stride, addr, length; | |
995b3017 GH |
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 | ||
9f5d9c19 | 91 | rom_add_vga("vgabios-ramfb.bin"); |
995b3017 GH |
92 | fw_cfg_add_file_callback(fw_cfg, "etc/ramfb", |
93 | NULL, ramfb_fw_cfg_write, s, | |
94 | &s->cfg, sizeof(s->cfg), false); | |
95 | return s; | |
96 | } |