Add support for the new bochs-display device in qemu.
Gerd Hoffmann (6): pci,optionrom: enable non-vga display devices cbvga: factor out cbvga_setup_modes() qemu: add bochs-display support cbvga_setup_modes: use real mode number instead of 0x140 cbvga_list_modes: don't list current mode twice [workaround] cbvga_set_mode: disable clearmem
vgasrc/vgahw.h | 28 ++++++------ vgasrc/vgautil.h | 1 + src/fw/pciinit.c | 15 +++++-- src/optionroms.c | 29 ++++++++++++- vgasrc/cbvga.c | 127 +++++++++++++++++++++++++++++++++++++++++++------------ vgasrc/Kconfig | 17 ++++++++ 6 files changed, 173 insertions(+), 44 deletions(-)
In case no VGA device was found look for other display devices, in both pci initialization and in vgabios rom scan.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/fw/pciinit.c | 15 +++++++++++---- src/optionroms.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 3a2f747984..e9518741b5 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -431,6 +431,7 @@ static void pci_bios_init_devices(void) static void pci_enable_default_vga(void) { struct pci_device *pci; + int is_vga = 1;
foreachpci(pci) { if (is_pci_vga(pci)) { @@ -441,16 +442,22 @@ static void pci_enable_default_vga(void)
pci = pci_find_class(PCI_CLASS_DISPLAY_VGA); if (!pci) { - dprintf(1, "PCI: No VGA devices found\n"); - return; + dprintf(1, "PCI: No VGA devices found, trying other display devices\n"); + pci = pci_find_class(PCI_CLASS_DISPLAY_OTHER); + if (!pci) { + dprintf(1, "PCI: No other display devices found\n"); + return; + } + is_vga = 0; }
- dprintf(1, "PCI: Enabling %pP for primary VGA\n", pci); + dprintf(1, "PCI: Enabling %pP for primary %s\n", pci + , is_vga ? "VGA" : "display");
pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- while (pci->parent) { + while (is_vga && pci->parent) { pci = pci->parent;
dprintf(1, "PCI: Setting VGA enable on bridge %pP\n", pci); diff --git a/src/optionroms.c b/src/optionroms.c index 092393a56c..7febd7fcf8 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -224,6 +224,17 @@ is_pci_vga(struct pci_device *pci) return 1; }
+int +is_pci_display_other(struct pci_device *pci) +{ + if (pci->class != PCI_CLASS_DISPLAY_OTHER) + return 0; + u16 cmd = pci_config_readw(pci->bdf, PCI_COMMAND); + if (!(cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY)) + return 0; + return 1; +} + // Copy a rom to its permanent location below 1MiB static struct rom_header * copy_rom(struct rom_header *rom) @@ -350,7 +361,9 @@ optionrom_setup(void) // Find and deploy PCI roms. struct pci_device *pci; foreachpci(pci) { - if (pci->class == PCI_CLASS_DISPLAY_VGA || pci->have_driver) + if (pci->class == PCI_CLASS_DISPLAY_VGA || + pci->class == PCI_CLASS_DISPLAY_OTHER || + pci->have_driver) continue; init_pcirom(pci, 0, sources); } @@ -404,6 +417,8 @@ struct rom_header *VgaROM; void vgarom_setup(void) { + int have_vga = 0; + if (! CONFIG_OPTIONROMS) return;
@@ -425,8 +440,20 @@ vgarom_setup(void) continue; vgahook_setup(pci); init_pcirom(pci, 1, NULL); + have_vga = 1; break; } + if (!have_vga) { + // no VGA, try fallback to display + dprintf(1, "no vga, try display\n"); + foreachpci(pci) { + if (!is_pci_display_other(pci)) + continue; + vgahook_setup(pci); + init_pcirom(pci, 1, NULL); + break; + } + }
// Find and deploy CBFS vga-style roms not associated with a device. run_file_roms("vgaroms/", 1, NULL);
On Thu, May 31, 2018 at 08:33:48AM +0200, Gerd Hoffmann wrote:
In case no VGA device was found look for other display devices, in both pci initialization and in vgabios rom scan.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
src/fw/pciinit.c | 15 +++++++++++---- src/optionroms.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 3a2f747984..e9518741b5 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -431,6 +431,7 @@ static void pci_bios_init_devices(void) static void pci_enable_default_vga(void) { struct pci_device *pci;
int is_vga = 1;
foreachpci(pci) { if (is_pci_vga(pci)) {
@@ -441,16 +442,22 @@ static void pci_enable_default_vga(void)
pci = pci_find_class(PCI_CLASS_DISPLAY_VGA); if (!pci) {
dprintf(1, "PCI: No VGA devices found\n");
return;
dprintf(1, "PCI: No VGA devices found, trying other display devices\n");
pci = pci_find_class(PCI_CLASS_DISPLAY_OTHER);
if (!pci) {
dprintf(1, "PCI: No other display devices found\n");
return;
}
}is_vga = 0;
- dprintf(1, "PCI: Enabling %pP for primary VGA\n", pci);
dprintf(1, "PCI: Enabling %pP for primary %s\n", pci
, is_vga ? "VGA" : "display");
pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- while (pci->parent) {
while (is_vga && pci->parent) { pci = pci->parent;
dprintf(1, "PCI: Setting VGA enable on bridge %pP\n", pci);
diff --git a/src/optionroms.c b/src/optionroms.c index 092393a56c..7febd7fcf8 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -224,6 +224,17 @@ is_pci_vga(struct pci_device *pci) return 1; }
+int +is_pci_display_other(struct pci_device *pci) +{
- if (pci->class != PCI_CLASS_DISPLAY_OTHER)
return 0;
- u16 cmd = pci_config_readw(pci->bdf, PCI_COMMAND);
- if (!(cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY))
return 0;
- return 1;
+}
// Copy a rom to its permanent location below 1MiB static struct rom_header * copy_rom(struct rom_header *rom) @@ -350,7 +361,9 @@ optionrom_setup(void) // Find and deploy PCI roms. struct pci_device *pci; foreachpci(pci) {
if (pci->class == PCI_CLASS_DISPLAY_VGA || pci->have_driver)
if (pci->class == PCI_CLASS_DISPLAY_VGA ||
pci->class == PCI_CLASS_DISPLAY_OTHER ||
}pci->have_driver) continue; init_pcirom(pci, 0, sources);
@@ -404,6 +417,8 @@ struct rom_header *VgaROM; void vgarom_setup(void) {
- int have_vga = 0;
- if (! CONFIG_OPTIONROMS) return;
@@ -425,8 +440,20 @@ vgarom_setup(void) continue; vgahook_setup(pci); init_pcirom(pci, 1, NULL);
}have_vga = 1; break;
- if (!have_vga) {
// no VGA, try fallback to display
dprintf(1, "no vga, try display\n");
foreachpci(pci) {
if (!is_pci_display_other(pci))
continue;
vgahook_setup(pci);
init_pcirom(pci, 1, NULL);
break;
}
- }
Is the goal of this patch to bring up the display device early during boot? If so, do we need to change pciinit.c? Could we instead add: if (!have_vga) try_setup_display_other(); here and then let that function do all the work? The funky pciinit.c stuff is there because on coreboot there could be multiple vga devices in the machine and we want to choose the primary vga device, which is the one that coreboot did the vga mapping for.
Separately, I don't think we need to call vgahook_setup() if a real vga device wasn't found.
Thanks, -Kevin
- if (!have_vga) {
// no VGA, try fallback to display
dprintf(1, "no vga, try display\n");
foreachpci(pci) {
if (!is_pci_display_other(pci))
continue;
vgahook_setup(pci);
init_pcirom(pci, 1, NULL);
break;
}
- }
Is the goal of this patch to bring up the display device early during boot?
Yes.
If so, do we need to change pciinit.c? Could we instead add: if (!have_vga) try_setup_display_other(); here and then let that function do all the work?
The only thing the pciinit patch effectively does (beside the printk) is setting the PCI_COMMAND register. We could do that elsewhere. Either the vgabios does it itself (are roms expected to do that?), or try_setup_display_other() does it.
Separately, I don't think we need to call vgahook_setup() if a real vga device wasn't found.
Indeed.
cheers, Gerd
Factor out generic data structure setup code from cbvga_setup().
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/cbvga.c | 57 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 25 deletions(-)
diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c index f85989a232..9ae97d5f51 100644 --- a/vgasrc/cbvga.c +++ b/vgasrc/cbvga.c @@ -232,10 +232,40 @@ struct cb_framebuffer { u8 reserved_mask_size; };
+void +cbvga_setup_modes(u64 addr, u8 bpp, u32 xlines, u32 ylines, u32 linelength) +{ + int i; + + SET_VGA(CBmode, 0x140); + SET_VGA(VBE_framebuffer, addr); + SET_VGA(VBE_total_memory, linelength * ylines); + SET_VGA(CBlinelength, linelength); + SET_VGA(CBmodeinfo.memmodel, MM_DIRECT); + SET_VGA(CBmodeinfo.width, xlines); + SET_VGA(CBmodeinfo.height, ylines); + SET_VGA(CBmodeinfo.depth, bpp); + SET_VGA(CBmodeinfo.cwidth, 8); + SET_VGA(CBmodeinfo.cheight, 16); + memcpy_far(get_global_seg(), &CBemulinfo + , get_global_seg(), &CBmodeinfo, sizeof(CBemulinfo)); + + // Validate modes + for (i = 0; i < ARRAY_SIZE(cbvesa_modes); i++) { + struct cbvga_mode_s *cbmode_g = &cbvesa_modes[i]; + /* Skip VBE modes that doesn't fit into coreboot's framebuffer */ + if ((GET_GLOBAL(cbmode_g->info.height) > ylines) + || (GET_GLOBAL(cbmode_g->info.width) > xlines) + || (GET_GLOBAL(cbmode_g->info.depth) != bpp)) { + dprintf(3, "Removing mode %x\n", GET_GLOBAL(cbmode_g->mode)); + SET_VGA(cbmode_g->mode, 0xffff); + } + } +} + int cbvga_setup(void) { - int i; dprintf(1, "coreboot vga init\n");
if (GET_GLOBAL(HaveRunInit)) @@ -277,29 +307,6 @@ cbvga_setup(void) return -1; }
- SET_VGA(CBmode, 0x140); - SET_VGA(VBE_framebuffer, addr); - SET_VGA(VBE_total_memory, linelength * ylines); - SET_VGA(CBlinelength, linelength); - SET_VGA(CBmodeinfo.memmodel, MM_DIRECT); - SET_VGA(CBmodeinfo.width, xlines); - SET_VGA(CBmodeinfo.height, ylines); - SET_VGA(CBmodeinfo.depth, bpp); - SET_VGA(CBmodeinfo.cwidth, 8); - SET_VGA(CBmodeinfo.cheight, 16); - memcpy_far(get_global_seg(), &CBemulinfo - , get_global_seg(), &CBmodeinfo, sizeof(CBemulinfo)); - - // Validate modes - for (i = 0; i < ARRAY_SIZE(cbvesa_modes); i++) { - struct cbvga_mode_s *cbmode_g = &cbvesa_modes[i]; - /* Skip VBE modes that doesn't fit into coreboot's framebuffer */ - if ((GET_GLOBAL(cbmode_g->info.height) > ylines) - || (GET_GLOBAL(cbmode_g->info.width) > xlines) - || (GET_GLOBAL(cbmode_g->info.depth) != bpp)) { - dprintf(3, "Removing mode %x\n", GET_GLOBAL(cbmode_g->mode)); - SET_VGA(cbmode_g->mode, 0xffff); - } - } + cbvga_setup_modes(addr, bpp, xlines, ylines, linelength); return 0; }
Use coreboot text mode emulation to also support the qemu bochs-display device. This is a new display device supporting simple linear framebuffers, using the bochs register interface. No support for legacy vga (text modes, planar modes, cga modes, 8bpp palette modes all dropped). The bochs interface is compatible with the qemu stdvga.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/vgahw.h | 28 +++++++++++++++------------- vgasrc/vgautil.h | 1 + vgasrc/cbvga.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/Kconfig | 17 +++++++++++++++++ 4 files changed, 90 insertions(+), 13 deletions(-)
diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h index 2a85eba8d7..6d6ff1aa7b 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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) 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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) 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) + else if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) cbvga_list_modes(seg, dest, last); else stdvga_list_modes(seg, dest, last); @@ -49,6 +49,8 @@ static inline int vgahw_setup(void) { return geodevga_setup(); if (CONFIG_VGA_COREBOOT) return cbvga_setup(); + if (CONFIG_DISPLAY_BOCHS) + return bochs_display_setup(); return stdvga_setup(); }
@@ -57,7 +59,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_get_window(vmode_g, window); return stdvga_get_window(vmode_g, window); } @@ -68,7 +70,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_set_window(vmode_g, window, val); return stdvga_set_window(vmode_g, window, val); } @@ -78,7 +80,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_get_linelength(vmode_g); return stdvga_get_linelength(vmode_g); } @@ -88,7 +90,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_set_linelength(vmode_g, val); return stdvga_set_linelength(vmode_g, val); } @@ -98,7 +100,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_get_displaystart(vmode_g); return stdvga_get_displaystart(vmode_g); } @@ -108,7 +110,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_set_displaystart(vmode_g, val); return stdvga_set_displaystart(vmode_g, val); } @@ -116,7 +118,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_get_dacformat(vmode_g); return stdvga_get_dacformat(vmode_g); } @@ -124,7 +126,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_set_dacformat(vmode_g, val); return stdvga_set_dacformat(vmode_g, val); } @@ -134,13 +136,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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) 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) + if (CONFIG_VGA_COREBOOT || CONFIG_DISPLAY_BOCHS) return cbvga_get_linesize(vmode_g); return stdvga_get_linesize(vmode_g); } diff --git a/vgasrc/vgautil.h b/vgasrc/vgautil.h index fae5fbaeef..563f2fc11f 100644 --- a/vgasrc/vgautil.h +++ b/vgasrc/vgautil.h @@ -19,6 +19,7 @@ int cbvga_save_restore(int cmd, u16 seg, void *data); int cbvga_set_mode(struct vgamode_s *vmode_g, int flags); int cbvga_get_linesize(struct vgamode_s *vmode_g); int cbvga_setup(void); +int bochs_display_setup(void);
// clext.c struct vgamode_s *clext_find_mode(int mode); diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c index 9ae97d5f51..672daa604c 100644 --- a/vgasrc/cbvga.c +++ b/vgasrc/cbvga.c @@ -8,6 +8,9 @@ #include "biosvar.h" // GET_BDA #include "output.h" // dprintf #include "stdvga.h" // SEG_CTEXT +#include "bochsvga.h" // VBE_BOCHS_* +#include "hw/pci.h" // pci_config_readl +#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0 #include "string.h" // memset16_far #include "util.h" // find_cb_table #include "vgabios.h" // SET_VGA @@ -310,3 +313,57 @@ cbvga_setup(void) cbvga_setup_modes(addr, bpp, xlines, ylines, linelength); return 0; } + +/* ------------------------------------------------------------------ */ + +#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) + +int +bochs_display_setup(void) +{ + dprintf(1, "bochs-display: setup called\n"); + + if (GET_GLOBAL(HaveRunInit)) + return 0; + + int bdf = GET_GLOBAL(VgaBDF); + if (bdf == 0) + return 0; + + u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0); + u32 lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK; + bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_2); + u32 io_addr = bar & PCI_BASE_ADDRESS_IO_MASK; + dprintf(1, "bochs-display: bdf %02x:%02x.%x, bar 0 at 0x%x, bar 1 at 0x%x\n" + , pci_bdf_to_bus(bdf) , pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf), + lfb_addr, io_addr); + + u16 *dispi = (void*)(io_addr + 0x500); + u8 *vga = (void*)(io_addr + 0x400); + u16 id = readw(dispi + VBE_DISPI_INDEX_ID); + dprintf(1, "bochs-display: id is 0x%x, %s\n", id + , id == VBE_DISPI_ID5 ? "good" : "FAIL"); + if (id != VBE_DISPI_ID5) + return 0; + + dprintf(1, "bochs-display: using %dx%d, %d bpp (%d stride)\n" + , FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT + , FRAMEBUFFER_BPP * 8, FRAMEBUFFER_STRIDE); + + cbvga_setup_modes(lfb_addr, FRAMEBUFFER_BPP * 8, + FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, + FRAMEBUFFER_STRIDE); + + writew(dispi + VBE_DISPI_INDEX_XRES, FRAMEBUFFER_WIDTH); + writew(dispi + VBE_DISPI_INDEX_YRES, FRAMEBUFFER_HEIGHT); + writew(dispi + VBE_DISPI_INDEX_BPP, FRAMEBUFFER_BPP * 8); + writew(dispi + VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED); + + writeb(vga, 0x20); /* unblank (for qemu -device VGA) */ + + return 0; +} diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig index f5098a4bdd..4443c0b37a 100644 --- a/vgasrc/Kconfig +++ b/vgasrc/Kconfig @@ -55,6 +55,21 @@ menu "VGA ROM" Build support for a vgabios wrapper around video devices initialized using coreboot native vga init.
+ config DISPLAY_BOCHS + depends on QEMU + bool "qemu bochs-display support" + select VGA_EMULATE_TEXT + help + Build support for the qemu bochs-display device, which + is basically qemu stdvga without the legacy vga + emulation, supporting only 16+32 bpp VESA video modes + in a linear framebuffer. So this uses cbvga text mode + emulation. + + The bochs-display device is available in qemu + v3.0+. The vgabios works with the qemu stdvga too (use + "qemu -device VGA,romfile=/path/to/vgabios.bin")". + endchoice
choice @@ -166,6 +181,7 @@ menu "VGA ROM" default 0x1af4 if VGA_BOCHS_VIRTIO default 0x100b if VGA_GEODEGX2 default 0x1022 if VGA_GEODELX + default 0x1234 if DISPLAY_BOCHS default 0x0000 help Vendor ID for the PCI ROM @@ -181,6 +197,7 @@ menu "VGA ROM" default 0x1050 if VGA_BOCHS_VIRTIO default 0x0030 if VGA_GEODEGX2 default 0x2081 if VGA_GEODELX + default 0x1111 if DISPLAY_BOCHS default 0x0000 help Device ID for the PCI ROM
On Thu, May 31, 2018 at 08:33:50AM +0200, Gerd Hoffmann wrote:
Use coreboot text mode emulation to also support the qemu bochs-display device. This is a new display device supporting simple linear framebuffers, using the bochs register interface. No support for legacy vga (text modes, planar modes, cga modes, 8bpp palette modes all dropped). The bochs interface is compatible with the qemu stdvga.
Thanks.
Is "display bochs" the official name for this device? I find the name a little confusing because it is both similar to regular "bochs" and similar to the "dispi" interface in the regular bochs driver. If the name isn't fixed, how about "bochs-lite" or "qemu-fb".
[...]
--- a/vgasrc/cbvga.c +++ b/vgasrc/cbvga.c @@ -8,6 +8,9 @@ #include "biosvar.h" // GET_BDA #include "output.h" // dprintf #include "stdvga.h" // SEG_CTEXT +#include "bochsvga.h" // VBE_BOCHS_* +#include "hw/pci.h" // pci_config_readl +#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0 #include "string.h" // memset16_far #include "util.h" // find_cb_table #include "vgabios.h" // SET_VGA @@ -310,3 +313,57 @@ cbvga_setup(void) cbvga_setup_modes(addr, bpp, xlines, ylines, linelength); return 0; }
+/* ------------------------------------------------------------------ */
+#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)
+int +bochs_display_setup(void) +{
- dprintf(1, "bochs-display: setup called\n");
Instead of adding this to cbvga.c could we add it to a new file? (It and cbvga.c could still be linked together into the final vgabios binary.)
-Kevin
On Thu, May 31, 2018 at 10:44:55AM -0400, Kevin O'Connor wrote:
On Thu, May 31, 2018 at 08:33:50AM +0200, Gerd Hoffmann wrote:
Use coreboot text mode emulation to also support the qemu bochs-display device. This is a new display device supporting simple linear framebuffers, using the bochs register interface. No support for legacy vga (text modes, planar modes, cga modes, 8bpp palette modes all dropped). The bochs interface is compatible with the qemu stdvga.
Thanks.
Is "display bochs" the official name for this device?
It is "qemu -device bochs-display".
I find the name a little confusing because it is both similar to regular "bochs" and similar to the "dispi" interface in the regular bochs driver.
Well, it actually is related. In qemu 1.3 stdvga got a 32bit mmio bar, and both vga and bochs dispi registers can be accessed using that bar[1], in addition to the classic vga and bochs dispi io ports.
bochs-display has that mmio bar too, and it is the only way to program the device. Only the bochs dispi registers are available though as the vga emulation is excluded.
+int +bochs_display_setup(void) +{
- dprintf(1, "bochs-display: setup called\n");
Instead of adding this to cbvga.c could we add it to a new file? (It and cbvga.c could still be linked together into the final vgabios binary.)
Sure.
cheers, Gerd
[1] details: https://git.qemu.org/?p=qemu.git;a=blob;f=docs/specs/standard-vga.txt;hb=HEA...
On Thu, May 31, 2018 at 08:33:50AM +0200, Gerd Hoffmann wrote: [...]
dprintf(1, "bochs-display: using %dx%d, %d bpp (%d stride)\n"
, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT
, FRAMEBUFFER_BPP * 8, FRAMEBUFFER_STRIDE);
- cbvga_setup_modes(lfb_addr, FRAMEBUFFER_BPP * 8,
FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
FRAMEBUFFER_STRIDE);
- writew(dispi + VBE_DISPI_INDEX_XRES, FRAMEBUFFER_WIDTH);
- writew(dispi + VBE_DISPI_INDEX_YRES, FRAMEBUFFER_HEIGHT);
- writew(dispi + VBE_DISPI_INDEX_BPP, FRAMEBUFFER_BPP * 8);
- writew(dispi + VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
- writeb(vga, 0x20); /* unblank (for qemu -device VGA) */
An additional question - if the mode can be changed why do we only change it on startup? Is the idea that the OS will have a driver installed that directly changes modes once the OS starts up?
-Kevin
On Thu, May 31, 2018 at 11:12:14AM -0400, Kevin O'Connor wrote:
On Thu, May 31, 2018 at 08:33:50AM +0200, Gerd Hoffmann wrote: [...]
dprintf(1, "bochs-display: using %dx%d, %d bpp (%d stride)\n"
, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT
, FRAMEBUFFER_BPP * 8, FRAMEBUFFER_STRIDE);
- cbvga_setup_modes(lfb_addr, FRAMEBUFFER_BPP * 8,
FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
FRAMEBUFFER_STRIDE);
- writew(dispi + VBE_DISPI_INDEX_XRES, FRAMEBUFFER_WIDTH);
- writew(dispi + VBE_DISPI_INDEX_YRES, FRAMEBUFFER_HEIGHT);
- writew(dispi + VBE_DISPI_INDEX_BPP, FRAMEBUFFER_BPP * 8);
- writew(dispi + VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
- writeb(vga, 0x20); /* unblank (for qemu -device VGA) */
An additional question - if the mode can be changed why do we only change it on startup? Is the idea that the OS will have a driver installed that directly changes modes once the OS starts up?
Yes. On linux bochs-drm.ko can handle the device.
Also modesetting isn't that easily in real mode due to the registers being in a 32bit mmio bar. setup() is fine due to running in big real mode.
cheers, Gerd
In case the framebuffer size matches one of the cbvga video modes just use that mode number instead of 0x140.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/cbvga.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c index 672daa604c..2139a00904 100644 --- a/vgasrc/cbvga.c +++ b/vgasrc/cbvga.c @@ -263,6 +263,11 @@ cbvga_setup_modes(u64 addr, u8 bpp, u32 xlines, u32 ylines, u32 linelength) dprintf(3, "Removing mode %x\n", GET_GLOBAL(cbmode_g->mode)); SET_VGA(cbmode_g->mode, 0xffff); } + if ((GET_GLOBAL(cbmode_g->info.height) == ylines) + && (GET_GLOBAL(cbmode_g->info.width) == xlines) + && (GET_GLOBAL(cbmode_g->info.depth) == bpp)) { + SET_VGA(CBmode, GET_GLOBAL(cbmode_g->mode)); + } } }
In case we've already added the framebuffer video mode to the list do not add number 0x140.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/cbvga.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c index 2139a00904..13a666b22b 100644 --- a/vgasrc/cbvga.c +++ b/vgasrc/cbvga.c @@ -107,6 +107,8 @@ struct vgamode_s *cbvga_find_mode(int mode) void cbvga_list_modes(u16 seg, u16 *dest, u16 *last) { + int seen = 0; + if (GET_GLOBAL(CBmode) != 0x3) { /* Advertise additional SVGA modes for Microsoft NTLDR graphical mode. * Microsoft NTLDR: @@ -122,9 +124,11 @@ cbvga_list_modes(u16 seg, u16 *dest, u16 *last) continue; SET_FARVAR(seg, *dest, mode); dest++; + if (GET_GLOBAL(CBmode) == mode) + seen = 1; } } - if (dest < last) { + if (dest < last && !seen) { SET_FARVAR(seg, *dest, GET_GLOBAL(CBmode)); dest++; }
Break windows, memcpy_high call is problematic. Possibly the windows x86 emulator doesn't support int 1587.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/cbvga.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c index 13a666b22b..6933fc72aa 100644 --- a/vgasrc/cbvga.c +++ b/vgasrc/cbvga.c @@ -196,6 +196,7 @@ cbvga_set_mode(struct vgamode_s *vmode_g, int flags) { u8 emul = vmode_g == &CBemulinfo || GET_GLOBAL(CBmode) == 0x03; MASK_BDA_EXT(flags, BF_EMULATE_TEXT, emul ? BF_EMULATE_TEXT : 0); +#if 0 if (!(flags & MF_NOCLEARMEM)) { if (GET_GLOBAL(CBmodeinfo.memmodel) == MM_TEXT) { memset16_far(SEG_CTEXT, (void*)0, 0x0720, 80*25*2); @@ -209,6 +210,7 @@ cbvga_set_mode(struct vgamode_s *vmode_g, int flags) op.op = GO_MEMSET; handle_gfx_op(&op); } +#endif return 0; }
On Thu, May 31, 2018 at 08:33:53AM +0200, Gerd Hoffmann wrote:
Break windows, memcpy_high call is problematic. Possibly the windows x86 emulator doesn't support int 1587.
Interesting. I think Patrick ran into this as well.
Are there any runtime checks we could do to avoid this? Perhaps do something like the existing BF_EXTRA_STACK check (eg, if we get a vesa mode call then we disable 1587 on subsequent calls).
-Kevin
On Thu, May 31, 2018 at 10:54:39AM -0400, Kevin O'Connor wrote:
On Thu, May 31, 2018 at 08:33:53AM +0200, Gerd Hoffmann wrote:
Break windows, memcpy_high call is problematic. Possibly the windows x86 emulator doesn't support int 1587.
Interesting. I think Patrick ran into this as well.
Are there any runtime checks we could do to avoid this?
Not investigated yet, happy for now I found the cause windows not booting ...
Perhaps do something like the existing BF_EXTRA_STACK check (eg, if we get a vesa mode call then we disable 1587 on subsequent calls).
Can try whenever the BF_EXTRA_STACK check can be used for this too.
cheers, Gerd
Hi,
Perhaps do something like the existing BF_EXTRA_STACK check (eg, if we get a vesa mode call then we disable 1587 on subsequent calls).
Can try whenever the BF_EXTRA_STACK check can be used for this too.
Yes, works (i.e. clear screen only in case BF_EXTRA_STACK is set).
cheers, Gerd