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 * A skeleton driver to implement the VBE interface
Bonus: * Preliminary BOCHS (DISPI) VBE support.
Julian Pidancet (9): Rename CONFIG_VBE in CONFIG_VGA_BOCHS and CONFIG_CIRRUS in CONFIG_VGA_CIRRUS Move optionroms definitions into a separate header Add a PCI header to the VGA ROM if needed Add configuration menu for the VGA ROM buildrom.py: Handle image size in PCI header Add vbe_flag field in BDA Merge bootsplash and VGA ROM vbe structure definitions Partially implement VBE interface, create VBE driver skeleton Preliminary DISPI VBE driver implementation
Makefile | 2 +- src/Kconfig | 39 ++++++ src/biosvar.h | 3 +- src/bootsplash.c | 86 ++----------- src/optionroms.c | 53 +-------- src/optionroms.h | 59 +++++++++ src/vbe.h | 157 ++++++++++++++++++++++++ tools/buildrom.py | 5 + vgasrc/dispi.h | 55 +++++++++ vgasrc/vbe.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/vga.c | 299 ++++++++++++++++++++++++++++++++++++++------- vgasrc/vgaentry.S | 11 ++- vgasrc/vgatables.h | 31 ++++- 13 files changed, 962 insertions(+), 178 deletions(-) create mode 100644 src/optionroms.h create mode 100644 src/vbe.h create mode 100644 vgasrc/dispi.h create mode 100644 vgasrc/vbe.c
On Mon, Dec 19, 2011 at 05:07:52AM +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
- A skeleton driver to implement the VBE interface
Bonus:
- Preliminary BOCHS (DISPI) VBE support.
It looks good to me!
-Kevin
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
Create optionroms.h so the VGA rom can reuse the definitions.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- src/optionroms.c | 53 +----------------------------------------------- src/optionroms.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 src/optionroms.h
diff --git a/src/optionroms.c b/src/optionroms.c index 2832eab..725767b 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -14,63 +14,12 @@ #include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA #include "boot.h" // IPL #include "paravirt.h" // qemu_cfg_* - +#include "optionroms.h" // struct rom_header
/**************************************************************** * Definitions ****************************************************************/
-struct rom_header { - u16 signature; - u8 size; - u8 initVector[4]; - u8 reserved[17]; - u16 pcioffset; - u16 pnpoffset; -} PACKED; - -struct pci_data { - u32 signature; - u16 vendor; - u16 device; - u16 vitaldata; - u16 dlen; - u8 drevision; - u8 class_lo; - u16 class_hi; - u16 ilen; - u16 irevision; - u8 type; - u8 indicator; - u16 reserved; -} PACKED; - -struct pnp_data { - u32 signature; - u8 revision; - u8 len; - u16 nextoffset; - u8 reserved_08; - u8 checksum; - u32 devid; - u16 manufacturer; - u16 productname; - u8 type_lo; - u16 type_hi; - u8 dev_flags; - u16 bcv; - u16 dv; - u16 bev; - u16 reserved_1c; - u16 staticresource; -} PACKED; - -#define OPTION_ROM_SIGNATURE 0xaa55 -#define OPTION_ROM_ALIGN 2048 -#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0]) -#define PCI_ROM_SIGNATURE 0x52494350 // PCIR -#define PCIROM_CODETYPE_X86 0 - // The end of the last deployed rom. u32 RomEnd = BUILD_ROM_START;
diff --git a/src/optionroms.h b/src/optionroms.h new file mode 100644 index 0000000..94ca4ae --- /dev/null +++ b/src/optionroms.h @@ -0,0 +1,59 @@ +#ifndef __OPTIONROMS_H +#define __OPTIONROMS_H + +#include "types.h" // u32 + +#define OPTION_ROM_SIGNATURE 0xaa55 + +struct rom_header { + u16 signature; + u8 size; + u8 initVector[4]; + u8 reserved[17]; + u16 pcioffset; + u16 pnpoffset; +} PACKED; + +#define PCI_ROM_SIGNATURE 0x52494350 // "PCIR" + +struct pci_data { + u32 signature; + u16 vendor; + u16 device; + u16 vitaldata; + u16 dlen; + u8 drevision; + u8 class_lo; + u16 class_hi; + u16 ilen; + u16 irevision; + u8 type; + u8 indicator; + u16 reserved; +} PACKED; + +struct pnp_data { + u32 signature; + u8 revision; + u8 len; + u16 nextoffset; + u8 reserved_08; + u8 checksum; + u32 devid; + u16 manufacturer; + u16 productname; + u8 type_lo; + u16 type_hi; + u8 dev_flags; + u16 bcv; + u16 dv; + u16 bev; + u16 reserved_1c; + u16 staticresource; +} PACKED; + +#define OPTION_ROM_ALIGN 2048 +#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0]) +#define PCIROM_CODETYPE_X86 0 + +#endif
Allows the ROM to be extracted from a PCI device.
V2: * Declare the PCI header in C * Replace #ifdef CONFIG_VGA_PCI with #if CONFIG_VGA_PCI == 1
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- vgasrc/vga.c | 17 +++++++++++++++++ vgasrc/vgaentry.S | 11 ++++++++++- 2 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/vgasrc/vga.c b/vgasrc/vga.c index b515d1d..748ddd4 100644 --- a/vgasrc/vga.c +++ b/vgasrc/vga.c @@ -15,6 +15,8 @@ #include "biosvar.h" // GET_BDA #include "util.h" // memset #include "vgatables.h" // find_vga_entry +#include "optionroms.h" // struct pci_data +#include "config.h" // CONFIG_*
// XXX #define CONFIG_VGA_BOCHS 0 @@ -26,6 +28,21 @@
#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
+/**************************************************************** + * PCI Data + ****************************************************************/ +#if CONFIG_VGA_PCI == 1 +struct pci_data rom_pci_data VAR16VISIBLE = { + .signature = PCI_ROM_SIGNATURE, + .vendor = CONFIG_VGA_VID, + .device = CONFIG_VGA_DID, + .dlen = 0x18, + .class_hi = 0x300, + .irevision = 1, + .type = PCIROM_CODETYPE_X86, + .indicator = 0x80, +}; +#endif
/**************************************************************** * Helper functions diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S index fbfa9f7..2dc07c1 100644 --- a/vgasrc/vgaentry.S +++ b/vgasrc/vgaentry.S @@ -12,6 +12,7 @@ .code16gcc #include "vgaccode.16.s"
+#include "config.h" // CONFIG_* #include "entryfuncs.S" // ENTRY_*
@@ -30,7 +31,15 @@ _rom_header_entry: _rom_header_checksum: .byte 0 _rom_header_other: - .space 21 + .space 17 +_rom_header_pcidata: +#if CONFIG_VGA_PCI == 1 + .word rom_pci_data +#else + .word 0 +#endif +_rom_header_pnpdata: + .word 0
/****************************************************************
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.
V2: Default Device IDs and Vendor IDs values for Cirrus and Bochs are now set by Kconfig.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- src/Kconfig | 39 +++++++++++++++++++++++++++++++++++++++ vgasrc/vga.c | 4 ---- 2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig index f8d245a..ad16502 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -324,6 +324,45 @@ 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 "PCI Vendor ID" + default 0x1013 if VGA_CIRRUS + default 0x1234 if VGA_BOCHS + default 0x0000 + help + Vendor ID for the PCI ROM + + config VGA_DID + depends on VGA_PCI + hex "PCI Device ID" + default 0x00b8 if VGA_CIRRUS + default 0x1111 if VGA_BOCHS + default 0x0000 + help + 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 748ddd4..3988da9 100644 --- a/vgasrc/vga.c +++ b/vgasrc/vga.c @@ -19,10 +19,6 @@ #include "config.h" // CONFIG_*
// XXX -#define CONFIG_VGA_BOCHS 0 -#define CONFIG_VGA_CIRRUS 0 - -// XXX #define DEBUG_VGA_POST 1 #define DEBUG_VGA_10 3
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:]
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;
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- src/bootsplash.c | 86 +++++------------------------- src/vbe.h | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 72 deletions(-) create mode 100644 src/vbe.h
diff --git a/src/bootsplash.c b/src/bootsplash.c index 9c33b80..76b72c1 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -12,68 +12,10 @@ #include "jpeg.h" // splash #include "biosvar.h" // SET_EBDA #include "paravirt.h" // romfile_find +#include "vbe.h" // struct vbe_info #include "bmp.h"
/**************************************************************** - * VESA structures - ****************************************************************/ - -struct vesa_info { - u32 vesa_signature; - u16 vesa_version; - struct segoff_s oem_string_ptr; - u8 capabilities[4]; - struct segoff_s video_mode_ptr; - u16 total_memory; - u16 oem_software_rev; - struct segoff_s oem_vendor_name_ptr; - struct segoff_s oem_product_name_ptr; - struct segoff_s oem_product_rev_ptr; - u8 reserved[222]; - u8 oem_data[256]; -} PACKED; - -#define VESA_SIGNATURE 0x41534556 // VESA -#define VBE2_SIGNATURE 0x32454256 // VBE2 - -struct vesa_mode_info { - u16 mode_attributes; - u8 win_a_attributes; - u8 win_b_attributes; - u16 win_granularity; - u16 win_size; - u16 win_a_segment; - u16 win_b_segment; - u32 win_func_ptr; - u16 bytes_per_scanline; - u16 x_resolution; - u16 y_resolution; - u8 x_charsize; - u8 y_charsize; - u8 number_of_planes; - u8 bits_per_pixel; - u8 number_of_banks; - u8 memory_model; - u8 bank_size; - u8 number_of_image_pages; - u8 reserved_page; - u8 red_mask_size; - u8 red_mask_pos; - u8 green_mask_size; - u8 green_mask_pos; - u8 blue_mask_size; - u8 blue_mask_pos; - u8 reserved_mask_size; - u8 reserved_mask_pos; - u8 direct_color_mode_info; - void *phys_base_ptr; - u32 offscreen_mem_offset; - u16 offscreen_mem_size; - u8 reserved[206]; -} PACKED; - - -/**************************************************************** * Helper functions ****************************************************************/
@@ -108,11 +50,11 @@ enable_vga_console(void) }
static int -find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info +find_videomode(struct vbe_info *vesa_info, struct vbe_mode_info *mode_info , int width, int height, int bpp_req) { dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height); - u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr); + u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode); for (;; videomodes++) { u16 videomode = *videomodes; if (videomode == 0xffff) { @@ -131,8 +73,8 @@ find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info dprintf(1, "get_mode failed.\n"); continue; } - if (mode_info->x_resolution != width - || mode_info->y_resolution != height) + if (mode_info->xres != width + || mode_info->yres != height) continue; u8 depth = mode_info->bits_per_pixel; if (bpp_req == 0) { @@ -169,32 +111,32 @@ enable_bootsplash(void) u8 *picture = NULL; /* data buff used to be flushed to the video buf */ struct jpeg_decdata *jpeg = NULL; struct bmp_decdata *bmp = NULL; - struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info)); - struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info)); + struct vbe_info *vesa_info = malloc_tmplow(sizeof(*vesa_info)); + struct vbe_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info)); if (!vesa_info || !mode_info) { warn_noalloc(); goto done; }
/* Check whether we have a VESA 2.0 compliant BIOS */ - memset(vesa_info, 0, sizeof(struct vesa_info)); - vesa_info->vesa_signature = VBE2_SIGNATURE; + memset(vesa_info, 0, sizeof(struct vbe_info)); + vesa_info->signature = VBE2_SIGNATURE; struct bregs br; memset(&br, 0, sizeof(br)); br.ax = 0x4f00; br.di = FLATPTR_TO_OFFSET(vesa_info); br.es = FLATPTR_TO_SEG(vesa_info); call16_int10(&br); - if (vesa_info->vesa_signature != VESA_SIGNATURE) { + if (vesa_info->signature != VESA_SIGNATURE) { dprintf(1,"No VBE2 found.\n"); goto done; }
/* Print some debugging information about our card. */ - char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr); - char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr); + char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_string); + char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_string); dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n", - vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff, + vesa_info->version>>8, vesa_info->version&0xff, vendor, product);
int ret, width, height; @@ -239,7 +181,7 @@ enable_bootsplash(void) width, height, bpp_require); goto done; } - void *framebuffer = mode_info->phys_base_ptr; + void *framebuffer = (void *)mode_info->phys_base; int depth = mode_info->bits_per_pixel; dprintf(3, "mode: %04x\n", videomode); dprintf(3, "framebuffer: %p\n", framebuffer); diff --git a/src/vbe.h b/src/vbe.h new file mode 100644 index 0000000..bfcd6b4 --- /dev/null +++ b/src/vbe.h @@ -0,0 +1,157 @@ +#ifndef __VBE_H +#define __VBE_H + +#include "types.h" // u8 +#include "farptr.h" // struct segoff_s + +#define VESA_SIGNATURE 0x41534556 // VESA +#define VBE2_SIGNATURE 0x32454256 // VBE2 + +struct vbe_info { + u32 signature; + u16 version; + struct segoff_s oem_string; + u8 capabilities[4]; + struct segoff_s video_mode; + u16 total_memory; + u16 oem_revision; + struct segoff_s oem_vendor_string; + struct segoff_s oem_product_string; + struct segoff_s oem_revision_string; + u8 reserved[222]; +} PACKED; + +struct vbe_mode_info { + /* 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]; +} PACKED; + +struct vbe_crtc_info { + 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]; +} PACKED; + +/* 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 + +#endif
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- Makefile | 2 +- vgasrc/vbe.c | 142 +++++++++++++++++++++++++++ vgasrc/vga.c | 276 ++++++++++++++++++++++++++++++++++++++++++++-------- vgasrc/vgatables.h | 31 +++++- 4 files changed, 404 insertions(+), 47 deletions(-) create mode 100644 vgasrc/vbe.c
diff --git a/Makefile b/Makefile index 4f0e6ab..7ac65fa 100644 --- a/Makefile +++ b/Makefile @@ -170,7 +170,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/vbe.c
CFLAGS16VGA = $(CFLAGS16INC) -g -Isrc
diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c new file mode 100644 index 0000000..b6e0037 --- /dev/null +++ b/vgasrc/vbe.c @@ -0,0 +1,142 @@ +#include "vgatables.h" +#include "vbe.h" + +struct mode +{ + u16 mode; + u16 width; + u16 height; + u8 depth; +} 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 0; +} + +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/vga.c b/vgasrc/vga.c index 3988da9..26f70ce 100644 --- a/vgasrc/vga.c +++ b/vgasrc/vga.c @@ -17,6 +17,7 @@ #include "vgatables.h" // find_vga_entry #include "optionroms.h" // struct pci_data #include "config.h" // CONFIG_* +#include "vbe.h" // vbe_*
// XXX #define DEBUG_VGA_POST 1 @@ -358,27 +359,9 @@ restore_bda_state(u16 seg, struct saveBDAstate *info) ****************************************************************/
// set video mode -static void -handle_1000(struct bregs *regs) +void +vga_set_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); @@ -478,6 +461,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); + + vga_set_mode(mode, noclearmem); +} + +static void handle_1001(struct bregs *regs) { set_cursor_shape(regs->ch, regs->cl); @@ -1198,72 +1204,261 @@ 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 vbe_info *info = (void*)(regs->di+0); + + if (GET_FARVAR(seg, info->signature) == VBE2_SIGNATURE) { + dprintf(4, "Get VBE Controller: VBE2 Signature found\n"); + } else if (GET_FARVAR(seg, info->signature) == VESA_SIGNATURE) { + 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, VESA_SIGNATURE); + + SET_FARVAR(seg, info->version, 0x0200); + + SET_FARVAR(seg, info->oem_string, + SEGOFF(get_global_seg(), (u32)VBE_OEM_STRING)); + 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, SEGOFF(seg, regs->di + 34)); + + /* Total memory (in 64 blocks) */ + SET_FARVAR(seg, info->total_memory, vbe_total_mem()); + + SET_FARVAR(seg, info->oem_vendor_string, + SEGOFF(get_global_seg(), (u32)VBE_VENDOR_STRING)); + SET_FARVAR(seg, info->oem_product_string, + SEGOFF(get_global_seg(), (u32)VBE_PRODUCT_STRING)); + SET_FARVAR(seg, info->oem_revision_string, + SEGOFF(get_global_seg(), (u32)VBE_REVISION_STRING)); + + /* 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 vbe_mode_info *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 vbe_crtc_info *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); + vga_set_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 @@ -1276,7 +1471,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; } @@ -1377,8 +1572,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..5c0f3bf 100644 --- a/vgasrc/vgatables.h +++ b/vgasrc/vgatables.h @@ -156,6 +156,7 @@ struct carattr { struct cursorpos { u8 x, y, page; }; +void vga_set_mode(u8 mode, u8 noclearmem);
// vgafb.c void clear_screen(struct vgamode_s *vmode_g); @@ -208,10 +209,30 @@ 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); +// vbe.c +#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 vbe_modeinfo +{ + u16 width; + u16 height; + u8 depth; + u16 linesize; + u32 phys_base; + u32 vram_size; +}; +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);
#endif // vgatables.h
It allowed me to boot Windows 7 with Qemu BOCHS VGA emulation and it seemed to work fine. It probably needs some further testing though.
Signed-off-by: Julian Pidancet julian.pidancet@gmail.com --- vgasrc/dispi.h | 55 +++++++++++++++ vgasrc/vbe.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 vgasrc/dispi.h
diff --git a/vgasrc/dispi.h b/vgasrc/dispi.h new file mode 100644 index 0000000..963cb13 --- /dev/null +++ b/vgasrc/dispi.h @@ -0,0 +1,55 @@ +#ifndef __DISPI_H +#define __DISPI_H + +#include "types.h" // u8 +#include "ioport.h" // outb + +#define VBE_DISPI_BANK_ADDRESS 0xA0000 +#define VBE_DISPI_BANK_SIZE_KB 64 + +#define VBE_DISPI_MAX_XRES 2560 +#define VBE_DISPI_MAX_YRES 1600 + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 +#define VBE_DISPI_ID5 0xB0C5 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 + +static inline u16 dispi_read(u16 reg) +{ + outw(reg, VBE_DISPI_IOPORT_INDEX); + return inw(VBE_DISPI_IOPORT_DATA); +} +static inline void dispi_write(u16 reg, u16 val) +{ + outw(reg, VBE_DISPI_IOPORT_INDEX); + outw(val, VBE_DISPI_IOPORT_DATA); +} + +#endif diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c index b6e0037..2a1e932 100644 --- a/vgasrc/vbe.c +++ b/vgasrc/vbe.c @@ -1,5 +1,9 @@ #include "vgatables.h" #include "vbe.h" +#include "dispi.h" +#include "util.h" +#include "config.h" // CONFIG_ +#include "biosvar.h" // SET_BDA
struct mode { @@ -74,23 +78,131 @@ struct mode { 0, }, };
+#define BYTES_PER_PIXEL(m) ((GET_GLOBAL((m)->depth) + 7) / 8) + +u32 pci_lfb_addr VAR16; + +static inline u32 pci_config_readl(u8 bus, u8 devfn, u16 addr) +{ + int status; + u32 val; + u16 bdf = (bus << 16) | devfn; + + addr &= ~3; + + asm volatile( + "int $0x1a\n" + "cli\n" + "cld" + : "=a"(status), "=c"(val) + : "a"(0xb10a), "b"(bdf), "D"(addr) + : "cc", "memory"); + + if ((status >> 16)) + return (u32)-1; + + return val; +} + + +static u16 dispi_get_max_xres(void) +{ + u16 en; + u16 xres; + + en = dispi_read(VBE_DISPI_INDEX_ENABLE); + + dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS); + xres = dispi_read(VBE_DISPI_INDEX_XRES); + dispi_write(VBE_DISPI_INDEX_ENABLE, en); + + return xres; +} + +static u16 dispi_get_max_bpp(void) +{ + u16 en; + u16 bpp; + + en = dispi_read(VBE_DISPI_INDEX_ENABLE); + + dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS); + bpp = dispi_read(VBE_DISPI_INDEX_BPP); + dispi_write(VBE_DISPI_INDEX_ENABLE, en); + + return bpp; +} + /* Called only during POST */ int vbe_init(u8 bus, u8 devfn) { - return -1; + u32 lfb_addr; + + if (!CONFIG_VGA_BOCHS) + return -1; + + /* Sanity checks */ + dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID0); + if (dispi_read(VBE_DISPI_INDEX_ID) != VBE_DISPI_ID0) { + dprintf(1, "No VBE DISPI interface detected\n"); + return -1; + } + + SET_BDA(vbe_flag, 0x1); + dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID5); + + if (CONFIG_VGA_PCI) + lfb_addr = pci_config_readl(bus, devfn, 0x10) & ~0xf; + else + lfb_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS; + + SET_FARVAR(get_global_seg(), pci_lfb_addr, lfb_addr); + + dprintf(1, "VBE DISPI detected. lfb_addr=%x\n", GET_GLOBAL(pci_lfb_addr)); + + return 0; }
int vbe_enabled(void) { - return 0; + return GET_BDA(vbe_flag); }
u16 vbe_total_mem(void) { - return 0; + return dispi_read(VBE_DISPI_INDEX_VIDEO_MEMORY_64K); +} + +static struct mode *find_mode_entry(u16 mode) +{ + struct mode *m; + + for (m = vbe_modes; GET_GLOBAL(m->mode); m++) { + if (GET_GLOBAL(m->mode) == mode) + return m; + } + + return NULL; +} + +static int mode_valid(struct mode *m) +{ + u16 max_xres = dispi_get_max_xres(); + u16 max_bpp = dispi_get_max_bpp(); + u32 max_mem = vbe_total_mem() * 64 * 1024; + + u32 mem = GET_GLOBAL(m->width) * GET_GLOBAL(m->height) * + BYTES_PER_PIXEL(m); + + if (GET_GLOBAL(m->width) > max_xres || + GET_GLOBAL(m->depth) > max_bpp || + mem > max_mem) + return 0; + + return 1; }
int @@ -98,6 +210,17 @@ vbe_list_modes(u16 seg, u16 ptr) { int count = 0; u16 *dest = (u16 *)(u32)ptr; + struct mode *m; + + for (m = vbe_modes; GET_GLOBAL(m->mode); m++) { + if (!mode_valid(m)) + continue; + + dprintf(1, "VBE found mode %x valid.\n", GET_GLOBAL(m->mode)); + SET_FARVAR(seg, dest[count], GET_GLOBAL(m->mode)); + + count++; + }
SET_FARVAR(seg, dest[count], 0xffff); /* End of list */
@@ -107,36 +230,111 @@ vbe_list_modes(u16 seg, u16 ptr) int vbe_mode_info(u16 mode, struct vbe_modeinfo *info) { - return -1; + struct mode *m; + + m = find_mode_entry(mode); + if (!m || !mode_valid(m)) + return -1; + + info->width = GET_GLOBAL(m->width); + info->height = GET_GLOBAL(m->height); + info->depth = GET_GLOBAL(m->depth); + + info->linesize = info->width * ((info->depth + 7) / 8); + info->phys_base = GET_GLOBAL(pci_lfb_addr); + info->vram_size = vbe_total_mem() * 64 * 1024; + + return 0; }
void vbe_hires_enable(int enable) { + u16 flags = enable ? + VBE_DISPI_ENABLED | + VBE_DISPI_LFB_ENABLED | + VBE_DISPI_NOCLEARMEM : 0;
+ dispi_write(VBE_DISPI_INDEX_ENABLE, flags); }
void vbe_set_mode(u16 mode, struct vbe_modeinfo *info) { + if (info->depth == 4) + vga_set_mode(0x6a, 0); + if (info->depth == 8) + // XXX load_dac_palette(3); + ; + + dispi_write(VBE_DISPI_INDEX_BPP, info->depth); + dispi_write(VBE_DISPI_INDEX_XRES, info->width); + dispi_write(VBE_DISPI_INDEX_YRES, info->height); + dispi_write(VBE_DISPI_INDEX_BANK, 0); + + /* VGA compat setup */ + //XXX: This probably needs some reverse engineering + u8 v; + outw(0x0011, VGAREG_VGA_CRTC_ADDRESS); + outw(((info->width * 4 - 1) << 8) | 0x1, VGAREG_VGA_CRTC_ADDRESS); + dispi_write(VBE_DISPI_INDEX_VIRT_WIDTH, info->width); + outw(((info->height - 1) << 8) | 0x12, VGAREG_VGA_CRTC_ADDRESS); + outw(((info->height - 1) & 0xff00) | 0x7, VGAREG_VGA_CRTC_ADDRESS); + v = inb(VGAREG_VGA_CRTC_DATA) & 0xbd; + if (v & 0x1) + v |= 0x2; + if (v & 0x2) + v |= 0x40; + outb(v, VGAREG_VGA_CRTC_DATA);
+ outw(0x9, VGAREG_VGA_CRTC_ADDRESS); + outb(0x17, VGAREG_VGA_CRTC_ADDRESS); + outb(inb(VGAREG_VGA_CRTC_DATA) | 0x3, VGAREG_VGA_CRTC_DATA); + v = inb(VGAREG_ACTL_RESET); + outw(0x10, VGAREG_ACTL_ADDRESS); + v = inb(VGAREG_ACTL_READ_DATA) | 0x1; + outb(v, VGAREG_ACTL_ADDRESS); + outb(0x20, VGAREG_ACTL_ADDRESS); + outw(0x0506, VGAREG_GRDC_ADDRESS); + outw(0x0f02, VGAREG_SEQU_ADDRESS); + if (info->depth >= 8) { + outb(0x14, VGAREG_VGA_CRTC_ADDRESS); + outb(inb(VGAREG_VGA_CRTC_DATA) | 0x40, VGAREG_VGA_CRTC_DATA); + v = inb(VGAREG_ACTL_RESET); + outw(0x10, VGAREG_ACTL_ADDRESS); + v = inb(VGAREG_ACTL_READ_DATA) | 0x40; + outb(v, VGAREG_ACTL_ADDRESS); + outb(0x20, VGAREG_ACTL_ADDRESS); + outb(0x04, VGAREG_SEQU_ADDRESS); + v = inb(VGAREG_SEQU_DATA) | 0x08; + outb(v, VGAREG_SEQU_DATA); + outb(0x05, VGAREG_GRDC_ADDRESS); + v = inb(VGAREG_GRDC_DATA) & 0x9f; + outb(v | 0x40, VGAREG_GRDC_DATA); + } + + SET_BDA(vbe_mode, mode); }
void vbe_clear_scr(void) { + u16 en;
+ en = dispi_read(VBE_DISPI_INDEX_ENABLE); + en &= ~VBE_DISPI_NOCLEARMEM; + dispi_write(VBE_DISPI_INDEX_ENABLE, en); }
int vbe_hires_enabled(void) { - return 0; + return dispi_read(VBE_DISPI_INDEX_ENABLE) & VBE_DISPI_ENABLED; }
u16 vbe_curr_mode(void) { - return 0; + return GET_BDA(vbe_mode); }
On Mon, Dec 19, 2011 at 05:07:52AM +0000, Julian Pidancet wrote:
This patch set contain ground work for a working VBE implementation.
I committed this series.
-Kevin