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
This commit is contained in:
parent
56aa0c51dc
commit
d3ff9cc39a
38
src/kernel/boot/platform/bios_ia32/vga.h
Normal file
38
src/kernel/boot/platform/bios_ia32/vga.h
Normal file
@ -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 */
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user