mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:54:57 +00:00
180 lines
5.2 KiB
C++
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);
|
|
}
|
|
|
|
}
|