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;