Compare commits

..

No commits in common. "9f4cb5c4dd5cd80fedd4d1ae47810d8fdba3ec91" and "95a80bfe81d535d5d50150525db3f9f2dcc30c6c" have entirely different histories.

18 changed files with 189 additions and 349 deletions

View File

@ -18,78 +18,78 @@ namespace BAN
using const_iterator = ConstIteratorSimple<T, Array>; using const_iterator = ConstIteratorSimple<T, Array>;
public: public:
constexpr Array() = default; Array() = default;
constexpr Array(const T&); Array(const T&);
iterator begin() { return iterator(m_data); } iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + size()); } iterator end() { return iterator(m_data + size()); }
const_iterator begin() const { return const_iterator(m_data); } const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + size()); } const_iterator end() const { return const_iterator(m_data + size()); }
constexpr const T& operator[](size_type) const; const T& operator[](size_type) const;
constexpr T& operator[](size_type); T& operator[](size_type);
constexpr const T& back() const; const T& back() const;
constexpr T& back(); T& back();
constexpr const T& front() const; const T& front() const;
constexpr T& front(); T& front();
Span<T> span() { return Span(m_data, size()); } Span<T> span() { return Span(m_data, size()); }
const Span<T> span() const { return Span(m_data, size()); } const Span<T> span() const { return Span(m_data, size()); }
constexpr size_type size() const; constexpr size_type size() const;
constexpr const T* data() const { return m_data; } const T* data() const { return m_data; }
constexpr T* data() { return m_data; } T* data() { return m_data; }
private: private:
T m_data[S] {}; T m_data[S] {};
}; };
template<typename T, size_t S> template<typename T, size_t S>
constexpr Array<T, S>::Array(const T& value) Array<T, S>::Array(const T& value)
{ {
for (size_type i = 0; i < S; i++) for (size_type i = 0; i < S; i++)
m_data[i] = value; m_data[i] = value;
} }
template<typename T, size_t S> template<typename T, size_t S>
constexpr const T& Array<T, S>::operator[](size_type index) const const T& Array<T, S>::operator[](size_type index) const
{ {
ASSERT(index < S); ASSERT(index < S);
return m_data[index]; return m_data[index];
} }
template<typename T, size_t S> template<typename T, size_t S>
constexpr T& Array<T, S>::operator[](size_type index) T& Array<T, S>::operator[](size_type index)
{ {
ASSERT(index < S); ASSERT(index < S);
return m_data[index]; return m_data[index];
} }
template<typename T, size_t S> template<typename T, size_t S>
constexpr const T& Array<T, S>::back() const const T& Array<T, S>::back() const
{ {
ASSERT(S != 0); ASSERT(S != 0);
return m_data[S - 1]; return m_data[S - 1];
} }
template<typename T, size_t S> template<typename T, size_t S>
constexpr T& Array<T, S>::back() T& Array<T, S>::back()
{ {
ASSERT(S != 0); ASSERT(S != 0);
return m_data[S - 1]; return m_data[S - 1];
} }
template<typename T, size_t S> template<typename T, size_t S>
constexpr const T& Array<T, S>::front() const const T& Array<T, S>::front() const
{ {
ASSERT(S != 0); ASSERT(S != 0);
return m_data[0]; return m_data[0];
} }
template<typename T, size_t S> template<typename T, size_t S>
constexpr T& Array<T, S>::front() T& Array<T, S>::front()
{ {
ASSERT(S != 0); ASSERT(S != 0);
return m_data[0]; return m_data[0];

View File

@ -27,10 +27,9 @@ namespace Kernel
const LibFont::Font& font() const override { return m_font; }; const LibFont::Font& font() const override { return m_font; };
private: private:
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device, const Palette& palette) FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device)
: TerminalDriver(palette) : m_framebuffer_device(framebuffer_device)
, m_framebuffer_device(framebuffer_device) { }
{}
void read_cursor(); void read_cursor();
void show_cursor(bool use_data); void show_cursor(bool use_data);
@ -43,7 +42,7 @@ namespace Kernel
uint32_t m_cursor_y { 0 }; uint32_t m_cursor_y { 0 };
bool m_cursor_shown { true }; bool m_cursor_shown { true };
BAN::Vector<uint32_t> m_cursor_data; BAN::Vector<uint32_t> m_cursor_data;
static constexpr Color m_cursor_color = TerminalColor::WHITE; static constexpr Color m_cursor_color = TerminalColor::BRIGHT_WHITE;
}; };
} }

View File

@ -20,7 +20,7 @@ namespace Kernel
BAN::ErrorOr<BAN::String> ptsname(); BAN::ErrorOr<BAN::String> ptsname();
bool putchar(uint8_t ch); void putchar(uint8_t ch);
protected: protected:
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override; BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
@ -61,7 +61,7 @@ namespace Kernel
void clear() override; void clear() override;
protected: protected:
bool putchar_impl(uint8_t ch) override; void putchar_impl(uint8_t ch) override;
BAN::ErrorOr<long> ioctl_impl(int, void*) override; BAN::ErrorOr<long> ioctl_impl(int, void*) override;

View File

@ -53,7 +53,7 @@ namespace Kernel
protected: protected:
virtual BAN::StringView name() const override { return m_name; } virtual BAN::StringView name() const override { return m_name; }
virtual bool putchar_impl(uint8_t) override; virtual void putchar_impl(uint8_t) override;
private: private:
SerialTTY(Serial); SerialTTY(Serial);

View File

@ -58,14 +58,14 @@ namespace Kernel
protected: protected:
TTY(mode_t mode, uid_t uid, gid_t gid); TTY(mode_t mode, uid_t uid, gid_t gid);
virtual bool putchar_impl(uint8_t ch) = 0; virtual void putchar_impl(uint8_t ch) = 0;
virtual void update_cursor() {} virtual void update_cursor() {}
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
private: private:
bool putchar(uint8_t ch); void putchar(uint8_t ch);
void do_backspace(); void do_backspace();
protected: protected:

View File

@ -12,28 +12,20 @@ namespace Kernel
public: public:
struct Color struct Color
{ {
constexpr Color()
: rgb(0)
{ }
constexpr Color(uint32_t rgb) constexpr Color(uint32_t rgb)
: rgb(rgb) : rgb(rgb)
{ } { }
constexpr Color(uint8_t r, uint8_t g, uint8_t b) constexpr Color(uint8_t r, uint8_t g, uint8_t b)
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b) : rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
{ } { }
constexpr uint8_t red() const { return (rgb >> 0x10) & 0xFF; } uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
constexpr uint8_t green() const { return (rgb >> 0x08) & 0xFF; } uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
constexpr uint8_t blue() const { return (rgb >> 0x00) & 0xFF; } uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
uint32_t rgb; uint32_t rgb;
}; };
using Palette = BAN::Array<Color, 16>;
public: public:
static BAN::ErrorOr<void> initialize_from_boot_info(); static BAN::ErrorOr<void> initialize_from_boot_info();
TerminalDriver(const Palette& palette)
: m_palette(palette)
{}
virtual ~TerminalDriver() {} virtual ~TerminalDriver() {}
virtual uint32_t width() const = 0; virtual uint32_t width() const = 0;
virtual uint32_t height() const = 0; virtual uint32_t height() const = 0;
@ -48,19 +40,29 @@ namespace Kernel
virtual bool has_font() const { return false; } virtual bool has_font() const { return false; }
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); } virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
virtual const LibFont::Font& font() const { ASSERT_NOT_REACHED(); } virtual const LibFont::Font& font() const { ASSERT_NOT_REACHED(); }
const Palette& palette() const { return m_palette; }
protected:
Palette m_palette;
}; };
extern BAN::RefPtr<TerminalDriver> g_terminal_driver; extern BAN::RefPtr<TerminalDriver> g_terminal_driver;
namespace TerminalColor namespace TerminalColor
{ {
constexpr TerminalDriver::Color BLACK = 0x000000; static constexpr TerminalDriver::Color BLACK = 0x000000;
constexpr TerminalDriver::Color WHITE = 0xFFFFFF; static constexpr TerminalDriver::Color RED = 0xFF0000;
static constexpr TerminalDriver::Color GREEN = 0x00FF00;
static constexpr TerminalDriver::Color YELLOW = 0xFFFF00;
static constexpr TerminalDriver::Color BLUE = 0x0000FF;
static constexpr TerminalDriver::Color MAGENTA = 0xFF00FF;
static constexpr TerminalDriver::Color CYAN = 0x00FFFF;
static constexpr TerminalDriver::Color WHITE = 0xBFBFBF;
static constexpr TerminalDriver::Color BRIGHT_BLACK = 0x3F3F3F;
static constexpr TerminalDriver::Color BRIGHT_RED = 0xFF7F7F;
static constexpr TerminalDriver::Color BRIGHT_GREEN = 0x7FFF7F;
static constexpr TerminalDriver::Color BRIGHT_YELLOW = 0xFFFF7F;
static constexpr TerminalDriver::Color BRIGHT_BLUE = 0x7F7FFF;
static constexpr TerminalDriver::Color BRIGHT_MAGENTA = 0xFF7FFF;
static constexpr TerminalDriver::Color BRIGHT_CYAN = 0x7FFFFF;
static constexpr TerminalDriver::Color BRIGHT_WHITE = 0xFFFFFF;
} }
} }

View File

@ -21,9 +21,8 @@ namespace Kernel
void set_cursor_position(uint32_t, uint32_t) override; void set_cursor_position(uint32_t, uint32_t) override;
private: private:
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, const Palette& palette) TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch)
: TerminalDriver(palette) : m_paddr(paddr)
, m_paddr(paddr)
, m_width(width) , m_width(width)
, m_height(height) , m_height(height)
, m_pitch(pitch) , m_pitch(pitch)
@ -37,7 +36,7 @@ namespace Kernel
const uint32_t m_height; const uint32_t m_height;
const uint32_t m_pitch; const uint32_t m_pitch;
vaddr_t m_vaddr { 0 }; vaddr_t m_vaddr { 0 };
static constexpr Color s_cursor_color = TerminalColor::WHITE; static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
}; };
} }

View File

@ -11,9 +11,6 @@ namespace Kernel
class VirtualTTY : public TTY class VirtualTTY : public TTY
{ {
public:
using Palette = TerminalDriver::Palette;
public: public:
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>); static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>);
@ -26,7 +23,7 @@ namespace Kernel
protected: protected:
virtual BAN::StringView name() const override { return m_name; } virtual BAN::StringView name() const override { return m_name; }
virtual bool putchar_impl(uint8_t ch) override; virtual void putchar_impl(uint8_t ch) override;
void update_cursor() override; void update_cursor() override;
private: private:
@ -38,7 +35,6 @@ namespace Kernel
void putcodepoint(uint32_t codepoint); void putcodepoint(uint32_t codepoint);
void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y); void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y);
void render_from_buffer(uint32_t x, uint32_t y); void render_from_buffer(uint32_t x, uint32_t y);
void scroll_if_needed();
private: private:
enum class State enum class State
@ -51,15 +47,11 @@ namespace Kernel
struct AnsiState struct AnsiState
{ {
static constexpr size_t max_nums = 5; int32_t nums[2] { -1, -1 };
int32_t nums[max_nums] { -1, -1, -1, -1, -1 }; int32_t index { 0 };
size_t index { 0 };
bool question { false }; bool question { false };
}; };
BAN::Optional<TerminalDriver::Color> get_8bit_color();
BAN::Optional<TerminalDriver::Color> get_24bit_color();
struct UTF8State struct UTF8State
{ {
uint32_t codepoint { 0 }; uint32_t codepoint { 0 };
@ -68,16 +60,14 @@ namespace Kernel
struct Cell struct Cell
{ {
TerminalDriver::Color foreground; TerminalDriver::Color foreground { TerminalColor::BRIGHT_WHITE };
TerminalDriver::Color background; TerminalDriver::Color background { TerminalColor::BLACK };
uint32_t codepoint { ' ' }; uint32_t codepoint { ' ' };
}; };
private: private:
BAN::String m_name; BAN::String m_name;
BAN::RefPtr<TerminalDriver> m_terminal_driver;
State m_state { State::Normal }; State m_state { State::Normal };
AnsiState m_ansi_state { }; AnsiState m_ansi_state { };
UTF8State m_utf8_state { }; UTF8State m_utf8_state { };
@ -94,11 +84,11 @@ namespace Kernel
uint32_t m_column { 0 }; uint32_t m_column { 0 };
Cell* m_buffer { nullptr }; Cell* m_buffer { nullptr };
const Palette& m_palette; TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
TerminalDriver::Color m_background { TerminalColor::BLACK };
TerminalDriver::Color m_foreground;
TerminalDriver::Color m_background;
bool m_colors_inverted { false }; bool m_colors_inverted { false };
BAN::RefPtr<TerminalDriver> m_terminal_driver;
}; };
} }

View File

@ -104,7 +104,7 @@ namespace Debug
{ {
if (!isprint(ch)) if (!isprint(ch))
ch = '?'; ch = '?';
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::WHITE, TerminalColor::BLACK); g_terminal_driver->putchar_at(ch, col, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
col++; col++;
if (col >= g_terminal_driver->width()) if (col >= g_terminal_driver->width())
@ -121,9 +121,9 @@ namespace Debug
{ {
for (uint32_t i = col; i < g_terminal_driver->width(); i++) for (uint32_t i = col; i < g_terminal_driver->width(); i++)
{ {
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::WHITE, TerminalColor::BLACK); g_terminal_driver->putchar_at(' ', i, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
if (row + 1 < g_terminal_driver->height()) if (row + 1 < g_terminal_driver->height())
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::WHITE, TerminalColor::BLACK); g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
} }
} }
} }

View File

@ -360,7 +360,7 @@ namespace Kernel
[&x, y](char ch) [&x, y](char ch)
{ {
if (x < g_terminal_driver->width() && y < g_terminal_driver->height()) if (x < g_terminal_driver->width() && y < g_terminal_driver->height())
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::WHITE, TerminalColor::BLACK); g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
}; };
BAN::Formatter::print(proc_putc, "CPU { 2}: { 3}.{3}%", current_id(), load_x1000 / 1000, load_x1000 % 1000); BAN::Formatter::print(proc_putc, "CPU { 2}: { 3}.{3}%", current_id(), load_x1000 / 1000, load_x1000 % 1000);

View File

@ -3,38 +3,15 @@
namespace Kernel namespace Kernel
{ {
static consteval TerminalDriver::Palette default_palette()
{
TerminalDriver::Palette palette;
palette[ 0] = 0x000000;
palette[ 1] = 0xFF0000;
palette[ 2] = 0x00FF00;
palette[ 3] = 0xFFFF00;
palette[ 4] = 0x0000FF;
palette[ 5] = 0xFF00FF;
palette[ 6] = 0x00FFFF;
palette[ 7] = 0xBFBFBF;
palette[ 8] = 0x3F3F3F;
palette[ 9] = 0xFF7F7F;
palette[10] = 0x7FFF7F;
palette[11] = 0xFFFF7F;
palette[12] = 0x7F7FFF;
palette[13] = 0xFF7FFF;
palette[14] = 0x7FFFFF;
palette[15] = 0xFFFFFF;
return palette;
}
BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device) BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
{ {
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device, default_palette()); auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device);
if (driver_ptr == nullptr) if (driver_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr); auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs())))); TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
driver->set_cursor_position(0, 0); driver->set_cursor_position(0, 0);
driver->clear(driver->m_palette[0]); driver->clear(TerminalColor::BLACK);
return driver; return driver;
} }
@ -83,9 +60,6 @@ namespace Kernel
for (uint32_t x = 0; x < m_framebuffer_device->width(); x++) for (uint32_t x = 0; x < m_framebuffer_device->width(); x++)
m_framebuffer_device->set_pixel(x, y, color.rgb); m_framebuffer_device->set_pixel(x, y, color.rgb);
m_framebuffer_device->sync_pixels_full(); m_framebuffer_device->sync_pixels_full();
if (m_cursor_shown)
show_cursor(false);
} }
void FramebufferTerminalDriver::read_cursor() void FramebufferTerminalDriver::read_cursor()
@ -104,11 +78,6 @@ namespace Kernel
void FramebufferTerminalDriver::show_cursor(bool use_data) void FramebufferTerminalDriver::show_cursor(bool use_data)
{ {
// NOTE: cursor is allowed to be on width as scrolling only
// happens after character gets printed to next line
if (m_cursor_x == width())
return;
if (!use_data) if (!use_data)
read_cursor(); read_cursor();

View File

@ -85,19 +85,16 @@ namespace Kernel
return BAN::Error::from_errno(ENODEV); return BAN::Error::from_errno(ENODEV);
} }
bool PseudoTerminalMaster::putchar(uint8_t ch) void PseudoTerminalMaster::putchar(uint8_t ch)
{ {
SpinLockGuard _(m_buffer_lock); SpinLockGuard _(m_buffer_lock);
if (m_buffer_size >= m_buffer->size())
return false;
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch; reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
if (m_buffer_size < m_buffer->size())
m_buffer_size++; m_buffer_size++;
else
m_buffer_blocker.unblock(); m_buffer_tail = (m_buffer_tail + 1) % m_buffer->size();
return true;
} }
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
@ -169,11 +166,10 @@ namespace Kernel
(void)write_impl(0, BAN::ConstByteSpan::from(message)); (void)write_impl(0, BAN::ConstByteSpan::from(message));
} }
bool PseudoTerminalSlave::putchar_impl(uint8_t ch) void PseudoTerminalSlave::putchar_impl(uint8_t ch)
{ {
if (auto master = m_master.lock()) if (auto master = m_master.lock())
return master->putchar(ch); master->putchar(ch);
return false;
} }
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument) BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)

View File

@ -258,10 +258,9 @@ namespace Kernel
return m_serial.height(); return m_serial.height();
} }
bool SerialTTY::putchar_impl(uint8_t ch) void SerialTTY::putchar_impl(uint8_t ch)
{ {
m_serial.putchar(ch); m_serial.putchar(ch);
return true;
} }
} }

View File

@ -327,12 +327,11 @@ namespace Kernel
} }
} }
bool TTY::putchar(uint8_t ch) void TTY::putchar(uint8_t ch)
{ {
SpinLockGuard _(m_write_lock); SpinLockGuard _(m_write_lock);
if (m_tty_ctrl.draw_graphics) if (m_tty_ctrl.draw_graphics)
return putchar_impl(ch); putchar_impl(ch);
return true;
} }
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
@ -366,12 +365,10 @@ namespace Kernel
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
{ {
SpinLockGuard _(m_write_lock); SpinLockGuard _(m_write_lock);
size_t written = 0; for (size_t i = 0; i < buffer.size(); i++)
for (; written < buffer.size(); written++) putchar(buffer[i]);
if (!putchar(buffer[written]))
break;
update_cursor(); update_cursor();
return written; return buffer.size();
} }
void TTY::putchar_current(uint8_t ch) void TTY::putchar_current(uint8_t ch)

View File

@ -7,39 +7,36 @@
namespace Kernel namespace Kernel
{ {
static consteval TerminalDriver::Palette default_palette() static constexpr TerminalDriver::Color s_palette[] {
{ TerminalColor::BLACK,
TerminalDriver::Palette palette; TerminalColor::BLUE,
palette[ 0] = 0x000000; TerminalColor::GREEN,
palette[ 1] = 0x0000AA; TerminalColor::CYAN,
palette[ 2] = 0x00AA00; TerminalColor::RED,
palette[ 3] = 0x00AAAA; TerminalColor::MAGENTA,
palette[ 4] = 0xAA0000; TerminalColor::YELLOW,
palette[ 5] = 0xAA00AA; TerminalColor::WHITE,
palette[ 6] = 0xAA5500; TerminalColor::BRIGHT_BLACK,
palette[ 7] = 0xAAAAAA; TerminalColor::BRIGHT_BLUE,
palette[ 8] = 0x555555; TerminalColor::BRIGHT_GREEN,
palette[ 9] = 0x5555FF; TerminalColor::BRIGHT_CYAN,
palette[10] = 0x55FF55; TerminalColor::BRIGHT_RED,
palette[11] = 0x55FFFF; TerminalColor::BRIGHT_MAGENTA,
palette[12] = 0xFF5555; TerminalColor::BRIGHT_YELLOW,
palette[13] = 0xFF55FF; TerminalColor::BRIGHT_WHITE,
palette[14] = 0xFFFF55; };
palette[15] = 0xFFFFFF;
return palette;
}
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color) static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
{ {
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max(); uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
uint8_t closest = 0; uint8_t closest = 0;
static_assert(default_palette().size() == 16); static_assert(sizeof(s_palette) / sizeof(*s_palette) == 16);
for (size_t i = 0; i < 16; i++) for (size_t i = 0; i < 16; i++)
{ {
const auto rdiff = color.red() - default_palette()[i].red(); const auto rdiff = color.red() - s_palette[i].red();
const auto gdiff = color.green() - default_palette()[i].green(); const auto gdiff = color.green() - s_palette[i].green();
const auto bdiff = color.blue() - default_palette()[i].blue(); const auto bdiff = color.blue() - s_palette[i].blue();
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff; const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
if (diff >= min_diff) if (diff >= min_diff)
continue; continue;
@ -59,8 +56,7 @@ namespace Kernel
g_boot_info.framebuffer.address, g_boot_info.framebuffer.address,
g_boot_info.framebuffer.width, g_boot_info.framebuffer.width,
g_boot_info.framebuffer.height, g_boot_info.framebuffer.height,
g_boot_info.framebuffer.pitch, g_boot_info.framebuffer.pitch
default_palette()
); );
if (driver_ptr == nullptr) if (driver_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
@ -87,7 +83,7 @@ namespace Kernel
m_vaddr = vaddr + (m_paddr % PAGE_SIZE); m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
set_cursor_position(0, 0); set_cursor_position(0, 0);
clear(m_palette[0]); clear(TerminalColor::BLACK);
return {}; return {};
} }
@ -118,7 +114,7 @@ namespace Kernel
{ {
for (uint32_t y = 0; y < m_height; y++) for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++) for (uint32_t x = 0; x < m_width; x++)
putchar_at(' ', x, y, color, color); putchar_at(' ', x, y, TerminalColor::BRIGHT_WHITE, color);
} }
void TextModeTerminalDriver::set_cursor_shown(bool shown) void TextModeTerminalDriver::set_cursor_shown(bool shown)
@ -140,10 +136,6 @@ namespace Kernel
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y) void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
{ {
// NOTE: cursor is allowed to be on width as scrolling only
// happens after character gets printed to next line
if (x == m_width)
return;
const uint16_t pos = y * m_width + x; const uint16_t pos = y * m_width + x;
IO::outb(0x3D4, 0x0F); IO::outb(0x3D4, 0x0F);
IO::outb(0x3D5, pos & 0xFF); IO::outb(0x3D5, pos & 0xFF);

View File

@ -39,9 +39,6 @@ namespace Kernel
: TTY(0600, 0, 0) : TTY(0600, 0, 0)
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++))) , m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
, m_terminal_driver(driver) , m_terminal_driver(driver)
, m_palette(driver->palette())
, m_foreground(m_palette[15])
, m_background(m_palette[0])
{ {
m_width = m_terminal_driver->width(); m_width = m_terminal_driver->width();
m_height = m_terminal_driver->height(); m_height = m_terminal_driver->height();
@ -98,11 +95,10 @@ namespace Kernel
void VirtualTTY::reset_ansi() void VirtualTTY::reset_ansi()
{ {
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
m_ansi_state = { m_ansi_state.index = 0;
.nums = { -1, -1, -1, -1, -1 }, m_ansi_state.nums[0] = -1;
.index = 0, m_ansi_state.nums[1] = -1;
.question = false, m_ansi_state.question = false;
};
m_state = State::Normal; m_state = State::Normal;
} }
@ -112,76 +108,64 @@ namespace Kernel
switch (ch) switch (ch)
{ {
case 0: case 0:
m_foreground = m_palette[15]; m_foreground = TerminalColor::BRIGHT_WHITE;
m_background = m_palette[0]; m_background = TerminalColor::BLACK;
m_colors_inverted = false; m_colors_inverted = false;
break; break;
case 7: m_colors_inverted = true; break; case 7: m_colors_inverted = true; break;
case 27: m_colors_inverted = false; break; case 27: m_colors_inverted = false; break;
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 30: m_foreground = TerminalColor::BLACK; break;
m_foreground = m_palette[ch - 30]; case 31: m_foreground = TerminalColor::RED; break;
break; case 32: m_foreground = TerminalColor::GREEN; break;
case 33: m_foreground = TerminalColor::YELLOW; break;
case 34: m_foreground = TerminalColor::BLUE; break;
case 35: m_foreground = TerminalColor::MAGENTA; break;
case 36: m_foreground = TerminalColor::CYAN; break;
case 37: m_foreground = TerminalColor::WHITE; break;
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 40: m_background = TerminalColor::BLACK; break;
m_background = m_palette[ch - 40]; case 41: m_background = TerminalColor::RED; break;
break; case 42: m_background = TerminalColor::GREEN; break;
case 43: m_background = TerminalColor::YELLOW; break;
case 44: m_background = TerminalColor::BLUE; break;
case 45: m_background = TerminalColor::MAGENTA; break;
case 46: m_background = TerminalColor::CYAN; break;
case 47: m_background = TerminalColor::WHITE; break;
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 90: m_foreground = TerminalColor::BRIGHT_BLACK; break;
m_foreground = m_palette[ch - 90 + 8]; case 91: m_foreground = TerminalColor::BRIGHT_RED; break;
break; case 92: m_foreground = TerminalColor::BRIGHT_GREEN; break;
case 93: m_foreground = TerminalColor::BRIGHT_YELLOW; break;
case 94: m_foreground = TerminalColor::BRIGHT_BLUE; break;
case 95: m_foreground = TerminalColor::BRIGHT_MAGENTA; break;
case 96: m_foreground = TerminalColor::BRIGHT_CYAN; break;
case 97: m_foreground = TerminalColor::BRIGHT_WHITE; break;
case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 100: m_background = TerminalColor::BRIGHT_BLACK; break;
m_background = m_palette[ch - 100 + 8]; case 101: m_background = TerminalColor::BRIGHT_RED; break;
break; case 102: m_background = TerminalColor::BRIGHT_GREEN; break;
case 103: m_background = TerminalColor::BRIGHT_YELLOW; break;
case 104: m_background = TerminalColor::BRIGHT_BLUE; break;
case 105: m_background = TerminalColor::BRIGHT_MAGENTA; break;
case 106: m_background = TerminalColor::BRIGHT_CYAN; break;
case 107: m_background = TerminalColor::BRIGHT_WHITE; break;
} }
} }
BAN::Optional<TerminalDriver::Color> VirtualTTY::get_8bit_color()
{
ASSERT(m_ansi_state.nums[1] == 5);
if (m_ansi_state.nums[2] < 1)
return {};
const uint8_t code = BAN::Math::min(m_ansi_state.nums[2], 256) - 1;
if (code < 16)
return m_palette[code];
if (code < 232)
{
const uint8_t r = (code - 16) / 36 % 6 * 40 + 55;
const uint8_t g = (code - 16) / 6 % 6 * 40 + 55;
const uint8_t b = (code - 16) / 1 % 6 * 40 + 55;
return TerminalDriver::Color(r, g, b);
}
const uint8_t gray = (code - 232) * 10 + 8;
return TerminalDriver::Color(gray, gray, gray);
}
BAN::Optional<TerminalDriver::Color> VirtualTTY::get_24bit_color()
{
ASSERT(m_ansi_state.nums[1] == 2);
if (m_ansi_state.nums[2] < 1) return {};
if (m_ansi_state.nums[3] < 1) return {};
if (m_ansi_state.nums[4] < 1) return {};
const uint8_t r = BAN::Math::min(m_ansi_state.nums[2], 256) - 1;
const uint8_t g = BAN::Math::min(m_ansi_state.nums[3], 256) - 1;
const uint8_t b = BAN::Math::min(m_ansi_state.nums[4], 256) - 1;
return TerminalDriver::Color(r, g, b);
}
void VirtualTTY::handle_ansi_csi(uint8_t ch) void VirtualTTY::handle_ansi_csi(uint8_t ch)
{ {
constexpr size_t max_ansi_args = sizeof(m_ansi_state.nums) / sizeof(*m_ansi_state.nums);
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
switch (ch) switch (ch)
{ {
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
{ {
if (m_ansi_state.index >= m_ansi_state.max_nums) if ((size_t)m_ansi_state.index >= max_ansi_args)
dwarnln("Only {} arguments supported with ANSI codes", m_ansi_state.max_nums); dwarnln("Only {} arguments supported with ANSI codes", max_ansi_args);
else else
{ {
int32_t& val = m_ansi_state.nums[m_ansi_state.index]; int32_t& val = m_ansi_state.nums[m_ansi_state.index];
@ -190,7 +174,7 @@ namespace Kernel
return; return;
} }
case ';': case ';':
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, m_ansi_state.max_nums); m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, max_ansi_args);
return; return;
case 'A': // Cursor Up case 'A': // Cursor Up
if (m_ansi_state.nums[0] == -1) if (m_ansi_state.nums[0] == -1)
@ -322,22 +306,7 @@ namespace Kernel
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f"); dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f");
return; return;
case 'm': case 'm':
if (m_ansi_state.nums[0] == 38 || m_ansi_state.nums[0] == 48) for (int i = 0; i <= m_ansi_state.index && i < static_cast<int>(max_ansi_args); i++)
{
if (m_ansi_state.nums[1] != 5 && m_ansi_state.nums[1] != 2)
{
reset_ansi();
dprintln_if(DEBUG_VTTY, "Unsupported ANSI SGR {}", m_ansi_state.nums[1]);
return;
}
const auto color = (m_ansi_state.nums[1] == 5)
? get_8bit_color()
: get_24bit_color();
if (color.has_value())
(m_ansi_state.nums[0] == 38 ? m_foreground : m_background) = *color;
return reset_ansi();
}
for (size_t i = 0; i <= m_ansi_state.index && i < m_ansi_state.max_nums; i++)
handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0)); handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0));
return reset_ansi(); return reset_ansi();
case 's': case 's':
@ -432,29 +401,6 @@ namespace Kernel
m_terminal_driver->putchar_at(codepoint, x, y, cell.foreground, cell.background); m_terminal_driver->putchar_at(codepoint, x, y, cell.foreground, cell.background);
} }
void VirtualTTY::scroll_if_needed()
{
while (m_row >= m_height)
{
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
// Clear last line in buffer
for (uint32_t x = 0; x < m_width; x++)
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
if (!m_terminal_driver->scroll(m_background))
{
// No fast scrolling, render the whole buffer to the screen
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
m_column = 0;
m_row--;
}
}
void VirtualTTY::putcodepoint(uint32_t codepoint) void VirtualTTY::putcodepoint(uint32_t codepoint)
{ {
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
@ -486,22 +432,40 @@ namespace Kernel
m_state = State::WaitingAnsiEscape; m_state = State::WaitingAnsiEscape;
break; break;
default: default:
if (m_column >= m_width)
{
m_column = 0;
m_row++;
}
scroll_if_needed();
putchar_at(codepoint, m_column, m_row); putchar_at(codepoint, m_column, m_row);
m_last_graphic_char = codepoint; m_last_graphic_char = codepoint;
m_column++; m_column++;
break; break;
} }
scroll_if_needed(); if (m_column >= m_width)
{
m_column = 0;
m_row++;
} }
bool VirtualTTY::putchar_impl(uint8_t ch) while (m_row >= m_height)
{
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
// Clear last line in buffer
for (uint32_t x = 0; x < m_width; x++)
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
if (!m_terminal_driver->scroll(m_background))
{
// No fast scrolling, render the whole buffer to the screen
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
m_column = 0;
m_row--;
}
}
void VirtualTTY::putchar_impl(uint8_t ch)
{ {
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
@ -531,10 +495,10 @@ namespace Kernel
{ {
reset_ansi(); reset_ansi();
dprintln_if(DEBUG_VTTY, "invalid utf8"); dprintln_if(DEBUG_VTTY, "invalid utf8");
return true; return;
} }
m_state = State::WaitingUTF8; m_state = State::WaitingUTF8;
return true; return;
case State::WaitingAnsiEscape: case State::WaitingAnsiEscape:
if (ch == CSI) if (ch == CSI)
m_state = State::WaitingAnsiCSI; m_state = State::WaitingAnsiCSI;
@ -543,21 +507,21 @@ namespace Kernel
reset_ansi(); reset_ansi();
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch); dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
} }
return true; return;
case State::WaitingAnsiCSI: case State::WaitingAnsiCSI:
handle_ansi_csi(ch); handle_ansi_csi(ch);
return true; return;
case State::WaitingUTF8: case State::WaitingUTF8:
if ((ch & 0xC0) != 0x80) if ((ch & 0xC0) != 0x80)
{ {
m_state = State::Normal; m_state = State::Normal;
dprintln_if(DEBUG_VTTY, "invalid utf8"); dprintln_if(DEBUG_VTTY, "invalid utf8");
return true; return;
} }
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F); m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
m_utf8_state.bytes_missing--; m_utf8_state.bytes_missing--;
if (m_utf8_state.bytes_missing) if (m_utf8_state.bytes_missing)
return true; return;
m_state = State::Normal; m_state = State::Normal;
codepoint = m_utf8_state.codepoint; codepoint = m_utf8_state.codepoint;
break; break;
@ -566,7 +530,6 @@ namespace Kernel
} }
putcodepoint(codepoint); putcodepoint(codepoint);
return true;
} }
void VirtualTTY::update_cursor() void VirtualTTY::update_cursor()

View File

@ -185,8 +185,6 @@ void Terminal::run()
void Terminal::hide_cursor() void Terminal::hide_cursor()
{ {
if (m_cursor.x == cols())
return;
const uint32_t cursor_base_x = m_cursor.x * m_font.width(); const uint32_t cursor_base_x = m_cursor.x * m_font.width();
const uint32_t cursor_base_y = m_cursor.y * m_font.height(); const uint32_t cursor_base_y = m_cursor.y * m_font.height();
for (uint32_t y = 0; y < m_font.height(); y++) for (uint32_t y = 0; y < m_font.height(); y++)
@ -197,8 +195,6 @@ void Terminal::hide_cursor()
void Terminal::show_cursor() void Terminal::show_cursor()
{ {
if (m_cursor.x == cols())
return;
const uint32_t cursor_base_x = m_cursor.x * m_font.width(); const uint32_t cursor_base_x = m_cursor.x * m_font.width();
const uint32_t cursor_base_y = m_cursor.y * m_font.height(); const uint32_t cursor_base_y = m_cursor.y * m_font.height();
for (uint32_t y = 0; y < m_font.height(); y++) for (uint32_t y = 0; y < m_font.height(); y++)
@ -325,42 +321,6 @@ void Terminal::handle_sgr(int32_t value)
} }
} }
BAN::Optional<uint32_t> Terminal::get_8bit_color()
{
ASSERT(m_csi_info.fields[1] == 5);
if (m_csi_info.fields[2] < 1)
return {};
const uint8_t code = BAN::Math::min(m_csi_info.fields[2], 256) - 1;
if (code < 8)
return s_colors_dark[code];
if (code < 16)
return s_colors_bright[code - 8];
if (code < 232)
{
const uint8_t r = (code - 16) / 36 % 6 * 40 + 55;
const uint8_t g = (code - 16) / 6 % 6 * 40 + 55;
const uint8_t b = (code - 16) / 1 % 6 * 40 + 55;
return b | (g << 8) | (r << 16) | (0xCC << 24);
}
const uint8_t gray = (code - 232) * 10 + 8;
return gray | (gray << 8) | (gray << 16) | (0xCC << 24);
}
BAN::Optional<uint32_t> Terminal::get_24bit_color()
{
ASSERT(m_csi_info.fields[1] == 2);
if (m_csi_info.fields[2] < 1) return {};
if (m_csi_info.fields[3] < 1) return {};
if (m_csi_info.fields[4] < 1) return {};
const uint8_t r = BAN::Math::min(m_csi_info.fields[2], 256) - 1;
const uint8_t g = BAN::Math::min(m_csi_info.fields[3], 256) - 1;
const uint8_t b = BAN::Math::min(m_csi_info.fields[4], 256) - 1;
return b | (g << 8) | (r << 16) | (0xCC << 24);
}
Rectangle Terminal::handle_csi(char ch) Rectangle Terminal::handle_csi(char ch)
{ {
if (ch == ';') if (ch == ';')
@ -544,20 +504,6 @@ Rectangle Terminal::handle_csi(char ch)
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1; m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
break; break;
case 'm': case 'm':
if (m_csi_info.fields[0] == 38 || m_csi_info.fields[0] == 48)
{
if (m_csi_info.fields[1] != 5 && m_csi_info.fields[1] != 2)
{
dprintln("unsupported ANSI SGR {}", m_csi_info.fields[1]);
break;
}
const auto color = (m_csi_info.fields[1] == 5)
? get_8bit_color()
: get_24bit_color();
if (color.has_value())
(m_csi_info.fields[0] == 38 ? m_fg_color : m_bg_color) = *color;
break;
}
for (size_t i = 0; i <= m_csi_info.index && i < m_csi_info.max_fields; i++) for (size_t i = 0; i <= m_csi_info.index && i < m_csi_info.max_fields; i++)
handle_sgr(m_csi_info.fields[i]); handle_sgr(m_csi_info.fields[i]);
break; break;
@ -617,20 +563,6 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
break; break;
default: default:
{ {
if (m_cursor.x >= cols())
{
m_cursor.x = 0;
m_cursor.y++;
}
if (m_cursor.y >= rows())
{
const uint32_t scroll = m_cursor.y - rows() + 1;
m_cursor.y -= scroll;
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
}
const uint32_t cell_w = m_font.width(); const uint32_t cell_w = m_font.width();
const uint32_t cell_h = m_font.height(); const uint32_t cell_h = m_font.height();
const uint32_t cell_x = m_cursor.x * cell_w; const uint32_t cell_x = m_cursor.x * cell_w;
@ -648,6 +580,12 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
} }
} }
if (m_cursor.x >= cols())
{
m_cursor.x = 0;
m_cursor.y++;
}
if (m_cursor.y >= rows()) if (m_cursor.y >= rows())
{ {
const uint32_t scroll = m_cursor.y - rows() + 1; const uint32_t scroll = m_cursor.y - rows() + 1;
@ -670,11 +608,10 @@ Rectangle Terminal::putchar(uint8_t ch)
return {}; return {};
} }
m_state = State::CSI; m_state = State::CSI;
m_csi_info = { m_csi_info.index = 0;
.fields = { -1, -1, -1, -1, -1 }, m_csi_info.fields[0] = -1;
.index = 0, m_csi_info.fields[1] = -1;
.question = false, m_csi_info.question = false;
};
return {}; return {};
} }

View File

@ -41,9 +41,6 @@ private:
Rectangle putchar(uint8_t ch); Rectangle putchar(uint8_t ch);
bool read_shell(); bool read_shell();
BAN::Optional<uint32_t> get_8bit_color();
BAN::Optional<uint32_t> get_24bit_color();
void hide_cursor(); void hide_cursor();
void show_cursor(); void show_cursor();
@ -73,7 +70,7 @@ private:
struct CSIInfo struct CSIInfo
{ {
static constexpr size_t max_fields = 5; static constexpr size_t max_fields = 2;
int32_t fields[max_fields]; int32_t fields[max_fields];
size_t index; size_t index;
bool question; bool question;