Hi,
This adds runtime hardware detection to vgabios. Survived light (vga text mode) testing. The isa bits are completely untested as qemu -M isapc is foobar atm.
Comments on the approach?
cheers, Gerd
Gerd Hoffmann (4): vga: move code to vgahw.c vga: add pci hardware detection vga: add isa hardware detection vga: adapt kconfig
Makefile | 2 +- vgasrc/Kconfig | 61 ++++++++++++--------------- vgasrc/bochsvga.c | 7 +++ vgasrc/bochsvga.h | 1 + vgasrc/clext.c | 6 +++ vgasrc/clext.h | 1 + vgasrc/vgahw.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/vgahw.h | 52 +++++++++-------------- 8 files changed, 184 insertions(+), 66 deletions(-) create mode 100644 vgasrc/vgahw.c
Create vgahw.c, move code from vgahw.h there, soon we will add more bits there which will make inlining less useful.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- Makefile | 2 +- vgasrc/vgahw.c | 37 +++++++++++++++++++++++++++++++++++++ vgasrc/vgahw.h | 38 ++++---------------------------------- 3 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 vgasrc/vgahw.c
diff --git a/Makefile b/Makefile index 0343ce5..1dcfaeb 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,7 @@ $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py SRCVGA=src/output.c src/util.c src/pci.c \ vgasrc/vgabios.c vgasrc/vgafb.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 + vgasrc/vgahw.c vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c
CFLAGS16VGA = $(CFLAGS16INC) -g -Isrc
diff --git a/vgasrc/vgahw.c b/vgasrc/vgahw.c new file mode 100644 index 0000000..0ef3af5 --- /dev/null +++ b/vgasrc/vgahw.c @@ -0,0 +1,37 @@ +#include "vgahw.h" + +struct vgamode_s *vgahw_find_mode(int mode) { + if (CONFIG_VGA_CIRRUS) + return clext_find_mode(mode); + if (CONFIG_VGA_BOCHS) + return bochsvga_find_mode(mode); + return stdvga_find_mode(mode); +} + +int vgahw_set_mode(int mode, int flags) { + if (CONFIG_VGA_CIRRUS) + return clext_set_mode(mode, flags); + if (CONFIG_VGA_BOCHS) + return bochsvga_set_mode(mode, flags); + return stdvga_set_mode(mode, flags); +} + +void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) { + if (CONFIG_VGA_CIRRUS) + clext_list_modes(seg, dest, last); + else if (CONFIG_VGA_BOCHS) + bochsvga_list_modes(seg, dest, last); + else + stdvga_list_modes(seg, dest, last); +} + +int vgahw_init(void) { + if (CONFIG_VGA_CIRRUS) + return clext_init(); + if (CONFIG_VGA_BOCHS) + return bochsvga_init(); + if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX) + return geodevga_init(); + return stdvga_init(); +} + diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h index 1101e51..34de00d 100644 --- a/vgasrc/vgahw.h +++ b/vgasrc/vgahw.h @@ -9,39 +9,9 @@ #include "stdvga.h" // stdvga_set_mode #include "geodevga.h" // geodevga_init
-static inline struct vgamode_s *vgahw_find_mode(int mode) { - if (CONFIG_VGA_CIRRUS) - return clext_find_mode(mode); - if (CONFIG_VGA_BOCHS) - return bochsvga_find_mode(mode); - return stdvga_find_mode(mode); -} - -static inline int vgahw_set_mode(int mode, int flags) { - if (CONFIG_VGA_CIRRUS) - return clext_set_mode(mode, flags); - if (CONFIG_VGA_BOCHS) - return bochsvga_set_mode(mode, flags); - return stdvga_set_mode(mode, flags); -} - -static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) { - if (CONFIG_VGA_CIRRUS) - clext_list_modes(seg, dest, last); - else if (CONFIG_VGA_BOCHS) - bochsvga_list_modes(seg, dest, last); - else - stdvga_list_modes(seg, dest, last); -} - -static inline int vgahw_init(void) { - if (CONFIG_VGA_CIRRUS) - return clext_init(); - if (CONFIG_VGA_BOCHS) - return bochsvga_init(); - if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX) - return geodevga_init(); - return stdvga_init(); -} +struct vgamode_s *vgahw_find_mode(int mode); +int vgahw_set_mode(int mode, int flags); +void vgahw_list_modes(u16 seg, u16 *dest, u16 *last); +int vgahw_init(void);
#endif // vgahw.h
Add support for pci hardware detection (using pci id lookup), so we can create a unified rom with support for different pieces of hardware.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/vgahw.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++------ vgasrc/vgahw.h | 20 +++++++++++++ 2 files changed, 95 insertions(+), 10 deletions(-)
diff --git a/vgasrc/vgahw.c b/vgasrc/vgahw.c index 0ef3af5..7620d59 100644 --- a/vgasrc/vgahw.c +++ b/vgasrc/vgahw.c @@ -1,37 +1,102 @@ #include "vgahw.h" +#include "config.h" // CONFIG_* +#include "util.h" // dprintf +#include "biosvar.h" // GET_GLOBAL +#include "pci.h" // pci_config_readw +#include "pci_regs.h" // PCI_VENDOR_ID + +struct vga_pci_table { + u16 vid; + u16 did; + char *name; + enum vga_type type; + int supported; +}; + +static struct vga_pci_table hwtab[] VAR16 = { + { + .vid = 0x1013, + .did = 0x00b8, + .name = "QEMU Cirrus VGA (CLGD 54xx)", + .type = VGA_TYPE_CIRRUS, + .supported = CONFIG_VGA_CIRRUS, + },{ + .vid = 0x1234, + .did = 0x1111, + .name = "QEMU Standard VGA", + .type = VGA_TYPE_BOCHS, + .supported = CONFIG_VGA_BOCHS, + },{ + .vid = 0x100b, + .did = 0x0030, + .name = "Geode GX2", + .type = VGA_TYPE_GEODEGX2, + .supported = CONFIG_VGA_GEODEGX2, + },{ + .vid = 0x1022, + .did = 0x2081, + .name = "Geode LX", + .type = VGA_TYPE_GEODELX, + .supported = CONFIG_VGA_GEODELX, + } +}; + +enum vga_type vga_type VAR16;
struct vgamode_s *vgahw_find_mode(int mode) { - if (CONFIG_VGA_CIRRUS) + if (HAVE_VGA_CIRRUS) return clext_find_mode(mode); - if (CONFIG_VGA_BOCHS) + if (HAVE_VGA_BOCHS) return bochsvga_find_mode(mode); return stdvga_find_mode(mode); }
int vgahw_set_mode(int mode, int flags) { - if (CONFIG_VGA_CIRRUS) + if (HAVE_VGA_CIRRUS) return clext_set_mode(mode, flags); - if (CONFIG_VGA_BOCHS) + if (HAVE_VGA_BOCHS) return bochsvga_set_mode(mode, flags); return stdvga_set_mode(mode, flags); }
void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) { - if (CONFIG_VGA_CIRRUS) + if (HAVE_VGA_CIRRUS) clext_list_modes(seg, dest, last); - else if (CONFIG_VGA_BOCHS) + else if (HAVE_VGA_BOCHS) bochsvga_list_modes(seg, dest, last); else stdvga_list_modes(seg, dest, last); }
int vgahw_init(void) { - if (CONFIG_VGA_CIRRUS) + if (CONFIG_VGA_PCI) { + u16 bdf = GET_GLOBAL(VgaBDF); + u16 vid = pci_config_readw(bdf, PCI_VENDOR_ID); + u16 did = pci_config_readw(bdf, PCI_DEVICE_ID); + int i; + + for (i = 0; i < ARRAY_SIZE(hwtab); i++) { + if (GET_GLOBAL(hwtab[i].vid) == vid && + GET_GLOBAL(hwtab[i].did) == did) { + dprintf(1, "vgahw: detected %s [pci %04x:%04x]\n", + GET_GLOBAL(hwtab[i].name), vid, did); + if (GET_GLOBAL(hwtab[i].supported)) { + SET_VGA(vga_type, GET_GLOBAL(hwtab[i].type)); + } else { + SET_VGA(vga_type, VGA_TYPE_STDVGA); + dprintf(1, "vgahw: support not compiled, using stdvga\n"); + } + break; + } + } + } else { + } + + if (HAVE_VGA_CIRRUS) return clext_init(); - if (CONFIG_VGA_BOCHS) + if (HAVE_VGA_BOCHS) return bochsvga_init(); - if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX) + if (HAVE_VGA_GEODEGX2 || HAVE_VGA_GEODELX) return geodevga_init(); return stdvga_init(); } - diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h index 34de00d..82caaea 100644 --- a/vgasrc/vgahw.h +++ b/vgasrc/vgahw.h @@ -9,6 +9,26 @@ #include "stdvga.h" // stdvga_set_mode #include "geodevga.h" // geodevga_init
+enum vga_type { + VGA_TYPE_UNDEFINED = 0, + VGA_TYPE_STDVGA, + VGA_TYPE_CIRRUS, + VGA_TYPE_BOCHS, + VGA_TYPE_GEODEGX2, + VGA_TYPE_GEODELX, +}; + +extern enum vga_type vga_type; + +#define HAVE_VGA_CIRRUS (CONFIG_VGA_CIRRUS && \ + (GET_GLOBAL(vga_type) == VGA_TYPE_CIRRUS)) +#define HAVE_VGA_BOCHS (CONFIG_VGA_BOCHS && \ + (GET_GLOBAL(vga_type) == VGA_TYPE_BOCHS)) +#define HAVE_VGA_GEODEGX2 (CONFIG_VGA_GEODEGX2 && \ + (GET_GLOBAL(vga_type) == VGA_TYPE_GEODEGX2)) +#define HAVE_VGA_GEODELX (CONFIG_VGA_GEODELX && \ + (GET_GLOBAL(vga_type) == VGA_TYPE_GEODELX)) + struct vgamode_s *vgahw_find_mode(int mode); int vgahw_set_mode(int mode, int flags); void vgahw_list_modes(u16 seg, u16 *dest, u16 *last);
Try to find isa vga cards in case pci probe found nothing.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- vgasrc/bochsvga.c | 7 +++++++ vgasrc/bochsvga.h | 1 + vgasrc/clext.c | 6 ++++++ vgasrc/clext.h | 1 + vgasrc/vgahw.c | 20 +++++++++++++++++++- 5 files changed, 34 insertions(+), 1 deletions(-)
diff --git a/vgasrc/bochsvga.c b/vgasrc/bochsvga.c index 82629b9..107bb70 100644 --- a/vgasrc/bochsvga.c +++ b/vgasrc/bochsvga.c @@ -140,6 +140,13 @@ bochsvga_init(void) return 0; }
+int +bochsvga_isa_probe(void) +{ + dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID0); + return dispi_read(VBE_DISPI_INDEX_ID) == VBE_DISPI_ID0; +} + static int mode_valid(struct vgamode_s *vmode_g) { u16 max_xres = dispi_get_max_xres(); diff --git a/vgasrc/bochsvga.h b/vgasrc/bochsvga.h index 81fb8f7..cf358b4 100644 --- a/vgasrc/bochsvga.h +++ b/vgasrc/bochsvga.h @@ -53,6 +53,7 @@ static inline void dispi_write(u16 reg, u16 val) }
int bochsvga_init(void); +int bochsvga_isa_probe(void); void bochsvga_list_modes(u16 seg, u16 *dest, u16 *last); struct vgamode_s *bochsvga_find_mode(int mode); int bochsvga_set_mode(int mode, int flags); diff --git a/vgasrc/clext.c b/vgasrc/clext.c index f08294a..e74e8c5 100644 --- a/vgasrc/clext.c +++ b/vgasrc/clext.c @@ -755,3 +755,9 @@ clext_init(void)
return 0; } + +int +clext_isa_probe(void) +{ + return cirrus_check(); +} diff --git a/vgasrc/clext.h b/vgasrc/clext.h index a14cf13..3b03298 100644 --- a/vgasrc/clext.h +++ b/vgasrc/clext.h @@ -7,6 +7,7 @@ struct vgamode_s *clext_find_mode(int mode); int clext_set_mode(int mode, int flags); void clext_list_modes(u16 seg, u16 *dest, u16 *last); int clext_init(void); +int clext_isa_probe(void); struct bregs; void clext_1012(struct bregs *regs);
diff --git a/vgasrc/vgahw.c b/vgasrc/vgahw.c index 7620d59..31d53bb 100644 --- a/vgasrc/vgahw.c +++ b/vgasrc/vgahw.c @@ -89,7 +89,25 @@ int vgahw_init(void) { break; } } - } else { + } + + if (GET_GLOBAL(vga_type) == VGA_TYPE_UNDEFINED) { + if (CONFIG_VGA_CIRRUS) { + if (clext_isa_probe()) { + SET_VGA(vga_type, VGA_TYPE_CIRRUS); + dprintf(1, "vgahw: detected Cirrus VGA [isa]\n"); + } + } else if (CONFIG_VGA_BOCHS) { + if (bochsvga_isa_probe()) { + SET_VGA(vga_type, VGA_TYPE_BOCHS); + dprintf(1, "vgahw: detected bochs svga [isa]\n"); + } + } + } + + if (GET_GLOBAL(vga_type) == VGA_TYPE_UNDEFINED) { + SET_VGA(vga_type, VGA_TYPE_STDVGA); + dprintf(1, "vgahw: no hw found, using stdvga\n"); }
if (HAVE_VGA_CIRRUS)
With support for multiple vga hardware types being selectable it isn't a choice any more. --- vgasrc/Kconfig | 61 ++++++++++++++++++++++++------------------------------- 1 files changed, 27 insertions(+), 34 deletions(-)
diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig index 881e9ec..fc7fec4 100644 --- a/vgasrc/Kconfig +++ b/vgasrc/Kconfig @@ -1,44 +1,37 @@ # Kconfig SeaBIOS VGA BIOS configuration
menu "VGA ROM" - choice - prompt "VGA Hardware Type" - default NO_VGABIOS - - config NO_VGABIOS - bool "None" - help - Do not build a VGA BIOS. - - config VGA_STANDARD_VGA - bool "Standard VGA" - help - Build basic VGA BIOS support. - - config VGA_CIRRUS - bool "QEMU Cirrus CLGD 54xx VGA BIOS" - help - Build support for Cirrus VGA emulation. + config BUILD_VGABIOS + bool "Build vgabios" + default !COREBOOT
- config VGA_BOCHS - bool "Bochs DISPI interface VGA BIOS" - help - Build support for Bochs DISPI interface. + config VGA_CIRRUS + bool "QEMU Cirrus CLGD 54xx support" + depends on BUILD_VGABIOS + default !COREBOOT + help + Build support for Cirrus VGA emulation.
- config VGA_GEODEGX2 - bool "GeodeGX2 interface VGA BIOS" - help - Build support for Geode GX2 vga. + config VGA_BOCHS + bool "Bochs DISPI interface support" + depends on BUILD_VGABIOS + default !COREBOOT + help + Build support for Bochs DISPI interface.
- config VGA_GEODELX - bool "GeodeLX interface VGA BIOS" - help - Build support for Geode LX vga. - endchoice + config VGA_GEODEGX2 + bool "GeodeGX2 interface support" + depends on BUILD_VGABIOS + default n + help + Build support for Geode GX2 vga.
- config BUILD_VGABIOS - bool - default !NO_VGABIOS + config VGA_GEODELX + bool "GeodeLX interface support" + depends on BUILD_VGABIOS + default n + help + Build support for Geode LX vga.
config VGA_VBE depends on BUILD_VGABIOS
On Tue, Jan 24, 2012 at 03:46:04PM +0100, Gerd Hoffmann wrote:
Hi,
This adds runtime hardware detection to vgabios. Survived light (vga text mode) testing. The isa bits are completely untested as qemu -M isapc is foobar atm.
Comments on the approach?
It's an interesting question - is it better to compile a vgabios for a specific hardware or to make a vgabios compatible with several different pieces of hardware. I don't know what the right answer is.
There's some simplicity for qemu/kvm in that only one blob is needed. BTW, the PCI spec does allow (with some magic to the pci struct) for multiple roms to be concatenated together to obtain a single blob for different hardware.
I have some changes in my repo pending for vgahw.h (to support the remaining cirrus vbe calls). I'd want to get those pushed before changing the way vgahw.h works.
Also, function pointers are available in 16bit mode - so something to consider in an auto-detection scheme.
-Kevin
On Wed, Jan 25, 2012 at 08:48:02PM -0500, Kevin O'Connor wrote:
Also, function pointers are available in 16bit mode - so something to consider in an auto-detection scheme.
Thinking on that further, though, should we end up supporting the 32bit VBE calls, then function pointers would likely get confusing.
-Kevin
On 01/26/12 02:58, Kevin O'Connor wrote:
Thinking on that further, though, should we end up supporting the 32bit VBE calls, then function pointers would likely get confusing.
I think we can get away with *not* supporting them.
First, the lgpl vgabios supports them only for the bochs dispi interface, not for cirrus (which is the default gfx card in qemu).
Second, the panning (i.e. set display start offsets via VBE_DISPI_INDEX_{X,Y}_OFFSET) is broken since commit 7d957bd8cbcbf56f7916d375e65042d767f544b5 and nobody noticed for three years.
Third, linux doesn't use the 32bit calls by default because there are broken bios implementations in the wild.
I don't think anyone will miss them ...
cheers, Gerd
Hi,
It's an interesting question - is it better to compile a vgabios for a specific hardware or to make a vgabios compatible with several different pieces of hardware. I don't know what the right answer is.
Alot of stuff seems to be shared, the size doesn't go up much:
-rw-rw-r--. 1 kraxel kraxel 35328 Jan 26 10:50 vgabios-bochs.bin -rw-rw-r--. 1 kraxel kraxel 36352 Jan 26 10:50 vgabios-cirrus.bin -rw-rw-r--. 1 kraxel kraxel 38400 Jan 26 10:50 vgabios-both.bin
There's some simplicity for qemu/kvm in that only one blob is needed. BTW, the PCI spec does allow (with some magic to the pci struct) for multiple roms to be concatenated together to obtain a single blob for different hardware.
That are multiple, independant roms which are chained together I guess? So the seabios could walk the list, then grab the one which matches the pci id of the device?
I have some changes in my repo pending for vgahw.h (to support the remaining cirrus vbe calls). I'd want to get those pushed before changing the way vgahw.h works.
Sure.
cheers, Gerd