qemu/hw/display/ramfb.c
<<
>>
Prefs
   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
  20struct 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
  29struct RAMFBState {
  30    DisplaySurface *ds;
  31    uint32_t width, height;
  32    struct RAMFBCfg cfg;
  33};
  34
  35static 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
  64void 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
  79RAMFBState *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    rom_add_vga("vgabios-ramfb.bin");
  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}
  97