290 lines
8.3 KiB
C
290 lines
8.3 KiB
C
#if defined (BIOS)
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
#include <drivers/vga_textmode.h>
|
|
#include <sys/cpu.h>
|
|
#include <lib/real.h>
|
|
#include <lib/libc.h>
|
|
#include <lib/misc.h>
|
|
#include <lib/term.h>
|
|
#include <mm/pmm.h>
|
|
|
|
#define VIDEO_BOTTOM ((VD_ROWS * VD_COLS) - 1)
|
|
#define VD_COLS (80 * 2)
|
|
#define VD_ROWS 25
|
|
|
|
static void draw_cursor(struct textmode_context *ctx) {
|
|
uint8_t pal = ctx->back_buffer[ctx->cursor_offset + 1];
|
|
ctx->video_mem[ctx->cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4);
|
|
}
|
|
|
|
void text_save_state(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->saved_state_text_palette = ctx->text_palette;
|
|
ctx->saved_state_cursor_offset = ctx->cursor_offset;
|
|
}
|
|
|
|
void text_restore_state(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = ctx->saved_state_text_palette;
|
|
ctx->cursor_offset = ctx->saved_state_cursor_offset;
|
|
}
|
|
|
|
void text_swap_palette(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = (ctx->text_palette << 4) | (ctx->text_palette >> 4);
|
|
}
|
|
|
|
void text_scroll(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
// move the text up by one row
|
|
for (size_t i = _ctx->scroll_top_margin * VD_COLS;
|
|
i < (_ctx->scroll_bottom_margin - 1) * VD_COLS; i++) {
|
|
ctx->back_buffer[i] = ctx->back_buffer[i + VD_COLS];
|
|
}
|
|
// clear the last line of the screen
|
|
for (size_t i = (_ctx->scroll_bottom_margin - 1) * VD_COLS;
|
|
i < _ctx->scroll_bottom_margin * VD_COLS; i += 2) {
|
|
ctx->back_buffer[i] = ' ';
|
|
ctx->back_buffer[i + 1] = ctx->text_palette;
|
|
}
|
|
}
|
|
|
|
void text_revscroll(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
// move the text up by one row
|
|
for (size_t i = (_ctx->scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) {
|
|
ctx->back_buffer[i + VD_COLS] = ctx->back_buffer[i];
|
|
if (i == _ctx->scroll_top_margin * VD_COLS) {
|
|
break;
|
|
}
|
|
}
|
|
// clear the first line of the screen
|
|
for (size_t i = _ctx->scroll_top_margin * VD_COLS;
|
|
i < (_ctx->scroll_top_margin + 1) * VD_COLS; i += 2) {
|
|
ctx->back_buffer[i] = ' ';
|
|
ctx->back_buffer[i + 1] = ctx->text_palette;
|
|
}
|
|
}
|
|
|
|
void text_clear(struct term_context *_ctx, bool move) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) {
|
|
ctx->back_buffer[i] = ' ';
|
|
ctx->back_buffer[i + 1] = ctx->text_palette;
|
|
}
|
|
if (move) {
|
|
ctx->cursor_offset = 0;
|
|
}
|
|
}
|
|
|
|
void text_enable_cursor(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
ctx->cursor_status = true;
|
|
}
|
|
|
|
bool text_disable_cursor(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
bool ret = ctx->cursor_status;
|
|
ctx->cursor_status = false;
|
|
return ret;
|
|
}
|
|
|
|
void text_full_refresh(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
|
|
ctx->video_mem[i] = ctx->front_buffer[i];
|
|
ctx->back_buffer[i] = ctx->front_buffer[i];
|
|
}
|
|
|
|
if (ctx->cursor_status) {
|
|
draw_cursor(ctx);
|
|
ctx->old_cursor_offset = ctx->cursor_offset;
|
|
}
|
|
}
|
|
|
|
void init_vga_textmode(size_t *_rows, size_t *_cols, bool managed) {
|
|
if (current_video_mode != 0x3) {
|
|
struct rm_regs r = {0};
|
|
r.eax = 0x0003;
|
|
rm_int(0x10, &r, &r);
|
|
|
|
current_video_mode = 0x3;
|
|
}
|
|
|
|
struct textmode_context *ctx = (void *)term;
|
|
|
|
if (ctx->back_buffer == NULL) {
|
|
ctx->back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
|
|
} else {
|
|
memset(ctx->back_buffer, 0, VD_ROWS * VD_COLS);
|
|
}
|
|
if (ctx->front_buffer == NULL) {
|
|
ctx->front_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
|
|
} else {
|
|
memset(ctx->front_buffer, 0, VD_ROWS * VD_COLS);
|
|
}
|
|
|
|
ctx->cursor_offset = 0;
|
|
ctx->cursor_status = true;
|
|
ctx->text_palette = 0x07;
|
|
|
|
ctx->video_mem = (volatile uint8_t *)0xb8000;
|
|
|
|
text_clear(term, false);
|
|
|
|
*_rows = VD_ROWS;
|
|
*_cols = VD_COLS / 2;
|
|
|
|
// VGA cursor code taken from: https://wiki.osdev.org/Text_Mode_Cursor
|
|
|
|
if (!managed) {
|
|
text_disable_cursor(term);
|
|
|
|
outb(0x3d4, 0x0a);
|
|
outb(0x3d5, (inb(0x3d5) & 0xc0) | 14);
|
|
outb(0x3d4, 0x0b);
|
|
outb(0x3d5, (inb(0x3d5) & 0xe0) | 15);
|
|
outb(0x3d4, 0x0f);
|
|
outb(0x3d5, 0);
|
|
outb(0x3d4, 0x0e);
|
|
outb(0x3d5, 0);
|
|
|
|
struct rm_regs r = {0};
|
|
r.eax = 0x0200;
|
|
rm_int(0x10, &r, &r);
|
|
} else {
|
|
outb(0x3d4, 0x0a);
|
|
outb(0x3d5, 0x20);
|
|
}
|
|
|
|
text_double_buffer_flush(term);
|
|
}
|
|
|
|
void text_double_buffer_flush(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
if (ctx->cursor_status) {
|
|
draw_cursor(ctx);
|
|
}
|
|
|
|
if (ctx->cursor_offset != ctx->old_cursor_offset || ctx->cursor_status == false) {
|
|
ctx->video_mem[ctx->old_cursor_offset + 1] = ctx->back_buffer[ctx->old_cursor_offset + 1];
|
|
}
|
|
|
|
for (size_t i = 0; i < VD_ROWS * VD_COLS; i++) {
|
|
if (ctx->back_buffer[i] == ctx->front_buffer[i]) {
|
|
continue;
|
|
}
|
|
|
|
if (ctx->cursor_status && i == ctx->cursor_offset + 1) {
|
|
continue;
|
|
}
|
|
|
|
ctx->front_buffer[i] = ctx->back_buffer[i];
|
|
ctx->video_mem[i] = ctx->back_buffer[i];
|
|
}
|
|
|
|
if (ctx->cursor_status) {
|
|
ctx->old_cursor_offset = ctx->cursor_offset;
|
|
}
|
|
}
|
|
|
|
void text_get_cursor_pos(struct term_context *_ctx, size_t *x, size_t *y) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
*x = (ctx->cursor_offset % VD_COLS) / 2;
|
|
*y = ctx->cursor_offset / VD_COLS;
|
|
}
|
|
|
|
void text_move_character(struct term_context *_ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
if (old_x >= VD_COLS / 2 || old_y >= VD_ROWS
|
|
|| new_x >= VD_COLS / 2 || new_y >= VD_ROWS) {
|
|
return;
|
|
}
|
|
|
|
ctx->back_buffer[new_y * VD_COLS + new_x * 2] = ctx->back_buffer[old_y * VD_COLS + old_x * 2];
|
|
}
|
|
|
|
void text_set_cursor_pos(struct term_context *_ctx, size_t x, size_t y) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
if (x >= VD_COLS / 2) {
|
|
if ((int)x < 0) {
|
|
x = 0;
|
|
} else {
|
|
x = VD_COLS / 2 - 1;
|
|
}
|
|
}
|
|
if (y >= VD_ROWS) {
|
|
if ((int)y < 0) {
|
|
y = 0;
|
|
} else {
|
|
y = VD_ROWS - 1;
|
|
}
|
|
}
|
|
ctx->cursor_offset = y * VD_COLS + x * 2;
|
|
}
|
|
|
|
static uint8_t ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
|
|
|
void text_set_text_fg(struct term_context *_ctx, size_t fg) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = (ctx->text_palette & 0xf0) | ansi_colours[fg];
|
|
}
|
|
|
|
void text_set_text_bg(struct term_context *_ctx, size_t bg) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = (ctx->text_palette & 0x0f) | (ansi_colours[bg] << 4);
|
|
}
|
|
|
|
void text_set_text_fg_bright(struct term_context *_ctx, size_t fg) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = (ctx->text_palette & 0xf0) | (ansi_colours[fg] | (1 << 3));
|
|
}
|
|
|
|
void text_set_text_bg_bright(struct term_context *_ctx, size_t bg) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = (ctx->text_palette & 0x0f) | ((ansi_colours[bg] | (1 << 3)) << 4);
|
|
}
|
|
|
|
void text_set_text_fg_default(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette = (ctx->text_palette & 0xf0) | 7;
|
|
}
|
|
|
|
void text_set_text_bg_default(struct term_context *_ctx) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
ctx->text_palette &= 0x0f;
|
|
}
|
|
|
|
void text_putchar(struct term_context *_ctx, uint8_t c) {
|
|
struct textmode_context *ctx = (void *)_ctx;
|
|
|
|
ctx->back_buffer[ctx->cursor_offset] = c;
|
|
ctx->back_buffer[ctx->cursor_offset + 1] = ctx->text_palette;
|
|
if (ctx->cursor_offset / VD_COLS == _ctx->scroll_bottom_margin - 1
|
|
&& ctx->cursor_offset % VD_COLS == VD_COLS - 2) {
|
|
if (_ctx->scroll_enabled) {
|
|
text_scroll(_ctx);
|
|
ctx->cursor_offset -= ctx->cursor_offset % VD_COLS;
|
|
}
|
|
} else if (ctx->cursor_offset >= (VIDEO_BOTTOM - 1)) {
|
|
ctx->cursor_offset -= ctx->cursor_offset % VD_COLS;
|
|
} else {
|
|
ctx->cursor_offset += 2;
|
|
}
|
|
}
|
|
|
|
#endif
|