From 7b52e9d3f99e7b3c677a6bf3ed5c2ea8bb8f4b44 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 24 Aug 2026 13:05:24 +0200 Subject: [PATCH] feat(drivers): add VGA text-mode driver with scrolling and cursor --- include/vga.h | 31 +++++++++++++++++ src/vga.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 include/vga.h create mode 100644 src/vga.c diff --git a/include/vga.h b/include/vga.h new file mode 100644 index 0000000..95b57fd --- /dev/null +++ b/include/vga.h @@ -0,0 +1,31 @@ +#ifndef FROSTBYTE_VGA_H +#define FROSTBYTE_VGA_H + +#include "types.h" + +typedef enum { + vgaBlack = 0, + vgaBlue = 1, + vgaGreen = 2, + vgaCyan = 3, + vgaRed = 4, + vgaMagenta = 5, + vgaBrown = 6, + vgaLightGrey = 7, + vgaDarkGrey = 8, + vgaLightBlue = 9, + vgaLightGreen = 10, + vgaLightCyan = 11, + vgaLightRed = 12, + vgaPink = 13, + vgaYellow = 14, + vgaWhite = 15 +} VgaColor; + +void vgaInit(void); +void vgaClear(void); +void vgaPutChar(char c); +void vgaWriteString(const char* str); +void vgaSetColor(VgaColor foreground, VgaColor background); + +#endif diff --git a/src/vga.c b/src/vga.c new file mode 100644 index 0000000..4ab6e2f --- /dev/null +++ b/src/vga.c @@ -0,0 +1,93 @@ +#include "vga.h" +#include "ports.h" + +#define vgaWidth 80 +#define vgaHeight 25 +#define vgaBuffer 0xB8000 + +static volatile uint16* const screen = (volatile uint16*)vgaBuffer; +static uint32 cursorRow; +static uint32 cursorColumn; +static uint8 currentColor; + +static uint16 makeCell(char c, uint8 color) +{ + return (uint16)c | ((uint16)color << 8); +} + +static void updateHardwareCursor(void) +{ + uint16 position = (uint16)(cursorRow * vgaWidth + cursorColumn); + outb(0x3D4, 0x0F); + outb(0x3D5, (uint8)(position & 0xFF)); + outb(0x3D4, 0x0E); + outb(0x3D5, (uint8)((position >> 8) & 0xFF)); +} + +void vgaSetColor(VgaColor foreground, VgaColor background) +{ + currentColor = (uint8)foreground | (uint8)(background << 4); +} + +void vgaClear(void) +{ + for (uint32 y = 0; y < vgaHeight; y++) { + for (uint32 x = 0; x < vgaWidth; x++) + screen[y * vgaWidth + x] = makeCell(' ', currentColor); + } + cursorRow = 0; + cursorColumn = 0; + updateHardwareCursor(); +} + +void vgaInit(void) +{ + currentColor = (uint8)vgaLightGrey | (uint8)(vgaBlack << 4); + vgaClear(); +} + +static void scroll(void) +{ + for (uint32 y = 1; y < vgaHeight; y++) { + for (uint32 x = 0; x < vgaWidth; x++) + screen[(y - 1) * vgaWidth + x] = screen[y * vgaWidth + x]; + } + for (uint32 x = 0; x < vgaWidth; x++) + screen[(vgaHeight - 1) * vgaWidth + x] = makeCell(' ', currentColor); + cursorRow = vgaHeight - 1; +} + +void vgaPutChar(char c) +{ + if (c == '\n') { + cursorColumn = 0; + cursorRow++; + } else if (c == '\r') { + cursorColumn = 0; + } else if (c == '\b') { + if (cursorColumn > 0) { + cursorColumn--; + screen[cursorRow * vgaWidth + cursorColumn] = makeCell(' ', currentColor); + } + } else if (c == '\t') { + cursorColumn = (cursorColumn + 4) & ~3u; + } else { + screen[cursorRow * vgaWidth + cursorColumn] = makeCell(c, currentColor); + cursorColumn++; + } + + if (cursorColumn >= vgaWidth) { + cursorColumn = 0; + cursorRow++; + } + if (cursorRow >= vgaHeight) + scroll(); + + updateHardwareCursor(); +} + +void vgaWriteString(const char* str) +{ + while (*str) + vgaPutChar(*str++); +}