]> git.proxmox.com Git - mirror_qemu.git/blame - hw/display/ramfb.c
i386: Add x-force-features option for testing
[mirror_qemu.git] / hw / display / ramfb.c
CommitLineData
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 <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"
f79081b4 15#include "qemu/option.h"
995b3017
GH
16#include "hw/loader.h"
17#include "hw/display/ramfb.h"
18#include "ui/console.h"
19#include "sysemu/sysemu.h"
20
21struct QEMU_PACKED RAMFBCfg {
22 uint64_t addr;
23 uint32_t fourcc;
24 uint32_t flags;
25 uint32_t width;
26 uint32_t height;
27 uint32_t stride;
28};
29
30struct RAMFBState {
31 DisplaySurface *ds;
32 uint32_t width, height;
f79081b4 33 uint32_t starting_width, starting_height;
995b3017 34 struct RAMFBCfg cfg;
a9e0cb67 35 bool locked;
995b3017
GH
36};
37
d57f252a
HQ
38static void ramfb_unmap_display_surface(pixman_image_t *image, void *unused)
39{
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);
44}
45
46static DisplaySurface *ramfb_create_display_surface(int width, int height,
47 pixman_format_code_t format,
48 int linesize, uint64_t addr)
49{
50 DisplaySurface *surface;
51 hwaddr size;
52 void *data;
53
54 if (linesize == 0) {
55 linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
56 }
57
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);
62 return NULL;
63 }
64
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);
69
70 return surface;
71}
72
995b3017
GH
73static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
74{
75 RAMFBState *s = dev;
a9e0cb67 76 uint32_t fourcc, format, width, height;
d57f252a 77 hwaddr stride, addr;
995b3017 78
a9e0cb67
HQ
79 width = be32_to_cpu(s->cfg.width);
80 height = be32_to_cpu(s->cfg.height);
995b3017
GH
81 stride = be32_to_cpu(s->cfg.stride);
82 fourcc = be32_to_cpu(s->cfg.fourcc);
83 addr = be64_to_cpu(s->cfg.addr);
995b3017
GH
84 format = qemu_drm_format_to_pixman(fourcc);
85
86 fprintf(stderr, "%s: %dx%d @ 0x%" PRIx64 "\n", __func__,
a9e0cb67
HQ
87 width, height, addr);
88 if (s->locked) {
89 fprintf(stderr, "%s: resolution locked, change rejected\n", __func__);
90 return;
91 }
92 s->locked = true;
93 s->width = width;
94 s->height = height;
d57f252a
HQ
95 s->ds = ramfb_create_display_surface(s->width, s->height,
96 format, stride, addr);
995b3017
GH
97}
98
99void ramfb_display_update(QemuConsole *con, RAMFBState *s)
100{
101 if (!s->width || !s->height) {
102 return;
103 }
104
105 if (s->ds) {
106 dpy_gfx_replace_surface(con, s->ds);
107 s->ds = NULL;
108 }
109
110 /* simple full screen update */
111 dpy_gfx_update_full(con);
112}
113
a9e0cb67
HQ
114static void ramfb_reset(void *opaque)
115{
116 RAMFBState *s = (RAMFBState *)opaque;
117 s->locked = false;
118 memset(&s->cfg, 0, sizeof(s->cfg));
f79081b4
HQ
119 s->cfg.width = s->starting_width;
120 s->cfg.height = s->starting_height;
a9e0cb67
HQ
121}
122
f79081b4 123RAMFBState *ramfb_setup(DeviceState* dev, Error **errp)
995b3017
GH
124{
125 FWCfgState *fw_cfg = fw_cfg_find();
126 RAMFBState *s;
127
128 if (!fw_cfg || !fw_cfg->dma_enabled) {
129 error_setg(errp, "ramfb device requires fw_cfg with DMA");
130 return NULL;
131 }
132
133 s = g_new0(RAMFBState, 1);
134
f79081b4
HQ
135 const char *s_fb_width = qemu_opt_get(dev->opts, "xres");
136 const char *s_fb_height = qemu_opt_get(dev->opts, "yres");
137 if (s_fb_width) {
138 s->cfg.width = atoi(s_fb_width);
139 s->starting_width = s->cfg.width;
140 }
141 if (s_fb_height) {
142 s->cfg.height = atoi(s_fb_height);
143 s->starting_height = s->cfg.height;
144 }
a9e0cb67
HQ
145 s->locked = false;
146
9f5d9c19 147 rom_add_vga("vgabios-ramfb.bin");
995b3017
GH
148 fw_cfg_add_file_callback(fw_cfg, "etc/ramfb",
149 NULL, ramfb_fw_cfg_write, s,
150 &s->cfg, sizeof(s->cfg), false);
a9e0cb67 151 qemu_register_reset(ramfb_reset, s);
995b3017
GH
152 return s;
153}