132 lines
2.7 KiB
C
132 lines
2.7 KiB
C
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <kernel/tty.h>
|
|
|
|
#include "vga.h"
|
|
#include "io.h"
|
|
|
|
/* I/O ports */
|
|
#define VGA_COMMAND_PORT 0x3D4
|
|
#define VGA_DATA_PORT 0x3D5
|
|
|
|
/* I/O port commands */
|
|
#define VGA_HIGH_BYTE_COMMAND 14
|
|
#define VGA_LOW_BYTE_COMMAND 15
|
|
|
|
static const size_t VGA_WIDTH = 80;
|
|
static const size_t VGA_HEIGHT = 25;
|
|
static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000;
|
|
|
|
static size_t terminal_row;
|
|
static size_t terminal_column;
|
|
static uint8_t terminal_colour;
|
|
static struct vga_entry* terminal_buffer;
|
|
|
|
struct vga_entry {
|
|
char c;
|
|
unsigned char colour;
|
|
} __attribute__((packed));
|
|
|
|
void terminal_set_colour(uint8_t colour)
|
|
{
|
|
terminal_colour = colour;
|
|
}
|
|
|
|
void terminal_clear(void)
|
|
{
|
|
for (size_t y = 0; y < VGA_HEIGHT; y++)
|
|
for (size_t x = 0; x < VGA_WIDTH; x++)
|
|
terminal_write_cell((y * VGA_WIDTH) + x, ' ');
|
|
terminal_move_cursor(0);
|
|
}
|
|
|
|
void terminal_initialize(void)
|
|
{
|
|
terminal_row = 0;
|
|
terminal_column = 0;
|
|
|
|
terminal_buffer = (struct vga_entry*) VGA_MEMORY;
|
|
terminal_set_colour(vga_entry_colour(VGA_COLOUR_LIGHT_GREY, VGA_COLOUR_BLACK));
|
|
|
|
terminal_clear();
|
|
}
|
|
|
|
void terminal_move_cursor(unsigned short pos)
|
|
{
|
|
if (terminal_row >= VGA_HEIGHT)
|
|
terminal_scroll_screen();
|
|
|
|
outb(VGA_COMMAND_PORT, VGA_HIGH_BYTE_COMMAND);
|
|
outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF));
|
|
outb(VGA_COMMAND_PORT, VGA_LOW_BYTE_COMMAND);
|
|
outb(VGA_DATA_PORT, pos & 0x00FF);
|
|
}
|
|
|
|
inline size_t terminal_get_pos(void)
|
|
{return (terminal_row * VGA_WIDTH) + terminal_column;}
|
|
|
|
void terminal_write_cell(unsigned int i, char c)
|
|
{
|
|
struct vga_entry entry;
|
|
|
|
entry.c = c;
|
|
entry.colour = terminal_colour;
|
|
|
|
terminal_buffer[i] = entry;
|
|
}
|
|
|
|
void terminal_write_character(unsigned int i, char c)
|
|
{
|
|
switch(c) {
|
|
case '\n':
|
|
terminal_row += 1;
|
|
__attribute__((fallthrough));
|
|
case '\r':
|
|
terminal_column = 0;
|
|
terminal_move_cursor(terminal_get_pos());
|
|
break;
|
|
default:
|
|
terminal_write_cell(i, c);
|
|
|
|
terminal_column += 1;
|
|
if (terminal_column >= VGA_WIDTH) {
|
|
terminal_column = 0;
|
|
terminal_row += 1;
|
|
}
|
|
|
|
terminal_move_cursor(terminal_get_pos());
|
|
}
|
|
}
|
|
|
|
void terminal_write(const char* buf, size_t len)
|
|
{
|
|
for (size_t i = 0; i < len; i++)
|
|
terminal_write_character(terminal_get_pos(), buf[i]);
|
|
}
|
|
|
|
void terminal_writestring(const char* buf)
|
|
{
|
|
terminal_write(buf, strlen(buf));
|
|
}
|
|
|
|
void terminal_scroll_screen(void)
|
|
{
|
|
size_t y, x;
|
|
for (y = 0; y < VGA_HEIGHT -1; y++) {
|
|
for (x = 0; x < VGA_WIDTH; x++) {
|
|
terminal_buffer[(y * VGA_WIDTH) + x] =
|
|
terminal_buffer[((y + 1) * VGA_WIDTH) + x];
|
|
}
|
|
}
|
|
for (x = 0; x < VGA_WIDTH; x++)
|
|
terminal_write_cell(((VGA_HEIGHT - 1) * VGA_WIDTH) + x, ' ');
|
|
|
|
terminal_row -= 1;
|
|
terminal_column = 0;
|
|
terminal_move_cursor(terminal_get_pos());
|
|
}
|
|
|