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