diff --git a/ChangeLog b/ChangeLog index 2437c7cac..44f14a0d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2009-08-04 Robert Millan + + Fix a bug resulting in black screen when loading Linux using a + packed video mode. + + * kern/i386/pc/startup.S (grub_vbe_bios_getset_dac_palette_width): New + function. + + * include/grub/i386/pc/vbe.h (GRUB_VBE_CAPABILITY_DACWIDTH): New macro. + (grub_vbe_bios_getset_dac_palette_width): New function. + (grub_vbe_bios_get_dac_palette_width) + (grub_vbe_bios_set_dac_palette_width): New macros (act as wrappers for + grub_vbe_bios_getset_dac_palette_width()). + + * video/i386/pc/vbe.c (grub_vbe_probe): Use `GRUB_VBE_STATUS_OK' to + check for return status. + (grub_vbe_get_video_mode_info): When getting information for a packed + mode (<= 8 bpp), obtain DAC palette width using + grub_vbe_bios_getset_dac_palette_width(), and use that for initializing + {red,green,blue}_mark_size. + 2009-08-04 Felix Zielcke * commands/search.c (options): Fix help output to match actual code. diff --git a/include/grub/i386/pc/vbe.h b/include/grub/i386/pc/vbe.h index bd6ecd7e4..fad3c6c36 100644 --- a/include/grub/i386/pc/vbe.h +++ b/include/grub/i386/pc/vbe.h @@ -30,6 +30,8 @@ /* VBE status codes. */ #define GRUB_VBE_STATUS_OK 0x004f +#define GRUB_VBE_CAPABILITY_DACWIDTH (1 << 0) + /* Bits from the GRUB_VBE "mode_attributes" field in the mode info struct. */ #define GRUB_VBE_MODEATTR_SUPPORTED (1 << 0) #define GRUB_VBE_MODEATTR_RESERVED_1 (1 << 1) @@ -181,6 +183,11 @@ grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_controller_info) (struct grub_vb grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_mode_info) (grub_uint32_t mode, struct grub_vbe_mode_info_block *mode_info); +grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_getset_dac_palette_width) (int set, int *width); + +#define grub_vbe_bios_get_dac_palette_width(width) grub_vbe_bios_getset_dac_palette_width(0, (width)) +#define grub_vbe_bios_set_dac_palette_width(width) grub_vbe_bios_getset_dac_palette_width(1, (width)) + /* Call VESA BIOS 0x4f02 to set video mode, return status. */ grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_mode) (grub_uint32_t mode, struct grub_vbe_crtc_info_block *crtc_info); diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index be258fb08..1a896eda1 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1732,6 +1732,52 @@ FUNCTION(grub_vbe_bios_get_mode) popl %ebp ret +/* + * grub_vbe_status_t grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size) + * + * Register allocations for parameters: + * %eax set + * %edx *dac_mask_size + */ +FUNCTION(grub_vbe_bios_getset_dac_palette_width) + pushl %ebp + pushl %ebx + + xorl %ebx, %ebx + + /* If we only want to fetch the value, set %bl to 1. */ + testl %eax, %eax + jne 1f + incb %bl +1: + + /* Put desired width in %bh. */ + movl (%edx), %eax + movb %al, %bh + + call prot_to_real + .code16 + + movw $0x4f08, %ax + int $0x10 + + movw %ax, %dx /* real_to_prot destroys %eax. */ + + DATA32 call real_to_prot + .code32 + + /* Move result back to *dac_mask_size. */ + movb %bh, %al + movl %eax, (%edx) + + /* Return value in %eax. */ + xorl %eax, %eax + movw %dx, %ax + + popl %ebx + popl %ebp + ret + /* * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window, * grub_uint32_t position); diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index ae0840234..1670a737d 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -116,7 +116,7 @@ grub_vbe_probe (struct grub_vbe_info_block *info_block) /* Try to get controller info block. */ status = grub_vbe_bios_get_controller_info (vbe_ib); - if (status == 0x004F) + if (status == GRUB_VBE_STATUS_OK) { /* Copy it for later usage. */ grub_memcpy (&controller_info, vbe_ib, sizeof (controller_info)); @@ -300,6 +300,24 @@ grub_vbe_get_video_mode_info (grub_uint32_t mode, /* Make copy of mode info block. */ grub_memcpy (mode_info, mi_tmp, sizeof (*mode_info)); + + /* Packed mode. Query DAC Palette width for color sizes. */ + if (mode_info->bits_per_pixel <= 8) + { + int width = 8; + status = 0; + + if (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH) + status = grub_vbe_bios_set_dac_palette_width (& width); + + if (status != GRUB_VBE_STATUS_OK) + /* 6 is default after mode reset. */ + width = 6; + + mode_info->red_mask_size = mode_info->green_mask_size + = mode_info->blue_mask_size = width; + mode_info->rsvd_mask_size = 0; + } } else /* Just clear mode info block if it isn't a VESA mode. */