Kernel: Add support for text mode terminal
This probably won't be used at all but it was so simple and made me do really nice refactorings so i decided to add it :)
This commit is contained in:
parent
40d1d20cd6
commit
7c6966a9c4
|
@ -90,6 +90,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/Terminal/PseudoTerminal.cpp
|
kernel/Terminal/PseudoTerminal.cpp
|
||||||
kernel/Terminal/Serial.cpp
|
kernel/Terminal/Serial.cpp
|
||||||
kernel/Terminal/TerminalDriver.cpp
|
kernel/Terminal/TerminalDriver.cpp
|
||||||
|
kernel/Terminal/TextModeTerminal.cpp
|
||||||
kernel/Terminal/TTY.cpp
|
kernel/Terminal/TTY.cpp
|
||||||
kernel/Terminal/VirtualTTY.cpp
|
kernel/Terminal/VirtualTTY.cpp
|
||||||
kernel/Thread.cpp
|
kernel/Thread.cpp
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#define BANAN_BOOTLOADER_MAGIC 0xD3C60CFF
|
#define BANAN_BOOTLOADER_MAGIC 0xD3C60CFF
|
||||||
#define BANAN_BOOTLOADER_FB_RGB 1
|
#define BANAN_BOOTLOADER_FB_RGB 1
|
||||||
|
#define BANAN_BOOTLOADER_FB_TEXT 2
|
||||||
|
|
||||||
struct BananBootFramebufferInfo
|
struct BananBootFramebufferInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Kernel
|
||||||
None,
|
None,
|
||||||
Unknown,
|
Unknown,
|
||||||
RGB,
|
RGB,
|
||||||
|
Text,
|
||||||
};
|
};
|
||||||
|
|
||||||
paddr_t address;
|
paddr_t address;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Terminal/TerminalDriver.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class TextModeTerminalDriver final : public TerminalDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<TextModeTerminalDriver>> create_from_boot_info();
|
||||||
|
~TextModeTerminalDriver();
|
||||||
|
|
||||||
|
uint32_t width() const override { return m_width; }
|
||||||
|
uint32_t height() const override { return m_height; }
|
||||||
|
|
||||||
|
void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override;
|
||||||
|
void clear(Color) override;
|
||||||
|
|
||||||
|
void set_cursor_shown(bool) override;
|
||||||
|
void set_cursor_position(uint32_t, uint32_t) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch)
|
||||||
|
: m_paddr(paddr)
|
||||||
|
, m_width(width)
|
||||||
|
, m_height(height)
|
||||||
|
, m_pitch(pitch)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const paddr_t m_paddr;
|
||||||
|
const uint32_t m_width;
|
||||||
|
const uint32_t m_height;
|
||||||
|
const uint32_t m_pitch;
|
||||||
|
vaddr_t m_vaddr { 0 };
|
||||||
|
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,7 @@
|
||||||
#define MULTIBOOT2_TAG_NEW_RSDP 15
|
#define MULTIBOOT2_TAG_NEW_RSDP 15
|
||||||
|
|
||||||
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
|
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
|
||||||
|
#define MULTIBOOT2_FRAMEBUFFER_TYPE_TEXT 2
|
||||||
|
|
||||||
#define MULTIBOOT2_MAGIC 0x36d76289
|
#define MULTIBOOT2_MAGIC 0x36d76289
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ namespace Kernel
|
||||||
g_boot_info.framebuffer.bpp = framebuffer_tag.framebuffer_bpp;
|
g_boot_info.framebuffer.bpp = framebuffer_tag.framebuffer_bpp;
|
||||||
if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_RGB)
|
if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_RGB)
|
||||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::RGB;
|
g_boot_info.framebuffer.type = FramebufferInfo::Type::RGB;
|
||||||
|
else if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_TEXT)
|
||||||
|
g_boot_info.framebuffer.type = FramebufferInfo::Type::Text;
|
||||||
else
|
else
|
||||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::Unknown;
|
g_boot_info.framebuffer.type = FramebufferInfo::Type::Unknown;
|
||||||
}
|
}
|
||||||
|
@ -107,6 +109,8 @@ namespace Kernel
|
||||||
g_boot_info.framebuffer.bpp = framebuffer.bpp;
|
g_boot_info.framebuffer.bpp = framebuffer.bpp;
|
||||||
if (framebuffer.type == BANAN_BOOTLOADER_FB_RGB)
|
if (framebuffer.type == BANAN_BOOTLOADER_FB_RGB)
|
||||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::RGB;
|
g_boot_info.framebuffer.type = FramebufferInfo::Type::RGB;
|
||||||
|
else if (framebuffer.type == BANAN_BOOTLOADER_FB_TEXT)
|
||||||
|
g_boot_info.framebuffer.type = FramebufferInfo::Type::Text;
|
||||||
else
|
else
|
||||||
g_boot_info.framebuffer.type = FramebufferInfo::Type::Unknown;
|
g_boot_info.framebuffer.type = FramebufferInfo::Type::Unknown;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <kernel/BootInfo.h>
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||||
|
#include <kernel/Terminal/TextModeTerminal.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -18,6 +19,9 @@ namespace Kernel
|
||||||
TRY(FramebufferDevice::create_from_boot_framebuffer())
|
TRY(FramebufferDevice::create_from_boot_framebuffer())
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
|
case FramebufferInfo::Type::Text:
|
||||||
|
g_terminal_driver = TRY(TextModeTerminalDriver::create_from_boot_info());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
#include <kernel/BootInfo.h>
|
||||||
|
#include <kernel/IO.h>
|
||||||
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
#include <kernel/MMIO.h>
|
||||||
|
#include <kernel/Terminal/TextModeTerminal.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
static constexpr TerminalDriver::Color s_palette[] {
|
||||||
|
TerminalColor::BLACK,
|
||||||
|
TerminalColor::BLUE,
|
||||||
|
TerminalColor::GREEN,
|
||||||
|
TerminalColor::CYAN,
|
||||||
|
TerminalColor::RED,
|
||||||
|
TerminalColor::MAGENTA,
|
||||||
|
TerminalColor::YELLOW,
|
||||||
|
TerminalColor::WHITE,
|
||||||
|
TerminalColor::BRIGHT_BLACK,
|
||||||
|
TerminalColor::BRIGHT_BLUE,
|
||||||
|
TerminalColor::BRIGHT_GREEN,
|
||||||
|
TerminalColor::BRIGHT_CYAN,
|
||||||
|
TerminalColor::BRIGHT_RED,
|
||||||
|
TerminalColor::BRIGHT_MAGENTA,
|
||||||
|
TerminalColor::BRIGHT_YELLOW,
|
||||||
|
TerminalColor::BRIGHT_WHITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
|
||||||
|
{
|
||||||
|
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
|
||||||
|
uint8_t closest = 0;
|
||||||
|
|
||||||
|
static_assert(sizeof(s_palette) / sizeof(*s_palette) == 16);
|
||||||
|
for (size_t i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
const auto rdiff = color.red() - s_palette[i].red();
|
||||||
|
const auto gdiff = color.green() - s_palette[i].green();
|
||||||
|
const auto bdiff = color.blue() - s_palette[i].blue();
|
||||||
|
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
|
||||||
|
if (diff >= min_diff)
|
||||||
|
continue;
|
||||||
|
min_diff = diff;
|
||||||
|
closest = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<TextModeTerminalDriver>> TextModeTerminalDriver::create_from_boot_info()
|
||||||
|
{
|
||||||
|
ASSERT(g_boot_info.framebuffer.type == FramebufferInfo::Type::Text);
|
||||||
|
if (g_boot_info.framebuffer.bpp != 16)
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
auto* driver_ptr = new TextModeTerminalDriver(
|
||||||
|
g_boot_info.framebuffer.address,
|
||||||
|
g_boot_info.framebuffer.width,
|
||||||
|
g_boot_info.framebuffer.height,
|
||||||
|
g_boot_info.framebuffer.pitch
|
||||||
|
);
|
||||||
|
if (driver_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto driver = BAN::RefPtr<TextModeTerminalDriver>::adopt(driver_ptr);
|
||||||
|
TRY(driver->initialize());
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> TextModeTerminalDriver::initialize()
|
||||||
|
{
|
||||||
|
const size_t page_count = range_page_count(m_paddr, m_height * m_pitch);
|
||||||
|
const vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(page_count, KERNEL_OFFSET);
|
||||||
|
if (vaddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
PageTable::kernel().map_range_at(
|
||||||
|
m_paddr & PAGE_ADDR_MASK,
|
||||||
|
vaddr,
|
||||||
|
page_count * PAGE_SIZE,
|
||||||
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
|
PageTable::MemoryType::WriteCombining
|
||||||
|
);
|
||||||
|
|
||||||
|
m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
|
||||||
|
|
||||||
|
set_cursor_position(0, 0);
|
||||||
|
clear(TerminalColor::BLACK);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TextModeTerminalDriver::~TextModeTerminalDriver()
|
||||||
|
{
|
||||||
|
if (m_vaddr == 0)
|
||||||
|
return;
|
||||||
|
const size_t page_count = range_page_count(m_paddr, m_height * m_pitch);
|
||||||
|
PageTable::kernel().unmap_range(m_vaddr & PAGE_ADDR_MASK, page_count * PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextModeTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
|
||||||
|
{
|
||||||
|
if (x >= m_width || y >= m_height)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ch >= 0x100)
|
||||||
|
ch = '?';
|
||||||
|
|
||||||
|
const uint8_t color =
|
||||||
|
(color_to_text_mode_color(bg) << 4) |
|
||||||
|
(color_to_text_mode_color(fg) << 0);
|
||||||
|
MMIO::write16(m_vaddr + y * m_pitch + 2 * x, ch | (color << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextModeTerminalDriver::clear(Color color)
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < m_height; y++)
|
||||||
|
for (uint32_t x = 0; x < m_width; x++)
|
||||||
|
putchar_at(' ', x, y, TerminalColor::BRIGHT_WHITE, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextModeTerminalDriver::set_cursor_shown(bool shown)
|
||||||
|
{
|
||||||
|
if (shown)
|
||||||
|
{
|
||||||
|
IO::outb(0x3D4, 0x0A);
|
||||||
|
IO::outb(0x3D5, (IO::inb(0x3D5) & 0xC0) | 14);
|
||||||
|
|
||||||
|
IO::outb(0x3D4, 0x0B);
|
||||||
|
IO::outb(0x3D5, (IO::inb(0x3D5) & 0xE0) | 15);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IO::outb(0x3D4, 0x0A);
|
||||||
|
IO::outb(0x3D5, 0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
|
||||||
|
{
|
||||||
|
const uint16_t pos = y * m_width + x;
|
||||||
|
IO::outb(0x3D4, 0x0F);
|
||||||
|
IO::outb(0x3D5, pos & 0xFF);
|
||||||
|
IO::outb(0x3D4, 0x0E);
|
||||||
|
IO::outb(0x3D5, pos >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue