qemu: add qemu ramfb support
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>
This commit is contained in:
parent
e1a9579acd
commit
d9a8b867a3
2
Makefile
2
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),$@)
|
||||
|
|
|
@ -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 ramfb"
|
||||
select VGA_EMULATE_TEXT
|
||||
help
|
||||
qemu ram framebuffer support (-device ramfb).
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue