148 lines
3.4 KiB
C
148 lines
3.4 KiB
C
|
//----------------------------------------------------------------------------//
|
||
|
// GNU GPL OS/K //
|
||
|
// //
|
||
|
// Authors: spectral` //
|
||
|
// NeoX //
|
||
|
// //
|
||
|
// Desc: Early terminal functions //
|
||
|
//----------------------------------------------------------------------------//
|
||
|
|
||
|
#include "kernel/io/terminal.h"
|
||
|
|
||
|
// VGA buffer size
|
||
|
static const size_t kterm_width = 80;
|
||
|
static const size_t kterm_height = 25;
|
||
|
|
||
|
// position in the buffer
|
||
|
static size_t current_row;
|
||
|
static size_t current_col;
|
||
|
|
||
|
static uchar current_color;
|
||
|
|
||
|
// each buffer entry is composed of two bytes
|
||
|
// one is the color code, the other the character
|
||
|
static ushort *const buffer = (ushort *)0xB8000;
|
||
|
|
||
|
#define ComputeColorCode(fg, bg) ((fg) | (bg) << 4)
|
||
|
#define ComputeEntryOffset(x, y) ((y) * kterm_width + (x))
|
||
|
#define ComputeEntry(ch, cl) (((ushort)(ch)) | (ushort)(cl) << 8)
|
||
|
|
||
|
void kterm_init(void)
|
||
|
{
|
||
|
assert_never_used(kterm_init);
|
||
|
|
||
|
kterm_change_color(ComputeColorCode(KTERM_COLOR_LIGHT_GREY, KTERM_COLOR_BLACK));
|
||
|
kterm_clear();
|
||
|
}
|
||
|
|
||
|
void kterm_clear(void)
|
||
|
{
|
||
|
size_t x, y;
|
||
|
|
||
|
assert_used_once(kterm_init);
|
||
|
|
||
|
for (x = 0; x < kterm_width; x++) {
|
||
|
for (y = 0; y < kterm_height; y++) {
|
||
|
const size_t offset = ComputeEntryOffset(x,y);
|
||
|
buffer[offset] = ComputeEntry(' ', current_color);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// go back to beginning
|
||
|
current_row = current_col = 0;
|
||
|
|
||
|
// XXX cursor update
|
||
|
}
|
||
|
|
||
|
status_t kterm_change_color(uchar color)
|
||
|
{
|
||
|
if (color > KTERM_COLOR_WHITE)
|
||
|
return BAD_ARG_RANGE;
|
||
|
|
||
|
current_color = color;
|
||
|
|
||
|
return SUCCESS;
|
||
|
}
|
||
|
|
||
|
void kterm_putchar(char ch)
|
||
|
{
|
||
|
int i;
|
||
|
size_t prev;
|
||
|
|
||
|
assert_used_once(kterm_init);
|
||
|
|
||
|
// carriage return takes us back to the beginning of the line
|
||
|
// no further test should be necessary
|
||
|
if (ch == '\r') { current_col = 0; return; }
|
||
|
|
||
|
// line feed first takes us to the very end of the line
|
||
|
// later in this function we actually do the line feed
|
||
|
else if (ch == '\n') { current_col = kterm_width - 1; }
|
||
|
|
||
|
// tabulations account for 4 spaces
|
||
|
else if (ch == '\t') {
|
||
|
prev = current_row;
|
||
|
// compiler will optimize this away
|
||
|
for (i = 0; i < 4; i++) {
|
||
|
// tabulations can't spread over two lines
|
||
|
if (current_row != prev) return;
|
||
|
|
||
|
kterm_putchar(' ');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// XXX check whether we were given a writable character
|
||
|
else {
|
||
|
const size_t offset = ComputeEntryOffset(current_col, current_row);
|
||
|
buffer[offset] = ComputeEntry(ch, current_color);
|
||
|
}
|
||
|
|
||
|
// end of line?
|
||
|
if (++current_col == kterm_width) {
|
||
|
current_col = 0;
|
||
|
|
||
|
// end of buffer?
|
||
|
if (++current_row == kterm_height) {
|
||
|
current_row = 0;
|
||
|
// XXX save previous buffer(?) and clear
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void kterm_print(const char *s)
|
||
|
{
|
||
|
while (*s) {
|
||
|
kterm_putchar(*s);
|
||
|
s++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void panic(const char *s)
|
||
|
{
|
||
|
cli();
|
||
|
|
||
|
panicstr = s;
|
||
|
|
||
|
kterm_clear();
|
||
|
|
||
|
kterm_print("panic! - ");
|
||
|
kterm_print(s);
|
||
|
|
||
|
while (1) hlt();
|
||
|
|
||
|
__builtin_unreachable();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|