Re: [Qemu-devel] [PATCH v5 1/4] hw/display: add ramfb, a simple boot framebuffer living in guest ram

2018-06-15 Thread Laszlo Ersek
On 06/13/18 14:29, Gerd Hoffmann wrote:
> The boot framebuffer is expected to be configured by the firmware, so it
> uses fw_cfg as interface.  Initialization goes as follows:
> 
>   (1) Check whenever etc/ramfb is present.
>   (2) Allocate framebuffer from RAM.
>   (3) Fill struct RAMFBCfg, write it to etc/ramfb.
> 
> Done.  You can write stuff to the framebuffer now, and it should appear
> automagically on the screen.
> 
> Note that this isn't very efficient because it does a full display
> update on each refresh.  No dirty tracking.  Dirty tracking would have
> to be active for the whole ram slot, so that wouldn't be very efficient
> either.  For a boot display which is active for a short time only this
> isn't a big deal.  As permanent guest display something better should be
> used (if possible).
> 
> This is the ramfb core code.  Some windup is needed for display devices
> which want have a ramfb boot display.
> 
> Signed-off-by: Gerd Hoffmann 
> ---
>  include/hw/display/ramfb.h |  9 +
>  hw/display/ramfb.c | 95 
> ++
>  hw/display/Makefile.objs   |  2 +
>  3 files changed, 106 insertions(+)
>  create mode 100644 include/hw/display/ramfb.h
>  create mode 100644 hw/display/ramfb.c

I tested this on KVM, built from Gerd's sirius/ramfb branch @ 778450b87275. 
Works fine with Gerd's corresponding edk2 QemuRamfbDxe driver (already merged):

  [edk2] [PATCH v3 0/4] Add QemuRamfbDxe driver
  http://mid.mail-archive.com/20180613072936.12480-1-kraxel@redhat.com

It also works fine with Ard's efifb patches:

  [PATCH 0/2] efi: add support for cacheable efifb mappings
  http://mid.mail-archive.com/20180615104818.23013-1-ard.biesheuvel@linaro.org

So, for this patch (not the series):

Tested-by: Laszlo Ersek 

Thanks!
Laszlo



[Qemu-devel] [PATCH v5 1/4] hw/display: add ramfb, a simple boot framebuffer living in guest ram

2018-06-13 Thread Gerd Hoffmann
The boot framebuffer is expected to be configured by the firmware, so it
uses fw_cfg as interface.  Initialization goes as follows:

  (1) Check whenever etc/ramfb is present.
  (2) Allocate framebuffer from RAM.
  (3) Fill struct RAMFBCfg, write it to etc/ramfb.

Done.  You can write stuff to the framebuffer now, and it should appear
automagically on the screen.

Note that this isn't very efficient because it does a full display
update on each refresh.  No dirty tracking.  Dirty tracking would have
to be active for the whole ram slot, so that wouldn't be very efficient
either.  For a boot display which is active for a short time only this
isn't a big deal.  As permanent guest display something better should be
used (if possible).

This is the ramfb core code.  Some windup is needed for display devices
which want have a ramfb boot display.

Signed-off-by: Gerd Hoffmann 
---
 include/hw/display/ramfb.h |  9 +
 hw/display/ramfb.c | 95 ++
 hw/display/Makefile.objs   |  2 +
 3 files changed, 106 insertions(+)
 create mode 100644 include/hw/display/ramfb.h
 create mode 100644 hw/display/ramfb.c

diff --git a/include/hw/display/ramfb.h b/include/hw/display/ramfb.h
new file mode 100644
index 00..a3d4c79942
--- /dev/null
+++ b/include/hw/display/ramfb.h
@@ -0,0 +1,9 @@
+#ifndef RAMFB_H
+#define RAMFB_H
+
+/* ramfb.c */
+typedef struct RAMFBState RAMFBState;
+void ramfb_display_update(QemuConsole *con, RAMFBState *s);
+RAMFBState *ramfb_setup(Error **errp);
+
+#endif /* RAMFB_H */
diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c
new file mode 100644
index 00..6867bce8ae
--- /dev/null
+++ b/hw/display/ramfb.c
@@ -0,0 +1,95 @@
+/*
+ * early boot framebuffer in guest ram
+ * configured using fw_cfg
+ *
+ * Copyright Red Hat, Inc. 2017
+ *
+ * Author:
+ * Gerd Hoffmann 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/loader.h"
+#include "hw/display/ramfb.h"
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+
+struct QEMU_PACKED RAMFBCfg {
+uint64_t addr;
+uint32_t fourcc;
+uint32_t flags;
+uint32_t width;
+uint32_t height;
+uint32_t stride;
+};
+
+struct RAMFBState {
+DisplaySurface *ds;
+uint32_t width, height;
+struct RAMFBCfg cfg;
+};
+
+static void ramfb_fw_cfg_write(void *dev, off_t offset, size_t len)
+{
+RAMFBState *s = dev;
+void *framebuffer;
+uint32_t stride, fourcc, format;
+hwaddr addr, length;
+
+s->width  = be32_to_cpu(s->cfg.width);
+s->height = be32_to_cpu(s->cfg.height);
+stride= be32_to_cpu(s->cfg.stride);
+fourcc= be32_to_cpu(s->cfg.fourcc);
+addr  = be64_to_cpu(s->cfg.addr);
+length= stride * s->height;
+format= qemu_drm_format_to_pixman(fourcc);
+
+fprintf(stderr, "%s: %dx%d @ 0x%" PRIx64 "\n", __func__,
+s->width, s->height, addr);
+framebuffer = address_space_map(_space_memory,
+addr, , false,
+MEMTXATTRS_UNSPECIFIED);
+if (!framebuffer || length < stride * s->height) {
+s->width = 0;
+s->height = 0;
+return;
+}
+s->ds = qemu_create_displaysurface_from(s->width, s->height,
+format, stride, framebuffer);
+}
+
+void ramfb_display_update(QemuConsole *con, RAMFBState *s)
+{
+if (!s->width || !s->height) {
+return;
+}
+
+if (s->ds) {
+dpy_gfx_replace_surface(con, s->ds);
+s->ds = NULL;
+}
+
+/* simple full screen update */
+dpy_gfx_update_full(con);
+}
+
+RAMFBState *ramfb_setup(Error **errp)
+{
+FWCfgState *fw_cfg = fw_cfg_find();
+RAMFBState *s;
+
+if (!fw_cfg || !fw_cfg->dma_enabled) {
+error_setg(errp, "ramfb device requires fw_cfg with DMA");
+return NULL;
+}
+
+s = g_new0(RAMFBState, 1);
+
+fw_cfg_add_file_callback(fw_cfg, "etc/ramfb",
+ NULL, ramfb_fw_cfg_write, s,
+ >cfg, sizeof(s->cfg), false);
+return s;
+}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index b5d97ab26d..0af04985d2 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -1,3 +1,5 @@
+common-obj-y += ramfb.o
+
 common-obj-$(CONFIG_ADS7846) += ads7846.o
 common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
 common-obj-$(CONFIG_G364FB) += g364fb.o
-- 
2.9.3