270 lines
5.9 KiB
C
270 lines
5.9 KiB
C
|
/* -*- Mode: C; c-basic-offset: 3 -*-
|
||
|
*
|
||
|
* console_vga.c - Console driver for VGA text mode.
|
||
|
*
|
||
|
* This file is part of Metalkit, a simple collection of modules for
|
||
|
* writing software that runs on the bare metal. Get the latest code
|
||
|
* at http://svn.navi.cx/misc/trunk/metalkit/
|
||
|
*
|
||
|
* Copyright (c) 2008-2009 Micah Dowty
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person
|
||
|
* obtaining a copy of this software and associated documentation
|
||
|
* files (the "Software"), to deal in the Software without
|
||
|
* restriction, including without limitation the rights to use,
|
||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the
|
||
|
* Software is furnished to do so, subject to the following
|
||
|
* conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be
|
||
|
* included in all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include "types.h"
|
||
|
#include "console_vga.h"
|
||
|
#include "io.h"
|
||
|
#include "intr.h"
|
||
|
|
||
|
#define VGA_TEXT_FRAMEBUFFER ((uint8*)0xB8000)
|
||
|
|
||
|
#define VGA_CRTCREG_CURSOR_LOC_HIGH 0x0E
|
||
|
#define VGA_CRTCREG_CURSOR_LOC_LOW 0x0F
|
||
|
|
||
|
typedef struct {
|
||
|
uint16 crtc_iobase;
|
||
|
struct {
|
||
|
int8 x, y;
|
||
|
} cursor;
|
||
|
int8 attr;
|
||
|
} ConsoleVGAObject;
|
||
|
|
||
|
ConsoleVGAObject gConsoleVGA[1];
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGAWriteCRTC --
|
||
|
*
|
||
|
* Write to a VGA CRT Control register.
|
||
|
*/
|
||
|
|
||
|
static fastcall void
|
||
|
ConsoleVGAWriteCRTC(uint8 addr, uint8 value)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
IO_Out8(self->crtc_iobase, addr);
|
||
|
IO_Out8(self->crtc_iobase + 1, value);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGAMoveHardwareCursor --
|
||
|
*
|
||
|
* Set the hardware cursor to the current cursor position.
|
||
|
*/
|
||
|
|
||
|
static fastcall void
|
||
|
ConsoleVGAMoveHardwareCursor(void)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
uint16 loc = self->cursor.x + self->cursor.y * VGA_TEXT_WIDTH;
|
||
|
|
||
|
ConsoleVGAWriteCRTC(VGA_CRTCREG_CURSOR_LOC_LOW, loc & 0xFF);
|
||
|
ConsoleVGAWriteCRTC(VGA_CRTCREG_CURSOR_LOC_HIGH, loc >> 8);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGAMoveTo --
|
||
|
*
|
||
|
* Set the text insertion point. This will move the hardware cursor
|
||
|
* at the next Console_Flush().
|
||
|
*/
|
||
|
|
||
|
static fastcall void
|
||
|
ConsoleVGAMoveTo(int x, int y)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
|
||
|
self->cursor.x = x;
|
||
|
self->cursor.y = y;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGA_Clear --
|
||
|
*
|
||
|
* Clear the screen and move the cursor to the home position.
|
||
|
*/
|
||
|
|
||
|
static fastcall void
|
||
|
ConsoleVGAClear(void)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
uint8 *fb = VGA_TEXT_FRAMEBUFFER;
|
||
|
int i, j;
|
||
|
|
||
|
ConsoleVGAMoveTo(0, 0);
|
||
|
|
||
|
for (j = 0; j < VGA_TEXT_HEIGHT; j++) {
|
||
|
for (i = 0; i < VGA_TEXT_WIDTH; i++) {
|
||
|
fb[0] = ' ';
|
||
|
fb[1] = self->attr;
|
||
|
fb += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGA_SetColor --
|
||
|
*
|
||
|
* Set the text foreground color.
|
||
|
*/
|
||
|
|
||
|
fastcall void
|
||
|
ConsoleVGA_SetColor(int8 fgColor)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
|
||
|
self->attr &= 0xF0;
|
||
|
self->attr |= fgColor;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGA_SetColor --
|
||
|
*
|
||
|
* Set the text background color.
|
||
|
*/
|
||
|
|
||
|
fastcall void
|
||
|
ConsoleVGA_SetBgColor(int8 bgColor)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
|
||
|
self->attr &= 0x0F;
|
||
|
self->attr |= bgColor << 4;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGAWriteChar --
|
||
|
*
|
||
|
* Write one character, TTY-style. Interprets \n characters.
|
||
|
*/
|
||
|
|
||
|
static fastcall void
|
||
|
ConsoleVGAWriteChar(char c)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
uint8 *fb = VGA_TEXT_FRAMEBUFFER;
|
||
|
|
||
|
if (c == '\n') {
|
||
|
self->cursor.y++;
|
||
|
self->cursor.x = 0;
|
||
|
|
||
|
} else if (c == '\t') {
|
||
|
while (self->cursor.x & 7) {
|
||
|
ConsoleVGAWriteChar(' ');
|
||
|
}
|
||
|
|
||
|
} else if (c == '\b') {
|
||
|
if (self->cursor.x > 0) {
|
||
|
self->cursor.x--;
|
||
|
ConsoleVGAWriteChar(' ');
|
||
|
self->cursor.x--;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
fb += self->cursor.x * 2 + self->cursor.y * VGA_TEXT_WIDTH * 2;
|
||
|
fb[0] = c;
|
||
|
fb[1] = self->attr;
|
||
|
self->cursor.x++;
|
||
|
}
|
||
|
|
||
|
if (self->cursor.x >= VGA_TEXT_WIDTH) {
|
||
|
self->cursor.x = 0;
|
||
|
self->cursor.y++;
|
||
|
}
|
||
|
|
||
|
if (self->cursor.y >= VGA_TEXT_HEIGHT) {
|
||
|
int i;
|
||
|
uint8 *fb = VGA_TEXT_FRAMEBUFFER;
|
||
|
const uint32 scrollSize = VGA_TEXT_WIDTH * 2 * (VGA_TEXT_HEIGHT - 1);
|
||
|
|
||
|
self->cursor.y = VGA_TEXT_HEIGHT - 1;
|
||
|
|
||
|
memcpy(fb, fb + VGA_TEXT_WIDTH * 2, scrollSize);
|
||
|
fb += scrollSize;
|
||
|
for (i = 0; i < VGA_TEXT_WIDTH; i++) {
|
||
|
fb[0] = ' ';
|
||
|
fb[1] = self->attr;
|
||
|
fb += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGABeginPanic --
|
||
|
*
|
||
|
* Prepare for a panic in VGA mode: Set up the panic colors,
|
||
|
* and clear the screen.
|
||
|
*/
|
||
|
|
||
|
static fastcall void
|
||
|
ConsoleVGABeginPanic(void)
|
||
|
{
|
||
|
ConsoleVGA_SetColor(VGA_COLOR_WHITE);
|
||
|
ConsoleVGA_SetBgColor(VGA_COLOR_RED);
|
||
|
ConsoleVGAClear();
|
||
|
ConsoleVGAMoveHardwareCursor();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConsoleVGA_Init --
|
||
|
*
|
||
|
* Perform first-time initialization for VGA text mode,
|
||
|
* set VGA as the current console driver, and clear the
|
||
|
* screen with a default color.
|
||
|
*/
|
||
|
|
||
|
fastcall void
|
||
|
ConsoleVGA_Init(void)
|
||
|
{
|
||
|
ConsoleVGAObject *self = gConsoleVGA;
|
||
|
|
||
|
/*
|
||
|
* Read the I/O address select bit, to determine where the CRTC
|
||
|
* registers are.
|
||
|
*/
|
||
|
if (IO_In8(0x3CC) & 1) {
|
||
|
self->crtc_iobase = 0x3D4;
|
||
|
} else {
|
||
|
self->crtc_iobase = 0x3B4;
|
||
|
}
|
||
|
|
||
|
gConsole.beginPanic = ConsoleVGABeginPanic;
|
||
|
gConsole.clear = ConsoleVGAClear;
|
||
|
gConsole.moveTo = ConsoleVGAMoveTo;
|
||
|
gConsole.writeChar = ConsoleVGAWriteChar;
|
||
|
gConsole.flush = ConsoleVGAMoveHardwareCursor;
|
||
|
|
||
|
ConsoleVGA_SetColor(VGA_COLOR_WHITE);
|
||
|
ConsoleVGA_SetBgColor(VGA_COLOR_BLUE);
|
||
|
|
||
|
ConsoleVGAClear();
|
||
|
ConsoleVGAMoveHardwareCursor();
|
||
|
}
|