mirror of
https://github.com/fergalmoran/ladybird.git
synced 2026-01-27 19:07:24 +00:00
As MMIO is placed at fixed physical addressed, and does not need to be backed by real RAM physical pages, there's no need to use PhysicalPage instances to track their pages. This results in slightly reduced allocations, but more importantly makes MMIO addresses which end up after the normal RAM ranges work, like 64-bit PCI BARs usually are.
181 lines
5.2 KiB
C++
181 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 {
|
|
|
|
NonnullLockRefPtr<VGATextModeConsole> VGATextModeConsole::initialize()
|
|
{
|
|
auto vga_window_size = MUST(Memory::page_round_up(0xc0000 - 0xa0000));
|
|
auto vga_window_region = MUST(MM.allocate_mmio_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)));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
}
|