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

Kevin O'Connor kevin at koconnor.net
Fri Jun 15 17:04:47 CEST 2018


On Fri, Jun 15, 2018 at 02:57:37PM +0200, Gerd Hoffmann wrote:
> 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).
> 
> Sharing fw_cfg code with seabios turned out to be difficuilt due to
> various dependencies the code has on infrastructure which only seabios
> has.  So include a copy of the code here, with those dependencies
> removed and also stripped down because we don't need a non-dma fallback
> here.
> 
> Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
> ---
>  Makefile         |   2 +-
>  vgasrc/vgahw.h   |  28 +++++-----
>  vgasrc/vgautil.h |   3 +
>  vgasrc/ramfb.c   | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  vgasrc/Kconfig   |   7 +++
>  5 files changed, 189 insertions(+), 14 deletions(-)
>  create mode 100644 vgasrc/ramfb.c
> 
> diff --git a/Makefile b/Makefile
> index de2a145c39..d2d11dbef8 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 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 0f2dba4c2a..4f37bf947c 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..8f8e2ef331
> --- /dev/null
> +++ b/vgasrc/ramfb.c
> @@ -0,0 +1,163 @@
> +#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"
> +
> +/* ---------------------------------------------------------------------- */
> +/* minimal qemu fc_cfg support bits, requires dma support                 */
> +
> +#define QEMU_CFG_FILE_DIR               0x19
> +
> +struct QemuCfgFile {
> +    u32  size;        /* file size */
> +    u16  select;      /* write this to 0x510 to read it */
> +    u16  reserved;
> +    char name[56];
> +};
> +
> +static void
> +qemu_cfg_dma_transfer(void *address, u32 length, u32 control)
> +{
> +    QemuCfgDmaAccess access;
> +
> +    if (length == 0) {
> +        return;
> +    }
> +
> +    access.address = cpu_to_be64((u64)(u32)address);
> +    access.length = cpu_to_be32(length);
> +    access.control = cpu_to_be32(control);
> +
> +    barrier();
> +
> +    outl(cpu_to_be32((u32)&access), PORT_QEMU_CFG_DMA_ADDR_LOW);
> +
> +    while(be32_to_cpu(access.control) & ~QEMU_CFG_DMA_CTL_ERROR)
> +        /* wait */;
> +}
> +
> +static void
> +qemu_cfg_read(void *buf, int len)
> +{
> +    qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ);
> +}
> +
> +static void
> +qemu_cfg_read_entry(void *buf, int e, int len)
> +{
> +    u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
> +        | QEMU_CFG_DMA_CTL_READ;
> +    qemu_cfg_dma_transfer(buf, len, control);
> +}
> +
> +static void
> +qemu_cfg_write_entry(void *buf, int e, int len)
> +{
> +    u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
> +        | QEMU_CFG_DMA_CTL_WRITE;
> +    qemu_cfg_dma_transfer(buf, len, control);
> +}
> +
> +static int
> +qemu_cfg_find_file(const char *filename)
> +{
> +    u32 count, e, select;
> +
> +    qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
> +    count = be32_to_cpu(count);
> +    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), filename, 10) == 0)
> +            select = be16_to_cpu(qfile.select);
> +    }
> +    return select;
> +}
> +
> +/* ---------------------------------------------------------------------- */
> +
> +#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 res = allocate_pmm(FRAMEBUFFER_SIZE, 1, 1);
> +    if (!res)
> +        return 0;
> +    dprintf(1, "ramfb: framebuffer allocated at %x\n", res);
> +    return res;
> +}
> +
> +int
> +ramfb_setup(void)
> +{
> +    dprintf(1, "ramfb: init\n");
> +
> +    if (GET_GLOBAL(HaveRunInit))
> +        return 0;
> +
> +    u32 select = qemu_cfg_find_file("etc/ramfb");
> +    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);
> +    u32 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

Thanks.  Series looks good to me.

-Kevin



More information about the SeaBIOS mailing list