1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 09:54:57 +00:00
serenity/Kernel/Devices/GPU/Console/VGATextModeConsole.cpp

180 lines
5.2 KiB
C++

/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Devices/GPU/Console/VGATextModeConsole.h>
#include <Kernel/Devices/GPU/Management.h>
#include <Kernel/Sections.h>
namespace Kernel::Graphics {
UNMAP_AFTER_INIT NonnullLockRefPtr<VGATextModeConsole> VGATextModeConsole::initialize()
{
auto vga_window_size = MUST(Memory::page_round_up(0xc0000 - 0xa0000));
auto vga_window_region = MUST(MM.allocate_kernel_region(PhysicalAddress(0xa0000), vga_window_size, "VGA Display"sv, Memory::Region::Access::ReadWrite));
return adopt_lock_ref(*new (nothrow) VGATextModeConsole(move(vga_window_region)));
}
UNMAP_AFTER_INIT VGATextModeConsole::VGATextModeConsole(NonnullOwnPtr<Memory::Region> vga_window_region)
: Console(80, 25)
, m_vga_window_region(move(vga_window_region))
, m_current_vga_window(m_vga_window_region->vaddr().offset(0x18000).as_ptr())
{
for (size_t index = 0; index < height(); index++) {
clear_vga_row(index);
}
dbgln("VGA Text mode console initialized!");
}
enum VGAColor : u8 {
Black = 0,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
LightGray,
DarkGray,
BrightBlue,
BrightGreen,
BrightCyan,
BrightRed,
BrightMagenta,
Yellow,
White,
};
[[maybe_unused]] static inline VGAColor convert_standard_color_to_vga_color(Console::Color color)
{
switch (color) {
case Console::Color::Black:
return VGAColor::Black;
case Console::Color::Red:
return VGAColor::Red;
case Console::Color::Brown:
return VGAColor::Brown;
case Console::Color::Blue:
return VGAColor::Blue;
case Console::Color::Magenta:
return VGAColor::Magenta;
case Console::Color::Green:
return VGAColor::Green;
case Console::Color::Cyan:
return VGAColor::Cyan;
case Console::Color::LightGray:
return VGAColor::LightGray;
case Console::Color::DarkGray:
return VGAColor::DarkGray;
case Console::Color::BrightRed:
return VGAColor::BrightRed;
case Console::Color::BrightGreen:
return VGAColor::BrightGreen;
case Console::Color::Yellow:
return VGAColor::Yellow;
case Console::Color::BrightBlue:
return VGAColor::BrightBlue;
case Console::Color::BrightMagenta:
return VGAColor::BrightMagenta;
case Console::Color::BrightCyan:
return VGAColor::BrightCyan;
case Console::Color::White:
return VGAColor::White;
default:
VERIFY_NOT_REACHED();
}
}
void VGATextModeConsole::set_cursor(size_t x, size_t y)
{
SpinlockLocker lock(m_vga_lock);
GraphicsManagement::the().set_vga_text_mode_cursor(width(), x, y);
m_x = x;
m_y = y;
}
void VGATextModeConsole::hide_cursor()
{
SpinlockLocker lock(m_vga_lock);
GraphicsManagement::the().disable_vga_text_mode_console_cursor();
}
void VGATextModeConsole::show_cursor()
{
set_cursor(m_x, m_y);
}
void VGATextModeConsole::clear(size_t x, size_t y, size_t length)
{
SpinlockLocker lock(m_vga_lock);
auto* buf = (u16*)m_current_vga_window.offset((x * 2) + (y * width() * 2)).as_ptr();
for (size_t index = 0; index < length; index++) {
buf[index] = 0x0720;
}
}
void VGATextModeConsole::scroll_up()
{
auto* start_of_buffer = m_current_vga_window.as_ptr();
auto* start_of_second_line = m_current_vga_window.offset(max_column() * 2).as_ptr();
auto size_to_move = (max_row() - 1) * max_column() * 2;
memmove(start_of_buffer, start_of_second_line, size_to_move);
// Clear the last row with a memset, we're called from `write` here which already
// grabs `m_vga_lock` so we will get a deadlock trying to call `clear_vga_row`
auto* last_line = m_current_vga_window.offset((max_row() - 1) * width() * 2).as_ptr();
memset(last_line, 0, width() * 2);
}
void VGATextModeConsole::write(size_t x, size_t y, char ch, bool critical)
{
write(x, y, ch, m_default_background_color, m_default_foreground_color, critical);
}
void VGATextModeConsole::write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical)
{
SpinlockLocker lock(m_vga_lock);
// If we are in critical printing mode, we need to handle new lines here
// because there's no other responsible object to do that in the print call path
if (critical && (ch == '\r' || ch == '\n')) {
// Disable hardware VGA cursor
GraphicsManagement::the().disable_vga_text_mode_console_cursor();
m_x = 0;
m_y += 1;
if (m_y >= max_row()) {
m_y = max_row() - 1;
scroll_up();
}
return;
}
auto* buf = (u16*)m_current_vga_window.offset((x * 2) + (y * width() * 2)).as_ptr();
*buf = foreground << 8 | background << 12 | ch;
m_x = x + 1;
if (m_x >= max_column()) {
m_x = 0;
m_y = y + 1;
if (m_y >= max_row()) {
if (critical) {
m_y = max_row() - 1;
scroll_up();
} else {
m_y = 0;
}
}
}
}
void VGATextModeConsole::clear_vga_row(u16 row)
{
clear(0, row, width());
}
void VGATextModeConsole::write(char ch, bool critical)
{
write(m_x, m_y, ch, critical);
}
}