From d3ff9cc39a45e28a15483f563cbbfe3f1fa672da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 4 Apr 2005 16:56:18 +0000 Subject: [PATCH] The boot menu no longer changes the meaning of the default video mode once you choose it in the menu. The boot loader now always switches into a graphics mode unless it's in debug mode (currently triggered by pressing the escape key on startup). That means, "Standard VGA" now actually means mode 0x12 (640x480x4) instead of text mode. Since the current limited boot logo code would do stupid things with VGA planes, there will now only be some colored blocks visible during boot. Implemented support for monochrome modes in the frame buffer console. Additionally, the frame buffer console now has support for the VGA mode; it will treat all 4 bit modes as monochrome for now (the VGA 0x12 mode is a planar mode so this works nicely). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12235 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/boot/platform/bios_ia32/vga.h | 38 ++++ src/kernel/boot/platform/bios_ia32/video.cpp | 195 ++++++++++++------ .../core/debug/frame_buffer_console.cpp | 95 +++++++-- 3 files changed, 249 insertions(+), 79 deletions(-) create mode 100644 src/kernel/boot/platform/bios_ia32/vga.h diff --git a/src/kernel/boot/platform/bios_ia32/vga.h b/src/kernel/boot/platform/bios_ia32/vga.h new file mode 100644 index 0000000000..b9f923e288 --- /dev/null +++ b/src/kernel/boot/platform/bios_ia32/vga.h @@ -0,0 +1,38 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef VGA_H +#define VGA_H + + +/* VGA ports */ + +// misc stuff +#define VGA_INPUT_STATUS_0 0x3c2 +#define VGA_INPUT_STATUS_1 0x3da + +// sequencer registers +#define VGA_SEQUENCER_INDEX 0x3c4 +#define VGA_SEQUENCER_DATA 0x3c5 + +// graphics registers +#define VGA_GRAPHICS_INDEX 0x3ce +#define VGA_GRAPHICS_DATA 0x3cf + +// CRTC registers +#define VGA_CRTC_INDEX 0x3d4 +#define VGA_CRTC_DATA 0x3d5 + +// attribute registers +#define VGA_ATTRIBUTE_READ 0x3c1 +#define VGA_ATTRIBUTE_WRITE 0x3c0 + +// color registers +#define VGA_COLOR_STATE 0x3c7 +#define VGA_COLOR_READ_MODE 0x3c7 +#define VGA_COLOR_WRITE_MODE 0x3c8 +#define VGA_COLOR_DATA 0x3c9 +#define VGA_COLOR_MASK 0x3c6 + +#endif /* VGA_H */ diff --git a/src/kernel/boot/platform/bios_ia32/video.cpp b/src/kernel/boot/platform/bios_ia32/video.cpp index 1d71ddb43a..2960fad257 100644 --- a/src/kernel/boot/platform/bios_ia32/video.cpp +++ b/src/kernel/boot/platform/bios_ia32/video.cpp @@ -7,6 +7,7 @@ #include "video.h" #include "bios.h" #include "vesa.h" +#include "vga.h" #include "mmu.h" #include "images.h" @@ -37,7 +38,7 @@ struct video_mode { }; static vbe_info_block sInfo; -static video_mode *sMode; +static video_mode *sMode, *sDefaultMode; static bool sVesaCompatible; struct list sModeList; static addr_t sFrameBuffer; @@ -48,13 +49,13 @@ static bool sSettingsLoaded; static void vga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) { - out8(firstIndex, 0x03c8); + out8(firstIndex, VGA_COLOR_WRITE_MODE); // write VGA palette for (int32 i = firstIndex; i < numEntries; i++) { // VGA (usually) has only 6 bits per gun - out8(palette[i * 3 + 0] >> 2, 0x03c9); - out8(palette[i * 3 + 1] >> 2, 0x03c9); - out8(palette[i * 3 + 2] >> 2, 0x03c9); + out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA); + out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA); + out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA); } } @@ -63,14 +64,14 @@ static void vga_enable_bright_background_colors(void) { // reset attribute controller - in8(0x03da); + in8(VGA_INPUT_STATUS_1); // select mode control register - out8(0x30, 0x03c0); + out8(0x30, VGA_ATTRIBUTE_WRITE); // read mode control register, change it (we need to clear bit 3), and write it back - uint8 mode = in8(0x03c1) & 0xf7; - out8(mode, 0x3c0); + uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7; + out8(mode, VGA_ATTRIBUTE_WRITE); } @@ -280,8 +281,22 @@ video_mode_hook(Menu *menu, MenuItem *item) menu = item->Submenu(); item = menu->FindMarked(); - if (item != NULL) - mode = (video_mode *)item->Data(); + if (item != NULL) { + switch (menu->IndexOf(item)) { + case 0: + // "Default" mode special + sMode = sDefaultMode; + sModeChosen = false; + return true; + case 1: + // "Standard VGA" mode special + // sets sMode to NULL which triggers VGA mode + break; + default: + mode = (video_mode *)item->Data(); + break; + } + } if (mode != sMode) { // update standard mode @@ -384,9 +399,20 @@ out: } +static void +set_vga_mode(void) +{ + // sets 640x480 16 colors graphics mode + bios_regs regs; + regs.eax = 0x12; + call_bios(0x10, ®s); +} + + static void set_text_mode(void) { + // sets 80x25 text console bios_regs regs; regs.eax = 3; call_bios(0x10, ®s); @@ -403,70 +429,119 @@ platform_switch_to_logo(void) if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0) return; - if (!sVesaCompatible || sMode == NULL) - // no logo for now... - return; + addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start; + size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size; + int32 bytesPerPixel = 1; - if (!sModeChosen) - get_mode_from_settings(); + if (sVesaCompatible && sMode != NULL) { + if (!sModeChosen) + get_mode_from_settings(); - if (vesa_set_mode(sMode->mode) != B_OK) - return; + if (vesa_set_mode(sMode->mode) != B_OK) + goto fallback; + + struct vbe_mode_info modeInfo; + if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK) + goto fallback; + + bytesPerPixel = (modeInfo.bits_per_pixel + 7) / 8; + + gKernelArgs.frame_buffer.width = modeInfo.width; + gKernelArgs.frame_buffer.height = modeInfo.height; + gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel; + gKernelArgs.frame_buffer.physical_buffer.size = gKernelArgs.frame_buffer.width + * gKernelArgs.frame_buffer.height * bytesPerPixel; + gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base; + } else { +fallback: + // use standard VGA mode 640x480x4 + set_vga_mode(); + + gKernelArgs.frame_buffer.width = 640; + gKernelArgs.frame_buffer.height = 480; + gKernelArgs.frame_buffer.depth = 4; + gKernelArgs.frame_buffer.physical_buffer.size = gKernelArgs.frame_buffer.width + * gKernelArgs.frame_buffer.height / 2; + gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000; + } gKernelArgs.frame_buffer.enabled = 1; - struct vbe_mode_info modeInfo; - if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK) { - platform_switch_to_text_mode(); - return; + // If the new frame buffer is either larger than the old one or located at + // a different address, we need to remap it, so we first have to throw + // away its previous mapping + if (lastBase != 0 + && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start + || lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) { + mmu_free((void *)sFrameBuffer, lastSize); + lastBase = 0; } - - addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start; - int32 bytesPerPixel = (modeInfo.bits_per_pixel + 7) / 8; - - gKernelArgs.frame_buffer.width = modeInfo.width; - gKernelArgs.frame_buffer.height = modeInfo.height; - gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel; - gKernelArgs.frame_buffer.physical_buffer.size = gKernelArgs.frame_buffer.width - * gKernelArgs.frame_buffer.height * bytesPerPixel; - gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base; - - // ToDo: we assume that physical base is constant through the different resolutions - // ToDo: this is broken - if the newly chosen video mode is larger than the old one - // the boot loader will crash while trying to access unmapped memory if (lastBase == 0) { // the graphics memory has not been mapped yet! - sFrameBuffer = mmu_map_physical_memory(modeInfo.physical_base, + sFrameBuffer = mmu_map_physical_memory(gKernelArgs.frame_buffer.physical_buffer.start, gKernelArgs.frame_buffer.physical_buffer.size, 0x03); } // clear the video memory // ToDo: this shouldn't be necessary on real hardware (and Bochs), but // at least booting with Qemu looks ugly when this is missing - memset((void *)sFrameBuffer, 0, gKernelArgs.frame_buffer.physical_buffer.size); + //memset((void *)sFrameBuffer, 0, gKernelArgs.frame_buffer.physical_buffer.size); - if (vesa_set_palette((const uint8 *)kPalette, 0, 256) != B_OK) - dprintf("set palette failed!\n"); + if (sMode != NULL) { + if (vesa_set_palette((const uint8 *)kPalette, 0, 256) != B_OK) + dprintf("set palette failed!\n"); -#if 0 - uint8 *bits = (uint8 *)gKernelArgs.fb.mapping.start; - uint32 bytesPerRow = gKernelArgs.fb.x_size; - for (int32 y = 10; y < 30; y++) { - for (int32 i = 0; i < 256; i++) { - bits[y * bytesPerRow + i * 3] = i; - bits[y * bytesPerRow + i * 3 + 1] = i; - bits[y * bytesPerRow + i * 3 + 2] = i; + // ToDo: this is a temporary hack! + addr_t start = sFrameBuffer + gKernelArgs.frame_buffer.width + * (gKernelArgs.frame_buffer.height - kHeight - 60) + * bytesPerPixel + gKernelArgs.frame_buffer.width - kWidth - 40; + for (int32 i = 0; i < kHeight; i++) { + memcpy((void *)(start + gKernelArgs.frame_buffer.width * i), + &kImageData[i * kWidth], kWidth); + } + } else { + // vga_set_palette((const uint8 *)kPalette16, 0, 16); + // ToDo: no boot logo yet in VGA mode +#if 1 +// this draws 16 big rectangles in all the available colors + uint8 *bits = (uint8 *)sFrameBuffer; + uint32 bytesPerRow = 80; + for (int32 i = 0; i < 32; i++) { + bits[9 * bytesPerRow + i + 2] = 0x55; + bits[30 * bytesPerRow + i + 2] = 0xaa; } - } -#endif - // ToDo: this is a temporary hack! - addr_t start = sFrameBuffer + gKernelArgs.frame_buffer.width - * (gKernelArgs.frame_buffer.height - kHeight - 60) - * bytesPerPixel + gKernelArgs.frame_buffer.width - kWidth - 40; - for (int32 i = 0; i < kHeight; i++) { - memcpy((void *)(start + gKernelArgs.frame_buffer.width * i), - &kImageData[i * kWidth], kWidth); + for (int32 y = 10; y < 30; y++) { + for (int32 i = 0; i < 16; i++) { + out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); + bits[32 * bytesPerRow + i*2 + 2] = i; + + if (i & 1) { + out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX); + bits[y * bytesPerRow + i*2 + 2] = 0xff; + bits[y * bytesPerRow + i*2 + 3] = 0xff; + } + if (i & 2) { + out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX); + bits[y * bytesPerRow + i*2 + 2] = 0xff; + bits[y * bytesPerRow + i*2 + 3] = 0xff; + } + if (i & 4) { + out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX); + bits[y * bytesPerRow + i*2 + 2] = 0xff; + bits[y * bytesPerRow + i*2 + 3] = 0xff; + } + if (i & 8) { + out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX); + bits[y * bytesPerRow + i*2 + 2] = 0xff; + bits[y * bytesPerRow + i*2 + 3] = 0xff; + } + } + } + + // enable all planes again + out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX); +#endif } } @@ -497,14 +572,16 @@ platform_init_video(void) // Obviously, some graphics card BIOS implementations don't // report all available modes unless you've done this before // getting the VESA information. - // One example of those is the SiS 630 chipset on my laptop. + // One example of those is the SiS 630 chipset in my laptop. - sVesaCompatible = vesa_init(&sInfo, &sMode) == B_OK; + sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK; if (!sVesaCompatible) { TRACE(("No VESA compatible graphics!\n")); return B_ERROR; } + sMode = sDefaultMode; + TRACE(("VESA compatible graphics!\n")); return B_OK; diff --git a/src/kernel/core/debug/frame_buffer_console.cpp b/src/kernel/core/debug/frame_buffer_console.cpp index 5b1423bef5..f9d0f12d08 100644 --- a/src/kernel/core/debug/frame_buffer_console.cpp +++ b/src/kernel/core/debug/frame_buffer_console.cpp @@ -100,24 +100,55 @@ get_palette_entry(uint8 index) static void render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr) { - uint8 *base = (uint8 *)(sConsole.frame_buffer + sConsole.bytes_per_row * y * CHAR_HEIGHT - + x * CHAR_WIDTH * sConsole.bytes_per_pixel); - uint8 *color = get_palette_entry(foreground_color(attr)); - uint8 *backgroundColor = get_palette_entry(background_color(attr)); - - for (y = 0; y < CHAR_HEIGHT; y++) { - uint8 bits = FONT[CHAR_HEIGHT * glyph + y]; - for (x = 0; x < CHAR_WIDTH; x++) { - for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) { - if (bits & 1) - base[x * sConsole.bytes_per_pixel + i] = color[i]; - else - base[x * sConsole.bytes_per_pixel + i] = backgroundColor[i]; + if (sConsole.depth >= 8) { + uint8 *base = (uint8 *)(sConsole.frame_buffer + sConsole.bytes_per_row * y * CHAR_HEIGHT + + x * CHAR_WIDTH * sConsole.bytes_per_pixel); + uint8 *color = get_palette_entry(foreground_color(attr)); + uint8 *backgroundColor = get_palette_entry(background_color(attr)); + + for (y = 0; y < CHAR_HEIGHT; y++) { + uint8 bits = FONT[CHAR_HEIGHT * glyph + y]; + for (x = 0; x < CHAR_WIDTH; x++) { + for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) { + if (bits & 1) + base[x * sConsole.bytes_per_pixel + i] = color[i]; + else + base[x * sConsole.bytes_per_pixel + i] = backgroundColor[i]; + } + bits >>= 1; } - bits >>= 1; + + base += sConsole.bytes_per_row; } + } else { + // monochrome mode - base += sConsole.bytes_per_row; + uint8 *base = (uint8 *)(sConsole.frame_buffer + sConsole.bytes_per_row * y * CHAR_HEIGHT + + x * CHAR_WIDTH / 8); + uint8 baseOffset = (x * CHAR_WIDTH) & 0x7; + + for (y = 0; y < CHAR_HEIGHT; y++) { + uint8 bits = FONT[CHAR_HEIGHT * glyph + y]; + uint8 offset = baseOffset; + uint8 mask = 1 << (7 - baseOffset); + + for (x = 0; x < CHAR_WIDTH; x++) { + if (mask == 0) + mask = 128; + + // black on white + if (bits & 1) + base[offset / 8] &= ~mask; + else + base[offset / 8] |= mask; + + bits >>= 1; + mask >>= 1; + offset += 1; + } + + base += sConsole.bytes_per_row; + } } } @@ -134,6 +165,11 @@ draw_cursor(int32 x, int32 y) int32 endY = y + CHAR_HEIGHT; uint8 *base = (uint8 *)(sConsole.frame_buffer + y * sConsole.bytes_per_row); + if (sConsole.depth < 8) { + x /= 8; + endY /= 8; + } + for (; y < endY; y++) { for (int32 x2 = x; x2 < endX; x2++) base[x2] = ~base[x2]; @@ -200,12 +236,20 @@ static void console_blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty) { height *= CHAR_HEIGHT; - width *= CHAR_WIDTH * sConsole.bytes_per_pixel; - srcx *= CHAR_WIDTH * sConsole.bytes_per_pixel; srcy *= CHAR_HEIGHT; - destx *= CHAR_WIDTH * sConsole.bytes_per_pixel; desty *= CHAR_HEIGHT; + if (sConsole.depth >= 8) { + width *= CHAR_WIDTH * sConsole.bytes_per_pixel; + srcx *= CHAR_WIDTH * sConsole.bytes_per_pixel; + destx *= CHAR_WIDTH * sConsole.bytes_per_pixel; + } else { + // monochrome mode + width = width * CHAR_WIDTH / 8; + srcx = srcx * CHAR_WIDTH / 8; + destx = destx * CHAR_WIDTH / 8; + } + for (int32 y = 0; y < height; y++) { memmove((void *)(sConsole.frame_buffer + (desty + y) * sConsole.bytes_per_row + destx), (void *)(sConsole.frame_buffer + (srcy + y) * sConsole.bytes_per_row + srcx), width); @@ -218,8 +262,14 @@ console_clear(uint8 attr) { switch (sConsole.bytes_per_pixel) { case 1: - memset((void *)sConsole.frame_buffer, sPalette8[background_color(attr)], - sConsole.height * sConsole.bytes_per_row); + if (sConsole.depth >= 8) { + memset((void *)sConsole.frame_buffer, sPalette8[background_color(attr)], + sConsole.height * sConsole.bytes_per_row); + } else { + // special case for VGA mode + memset((void *)sConsole.frame_buffer, 0xff, + sConsole.height * sConsole.bytes_per_row); + } break; default: { @@ -323,6 +373,11 @@ frame_buffer_console_init(kernel_args *args) int32 bytesPerRow = args->frame_buffer.width; switch (args->frame_buffer.depth) { + case 1: + case 4: + // special VGA mode (will always be treated as monochrome) + bytesPerRow /= 8; + break; case 15: case 16: bytesPerRow *= 2;