Hi,
Second version of the ramfb series. Turned out the previous version didn't work at all, appearently I've tested by accident with an older rom version which had a copy of the fw_cfg code instead of linking paravirt.o. Making the linked paravirt.o work turned out to be difficuilt due to dependencies on stuff like threads which isn't present in the vgabios builds. So I'm back to the version with the (stripped down) copy of the fw_cfg code ...
Gerd Hoffmann (3): pmm: use tmp zone on oom vgasrc: add allocate_pmm() qemu: add qemu ramfb support
Makefile | 2 +- vgasrc/vgahw.h | 28 +++++----- vgasrc/vgautil.h | 4 ++ src/pmm.c | 13 +++++ vgasrc/ramfb.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/vgainit.c | 48 ++++++++++------ vgasrc/Kconfig | 7 +++ 7 files changed, 235 insertions(+), 30 deletions(-) create mode 100644 vgasrc/ramfb.c
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/pmm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/src/pmm.c b/src/pmm.c index 6403414724..28b253b2d3 100644 --- a/src/pmm.c +++ b/src/pmm.c @@ -8,6 +8,7 @@ #include "config.h" // CONFIG_* #include "malloc.h" // _malloc #include "output.h" // dprintf +#include "e820map.h" // struct e820entry #include "std/pmm.h" // PMM_SIGNATURE #include "string.h" // checksum #include "util.h" // pmm_init @@ -75,6 +76,18 @@ handle_pmm00(u16 *args) break; case 2: data = malloc_palloc(highzone, size, align); + if (!data && (flags & 8)) { + /* + * We are out of meory. So go allocate from the (big) + * ZoneTmpHigh instead and reserve the block in the e820 + * map so the OS will not override it. That way we can + * handle big permanent allocations without needing a big + * ZoneHigh. + */ + data = malloc_palloc(&ZoneTmpHigh, size, align); + if (data) + e820_add(data, size, E820_RESERVED); + } break; case 3: { data = malloc_palloc(lowzone, size, align);
Factor out pmm allocation function from stack allocator.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/vgautil.h | 1 + vgasrc/vgainit.c | 48 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/vgasrc/vgautil.h b/vgasrc/vgautil.h index d93da76b4a..0f2dba4c2a 100644 --- a/vgasrc/vgautil.h +++ b/vgasrc/vgautil.h @@ -92,6 +92,7 @@ extern u8 vgafont16alt[]; // vgainit.c extern int VgaBDF; extern int HaveRunInit; +u32 allocate_pmm(u32 size, int highmem, int aligned);
// vgaversion.c extern const char VERSION[], BUILDINFO[]; diff --git a/vgasrc/vgainit.c b/vgasrc/vgainit.c index 26570dc8fa..cd9108d2de 100644 --- a/vgasrc/vgainit.c +++ b/vgasrc/vgainit.c @@ -42,13 +42,9 @@ struct pci_data rom_pci_data VAR16 VISIBLE16 = { * PMM call and extra stack setup ****************************************************************/
-u16 ExtraStackSeg VAR16 VISIBLE16; - -static void -allocate_extra_stack(void) +u32 +allocate_pmm(u32 size, int highmem, int aligned) { - if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK) - return; u32 pmmscan; for (pmmscan=0; pmmscan < BUILD_BIOS_SIZE; pmmscan+=16) { struct pmmheader *pmm = (void*)pmmscan; @@ -57,29 +53,49 @@ allocate_extra_stack(void) 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, "Attempting to allocate VGA stack via pmm call to %04x:%04x\n" + dprintf(1, "Attempting to allocate %u bytes %s via pmm call to %04x:%04x\n" + , size, highmem ? "highmem" : "lowmem" , entry.seg, entry.offset); u16 res1, res2; + u16 flags = 8 | + ( highmem ? 2 : 1 )| + ( aligned ? 4 : 0 ); + size >>= 4; asm volatile( "pushl %0\n" - "pushw $(8|1)\n" // Permanent low memory request + "pushw %2\n" // flags "pushl $0xffffffff\n" // Anonymous handle - "pushl $" __stringify(CONFIG_VGA_EXTRA_STACK_SIZE/16) "\n" + "pushl %1\n" // size "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"); + : "+r" (entry.segoff), "+r" (size), "+r" (flags), + "=a" (res1), "=d" (res2) : : "cc", "memory"); u32 res = res1 | (res2 << 16); if (!res || res == PMM_FUNCTION_NOT_SUPPORTED) - return; - dprintf(1, "VGA stack allocated at %x\n", res); - SET_VGA(ExtraStackSeg, res >> 4); - extern void entry_10_extrastack(void); - SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10_extrastack)); - return; + return 0; + return res; } + return 0; +} + +u16 ExtraStackSeg VAR16 VISIBLE16; + +static void +allocate_extra_stack(void) +{ + if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK) + return; + u32 res = allocate_pmm(CONFIG_VGA_EXTRA_STACK_SIZE, 0, 0); + if (!res) + return; + dprintf(1, "VGA stack allocated at %x\n", res); + SET_VGA(ExtraStackSeg, res >> 4); + extern void entry_10_extrastack(void); + SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10_extrastack)); + return; }
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@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
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@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 stdvga_setup();return ramfb_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
Hi,
Thanks. Series looks good to me.
qemu patches have been merged, so I pushed these now.
cheers, Gerd