[SeaBIOS] [PATCH 3/3] qemu: add qemu ramfb support

Gerd Hoffmann kraxel at redhat.com
Wed Jun 13 10:51:57 CEST 2018


Add support for qemu ramfb.  This is a simple boot framebuffer device,
with normal ram being used to back the framebuffer and fw_cfg being used
to configure the device.

Use case (on x86): boot display for vgpu devices (which neither emulate
vga nor have a vgabios).

Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
---
 Makefile         |   2 +-
 vgasrc/vgahw.h   |  28 +++++++------
 vgasrc/vgautil.h |   3 ++
 vgasrc/ramfb.c   | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vgasrc/Kconfig   |   7 ++++
 5 files changed, 149 insertions(+), 14 deletions(-)
 create mode 100644 vgasrc/ramfb.c

diff --git a/Makefile b/Makefile
index de2a145c39..e13a60e647 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,7 @@ SRCVGA=src/output.c src/string.c src/hw/pci.c src/hw/serialio.c \
     vgasrc/vgafonts.c vgasrc/vbe.c \
     vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \
     vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c \
-    src/fw/coreboot.c vgasrc/cbvga.c vgasrc/bochsdisplay.c
+    src/fw/coreboot.c src/fw/paravirt.c vgasrc/cbvga.c vgasrc/bochsdisplay.c vgasrc/ramfb.c
 
 ifeq "$(CONFIG_VGA_FIXUP_ASM)" "y"
 $(OUT)vgaccode16.raw.s: $(OUT)autoconf.h $(patsubst %.c, $(OUT)%.o,$(SRCVGA)) ; $(call whole-compile, $(filter-out -fomit-frame-pointer,$(CFLAGS16)) -fno-omit-frame-pointer -S -Isrc, $(SRCVGA),$@)
diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h
index 6d6ff1aa7b..51777458da 100644
--- a/vgasrc/vgahw.h
+++ b/vgasrc/vgahw.h
@@ -14,7 +14,7 @@ static inline struct vgamode_s *vgahw_find_mode(int mode) {
         return clext_find_mode(mode);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_find_mode(mode);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_find_mode(mode);
     return stdvga_find_mode(mode);
 }
@@ -24,7 +24,7 @@ static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
         return clext_set_mode(vmode_g, flags);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_set_mode(vmode_g, flags);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_set_mode(vmode_g, flags);
     return stdvga_set_mode(vmode_g, flags);
 }
@@ -34,7 +34,7 @@ static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
         clext_list_modes(seg, dest, last);
     else if (CONFIG_VGA_BOCHS)
         bochsvga_list_modes(seg, dest, last);
-    else if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    else if (CONFIG_VGA_EMULATE_TEXT)
         cbvga_list_modes(seg, dest, last);
     else
         stdvga_list_modes(seg, dest, last);
@@ -51,6 +51,8 @@ static inline int vgahw_setup(void) {
         return cbvga_setup();
     if (CONFIG_DISPLAY_BOCHS)
         return bochs_display_setup();
+    if (CONFIG_VGA_RAMFB)
+        return ramfb_setup();
     return stdvga_setup();
 }
 
@@ -59,7 +61,7 @@ static inline int vgahw_get_window(struct vgamode_s *vmode_g, int window) {
         return clext_get_window(vmode_g, window);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_get_window(vmode_g, window);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_get_window(vmode_g, window);
     return stdvga_get_window(vmode_g, window);
 }
@@ -70,7 +72,7 @@ static inline int vgahw_set_window(struct vgamode_s *vmode_g, int window
         return clext_set_window(vmode_g, window, val);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_set_window(vmode_g, window, val);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_set_window(vmode_g, window, val);
     return stdvga_set_window(vmode_g, window, val);
 }
@@ -80,7 +82,7 @@ static inline int vgahw_get_linelength(struct vgamode_s *vmode_g) {
         return clext_get_linelength(vmode_g);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_get_linelength(vmode_g);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_get_linelength(vmode_g);
     return stdvga_get_linelength(vmode_g);
 }
@@ -90,7 +92,7 @@ static inline int vgahw_set_linelength(struct vgamode_s *vmode_g, int val) {
         return clext_set_linelength(vmode_g, val);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_set_linelength(vmode_g, val);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_set_linelength(vmode_g, val);
     return stdvga_set_linelength(vmode_g, val);
 }
@@ -100,7 +102,7 @@ static inline int vgahw_get_displaystart(struct vgamode_s *vmode_g) {
         return clext_get_displaystart(vmode_g);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_get_displaystart(vmode_g);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_get_displaystart(vmode_g);
     return stdvga_get_displaystart(vmode_g);
 }
@@ -110,7 +112,7 @@ static inline int vgahw_set_displaystart(struct vgamode_s *vmode_g, int val) {
         return clext_set_displaystart(vmode_g, val);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_set_displaystart(vmode_g, val);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_set_displaystart(vmode_g, val);
     return stdvga_set_displaystart(vmode_g, val);
 }
@@ -118,7 +120,7 @@ static inline int vgahw_set_displaystart(struct vgamode_s *vmode_g, int val) {
 static inline int vgahw_get_dacformat(struct vgamode_s *vmode_g) {
     if (CONFIG_VGA_BOCHS)
         return bochsvga_get_dacformat(vmode_g);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_get_dacformat(vmode_g);
     return stdvga_get_dacformat(vmode_g);
 }
@@ -126,7 +128,7 @@ static inline int vgahw_get_dacformat(struct vgamode_s *vmode_g) {
 static inline int vgahw_set_dacformat(struct vgamode_s *vmode_g, int val) {
     if (CONFIG_VGA_BOCHS)
         return bochsvga_set_dacformat(vmode_g, val);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_set_dacformat(vmode_g, val);
     return stdvga_set_dacformat(vmode_g, val);
 }
@@ -136,13 +138,13 @@ static inline int vgahw_save_restore(int cmd, u16 seg, void *data) {
         return clext_save_restore(cmd, seg, data);
     if (CONFIG_VGA_BOCHS)
         return bochsvga_save_restore(cmd, seg, data);
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_save_restore(cmd, seg, data);
     return stdvga_save_restore(cmd, seg, data);
 }
 
 static inline int vgahw_get_linesize(struct vgamode_s *vmode_g) {
-    if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS)
+    if (CONFIG_VGA_EMULATE_TEXT)
         return cbvga_get_linesize(vmode_g);
     return stdvga_get_linesize(vmode_g);
 }
diff --git a/vgasrc/vgautil.h b/vgasrc/vgautil.h
index d93da76b4a..9d969bbe46 100644
--- a/vgasrc/vgautil.h
+++ b/vgasrc/vgautil.h
@@ -24,6 +24,9 @@ int cbvga_setup(void);
 // bochsdisplay.c
 int bochs_display_setup(void);
 
+// ramfb.c
+int ramfb_setup(void);
+
 // clext.c
 struct vgamode_s *clext_find_mode(int mode);
 void clext_list_modes(u16 seg, u16 *dest, u16 *last);
diff --git a/vgasrc/ramfb.c b/vgasrc/ramfb.c
new file mode 100644
index 0000000000..30b8cebaa6
--- /dev/null
+++ b/vgasrc/ramfb.c
@@ -0,0 +1,123 @@
+#include "biosvar.h" // GET_BDA
+#include "output.h" // dprintf
+#include "string.h" // memset16_far
+#include "vgautil.h" // VBE_total_memory
+#include "std/pmm.h" // struct pmmheader
+#include "byteorder.h"
+#include "fw/paravirt.h"
+
+#define FRAMEBUFFER_WIDTH      1024
+#define FRAMEBUFFER_HEIGHT     768
+#define FRAMEBUFFER_BPP        4
+#define FRAMEBUFFER_STRIDE     (FRAMEBUFFER_BPP * FRAMEBUFFER_WIDTH)
+#define FRAMEBUFFER_SIZE       (FRAMEBUFFER_STRIDE * FRAMEBUFFER_HEIGHT)
+
+struct QemuRAMFBCfg {
+    u64 addr;
+    u32 fourcc;
+    u32 flags;
+    u32 width;
+    u32 height;
+    u32 stride;
+};
+
+#define fourcc_code(a, b, c, d) ((u32)(a) | ((u32)(b) << 8) | \
+                                 ((u32)(c) << 16) | ((u32)(d) << 24))
+
+#define DRM_FORMAT_RGB565       fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
+#define DRM_FORMAT_RGB888       fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
+#define DRM_FORMAT_XRGB8888     fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */
+
+static u32
+allocate_framebuffer(void)
+{
+    u32 pmmscan;
+    for (pmmscan=0; pmmscan < BUILD_BIOS_SIZE; pmmscan+=16) {
+        struct pmmheader *pmm = (void*)pmmscan;
+        if (GET_FARVAR(SEG_BIOS, pmm->signature) != PMM_SIGNATURE)
+            continue;
+        if (checksum_far(SEG_BIOS, pmm, GET_FARVAR(SEG_BIOS, pmm->length)))
+            continue;
+        struct segoff_s entry = GET_FARVAR(SEG_BIOS, pmm->entry);
+        dprintf(1, "ramfb: alloc framebuffer via pmm call to %04x:%04x\n"
+                , entry.seg, entry.offset);
+        u16 res1, res2;
+        asm volatile(
+            "pushl %0\n"
+            "pushw $(8|2)\n"            // Permanent high memory request
+            "pushl $0xffffffff\n"       // Anonymous handle
+            "pushl $" __stringify(FRAMEBUFFER_SIZE / 16) "\n"
+            "pushw $0x00\n"             // PMM allocation request
+            "lcallw *12(%%esp)\n"
+            "addl $16, %%esp\n"
+            "cli\n"
+            "cld\n"
+            : "+r" (entry.segoff), "=a" (res1), "=d" (res2) : : "cc", "memory");
+        u32 res = res1 | (res2 << 16);
+        if (!res || res == PMM_FUNCTION_NOT_SUPPORTED)
+            return 0;
+        dprintf(1, "ramfb: framebuffer allocated at %x\n", res);
+        return res;
+    }
+    return 0;
+}
+
+int
+ramfb_setup(void)
+{
+    dprintf(1, "ramfb: init\n");
+
+    if (GET_GLOBAL(HaveRunInit))
+        return 0;
+
+    u32 count;
+    qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+    count = be32_to_cpu(count);
+    u32 select, e, fb;
+    for (select = 0, e = 0; e < count; e++) {
+        struct QemuCfgFile qfile;
+        qemu_cfg_read(&qfile, sizeof(qfile));
+        if (memcmp_far(GET_SEG(SS), qfile.name,
+                       GET_SEG(CS), "etc/ramfb", 10) == 0)
+            select = be16_to_cpu(qfile.select);
+    }
+    if (select == 0) {
+        dprintf(1, "ramfb: fw_cfg (etc/ramfb) file not found\n");
+        return -1;
+    }
+
+    dprintf(1, "ramfb: fw_cfg (etc/ramfb) file at slot 0x%x\n", select);
+    fb = allocate_framebuffer();
+    if (!fb) {
+        dprintf(1, "ramfb: allocating framebuffer failed\n");
+        return -1;
+    }
+
+    u64 addr = fb;
+    u8 bpp = FRAMEBUFFER_BPP * 8;
+    u32 xlines = FRAMEBUFFER_WIDTH;
+    u32 ylines = FRAMEBUFFER_HEIGHT;
+    u32 linelength = FRAMEBUFFER_STRIDE;
+    dprintf(1, "Found FB @ %llx %dx%d with %d bpp (%d stride)\n"
+            , addr, xlines, ylines, bpp, linelength);
+
+    if (!addr || addr > 0xffffffff
+        || (bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32)) {
+        dprintf(1, "Unable to use FB\n");
+        return -1;
+    }
+
+    cbvga_setup_modes(addr, bpp, xlines, ylines, linelength);
+
+    struct QemuRAMFBCfg cfg = {
+        .addr   = cpu_to_be64(fb),
+        .fourcc = cpu_to_be32(DRM_FORMAT_XRGB8888),
+        .flags  = cpu_to_be32(0),
+        .width  = cpu_to_be32(FRAMEBUFFER_WIDTH),
+        .height = cpu_to_be32(FRAMEBUFFER_HEIGHT),
+        .stride = cpu_to_be32(FRAMEBUFFER_STRIDE),
+    };
+    qemu_cfg_write_entry(&cfg, select, sizeof(cfg));
+
+    return 0;
+}
diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig
index 4443c0b37a..1933b0e23f 100644
--- a/vgasrc/Kconfig
+++ b/vgasrc/Kconfig
@@ -70,6 +70,13 @@ menu "VGA ROM"
                 v3.0+. The vgabios works with the qemu stdvga too (use
                 "qemu -device VGA,romfile=/path/to/vgabios.bin")".
 
+        config VGA_RAMFB
+            depends on QEMU
+            bool "qemu ram framebuffer (experimental)"
+            select VGA_EMULATE_TEXT
+            help
+                qemu ram framebuffer (experimental)
+
     endchoice
 
     choice
-- 
2.9.3




More information about the SeaBIOS mailing list