#include #include #include #include #include #include #include "vga.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()); }