util/hbitmap: update orig_size on truncate
[qemu/ar7.git] / hw / display / ramfb.c
blobb4eb283ef8cf7bc1bb60e30054ab0559ff9e1953
1 /*
2 * early boot framebuffer in guest ram
3 * configured using fw_cfg
5 * Copyright Red Hat, Inc. 2017
7 * Author:
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 {
22 uint64_t addr;
23 uint32_t fourcc;
24 uint32_t flags;
25 uint32_t width;
26 uint32_t height;
27 uint32_t stride;
30 struct RAMFBState {
31 DisplaySurface *ds;
32 uint32_t width, height;
33 uint32_t starting_width, starting_height;
34 struct RAMFBCfg cfg;
35 bool locked;
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;
51 hwaddr size;
52 void *data;
54 if (linesize == 0) {
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);
62 return NULL;
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);
70 return surface;
73 static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
75 RAMFBState *s = dev;
76 uint32_t fourcc, format, width, height;
77 hwaddr stride, addr;
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__,
87 width, height, addr);
88 if (s->locked) {
89 fprintf(stderr, "%s: resolution locked, change rejected\n", __func__);
90 return;
92 s->locked = true;
93 s->width = width;
94 s->height = height;
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) {
102 return;
105 if (s->ds) {
106 dpy_gfx_replace_surface(con, s->ds);
107 s->ds = NULL;
110 /* simple full screen update */
111 dpy_gfx_update_full(con);
114 static void ramfb_reset(void *opaque)
116 RAMFBState *s = (RAMFBState *)opaque;
117 s->locked = false;
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();
126 RAMFBState *s;
128 if (!fw_cfg || !fw_cfg->dma_enabled) {
129 error_setg(errp, "ramfb device requires fw_cfg with DMA");
130 return NULL;
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");
137 if (s_fb_width) {
138 s->cfg.width = atoi(s_fb_width);
139 s->starting_width = s->cfg.width;
141 if (s_fb_height) {
142 s->cfg.height = atoi(s_fb_height);
143 s->starting_height = s->cfg.height;
145 s->locked = false;
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);
152 return s;