qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

ramfb.c (3590B)


      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 
     14 #include "qemu/osdep.h"
     15 #include "qapi/error.h"
     16 #include "hw/loader.h"
     17 #include "hw/display/ramfb.h"
     18 #include "hw/display/bochs-vbe.h" /* for limits */
     19 #include "ui/console.h"
     20 #include "sysemu/reset.h"
     21 
     22 struct QEMU_PACKED RAMFBCfg {
     23     uint64_t addr;
     24     uint32_t fourcc;
     25     uint32_t flags;
     26     uint32_t width;
     27     uint32_t height;
     28     uint32_t stride;
     29 };
     30 
     31 struct RAMFBState {
     32     DisplaySurface *ds;
     33     uint32_t width, height;
     34     struct RAMFBCfg cfg;
     35 };
     36 
     37 static void ramfb_unmap_display_surface(pixman_image_t *image, void *unused)
     38 {
     39     void *data = pixman_image_get_data(image);
     40     uint32_t size = pixman_image_get_stride(image) *
     41         pixman_image_get_height(image);
     42     cpu_physical_memory_unmap(data, size, 0, 0);
     43 }
     44 
     45 static DisplaySurface *ramfb_create_display_surface(int width, int height,
     46                                                     pixman_format_code_t format,
     47                                                     hwaddr stride, hwaddr addr)
     48 {
     49     DisplaySurface *surface;
     50     hwaddr size, mapsize, linesize;
     51     void *data;
     52 
     53     if (width < 16 || width > VBE_DISPI_MAX_XRES ||
     54         height < 16 || height > VBE_DISPI_MAX_YRES ||
     55         format == 0 /* unknown format */)
     56         return NULL;
     57 
     58     linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
     59     if (stride == 0) {
     60         stride = linesize;
     61     }
     62 
     63     mapsize = size = stride * (height - 1) + linesize;
     64     data = cpu_physical_memory_map(addr, &mapsize, false);
     65     if (size != mapsize) {
     66         cpu_physical_memory_unmap(data, mapsize, 0, 0);
     67         return NULL;
     68     }
     69 
     70     surface = qemu_create_displaysurface_from(width, height,
     71                                               format, stride, data);
     72     pixman_image_set_destroy_function(surface->image,
     73                                       ramfb_unmap_display_surface, NULL);
     74 
     75     return surface;
     76 }
     77 
     78 static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
     79 {
     80     RAMFBState *s = dev;
     81     DisplaySurface *surface;
     82     uint32_t fourcc, format, width, height;
     83     hwaddr stride, addr;
     84 
     85     width  = be32_to_cpu(s->cfg.width);
     86     height = be32_to_cpu(s->cfg.height);
     87     stride = be32_to_cpu(s->cfg.stride);
     88     fourcc = be32_to_cpu(s->cfg.fourcc);
     89     addr   = be64_to_cpu(s->cfg.addr);
     90     format = qemu_drm_format_to_pixman(fourcc);
     91 
     92     surface = ramfb_create_display_surface(width, height,
     93                                            format, stride, addr);
     94     if (!surface) {
     95         return;
     96     }
     97 
     98     s->width = width;
     99     s->height = height;
    100     s->ds = surface;
    101 }
    102 
    103 void ramfb_display_update(QemuConsole *con, RAMFBState *s)
    104 {
    105     if (!s->width || !s->height) {
    106         return;
    107     }
    108 
    109     if (s->ds) {
    110         dpy_gfx_replace_surface(con, s->ds);
    111         s->ds = NULL;
    112     }
    113 
    114     /* simple full screen update */
    115     dpy_gfx_update_full(con);
    116 }
    117 
    118 RAMFBState *ramfb_setup(Error **errp)
    119 {
    120     FWCfgState *fw_cfg = fw_cfg_find();
    121     RAMFBState *s;
    122 
    123     if (!fw_cfg || !fw_cfg->dma_enabled) {
    124         error_setg(errp, "ramfb device requires fw_cfg with DMA");
    125         return NULL;
    126     }
    127 
    128     s = g_new0(RAMFBState, 1);
    129 
    130     rom_add_vga("vgabios-ramfb.bin");
    131     fw_cfg_add_file_callback(fw_cfg, "etc/ramfb",
    132                              NULL, ramfb_fw_cfg_write, s,
    133                              &s->cfg, sizeof(s->cfg), false);
    134     return s;
    135 }