This patch set contain ground work for a working VBE implementation.
It adds several things: * A configuration menu in seabios Kconfig * The ability to generate a PCI ROM * PMM facilities that the ROM can use to allocate memory * A skeleton driver to implement the VBE interface
As a bonus, it fixes an issue when real-mode VGA ROM code is emulated by Windows 7, and is unable to cope with code generated with the -fomit-frame-pointer option.
It should make pretty easy to implement the BOCHS DISPI interface.
Also, I use these patchs to implement VBE for an experimental gfx device emulation. So far I managed to get Windows 7 to boot and show up a 1280x1024 desktop.
Julian Pidancet (7): Only use -fomit-frame-pointer with 32bit flat code Rename CONFIG_VBE in CONFIG_VGA_BOCHS and CONFIG_CIRRUS in CONFIG_VGA_CIRRUS Add configuration menu for the VGA ROM buildrom.py: Handle PCI header checksum Add PMM memory allocation facilities for VGA option ROMs Partially implement VBE interface, create VBE driver skeleton Add vbe_flag field in BDA
Makefile | 7 +- src/Kconfig | 35 +++++++ src/biosvar.h | 3 +- tools/buildrom.py | 5 + vgasrc/pmm.c | 50 +++++++++ vgasrc/pmm.h | 16 +++ vgasrc/vbe.c | 135 ++++++++++++++++++++++++ vgasrc/vbe.h | 194 +++++++++++++++++++++++++++++++++++ vgasrc/vga.c | 290 ++++++++++++++++++++++++++++++++++++++++++++-------- vgasrc/vgaentry.S | 47 ++++++++- vgasrc/vgatables.h | 6 - 11 files changed, 731 insertions(+), 57 deletions(-) create mode 100644 vgasrc/pmm.c create mode 100644 vgasrc/pmm.h create mode 100644 vgasrc/vbe.c create mode 100644 vgasrc/vbe.h
The real-mode emulator that Windows 7 uses to execute the vga bios rom becomes very confused when the code tries to dereference the stack pointer instead of using the frame pointer, leading to corruption of parameters passed on the stack from one function to another.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile index c3ba2f3..cb00958 100644 --- a/Makefile +++ b/Makefile @@ -32,14 +32,14 @@ COMMONCFLAGS = -I$(OUT) -Os -MD \ $(call cc-option,$(CC),-Wtype-limits,) \ -m32 -march=i386 -mregparm=3 -mpreferred-stack-boundary=2 \ -mrtd -minline-all-stringops \ - -freg-struct-return -ffreestanding -fomit-frame-pointer \ + -freg-struct-return -ffreestanding \ -fno-delete-null-pointer-checks \ -ffunction-sections -fdata-sections -fno-common COMMONCFLAGS += $(call cc-option,$(CC),-nopie,) COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
-CFLAGS32FLAT = $(COMMONCFLAGS) -g -DMODE16=0 -DMODESEGMENT=0 +CFLAGS32FLAT = $(COMMONCFLAGS) -fomit-frame-pointer -g -DMODE16=0 -DMODESEGMENT=0 CFLAGSSEG = $(COMMONCFLAGS) -DMODESEGMENT=1 -fno-defer-pop \ $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \ $(call cc-option,$(CC),-fno-tree-switch-conversion,)
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- vgasrc/vga.c | 18 +++++++++--------- vgasrc/vgatables.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/vgasrc/vga.c b/vgasrc/vga.c index d734e23..b515d1d 100644 --- a/vgasrc/vga.c +++ b/vgasrc/vga.c @@ -17,8 +17,8 @@ #include "vgatables.h" // find_vga_entry
// XXX -#define CONFIG_VBE 0 -#define CONFIG_CIRRUS 0 +#define CONFIG_VGA_BOCHS 0 +#define CONFIG_VGA_CIRRUS 0
// XXX #define DEBUG_VGA_POST 1 @@ -359,11 +359,11 @@ handle_1000(struct bregs *regs) else regs->al = 0x30;
- if (CONFIG_CIRRUS) + if (CONFIG_VGA_CIRRUS) cirrus_set_video_mode(mode);
- if (CONFIG_VBE) - if (vbe_has_vbe_display()) + if (CONFIG_VGA_BOCHS) + if (bochs_has_vbe_display()) dispi_set_enable(VBE_DISPI_DISABLED);
// find the entry in the video modes @@ -1263,7 +1263,7 @@ handle_104fXX(struct bregs *regs) static void handle_104f(struct bregs *regs) { - if (! CONFIG_VBE || !vbe_has_vbe_display()) { + if (! CONFIG_VGA_BOCHS || !bochs_has_vbe_display()) { handle_104fXX(regs); return; } @@ -1364,13 +1364,13 @@ vga_post(struct bregs *regs)
init_bios_area();
- if (CONFIG_VBE) - vbe_init(); + if (CONFIG_VGA_BOCHS) + bochs_init();
extern void entry_10(void); SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
- if (CONFIG_CIRRUS) + if (CONFIG_VGA_CIRRUS) cirrus_init();
// XXX - clear screen and display info diff --git a/vgasrc/vgatables.h b/vgasrc/vgatables.h index 1e76b3a..1f877c5 100644 --- a/vgasrc/vgatables.h +++ b/vgasrc/vgatables.h @@ -211,7 +211,7 @@ void cirrus_init(void); // vbe.c -- not implemented yet. #define VBE_DISPI_DISABLED 0x00 void dispi_set_enable(int enable); -void vbe_init(void); -int vbe_has_vbe_display(void); +void bochs_init(void); +int bochs_has_vbe_display(void);
#endif // vgatables.h
This patch adds a configuration menu for the VGA ROM, it also allow the creation of a PCI header so the ROM can be extracted from a PCI device.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- src/Kconfig | 35 +++++++++++++++++++++++++++++++++++ vgasrc/vga.c | 4 ---- vgasrc/vgaentry.S | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 6 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig index f8d245a..a6e11da 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -324,6 +324,41 @@ menu "BIOS Tables" Support generation of ACPI tables. endmenu
+menu "VGA ROM" + config VGA_CIRRUS + bool "QEMU Cirrus CLGD 54xx VGA BIOS" + default n + help + Build support for Cirrus VGA emulation. + + config VGA_BOCHS + bool "Bochs DISPI interface VGA BIOS" + default n + help + Build support for Bochs DISPI interface + + config VGA_PCI + bool "PCI ROM Headers" + default y + help + Build PCI ROM headers so the vga rom can be extracted from + a PCI device. + + config VGA_VID + depends on VGA_PCI + hex "Custom PCI Vendor ID" + default 0x0000 + help + Custom Vendor ID for the PCI ROM + + config VGA_DID + depends on VGA_PCI + hex "Custom PCI Device ID" + default 0x0000 + help + Custom Device ID for the PCI ROM +endmenu + menu "Debugging" config DEBUG_LEVEL int "Debug level" diff --git a/vgasrc/vga.c b/vgasrc/vga.c index b515d1d..b0d2598 100644 --- a/vgasrc/vga.c +++ b/vgasrc/vga.c @@ -17,10 +17,6 @@ #include "vgatables.h" // find_vga_entry
// XXX -#define CONFIG_VGA_BOCHS 0 -#define CONFIG_VGA_CIRRUS 0 - -// XXX #define DEBUG_VGA_POST 1 #define DEBUG_VGA_10 3
diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S index fbfa9f7..6471928 100644 --- a/vgasrc/vgaentry.S +++ b/vgasrc/vgaentry.S @@ -12,15 +12,21 @@ .code16gcc #include "vgaccode.16.s"
+#include "config.h" // CONFIG_* #include "entryfuncs.S" // ENTRY_*
+ /**************************************************************** * Rom Header ****************************************************************/
.section .rom.header .global _rom_header, _rom_header_size, _rom_header_checksum +#ifdef CONFIG_VGA_PCI + .global _rom_pci_data +#endif + _rom_header: .word 0xaa55 _rom_header_size: @@ -29,9 +35,46 @@ _rom_header_entry: jmp _optionrom_entry _rom_header_checksum: .byte 0 -_rom_header_other: - .space 21 +_rom_header_rsrvd: + .space 17 +_rom_header_pcidata: +#ifdef CONFIG_VGA_PCI + .word _rom_pci_data +#else + .word 0 +#endif +_rom_header_pnpdata: + .word 0
+/**************************************************************** + * PCI Data + ****************************************************************/ +#ifdef CONFIG_PCIBIOS +_rom_pci_data: + .ascii "PCIR" +#if defined(CONFIG_VGA_VID) && defined(CONFIG_VGA_DID) + .word CONFIG_VGA_VID /* VendorID */ + .word CONFIG_VGA_DID /* DeviceID */ +#elif defined(CONFIG_VGA_CIRRUS) + .word 0x1013 + .word 0x00b8 +#elif defined(CONFIG_VGA_BOCHS) + .word 0x1234 + .word 0x1111 +#else +#error "Uknown PCI vendor or device ID" +#endif + .word 0x0 /* Reserved */ + .word 0x18 /* dlen */ + .byte 0x0 /* Revision */ + .byte 0x0 /* Class lo */ + .word 0x300 /* Class hi */ + .word 0x0 /* ilen */ + .word 0x1 /* Revision */ + .byte 0 /* Type */ + .byte 0x80 /* Indicator */ + .word 0x0 /* Reserved */ +#endif
/**************************************************************** * Entry points
This patch makes buildrom.py check if a PCI is present in the ROM, and fills in the image size field.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- tools/buildrom.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/tools/buildrom.py b/tools/buildrom.py index 19b715a..7ed8107 100755 --- a/tools/buildrom.py +++ b/tools/buildrom.py @@ -28,6 +28,11 @@ def main(): data += "\0" * (alignpos(count, 512) - count) count = len(data)
+ # Check if a pci header is present + pcidata = ord(data[24:25]) + (ord(data[25:26]) << 8) + if pcidata != 0: + data = data[:pcidata + 16] + chr(count/512) + chr(0) + data[pcidata + 18:] + # Fill in size field; clear checksum field data = data[:2] + chr(count/512) + data[3:6] + "\0" + data[7:]
This patch implements a way for option ROMs to allocate some space using the bios PMM interface.
Since the VGA option ROM is placed in read only memory, the only way to get memory to store global variables is either use the EBDA, or use the PMM if the BIOS supports it.
This simple patchs adds only pmm_scan and pmm_allocate. The first one is used to scan the memory and find the PMM entry point, the second one is used to request the BIOS to allocate blocks of memory.
The pmm_find and pmm_deallocate functions are yet to be implemented.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- Makefile | 2 +- vgasrc/pmm.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/pmm.h | 16 ++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletions(-) create mode 100644 vgasrc/pmm.c create mode 100644 vgasrc/pmm.h
diff --git a/Makefile b/Makefile index cb00958..1b8ba60 100644 --- a/Makefile +++ b/Makefile @@ -171,7 +171,7 @@ $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
# VGA src files SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \ - vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c + vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c vgasrc/pmm.c
$(OUT)vgaccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@)
diff --git a/vgasrc/pmm.c b/vgasrc/pmm.c new file mode 100644 index 0000000..1732149 --- /dev/null +++ b/vgasrc/pmm.c @@ -0,0 +1,50 @@ +#include "biosvar.h" // GET_GLOBAL +#include "util.h" // memset + +#define PMM_SIGNATURE 0x4d4d5024 // $PMM + +struct pmmheader { + u32 signature; + u8 version; + u8 length; + u8 checksum; + u16 entry_offset; + u16 entry_seg; + u8 reserved[5]; +} PACKED; + +u32 pmm_allocate(u16 seg, u32 length, u32 handle, u16 flags) +{ + u16 ax, dx; + + asm volatile ("movw %2, %%es\n" + "pushw %3\n" + "pushl %4\n" + "pushl %5\n" + "pushw $0x0\n" /* PMM_ALLOCATE */ + "lcallw *%%es:7\n" + "addw $12, %%sp\n" + : "=a"(ax), "=d"(dx) + : "r"(seg), "r"(flags), "r"(handle), "r"(length) + : "cc", "memory"); + + return (dx << 16) | ax; +} + +u16 pmm_scan(void) +{ + u16 seg; + struct pmmheader *hdr = (struct pmmheader *)0; + + for (seg = 0xe000; seg; seg++) { + u32 val = GET_FARVAR(seg, hdr->signature); + + if (val == PMM_SIGNATURE && + !checksum_far(seg, hdr, GET_FARVAR(seg, hdr->length))) { + return seg; + } + } + + return 0; +} + diff --git a/vgasrc/pmm.h b/vgasrc/pmm.h new file mode 100644 index 0000000..f6479ad --- /dev/null +++ b/vgasrc/pmm.h @@ -0,0 +1,16 @@ +#include "biosvar.h" // GET_GLOBAL +#include "util.h" // memset + +#define PMM_MEMORY_TYPE_INVALID (0 << 0) +#define PMM_MEMORY_TYPE_CONVENTION (1 << 0) +#define PMM_MEMORY_TYPE_EXTENDED (2 << 0) + +#define PMM_BLOCK_NOT_ALIGNED (0 << 2) +#define PMM_BLOCK_ALIGNED (1 << 2) + +/* Only in PCI FW spec: */ +#define PMM_MEMORY_ATTR_TEMPORARY (0 << 3) +#define PMM_MEMORY_ATTR_PERMANENT (1 << 3) + +u32 pmm_allocate(u16 seg, u32 length, u32 handle, u16 flags); +u16 pmm_scan(void);
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- Makefile | 3 +- vgasrc/vbe.c | 135 +++++++++++++++++++++++++ vgasrc/vbe.h | 194 +++++++++++++++++++++++++++++++++++ vgasrc/vga.c | 284 ++++++++++++++++++++++++++++++++++++++++++++-------- vgasrc/vgatables.h | 6 - 5 files changed, 575 insertions(+), 47 deletions(-) create mode 100644 vgasrc/vbe.c create mode 100644 vgasrc/vbe.h
diff --git a/Makefile b/Makefile index 1b8ba60..e01f713 100644 --- a/Makefile +++ b/Makefile @@ -171,7 +171,8 @@ $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
# VGA src files SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \ - vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c vgasrc/pmm.c + vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c vgasrc/pmm.c \ + vgasrc/vbe.c
$(OUT)vgaccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@)
diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c new file mode 100644 index 0000000..faddc99 --- /dev/null +++ b/vgasrc/vbe.c @@ -0,0 +1,135 @@ +#include "vbe.h" + +const struct vbe_mode vbe_modes[] VAR16 = { + /* standard modes */ + { 0x100, 640, 400, 8 }, + { 0x101, 640, 480, 8 }, + { 0x102, 800, 600, 4 }, + { 0x103, 800, 600, 8 }, + { 0x104, 1024, 768, 4 }, + { 0x105, 1024, 768, 8 }, + { 0x106, 1280, 1024, 4 }, + { 0x107, 1280, 1024, 8 }, + { 0x10D, 320, 200, 15 }, + { 0x10E, 320, 200, 16 }, + { 0x10F, 320, 200, 24 }, + { 0x110, 640, 480, 15 }, + { 0x111, 640, 480, 16 }, + { 0x112, 640, 480, 24 }, + { 0x113, 800, 600, 15 }, + { 0x114, 800, 600, 16 }, + { 0x115, 800, 600, 24 }, + { 0x116, 1024, 768, 15 }, + { 0x117, 1024, 768, 16 }, + { 0x118, 1024, 768, 24 }, + { 0x119, 1280, 1024, 15 }, + { 0x11A, 1280, 1024, 16 }, + { 0x11B, 1280, 1024, 24 }, + { 0x11C, 1600, 1200, 8 }, + { 0x11D, 1600, 1200, 15 }, + { 0x11E, 1600, 1200, 16 }, + { 0x11F, 1600, 1200, 24 }, + /* BOCHS modes */ + { 0x140, 320, 200, 32 }, + { 0x141, 640, 400, 32 }, + { 0x142, 640, 480, 32 }, + { 0x143, 800, 600, 32 }, + { 0x144, 1024, 768, 32 }, + { 0x145, 1280, 1024, 32 }, + { 0x146, 320, 200, 8 }, + { 0x147, 1600, 1200, 32 }, + { 0x148, 1152, 864, 8 }, + { 0x149, 1152, 864, 15 }, + { 0x14a, 1152, 864, 16 }, + { 0x14b, 1152, 864, 24 }, + { 0x14c, 1152, 864, 32 }, + { 0x178, 1280, 800, 16 }, + { 0x179, 1280, 800, 24 }, + { 0x17a, 1280, 800, 32 }, + { 0x17b, 1280, 960, 16 }, + { 0x17c, 1280, 960, 24 }, + { 0x17d, 1280, 960, 32 }, + { 0x17e, 1440, 900, 16 }, + { 0x17f, 1440, 900, 24 }, + { 0x180, 1440, 900, 32 }, + { 0x181, 1400, 1050, 16 }, + { 0x182, 1400, 1050, 24 }, + { 0x183, 1400, 1050, 32 }, + { 0x184, 1680, 1050, 16 }, + { 0x185, 1680, 1050, 24 }, + { 0x186, 1680, 1050, 32 }, + { 0x187, 1920, 1200, 16 }, + { 0x188, 1920, 1200, 24 }, + { 0x189, 1920, 1200, 32 }, + { 0x18a, 2560, 1600, 16 }, + { 0x18b, 2560, 1600, 24 }, + { 0x18c, 2560, 1600, 32 }, + { 0, }, +}; + +/* Called only during POST */ +int +vbe_init(u8 bus, u8 devfn) +{ + return -1; +} + +int +vbe_enabled(void) +{ + return -1; +} + +u16 +vbe_total_mem(void) +{ + return 0; +} + +int +vbe_list_modes(u16 seg, u16 ptr) +{ + int count = 0; + u16 *dest = (u16 *)(u32)ptr; + + SET_FARVAR(seg, dest[count], 0xffff); /* End of list */ + + return count; +} + +int +vbe_mode_info(u16 mode, struct vbe_modeinfo *info) +{ + return -1; +} + +void +vbe_hires_enable(int enable) +{ + +} + +void +vbe_set_mode(u16 mode, struct vbe_modeinfo *info) +{ + +} + +void +vbe_clear_scr(void) +{ + +} + +int +vbe_hires_enabled(void) +{ + return 0; +} + +u16 +vbe_curr_mode(void) +{ + return 0; +} + diff --git a/vgasrc/vbe.h b/vgasrc/vbe.h new file mode 100644 index 0000000..24e7783 --- /dev/null +++ b/vgasrc/vbe.h @@ -0,0 +1,194 @@ +#include "types.h" // u8 +#include "farptr.h" // struct segoff_s + +#define VBE_OEM_STRING "SeaBIOS VBE(C) 2011" +#define VBE_VENDOR_STRING "SeaBIOS Developers" +#define VBE_PRODUCT_STRING "SeaBIOS VBE Adapter" +#define VBE_REVISION_STRING "Rev. 1" + +struct VbeInfoBlock +{ + u8 signature[4]; + u16 version; + u16 oem_string_off; + u16 oem_string_seg; + u8 capabilities[4]; + u16 video_mode_off; + u16 video_mode_seg; + u16 total_memory; + u16 oem_revision; + u16 oem_vendor_string_off; + u16 oem_vendor_string_seg; + u16 oem_product_string_off; + u16 oem_product_string_seg; + u16 oem_revision_string_off; + u16 oem_revision_string_seg; + u8 reserved[222]; +}; + +struct ModeInfoBlock +{ + /* VBE */ + u16 mode_attributes; + u8 winA_attributes; + u8 winB_attributes; + u16 win_granularity; + u16 win_size; + u16 winA_seg; + u16 winB_seg; + u32 win_func_ptr; + u16 bytes_per_scanline; + /* VBE 1.2 */ + u16 xres; + u16 yres; + u8 xcharsize; + u8 ycharsize; + u8 planes; + u8 bits_per_pixel; + u8 banks; + u8 mem_model; + u8 bank_size; + u8 pages; + u8 reserved0; + /* Direct Color */ + u8 red_size; + u8 red_pos; + u8 green_size; + u8 green_pos; + u8 blue_size; + u8 blue_pos; + u8 alpha_size; + u8 alpha_pos; + u8 directcolor_info; + /* VBE 2.0 */ + u32 phys_base; + u32 reserved1; + u16 reserved2; + /* VBE 3.0 */ + u16 linear_bytes_per_scanline; + u8 bank_pages; + u8 linear_pages; + u8 linear_red_size; + u8 linear_red_pos; + u8 linear_green_size; + u8 linear_green_pos; + u8 linear_blue_size; + u8 linear_blue_pos; + u8 linear_alpha_size; + u8 linear_alpha_pos; + u32 pixclock_max; + u8 reserved[189]; +}; + +struct CRTCInfoBlock +{ + u16 horiz_total; + u16 horiz_sync_start; + u16 horiz_sync_end; + u16 vert_total; + u16 vert_sync_start; + u16 vert_sync_end; + u8 flags; + u32 pixclock; + u16 refresh_rate; + u8 reserved[40]; +}; + +struct vbe_mode +{ + u16 mode; + u16 width; + u16 height; + u8 depth; +}; + +struct vbe_modeinfo +{ + u16 width; + u16 height; + u8 depth; + u16 linesize; + u32 phys_base; + u32 vram_size; +}; + +extern const struct vbe_mode vbe_modes[]; + +int vbe_init(u8 bus, u8 devfn); +int vbe_enabled(void); +u16 vbe_total_mem(void); +int vbe_list_modes(u16 seg, u16 ptr); +int vbe_mode_info(u16 mode, struct vbe_modeinfo *info); +void vbe_hires_enable(int enable); +void vbe_set_mode(u16 mode, struct vbe_modeinfo *info); +void vbe_clear_scr(void); +int vbe_hires_enabled(void); +u16 vbe_curr_mode(void); + +/* VBE Return Status Info */ +/* AL */ +#define VBE_RETURN_STATUS_SUPPORTED 0x4F +#define VBE_RETURN_STATUS_UNSUPPORTED 0x00 +/* AH */ +#define VBE_RETURN_STATUS_SUCCESSFULL 0x00 +#define VBE_RETURN_STATUS_FAILED 0x01 +#define VBE_RETURN_STATUS_NOT_SUPPORTED 0x02 +#define VBE_RETURN_STATUS_INVALID 0x03 + +/* VBE Mode Numbers */ + +#define VBE_MODE_VESA_DEFINED 0x0100 +#define VBE_MODE_REFRESH_RATE_USE_CRTC 0x0800 +#define VBE_MODE_LINEAR_FRAME_BUFFER 0x4000 +#define VBE_MODE_PRESERVE_DISPLAY_MEMORY 0x8000 + +#define VBE_VESA_MODE_END_OF_LIST 0xFFFF + +/* Capabilities */ + +#define VBE_CAPABILITY_8BIT_DAC 0x0001 +#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE 0x0002 +#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT 0x0004 +#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT 0x0008 +#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC 0x0010 + +/* Mode Attributes */ + +#define VBE_MODE_ATTRIBUTE_SUPPORTED 0x0001 +#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE 0x0002 +#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT 0x0004 +#define VBE_MODE_ATTRIBUTE_COLOR_MODE 0x0008 +#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE 0x0010 +#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE 0x0020 +#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW 0x0040 +#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE 0x0080 +#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE 0x0100 +#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE 0x0200 +#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER 0x0400 +#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800 +#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS 0x1000 + +#define VBE_MODE_ATTTRIBUTE_LFB_ONLY ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE ) + +/* Window attributes */ + +#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE 0x01 +#define VBE_WINDOW_ATTRIBUTE_READABLE 0x02 +#define VBE_WINDOW_ATTRIBUTE_WRITEABLE 0x04 + +/* Memory model */ + +#define VBE_MEMORYMODEL_TEXT_MODE 0x00 +#define VBE_MEMORYMODEL_CGA_GRAPHICS 0x01 +#define VBE_MEMORYMODEL_HERCULES_GRAPHICS 0x02 +#define VBE_MEMORYMODEL_PLANAR 0x03 +#define VBE_MEMORYMODEL_PACKED_PIXEL 0x04 +#define VBE_MEMORYMODEL_NON_CHAIN_4_256 0x05 +#define VBE_MEMORYMODEL_DIRECT_COLOR 0x06 +#define VBE_MEMORYMODEL_YUV 0x07 + +/* DirectColorModeInfo */ + +#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE 0x01 +#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE 0x02 + diff --git a/vgasrc/vga.c b/vgasrc/vga.c index b0d2598..966ef3d 100644 --- a/vgasrc/vga.c +++ b/vgasrc/vga.c @@ -15,6 +15,7 @@ #include "biosvar.h" // GET_BDA #include "util.h" // memset #include "vgatables.h" // find_vga_entry +#include "vbe.h" // VBE_*
// XXX #define DEBUG_VGA_POST 1 @@ -342,26 +343,8 @@ restore_bda_state(u16 seg, struct saveBDAstate *info)
// set video mode static void -handle_1000(struct bregs *regs) +set_vga_mode(u8 mode, u8 noclearmem) { - u8 noclearmem = regs->al & 0x80; - u8 mode = regs->al & 0x7f; - - // Set regs->al - if (mode > 7) - regs->al = 0x20; - else if (mode == 6) - regs->al = 0x3f; - else - regs->al = 0x30; - - if (CONFIG_VGA_CIRRUS) - cirrus_set_video_mode(mode); - - if (CONFIG_VGA_BOCHS) - if (bochs_has_vbe_display()) - dispi_set_enable(VBE_DISPI_DISABLED); - // find the entry in the video modes struct vgamode_s *vmode_g = find_vga_entry(mode); dprintf(1, "mode search %02x found %p\n", mode, vmode_g); @@ -461,6 +444,29 @@ handle_1000(struct bregs *regs) }
static void +handle_1000(struct bregs *regs) +{ + u8 noclearmem = regs->al & 0x80; + u8 mode = regs->al & 0x7f; + + // Set regs->al + if (mode > 7) + regs->al = 0x20; + else if (mode == 6) + regs->al = 0x3f; + else + regs->al = 0x30; + + if (CONFIG_VGA_CIRRUS) + cirrus_set_video_mode(mode); + + if (vbe_enabled()) + vbe_hires_enable(0); + + set_vga_mode(mode, noclearmem); +} + +static void handle_1001(struct bregs *regs) { set_cursor_shape(regs->ch, regs->cl); @@ -1181,72 +1187,271 @@ handle_101c(struct bregs *regs) } }
- static void handle_104f00(struct bregs *regs) { - // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI); - // XXX - OR cirrus_vesa_00h + u16 seg = regs->es; + struct VbeInfoBlock *info = (void*)(regs->di+0); + + if (GET_FARVAR(seg, info->signature[0]) == 'V' && + GET_FARVAR(seg, info->signature[1]) == 'B' && + GET_FARVAR(seg, info->signature[2]) == 'E' && + GET_FARVAR(seg, info->signature[3]) == '2') { + dprintf(4, "Get VBE Controller: VBE2 Signature found\n"); + } else if (GET_FARVAR(seg, info->signature[0]) == 'V' && + GET_FARVAR(seg, info->signature[1]) == 'E' && + GET_FARVAR(seg, info->signature[2]) == 'S' && + GET_FARVAR(seg, info->signature[3]) == 'A') { + dprintf(4, "Get VBE Controller: VESA Signature found\n"); + } else { + dprintf(4, "Get VBE Controller: Invalid Signature\n"); + } + + memset_far(seg, info, 0, sizeof(*info)); + + SET_FARVAR(seg, info->signature[0], 'V'); + SET_FARVAR(seg, info->signature[1], 'E'); + SET_FARVAR(seg, info->signature[2], 'S'); + SET_FARVAR(seg, info->signature[3], 'A'); + + SET_FARVAR(seg, info->version, 0x0200); + + SET_FARVAR(seg, info->oem_string_off, (u32)VBE_OEM_STRING); + SET_FARVAR(seg, info->oem_string_seg, get_global_seg()); + SET_FARVAR(seg, info->capabilities[0], 0x1); /* 8BIT DAC */ + + /* We generate our mode list in the reserved field of the info block */ + SET_FARVAR(seg, info->video_mode_off, regs->di + 34); + SET_FARVAR(seg, info->video_mode_seg, seg); + + /* Total memory (in 64 blocks) */ + SET_FARVAR(seg, info->total_memory, vbe_total_mem()); + + SET_FARVAR(seg, info->oem_vendor_string_off, (u32)VBE_VENDOR_STRING); + SET_FARVAR(seg, info->oem_vendor_string_seg, get_global_seg()); + SET_FARVAR(seg, info->oem_product_string_off, (u32)VBE_PRODUCT_STRING); + SET_FARVAR(seg, info->oem_product_string_seg, get_global_seg()); + SET_FARVAR(seg, info->oem_revision_string_off, (u32)VBE_REVISION_STRING); + SET_FARVAR(seg, info->oem_revision_string_seg, get_global_seg()); + + /* Fill list of modes */ + vbe_list_modes(seg, regs->di + 32); + + regs->al = regs->ah; /* 0x4F, Function supported */ + regs->ah = 0x0; /* 0x0, Function call successful */ }
static void handle_104f01(struct bregs *regs) { - // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI); - // XXX - OR cirrus_vesa_01h + u16 seg = regs->es; + struct ModeInfoBlock *info = (void*)(regs->di+0); + u16 mode = regs->cx; + struct vbe_modeinfo modeinfo; + int rc; + + dprintf(1, "VBE mode info request: %x\n", mode); + + rc = vbe_mode_info(mode, &modeinfo); + if (rc) { + dprintf(1, "VBE mode %x not found\n", mode); + regs->ax = 0x100; + return; + } + + u16 mode_attr = VBE_MODE_ATTRIBUTE_SUPPORTED | + VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | + VBE_MODE_ATTRIBUTE_COLOR_MODE | + VBE_MODE_ATTRIBUTE_GRAPHICS_MODE; + if (modeinfo.depth == 4) + mode_attr |= VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT; + else + mode_attr |= VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE; + SET_FARVAR(seg, info->mode_attributes, mode_attr); + SET_FARVAR(seg, info->winA_attributes, + VBE_WINDOW_ATTRIBUTE_RELOCATABLE | + VBE_WINDOW_ATTRIBUTE_READABLE | + VBE_WINDOW_ATTRIBUTE_WRITEABLE); + SET_FARVAR(seg, info->winB_attributes, 0); + SET_FARVAR(seg, info->win_granularity, 64); /* Bank size 64K */ + SET_FARVAR(seg, info->win_size, 64); /* Bank size 64K */ + SET_FARVAR(seg, info->winA_seg, 0xA000); + SET_FARVAR(seg, info->winB_seg, 0x0); + SET_FARVAR(seg, info->win_func_ptr, 0x0); + SET_FARVAR(seg, info->bytes_per_scanline, modeinfo.linesize); + SET_FARVAR(seg, info->xres, modeinfo.width); + SET_FARVAR(seg, info->yres, modeinfo.height); + SET_FARVAR(seg, info->xcharsize, 8); + SET_FARVAR(seg, info->ycharsize, 16); + if (modeinfo.depth == 4) + SET_FARVAR(seg, info->planes, 4); + else + SET_FARVAR(seg, info->planes, 1); + SET_FARVAR(seg, info->bits_per_pixel, modeinfo.depth); + SET_FARVAR(seg, info->banks, + (modeinfo.linesize * modeinfo.height + 65535) / 65536); + if (modeinfo.depth == 4) + SET_FARVAR(seg, info->mem_model, VBE_MEMORYMODEL_PLANAR); + else if (modeinfo.depth == 8) + SET_FARVAR(seg, info->mem_model, VBE_MEMORYMODEL_PACKED_PIXEL); + else + SET_FARVAR(seg, info->mem_model, VBE_MEMORYMODEL_DIRECT_COLOR); + SET_FARVAR(seg, info->bank_size, 0); + u32 pages = modeinfo.vram_size / (modeinfo.height * modeinfo.linesize); + if (modeinfo.depth == 4) + SET_FARVAR(seg, info->pages, (pages / 4) - 1); + else + SET_FARVAR(seg, info->pages, pages - 1); + SET_FARVAR(seg, info->reserved0, 1); + + u8 r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos; + + switch (modeinfo.depth) { + case 15: r_size = 5; r_pos = 10; g_size = 5; g_pos = 5; + b_size = 5; b_pos = 0; a_size = 1; a_pos = 15; break; + case 16: r_size = 5; r_pos = 11; g_size = 6; g_pos = 5; + b_size = 5; b_pos = 0; a_size = 0; a_pos = 0; break; + case 24: r_size = 8; r_pos = 16; g_size = 8; g_pos = 8; + b_size = 8; b_pos = 0; a_size = 0; a_pos = 0; break; + case 32: r_size = 8; r_pos = 16; g_size = 8; g_pos = 8; + b_size = 8; b_pos = 0; a_size = 8; a_pos = 24; break; + default: r_size = 0; r_pos = 0; g_size = 0; g_pos = 0; + b_size = 0; b_pos = 0; a_size = 0; a_pos = 0; break; + } + + SET_FARVAR(seg, info->red_size, r_size); + SET_FARVAR(seg, info->red_pos, r_pos); + SET_FARVAR(seg, info->green_size, g_size); + SET_FARVAR(seg, info->green_pos, g_pos); + SET_FARVAR(seg, info->blue_size, b_size); + SET_FARVAR(seg, info->blue_pos, b_pos); + SET_FARVAR(seg, info->alpha_size, a_size); + SET_FARVAR(seg, info->alpha_pos, a_pos); + + if (modeinfo.depth == 32) + SET_FARVAR(seg, info->directcolor_info, + VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE); + else + SET_FARVAR(seg, info->directcolor_info, 0); + + if (modeinfo.depth > 4) + SET_FARVAR(seg, info->phys_base, modeinfo.phys_base); + else + SET_FARVAR(seg, info->phys_base, 0); + + SET_FARVAR(seg, info->reserved1, 0); + SET_FARVAR(seg, info->reserved2, 0); + SET_FARVAR(seg, info->linear_bytes_per_scanline, modeinfo.linesize); + SET_FARVAR(seg, info->bank_pages, 0); + SET_FARVAR(seg, info->linear_pages, 0); + SET_FARVAR(seg, info->linear_red_size, r_size); + SET_FARVAR(seg, info->linear_red_pos, r_pos); + SET_FARVAR(seg, info->linear_green_size, g_size); + SET_FARVAR(seg, info->linear_green_pos, g_pos); + SET_FARVAR(seg, info->linear_blue_size, b_size); + SET_FARVAR(seg, info->linear_blue_pos, b_pos); + SET_FARVAR(seg, info->linear_alpha_size, a_size); + SET_FARVAR(seg, info->linear_alpha_pos, a_pos); + SET_FARVAR(seg, info->pixclock_max, 0); + + regs->al = regs->ah; /* 0x4F, Function supported */ + regs->ah = 0x0; /* 0x0, Function call successful */ }
static void handle_104f02(struct bregs *regs) { - // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI); - // XXX - OR cirrus_vesa_02h + //u16 seg = regs->es; + //struct CRTCInfoBlock *crtc_info = (void*)(regs->di+0); + u16 mode = regs->bx; + struct vbe_modeinfo modeinfo; + int rc; + + dprintf(1, "VBE mode set: %x\n", mode); + + if (mode < 0x100) { /* VGA */ + dprintf(1, "set VGA mode %x\n", mode); + + vbe_hires_enable(0); + set_vga_mode(mode, 0); + } else { /* VBE */ + rc = vbe_mode_info(mode & 0x1ff, &modeinfo); + if (rc) { + dprintf(1, "VBE mode %x not found\n", mode & 0x1ff); + regs->ax = 0x100; + return; + } + vbe_hires_enable(1); + vbe_set_mode(mode & 0x1ff, &modeinfo); + + if (mode & 0x4000) { + /* Linear frame buffer */ + /* XXX: ??? */ + } + if (!(mode & 0x8000)) { + vbe_clear_scr(); + } + } + + regs->al = regs->ah; /* 0x4F, Function supported */ + regs->ah = 0x0; /* 0x0, Function call successful */ }
static void handle_104f03(struct bregs *regs) { - // XXX - vbe_biosfn_return_current_mode - // XXX - OR cirrus_vesa_03h + if (!vbe_hires_enabled()) { + regs->bx = GET_BDA(video_mode); + } else { + regs->bx = vbe_curr_mode(); + } + + dprintf(1, "VBE current mode=%x\n", regs->bx); + + regs->al = regs->ah; /* 0x4F, Function supported */ + regs->ah = 0x0; /* 0x0, Function call successful */ }
static void handle_104f04(struct bregs *regs) { - // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX); + debug_enter(regs, DEBUG_VGA_10); + regs->ax = 0x0100; }
static void handle_104f05(struct bregs *regs) { - // XXX - vbe_biosfn_display_window_control - // XXX - OR cirrus_vesa_05h + debug_enter(regs, DEBUG_VGA_10); + regs->ax = 0x0100; }
static void handle_104f06(struct bregs *regs) { - // XXX - vbe_biosfn_set_get_logical_scan_line_length - // XXX - OR cirrus_vesa_06h + debug_enter(regs, DEBUG_VGA_10); + regs->ax = 0x0100; }
static void handle_104f07(struct bregs *regs) { - // XXX - vbe_biosfn_set_get_display_start - // XXX - OR cirrus_vesa_07h + debug_enter(regs, DEBUG_VGA_10); + regs->ax = 0x0100; }
static void handle_104f08(struct bregs *regs) { - // XXX - vbe_biosfn_set_get_dac_palette_format + debug_enter(regs, DEBUG_VGA_10); + regs->ax = 0x0100; }
static void handle_104f0a(struct bregs *regs) { - // XXX - vbe_biosfn_return_protected_mode_interface + debug_enter(regs, DEBUG_VGA_10); + regs->ax = 0x0100; }
static void @@ -1259,7 +1464,7 @@ handle_104fXX(struct bregs *regs) static void handle_104f(struct bregs *regs) { - if (! CONFIG_VGA_BOCHS || !bochs_has_vbe_display()) { + if (!vbe_enabled()) { handle_104fXX(regs); return; } @@ -1360,8 +1565,7 @@ vga_post(struct bregs *regs)
init_bios_area();
- if (CONFIG_VGA_BOCHS) - bochs_init(); + vbe_init(regs->ah, regs->al);
extern void entry_10(void); SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10)); diff --git a/vgasrc/vgatables.h b/vgasrc/vgatables.h index 1f877c5..0d98cec 100644 --- a/vgasrc/vgatables.h +++ b/vgasrc/vgatables.h @@ -208,10 +208,4 @@ void vgahw_init(void); void cirrus_set_video_mode(u8 mode); void cirrus_init(void);
-// vbe.c -- not implemented yet. -#define VBE_DISPI_DISABLED 0x00 -void dispi_set_enable(int enable); -void bochs_init(void); -int bochs_has_vbe_display(void); - #endif // vgatables.h
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- src/biosvar.h | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/src/biosvar.h b/src/biosvar.h index 2b755e3..ad791ab 100644 --- a/src/biosvar.h +++ b/src/biosvar.h @@ -112,7 +112,8 @@ struct bios_data_area_s { struct segoff_s video_savetable; u8 other_ac[4]; // 40:B0 - u8 other_b0[10]; + u8 other_b0[9]; + u8 vbe_flag; u16 vbe_mode; } PACKED;
On 12/16/11 15:15, Julian Pidancet wrote:
This patch set contain ground work for a working VBE implementation.
It adds several things:
- A configuration menu in seabios Kconfig
- The ability to generate a PCI ROM
- PMM facilities that the ROM can use to allocate memory
- A skeleton driver to implement the VBE interface
As a bonus, it fixes an issue when real-mode VGA ROM code is emulated by Windows 7, and is unable to cope with code generated with the -fomit-frame-pointer option.
It should make pretty easy to implement the BOCHS DISPI interface.
Series looks good to me. Nice work.
cheers, Gerd
On Fri, Dec 16, 2011 at 02:15:06PM +0000, Julian Pidancet wrote:
This patch set contain ground work for a working VBE implementation.
It adds several things:
- A configuration menu in seabios Kconfig
- The ability to generate a PCI ROM
- PMM facilities that the ROM can use to allocate memory
- A skeleton driver to implement the VBE interface
As a bonus, it fixes an issue when real-mode VGA ROM code is emulated by Windows 7, and is unable to cope with code generated with the -fomit-frame-pointer option.
Thanks. In general, it looks good to me.
It should make pretty easy to implement the BOCHS DISPI interface.
Also, I use these patchs to implement VBE for an experimental gfx device emulation. So far I managed to get Windows 7 to boot and show up a 1280x1024 desktop.
Will you be sending "BOCHS DISPI" or "gfx" code as well? What are your plans from here?
Thanks again, -Kevin
On Sat, Dec 17, 2011 at 4:22 PM, Kevin O'Connor kevin@koconnor.net wrote:
It should make pretty easy to implement the BOCHS DISPI interface.
Also, I use these patchs to implement VBE for an experimental gfx device emulation. So far I managed to get Windows 7 to boot and show up a 1280x1024 desktop.
Will you be sending "BOCHS DISPI" or "gfx" code as well? What are your plans from here?
Well, I have to admit that in a sense, this patch set is not particularly useful if it does not implement at least one driver.
The gfx device I'm currently working on doesn't use the DISPI interface and is pretty experimental for now and I guess the emulation code would have to be accepted first in Qemu before I can submit the driver in seabios, which could take some significant time.
I could have a look and see how much work remains to have a complete DISPI VBE driver, but it was not initially in my plans to be honest. Maybe the RedHat people would me more interested by this project, since they need it for QXL.
Also, I implemented this vbe driver skeleton with an interface which could be as generic as possible to allow to implement several different drivers. But I am actually wondering now what would be the best way for several drivers to share the same interface in terms of code.
Hi,
I think this could make Windows 7 boot with this kind "VGA ROM". The integrated VIA VGA does not need any other code (besided coreboot init). I remember it kind of worked with grub but windows failed to boot. Maybe this was the reason ;) so, I could test it in the future and the code could have also some real target.
Thanks Rudolf