Kernel: Rewrite the whole VESA driver

We dont support vga text mode currently. I might add it later if needed.

I also removed mouse 'support' from Shell since it didn't do anything
and I didn't implement arbitary bitmap rendering to framebuffer
This commit is contained in:
Bananymous
2023-01-23 13:07:52 +02:00
parent 10c7ef7baa
commit 1b9f7aa815
14 changed files with 327 additions and 454 deletions

View File

@@ -22,30 +22,10 @@ namespace Kernel
static auto s_default_prompt = "\\[\e[32m\\]user\\[\e[m\\]# "_sv;
static uint8_t s_pointer[] {
________,
________,
________,
________,
________,
X_______,
XX______,
XXX_____,
XXXX____,
XXXXX___,
XXXXXX__,
XXXXXXX_,
XXXXXXXX,
XXX_____,
XX______,
X_______,
};
Shell::Shell(TTY* tty)
: m_tty(tty)
{
Input::register_key_event_callback({ &Shell::KeyEventCallback, this });
Input::register_mouse_move_event_callback({ &Shell::MouseMoveEventCallback, this });
SetPrompt(s_default_prompt);
MUST(m_buffer.PushBack(""_sv));
}
@@ -415,18 +395,6 @@ argument_done:
}
TTY_PRINT("\e[{}G", m_prompt_length + m_cursor_pos.col + 1);
if (m_mouse_pos.exists)
VESA::PutBitmapAt(s_pointer, m_mouse_pos.x, m_mouse_pos.y, VESA::Color::BRIGHT_WHITE);
}
void Shell::MouseMoveEventCallback(Input::MouseMoveEvent event)
{
m_mouse_pos.exists = true;
m_tty->RenderFromBuffer(m_mouse_pos.x, m_mouse_pos.y);
m_mouse_pos.x = Math::clamp<int32_t>(m_mouse_pos.x + event.dx, 0, m_tty->Width() - 1);
m_mouse_pos.y = Math::clamp<int32_t>(m_mouse_pos.y - event.dy, 0, m_tty->Height() - 1);
VESA::PutBitmapAt(s_pointer, m_mouse_pos.x, m_mouse_pos.y, VESA::Color::BRIGHT_WHITE);
}
}

View File

@@ -1,7 +1,6 @@
#include <BAN/Errors.h>
#include <kernel/Serial.h>
#include <kernel/TTY.h>
#include <kernel/VESA.h>
#include <string.h>
@@ -21,10 +20,11 @@ template<typename T> inline constexpr T clamp(T x, T a, T b) { return x < a ? a
static TTY* s_tty = nullptr;
TTY::TTY()
TTY::TTY(TerminalDriver* driver)
: m_terminal_driver(driver)
{
m_width = VESA::GetTerminalWidth();
m_height = VESA::GetTerminalHeight();
m_width = m_terminal_driver->Width();
m_height = m_terminal_driver->Height();
m_buffer = new Cell[m_width * m_height];
@@ -36,7 +36,7 @@ void TTY::Clear()
{
for (uint32_t i = 0; i < m_width * m_height; i++)
m_buffer[i] = { .foreground = m_foreground, .background = m_background, .character = ' ' };
VESA::Clear(m_background);
m_terminal_driver->Clear(m_background);
}
void TTY::SetCursorPosition(uint32_t x, uint32_t y)
@@ -45,7 +45,7 @@ void TTY::SetCursorPosition(uint32_t x, uint32_t y)
static uint32_t last_y = -1;
if (last_x != uint32_t(-1) && last_y != uint32_t(-1))
RenderFromBuffer(last_x, last_y); // Hacky way to clear previous cursor in graphics mode :D
VESA::SetCursorPosition(x, y, VESA::Color::BRIGHT_WHITE);
m_terminal_driver->SetCursorPosition(x, y);
last_x = m_column = x;
last_y = m_row = y;
}
@@ -111,27 +111,27 @@ void TTY::HandleAnsiSGR()
{
case -1:
case 0:
m_foreground = VESA::Color::BRIGHT_WHITE;
m_background = VESA::Color::BLACK;
m_foreground = TerminalColor::BRIGHT_WHITE;
m_background = TerminalColor::BLACK;
break;
case 30: m_foreground = VESA::Color::BRIGHT_BLACK; break;
case 31: m_foreground = VESA::Color::BRIGHT_RED; break;
case 32: m_foreground = VESA::Color::BRIGHT_GREEN; break;
case 33: m_foreground = VESA::Color::BRIGHT_YELLOW; break;
case 34: m_foreground = VESA::Color::BRIGHT_BLUE; break;
case 35: m_foreground = VESA::Color::BRIGHT_MAGENTA; break;
case 36: m_foreground = VESA::Color::BRIGHT_CYAN; break;
case 37: m_foreground = VESA::Color::BRIGHT_WHITE; break;
case 30: m_foreground = TerminalColor::BRIGHT_BLACK; break;
case 31: m_foreground = TerminalColor::BRIGHT_RED; break;
case 32: m_foreground = TerminalColor::BRIGHT_GREEN; break;
case 33: m_foreground = TerminalColor::BRIGHT_YELLOW; break;
case 34: m_foreground = TerminalColor::BRIGHT_BLUE; break;
case 35: m_foreground = TerminalColor::BRIGHT_MAGENTA; break;
case 36: m_foreground = TerminalColor::BRIGHT_CYAN; break;
case 37: m_foreground = TerminalColor::BRIGHT_WHITE; break;
case 40: m_background = VESA::Color::BRIGHT_BLACK; break;
case 41: m_background = VESA::Color::BRIGHT_RED; break;
case 42: m_background = VESA::Color::BRIGHT_GREEN; break;
case 43: m_background = VESA::Color::BRIGHT_YELLOW; break;
case 44: m_background = VESA::Color::BRIGHT_BLUE; break;
case 45: m_background = VESA::Color::BRIGHT_MAGENTA; break;
case 46: m_background = VESA::Color::BRIGHT_CYAN; break;
case 47: m_background = VESA::Color::BRIGHT_WHITE; break;
case 40: m_background = TerminalColor::BRIGHT_BLACK; break;
case 41: m_background = TerminalColor::BRIGHT_RED; break;
case 42: m_background = TerminalColor::BRIGHT_GREEN; break;
case 43: m_background = TerminalColor::BRIGHT_YELLOW; break;
case 44: m_background = TerminalColor::BRIGHT_BLUE; break;
case 45: m_background = TerminalColor::BRIGHT_MAGENTA; break;
case 46: m_background = TerminalColor::BRIGHT_CYAN; break;
case 47: m_background = TerminalColor::BRIGHT_WHITE; break;
}
}
@@ -246,7 +246,7 @@ void TTY::RenderFromBuffer(uint32_t x, uint32_t y)
{
ASSERT(x < m_width && y < m_height);
const auto& cell = m_buffer[y * m_width + x];
VESA::PutCharAt(cell.character, x, y, cell.foreground, cell.background);
m_terminal_driver->PutCharAt(cell.character, x, y, cell.foreground, cell.background);
}
void TTY::PutCharAt(uint16_t ch, uint32_t x, uint32_t y)
@@ -256,7 +256,7 @@ void TTY::PutCharAt(uint16_t ch, uint32_t x, uint32_t y)
cell.character = ch;
cell.foreground = m_foreground;
cell.background = m_background;
VESA::PutCharAt(ch, x, y, m_foreground, m_background);
m_terminal_driver->PutCharAt(ch, x, y, m_foreground, m_background);
}
void TTY::PutChar(char ch)

View File

@@ -0,0 +1,167 @@
#include <BAN/Errors.h>
#include <kernel/MMU.h>
#include <kernel/multiboot.h>
#include <kernel/Serial.h>
#include <kernel/VesaTerminalDriver.h>
extern const struct bitmap_font font;
VesaTerminalDriver* VesaTerminalDriver::Create()
{
if (!(g_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER))
{
dprintln("Bootloader did not provide framebuffer");
return nullptr;
}
auto& framebuffer = g_multiboot_info->framebuffer;
if (framebuffer.type == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS)
{
if (framebuffer.bpp != 24 && framebuffer.bpp != 32)
{
dprintln("Unsupported bpp {}", framebuffer.bpp);
return nullptr;
}
dprintln("Graphics Mode {}x{} ({} bpp)", framebuffer.width, framebuffer.height, framebuffer.bpp);
}
else if (framebuffer.type == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT)
{
dprintln("Text Mode is currently not supported");
return nullptr;
}
else
{
dprintln("Unknown framebuffer type {}", framebuffer.type);
return nullptr;
}
MMU::Get().AllocateRange(framebuffer.addr, framebuffer.pitch * framebuffer.height);
auto* driver = new VesaTerminalDriver(
framebuffer.width,
framebuffer.height,
framebuffer.pitch,
framebuffer.bpp,
framebuffer.addr,
font
);
driver->SetCursorPosition(0, 0);
driver->Clear(TerminalColor::BLACK);
return driver;
}
VesaTerminalDriver::~VesaTerminalDriver()
{
MMU::Get().UnAllocateRange(m_address, m_pitch * m_height);
}
void VesaTerminalDriver::SetPixel(uint32_t offset, Color color)
{
uint32_t* pixel = (uint32_t*)(m_address + offset);
switch (m_bpp)
{
case 24:
*pixel = (*pixel & 0xFF000000) | (color.rgb & 0x00FFFFFF);
break;
case 32:
*pixel = color.rgb;
break;
}
}
void VesaTerminalDriver::PutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
{
uint32_t glyph_index = 0;
for (uint32_t i = 0; i < m_font.Chars; i++)
{
if (m_font.Index[i] == ch)
{
glyph_index = i;
break;
}
}
const uint8_t* glyph = m_font.Bitmap + glyph_index * m_font.Height;
x *= m_font.Width;
y *= m_font.Height;
uint32_t row_offset = y * m_pitch + x * m_bpp / 8;
for (uint32_t dy = 0; dy < m_font.Height && y + dy < m_height; dy++)
{
uint32_t pixel_offset = row_offset;
for (uint32_t dx = 0; dx < m_font.Width && x + dx < m_width; dx++)
{
uint8_t bitmask = 1 << (font.Width - dx - 1);
SetPixel(pixel_offset, glyph[dy] & bitmask ? fg : bg);
pixel_offset += m_bpp / 8;
}
row_offset += m_pitch;
}
}
void VesaTerminalDriver::Clear(Color color)
{
if (m_bpp == 32)
{
uint32_t cells_per_row = m_pitch / 4;
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
((uint32_t*)m_address)[y * cells_per_row + x] = color.rgb;
return;
}
uint32_t row_offset = 0;
for (uint32_t y = 0; y < m_height; y++)
{
uint32_t pixel_offset = row_offset;
for (uint32_t x = 0; x < m_width; x++)
{
SetPixel(pixel_offset, color);
pixel_offset += m_bpp / 8;
}
row_offset += m_pitch;
}
}
void VesaTerminalDriver::SetCursorPosition(uint32_t x, uint32_t y)
{
ASSERT(m_font.Height == 16 && m_font.Width == 8);
constexpr uint8_t cursor[] = {
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
XXXXXXXX,
XXXXXXXX,
________,
};
x *= m_font.Width;
y *= m_font.Height;
uint32_t row_offset = y * m_pitch + x * m_bpp / 8;
for (uint32_t dy = 0; dy < m_font.Height && y + dy < m_height; dy++)
{
uint32_t pixel_offset = row_offset;
for (uint32_t dx = 0; dx < m_font.Width && x + dx < m_width; dx++)
{
uint8_t bitmask = 1 << (font.Width - dx - 1);
if (cursor[dy] & bitmask)
SetPixel(pixel_offset, s_cursor_color);
pixel_offset += m_bpp / 8;
}
row_offset += m_pitch;
}
}

View File

@@ -13,7 +13,7 @@
#include <kernel/Serial.h>
#include <kernel/Shell.h>
#include <kernel/TTY.h>
#include <kernel/VESA.h>
#include <kernel/VesaTerminalDriver.h>
#define DISABLE_INTERRUPTS() asm volatile("cli")
#define ENABLE_INTERRUPTS() asm volatile("sti")
@@ -76,10 +76,10 @@ extern "C" void kernel_main()
MMU::Intialize();
dprintln("MMU initialized");
if (!VESA::Initialize())
return;
TerminalDriver* terminal_driver = VesaTerminalDriver::Create();
ASSERT(terminal_driver);
dprintln("VESA initialized");
TTY* tty1 = new TTY;
TTY* tty1 = new TTY(terminal_driver);
APIC::Initialize(cmdline.force_pic);
dprintln("APIC initialized");