#include "x86_64/vga/text.hpp" #include "kapi/boot.hpp" #include "kapi/cio.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" #include "x86_64/vga/crtc.hpp" #include #include #include #include #include #include #include namespace teachos::vga::x86_64::text { namespace { constexpr auto BUFFER_BASE_ADDRESS = std::uintptr_t{0xb8000}; constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80z; constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25z; constexpr auto CURSOR_ENABLED_BIT = 5U; } // namespace std::span const device::buffer = std::span{std::bit_cast(BUFFER_BASE_ADDRESS + std::bit_cast(&teachos::boot::x86_64::TEACHOS_VMA)), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT}; device::device() : m_position{boot::bootstrap_information.vga_buffer_index} {} auto device::clear(attribute attribute) -> void { m_position = 0; std::ranges::fill(buffer, std::pair{' ', std::bit_cast(attribute)}); } auto device::cursor(bool enabled) -> void { auto cursor_disable_byte = std::byte{!enabled} << CURSOR_ENABLED_BIT; crtc::address::write(crtc::registers::cursor_start); crtc::data::write(crtc::data::read() | cursor_disable_byte); } [[nodiscard]] auto device::column() const noexcept -> std::ptrdiff_t { return m_position % DEFAULT_TEXT_BUFFER_WIDTH; } [[nodiscard]] auto device::line() const noexcept -> std::ptrdiff_t { return m_position / DEFAULT_TEXT_BUFFER_WIDTH; } auto device::newline() -> void { auto free_glyphs_in_line = DEFAULT_TEXT_BUFFER_WIDTH - column(); m_position += free_glyphs_in_line; } auto device::scroll(std::ptrdiff_t nof_lines) -> void { auto scroll_count = std::min(nof_lines, DEFAULT_TEXT_BUFFER_HEIGHT); auto scroll_start = buffer.begin() + (scroll_count * DEFAULT_TEXT_BUFFER_WIDTH); std::ranges::move(scroll_start, buffer.end(), buffer.begin()); auto clear_start = buffer.begin() + (DEFAULT_TEXT_BUFFER_HEIGHT - scroll_count) * DEFAULT_TEXT_BUFFER_WIDTH; std::ranges::fill(clear_start, buffer.end(), glyph{}); m_position = (line() - scroll_count) * DEFAULT_TEXT_BUFFER_WIDTH; } auto device::write(cio::output_stream stream, std::string_view text) -> void { auto attributes = [&] -> attribute { switch (stream) { case cio::output_stream::stderr: return common_attributes::red_on_black; default: return common_attributes::green_on_black; } }(); write(text, attributes); } auto device::write(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); } auto device::write(char code_point, attribute attribute) -> void { if (m_position + 1 > DEFAULT_TEXT_BUFFER_HEIGHT * DEFAULT_TEXT_BUFFER_WIDTH) { scroll(); } if (code_point == '\n') { if (column()) { newline(); } return; } buffer[m_position++] = std::pair{code_point, std::bit_cast(attribute)}; }; } // namespace teachos::vga::x86_64::text