From 9274c9ee2fb9562ad2548c5b0bf2102e4a194d68 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 15 Dec 2022 19:05:07 +0200 Subject: [PATCH] Kernel: Abstract TTY to use new VESA --- kernel/arch/i386/VESA.cpp | 171 ++++++++++++++++++++++++++++++ kernel/arch/i386/make.config | 1 + kernel/arch/i386/tty.cpp | 200 +++++++++++------------------------ kernel/include/kernel/VESA.h | 36 +++++++ kernel/kernel/kernel.cpp | 19 +++- 5 files changed, 284 insertions(+), 143 deletions(-) create mode 100644 kernel/arch/i386/VESA.cpp create mode 100644 kernel/include/kernel/VESA.h diff --git a/kernel/arch/i386/VESA.cpp b/kernel/arch/i386/VESA.cpp new file mode 100644 index 000000000..4db9bbc41 --- /dev/null +++ b/kernel/arch/i386/VESA.cpp @@ -0,0 +1,171 @@ +#include +#include +#include + +#define MULTIBOOT_FLAGS_FRAMEBUFFER (1 << 12) +#define MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_TEXT 2 + +extern multiboot_info_t* s_multiboot_info; + +namespace VESA +{ + static void* s_addr = nullptr; + static uint8_t s_bpp = 0; + static uint32_t s_width = 0; + static uint32_t s_height = 0; + static uint8_t s_mode = 0; + + static void GraphicsPutCharAt(char ch, uint32_t x, uint32_t y, Color fg, Color bg); + static void GraphicsClear(Color color); + static void GraphicsScrollLine(uint32_t line); + static bool InitializeGraphicsMode(); + + static inline uint8_t TextColor(Color fg, Color bg); + static inline uint16_t TextEntry(uint8_t ch, uint8_t color); + static void TextPutCharAt(char c, uint32_t x, uint32_t y, Color fg, Color bg); + static void TextClear(Color color); + static void TextScrollLine(uint32_t line); + static bool InitializeTextMode(); + + void PutEntryAt(char ch, uint32_t x, uint32_t y, Color fg, Color bg) + { + if (x >= s_width) + return; + if (y >= s_height) + return; + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) + return GraphicsPutCharAt(ch, x, y, fg, bg); + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT) + return TextPutCharAt(ch, x, y, fg, bg); + } + + void Clear(Color color) + { + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) + return GraphicsClear(color); + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT) + return TextClear(color); + } + + void ScrollLine(uint32_t line) + { + if (line == 0 || line >= s_height) + return; + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) + return GraphicsScrollLine(line); + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT) + return TextScrollLine(line); + } + + uint32_t GetWidth() + { + return s_width; + } + + uint32_t GetHeight() + { + return s_height; + } + + bool Initialize() + { + if (!(s_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER)) + return false; + + auto& framebuffer = s_multiboot_info->framebuffer; + s_addr = (void*)framebuffer.addr; + s_bpp = framebuffer.bpp; + s_width = framebuffer.width; + s_height = framebuffer.height; + s_mode = framebuffer.type; + + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) + { + dprintln("VESA in Graphics mode {}x{} ({} bpp)", s_width, s_height, s_bpp); + GraphicsClear(Color::BLACK); + return false; + } + + if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT) + { + dprintln("VESA in Text mode {}x{}", s_width, s_height); + TextClear(Color::BLACK); + return true; + } + + dprintln("Unsupported type for VESA framebuffer"); + return false; + } + + + + + + + static void GraphicsPutCharAt(char ch, uint32_t x, uint32_t y, Color fg, Color bg) + { + + } + + static void GraphicsClear(Color color) + { + + } + + static void GraphicsScrollLine(uint32_t line) + { + + } + + static bool InitializeGraphicsMode() + { + return false; + } + + + + + + + + static inline uint8_t TextColor(Color fg, Color bg) + { + return ((bg & 0x0F) << 4) | (fg & 0x0F); + } + + static inline uint16_t TextEntry(uint8_t ch, uint8_t color) + { + return ((uint16_t)color << 8) | ch; + } + + static void TextPutCharAt(char c, uint32_t x, uint32_t y, Color fg, Color bg) + { + uint64_t index = y * s_width + x; + ((uint16_t*)s_addr)[index] = TextEntry(c, TextColor(fg, bg)); + } + + static void TextClear(Color color) + { + for (uint32_t y = 0; y < s_height; y++) + for (uint32_t x = 0; x < s_width; x++) + TextPutCharAt(' ', x, y, Color::WHITE, color); + } + + static void TextScrollLine(uint32_t line) + { + for (uint32_t x = 0; x < s_width; x++) + { + uint64_t index1 = (line - 0) * s_width + x; + uint64_t index2 = (line - 1) * s_width + x; + ((uint16_t*)s_addr)[index2] = ((uint16_t*)s_addr)[index1]; + } + } + + static bool InitializeTextMode() + { + TextClear(Color::BLACK); + return true; + } + +} \ No newline at end of file diff --git a/kernel/arch/i386/make.config b/kernel/arch/i386/make.config index 1b4311e6e..72d64f34a 100644 --- a/kernel/arch/i386/make.config +++ b/kernel/arch/i386/make.config @@ -11,3 +11,4 @@ $(ARCHDIR)/GDT.o \ $(ARCHDIR)/GDT_asm.o \ $(ARCHDIR)/IDT.o \ $(ARCHDIR)/IDT_asm.o \ +$(ARCHDIR)/VESA.o \ diff --git a/kernel/arch/i386/tty.cpp b/kernel/arch/i386/tty.cpp index 522fab2d7..68957528a 100644 --- a/kernel/arch/i386/tty.cpp +++ b/kernel/arch/i386/tty.cpp @@ -1,12 +1,9 @@ #include -#include #include #include #include +#include -#include "vga.h" - -#include #include #define BEL 0x07 @@ -21,90 +18,48 @@ namespace TTY { - - static size_t VGA_WIDTH; - static size_t VGA_HEIGHT; - static uint16_t* VGA_MEMORY = nullptr; - - static size_t terminal_row; - static size_t terminal_col; - static uint8_t terminal_color; - static uint16_t* terminal_buffer = nullptr; + + static uint32_t terminal_height = 0; + static uint32_t terminal_width = 0; + static uint32_t terminal_row = 0; + static uint32_t terminal_col = 0; + static VESA::Color terminal_fg = VESA::Color::WHITE; + static VESA::Color terminal_bg = VESA::Color::BLACK; static char s_ansi_escape_mode = '\0'; static int s_ansi_escape_index = 0; static int s_ansi_escape_nums[2] = { -1, -1 }; + template inline constexpr T max(T a, T b) { return a > b ? a : b; } + template inline constexpr T min(T a, T b) { return a < b ? a : b; } + template inline constexpr T clamp(T x, T a, T b) { return x < a ? a : x > b ? b : x; } - inline constexpr int max(int a, int b) { return a > b ? a : b; } - inline constexpr int min(int a, int b) { return a < b ? a : b; } - inline constexpr int clamp(int x, int a, int b) { return x < a ? a : x > b ? b : x; } - - void putentryat(unsigned char c, uint8_t color, size_t x, size_t y) + void initialize() { - const size_t index = y * VGA_WIDTH + x; - terminal_buffer[index] = vga_entry(c, color); + terminal_width = VESA::GetWidth(); + terminal_height = VESA::GetHeight(); } void clear() { - for (size_t y = 0; y < VGA_HEIGHT; y++) - for (size_t x = 0; x < VGA_WIDTH; x++) - putentryat(' ', terminal_color, x, y); + VESA::Clear(VESA::Color::BLACK); } - void initialize() + void setcolor(VESA::Color fg, VESA::Color bg) { - if (s_multiboot_info->flags & (1 << 12)) - { - const framebuffer_info_t& fb = s_multiboot_info->framebuffer; - VGA_WIDTH = fb.width; - VGA_HEIGHT = fb.height; - VGA_MEMORY = (uint16_t*)fb.addr; - - dprintln("width: {}, height: {}, bpp: {}, pitch: {}", fb.width, fb.height, fb.bpp, fb.pitch); - } - else - { - VGA_WIDTH = 80; - VGA_HEIGHT = 25; - VGA_MEMORY = (uint16_t*)0xB8000; - } - - terminal_row = 0; - terminal_col = 0; - terminal_color = vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK); - terminal_buffer = VGA_MEMORY; - clear(); - - if (s_multiboot_info->flags & (1 << 12)) - if (s_multiboot_info->framebuffer.type != 2) - dprintln("Invalid framebuffer_type in multiboot info"); - } - - void setcolor(uint8_t color) - { - terminal_color = color; - } - - void scroll_line(size_t line) - { - for (size_t x = 0; x < VGA_WIDTH; x++) - { - const size_t index = line * VGA_WIDTH + x; - terminal_buffer[index - VGA_WIDTH] = terminal_buffer[index]; - } + terminal_fg = fg; + terminal_bg = bg; } void clear_line(size_t line) { - for (size_t x = 0; x < VGA_WIDTH; x++) - putentryat(' ', terminal_color, x, line); + for (size_t x = 0; x < terminal_width; x++) + VESA::PutEntryAt(' ', x, line, terminal_fg, terminal_bg); } static void update_cursor() { - uint16_t pos = terminal_row * VGA_WIDTH + terminal_col; + uint16_t pos = terminal_row * terminal_width + terminal_col; IO::outb(0x3D4, 0x0F); IO::outb(0x3D5, (uint8_t) (pos & 0xFF)); IO::outb(0x3D4, 0x0E); @@ -130,59 +85,29 @@ namespace TTY { switch (s_ansi_escape_nums[0]) { - case -1: case 0: - terminal_color = vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK); + case -1: + case 0: + terminal_fg = VESA::Color::WHITE; + terminal_bg = VESA::Color::BLACK; break; - case 30: - terminal_color = vga_set_foreground(VGA_COLOR_BLACK, terminal_color); - break; - case 31: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_RED, terminal_color); - break; - case 32: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_GREEN, terminal_color); - break; - case 33: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_BROWN, terminal_color); - break; - case 34: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_BLUE, terminal_color); - break; - case 35: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_MAGENTA, terminal_color); - break; - case 36: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_CYAN, terminal_color); - break; - case 37: - terminal_color = vga_set_foreground(VGA_COLOR_LIGHT_GREY, terminal_color); - break; + case 30: terminal_fg = VESA::Color::BLACK; break; + case 31: terminal_fg = VESA::Color::LIGHT_RED; break; + case 32: terminal_fg = VESA::Color::LIGHT_GREEN; break; + case 33: terminal_fg = VESA::Color::LIGHT_BROWN; break; + case 34: terminal_fg = VESA::Color::LIGHT_BLUE; break; + case 35: terminal_fg = VESA::Color::LIGHT_MAGENTA; break; + case 36: terminal_fg = VESA::Color::LIGHT_CYAN; break; + case 37: terminal_fg = VESA::Color::LIGHT_GREY; break; - case 40: - terminal_color = vga_set_background(VGA_COLOR_BLACK, terminal_color); - break; - case 41: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_RED, terminal_color); - break; - case 42: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_GREEN, terminal_color); - break; - case 43: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_BROWN, terminal_color); - break; - case 44: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_BLUE, terminal_color); - break; - case 45: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_MAGENTA, terminal_color); - break; - case 46: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_CYAN, terminal_color); - break; - case 47: - terminal_color = vga_set_background(VGA_COLOR_LIGHT_GREY, terminal_color); - break; + case 40: terminal_bg = VESA::Color::BLACK; break; + case 41: terminal_bg = VESA::Color::LIGHT_RED; break; + case 42: terminal_bg = VESA::Color::LIGHT_GREEN; break; + case 43: terminal_bg = VESA::Color::LIGHT_BROWN; break; + case 44: terminal_bg = VESA::Color::LIGHT_BLUE; break; + case 45: terminal_bg = VESA::Color::LIGHT_MAGENTA; break; + case 46: terminal_bg = VESA::Color::LIGHT_CYAN; break; + case 47: terminal_bg = VESA::Color::LIGHT_GREY; break; } } @@ -217,47 +142,47 @@ namespace TTY case 'A': // Cursor Up if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_row = max(terminal_row - s_ansi_escape_nums[0], 0); + terminal_row = max(terminal_row - s_ansi_escape_nums[0], 0); return reset_ansi_escape(); case 'B': // Curson Down if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_row = min(terminal_row + s_ansi_escape_nums[0], VGA_HEIGHT - 1); + terminal_row = min(terminal_row + s_ansi_escape_nums[0], terminal_height - 1); return reset_ansi_escape(); case 'C': // Cursor Forward if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_col = min(terminal_col + s_ansi_escape_nums[0], VGA_WIDTH - 1); + terminal_col = min(terminal_col + s_ansi_escape_nums[0], terminal_width - 1); return reset_ansi_escape(); case 'D': // Cursor Back if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_col = max(terminal_col - s_ansi_escape_nums[0], 0); + terminal_col = max(terminal_col - s_ansi_escape_nums[0], 0); return reset_ansi_escape(); case 'E': // Cursor Next Line if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_row = min(terminal_row + s_ansi_escape_nums[0], VGA_HEIGHT - 1); + terminal_row = min(terminal_row + s_ansi_escape_nums[0], terminal_height - 1); terminal_col = 0; return reset_ansi_escape(); case 'F': // Cursor Previous Line if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_row = max(terminal_row - s_ansi_escape_nums[0], 0); + terminal_row = max(terminal_row - s_ansi_escape_nums[0], 0); terminal_col = 0; return reset_ansi_escape(); case 'G': // Cursor Horizontal Absolute if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; - terminal_col = clamp(s_ansi_escape_nums[0] - 1, 0, VGA_WIDTH - 1); + terminal_col = clamp(s_ansi_escape_nums[0] - 1, 0, terminal_width - 1); return reset_ansi_escape(); case 'H': // Cursor Position if (s_ansi_escape_nums[0] == -1) s_ansi_escape_nums[0] = 1; if (s_ansi_escape_nums[1] == -1) s_ansi_escape_nums[1] = 1; - terminal_row = clamp(s_ansi_escape_nums[0] - 1, 0, VGA_HEIGHT - 1); - terminal_col = clamp(s_ansi_escape_nums[1] - 1, 0, VGA_WIDTH - 1); + terminal_row = clamp(s_ansi_escape_nums[0] - 1, 0, terminal_height - 1); + terminal_col = clamp(s_ansi_escape_nums[1] - 1, 0, terminal_width - 1); return reset_ansi_escape(); case 'J': // Erase in Display dprintln("Unsupported ANSI CSI character J"); @@ -266,16 +191,16 @@ namespace TTY switch (s_ansi_escape_nums[0]) { case -1: case 0: - for (size_t i = terminal_col; i < VGA_WIDTH; i++) - putentryat(' ', terminal_color, i, terminal_row); + for (size_t i = terminal_col; i < terminal_width; i++) + VESA::PutEntryAt(' ', i, terminal_row, terminal_fg, terminal_bg); break; case 1: for (size_t i = 0; i <= terminal_col; i++) - putentryat(' ', terminal_color, i, terminal_row); + VESA::PutEntryAt(' ', i, terminal_row, terminal_fg, terminal_bg); break; case 2: - for (size_t i = 0; i < VGA_WIDTH; i++) - putentryat(' ', terminal_color, i, terminal_row); + for (size_t i = 0; i < terminal_width; i++) + VESA::PutEntryAt(' ', i, terminal_row, terminal_fg, terminal_bg); break; } return reset_ansi_escape(); @@ -305,9 +230,6 @@ namespace TTY void putchar(char c) { - if (VGA_MEMORY == nullptr) - return; - if (s_ansi_escape_mode) return handle_ansi_escape(c); @@ -339,22 +261,22 @@ namespace TTY s_ansi_escape_mode = '\1'; break; default: - putentryat(c, terminal_color, terminal_col, terminal_row); + VESA::PutEntryAt(c, terminal_col, terminal_row, terminal_fg, terminal_bg); terminal_col++; break; } - if (terminal_col >= VGA_WIDTH) + if (terminal_col >= terminal_width) { terminal_col = 0; terminal_row++; } - while (terminal_row >= VGA_HEIGHT) + while (terminal_row >= terminal_height) { - for (size_t line = 1; line < VGA_HEIGHT; line++) - scroll_line(line); - clear_line(VGA_HEIGHT - 1); + for (size_t line = 1; line < terminal_height; line++) + VESA::ScrollLine(line); + clear_line(terminal_height - 1); terminal_col = 0; terminal_row--; diff --git a/kernel/include/kernel/VESA.h b/kernel/include/kernel/VESA.h new file mode 100644 index 000000000..d89ceca8f --- /dev/null +++ b/kernel/include/kernel/VESA.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +namespace VESA +{ + + enum Color : uint8_t + { + BLACK = 0, + BLUE = 1, + GREEN = 2, + CYAN = 3, + RED = 4, + MAGENTA = 5, + BROWN = 6, + LIGHT_GREY = 7, + DARK_GREY = 8, + LIGHT_BLUE = 9, + LIGHT_GREEN = 10, + LIGHT_CYAN = 11, + LIGHT_RED = 12, + LIGHT_MAGENTA = 13, + LIGHT_BROWN = 14, + WHITE = 15, + }; + + bool Initialize(); + void PutEntryAt(char, uint32_t, uint32_t, Color, Color); + void Clear(Color); + void ScrollLine(uint32_t line); + + uint32_t GetWidth(); + uint32_t GetHeight(); + +} \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 0b8a5652b..0c820316f 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #define DISABLE_INTERRUPTS() asm volatile("cli") #define ENABLE_INTERRUPTS() asm volatile("sti") @@ -23,14 +24,24 @@ void kernel_main(multiboot_info_t* mbi, uint32_t magic) { DISABLE_INTERRUPTS(); + Serial::initialize(); + if (magic != 0x2BADB002) + { + dprintln("Invalid multiboot magic number"); + return; + } + s_multiboot_info = mbi; - if (magic != 0x2BADB002) + if (!VESA::Initialize()) + { + dprintln("Could not initialize VESA"); return; - - Serial::initialize(); + } TTY::initialize(); - + + dprintln("{}", mbi->framebuffer.type); + kmalloc_initialize(); PIC::initialize();