diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-11-24 16:59:24 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-11-24 16:59:24 +0100 |
| commit | 1a3c20cc9ea191a862eb7e8ac55b3a69ac74ad5e (patch) | |
| tree | e740d842eb64f9dcde4a70ff138092d349e717c1 | |
| parent | 2b3dca0d0329b61881ffbecca0f120cfda3314fa (diff) | |
| download | teachos-1a3c20cc9ea191a862eb7e8ac55b3a69ac74ad5e.tar.xz teachos-1a3c20cc9ea191a862eb7e8ac55b3a69ac74ad5e.zip | |
x86_64/vga: rely less on magic state
| -rw-r--r-- | .vscode/settings.json | 2 | ||||
| -rw-r--r-- | arch/x86_64/CMakeLists.txt | 24 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/boot/boot.hpp | 24 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/boot/ld.hpp | 9 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/vga/text.hpp | 11 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/entry64.s | 19 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/memory.cpp | 4 | ||||
| -rw-r--r-- | arch/x86_64/src/vga/text.cpp | 50 | ||||
| -rw-r--r-- | kapi/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | kapi/include/kapi/boot.hpp | 11 |
10 files changed, 118 insertions, 37 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index dcf1d1a..4f3f047 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,9 +24,11 @@ "cSpell.words": [ "crtc", "efer", + "INTERPROCEDURAL", "invlpg", "kapi", "kstd", + "multiboot", "NOLINTNEXTLINE", "rdmsr", "rvalues", diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9c6d818..cf85b36 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -30,6 +30,30 @@ target_sources("x86_64" PRIVATE "src/vga/text.cpp" ) +target_sources("x86_64" PRIVATE + FILE_SET HEADERS + BASE_DIRS "include" + FILES + # Low-level bootstrap + "include/x86_64/boot/boot.hpp" + "include/x86_64/boot/ld.hpp" + + # Low-level CPU access + "include/x86_64/cpu/registers.hpp" + "include/x86_64/cpu/impl/control_registers.hpp" + "include/x86_64/cpu/impl/model_specific_register.hpp" + + # Low-level device I/O + "include/x86_64/device_io/port_io.hpp" + + # Memory management + "include/x86_64/memory/mmu.hpp" + "include/x86_64/memory/region_allocator.hpp" + + # VGA I/O + "include/x86_64/vga/text.hpp" +) + set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" PARENT_SCOPE diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 3a3620d..6dcd2de 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -45,26 +45,22 @@ /* clang-format on */ #else +#include "kapi/boot.hpp" // IWYU pragma: export + #include <multiboot2/information.hpp> -#include <kstd/asm_ptr> +#include <cstddef> -namespace teachos::boot::x86_64 +namespace teachos::boot { - extern "C" + struct information { - /** - * @brief A pointer to the multiboot 2 information structure provided by the boot loader. - */ - extern kstd::asm_ptr<multiboot2::information_view> multiboot_information_pointer; - - /** - * @brief A pointer to the VGA text mode buffer. - */ - extern kstd::asm_ptr<std::pair<char, std::byte>> vga_buffer_pointer; - } -} // namespace teachos::boot::x86_64 + multiboot2::information_view const * mbi; + std::size_t vga_buffer_index; + }; + +} // namespace teachos::boot #endif diff --git a/arch/x86_64/include/x86_64/boot/ld.hpp b/arch/x86_64/include/x86_64/boot/ld.hpp index 104e6ee..9af3dc8 100644 --- a/arch/x86_64/include/x86_64/boot/ld.hpp +++ b/arch/x86_64/include/x86_64/boot/ld.hpp @@ -61,6 +61,15 @@ namespace teachos::boot::x86_64 * To use this symbol for its intended purpose, the address of it shall be taken. */ extern std::byte _end_virtual; + + /** + * @brief The first byte of the kernel's virtual address space. + * + * @details + * This symbol is defined in the kernel linker script and marks beginning of the kernel virtual address space. To + * use this symbol for its intended purpose, the address of it shall be taken. + */ + extern std::byte TEACHOS_VMA; } } // namespace teachos::boot::x86_64 diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index d8919bf..bb593e7 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -4,6 +4,7 @@ #include "kapi/cio.hpp" #include <cstdint> +#include <span> #include <string_view> namespace teachos::vga::x86_64::text @@ -100,6 +101,8 @@ namespace teachos::vga::x86_64::text struct device final : teachos::cio::output_device { + device(); + /** * @brief Clear the VGA text mode buffer. * @@ -134,6 +137,8 @@ namespace teachos::vga::x86_64::text } private: + using glyph = std::pair<char, std::byte>; + /** * @brief Move the cursor to a new line, scrolling the buffer if necessary. */ @@ -150,6 +155,8 @@ namespace teachos::vga::x86_64::text */ auto write(std::string_view code_points, attribute attribute) -> void; + auto write(char code_point, attribute attribute) -> void; + /** * @brief Write a string of code points followed by a newline to the VGA text buffer. * @@ -160,6 +167,10 @@ namespace teachos::vga::x86_64::text * @see vga::text::attribute */ auto writeln(std::string_view code_points, attribute attribute) -> void; + + std::span<glyph> static const buffer; + + std::size_t m_position{}; }; } // namespace teachos::vga::x86_64::text diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index c5df5db..636e4cd 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -1,3 +1,16 @@ +.section .bss, "aw", @nobits + +//! A structure containing information gathered during the bootstrap process. +//! Expected layout (as described by teachos::boot::information): +//! +//! struct +//! { +//! multiboot2::information_view const * mbi; +//! std::size_t vga_buffer_index; +//! } +.global bootstrap_information +bootstrap_information: .skip 16 + .section .boot_text, "ax", @progbits .code64 @@ -10,6 +23,12 @@ _entry64: mov %rax, %fs mov %rax, %gs + mov multiboot_information_pointer, %rax + mov vga_buffer_pointer, %rdx + sub $0xb8000, %rdx + mov %rax, (bootstrap_information) + mov %rdx, (bootstrap_information + 8) + call invoke_global_constructors xor %rax, %rax diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 5142a2a..3848fb8 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -24,7 +24,7 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { - auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); + auto const & mbi = boot::bootstrap_information.mbi; return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), @@ -35,7 +35,7 @@ namespace teachos::memory auto create_early_frame_allocator() { - auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); + auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map(); if (!memory_map) { system::panic("[x86_64] Failed to create early allocator, no memory map available."); diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 6ecffa3..8b7f01b 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,38 +1,41 @@ #include "x86_64/vga/text.hpp" +#include "kapi/boot.hpp" + #include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" #include "x86_64/vga/crtc.hpp" #include <algorithm> #include <bit> #include <cstddef> +#include <cstdint> #include <string_view> #include <utility> namespace teachos::vga::x86_64::text { - using boot::x86_64::vga_buffer_pointer; - namespace { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit buffer_offset = std::ptrdiff_t{}; - + constexpr auto BUFFER_BASE_ADDRESS = std::uintptr_t{0xb8000}; constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; constexpr auto CURSOR_ENABLED_BIT = 5U; - - auto write_char(char code_point, attribute attribute) -> void - { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)}; - }; } // namespace + std::span<device::glyph> const device::buffer = + std::span{std::bit_cast<device::glyph *>(BUFFER_BASE_ADDRESS + + std::bit_cast<std::uintptr_t>(&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 { - buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT, - std::pair{' ', std::bit_cast<std::byte>(attribute)}); + m_position = 0; + std::ranges::fill(buffer, std::pair{' ', std::bit_cast<std::byte>(attribute)}); } auto device::cursor(bool enabled) -> void @@ -45,30 +48,35 @@ namespace teachos::vga::x86_64::text auto device::newline() -> void { - auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; + auto current_line = m_position / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; if (std::cmp_greater_equal(next_line, DEFAULT_TEXT_BUFFER_HEIGHT)) { - auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; - auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; - std::ranges::move(begin, end, vga_buffer_pointer.get()); - buffer_offset = current_line * DEFAULT_TEXT_BUFFER_WIDTH; + auto begin = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH; + auto end = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; + std::ranges::move(begin, end, buffer.begin()); + m_position = current_line * DEFAULT_TEXT_BUFFER_WIDTH; } else { - buffer_offset = next_line * DEFAULT_TEXT_BUFFER_WIDTH; + m_position = next_line * DEFAULT_TEXT_BUFFER_WIDTH; } } auto device::write(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); } + auto device::write(char code_point, attribute attribute) -> void + { + buffer[m_position++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)}; + }; + auto device::writeln(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); newline(); } diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index 86b0fb6..553b9ba 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources("kapi" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES + "include/kapi/boot.hpp" "include/kapi/cio.hpp" "include/kapi/memory.hpp" "include/kapi/system.hpp" diff --git a/kapi/include/kapi/boot.hpp b/kapi/include/kapi/boot.hpp new file mode 100644 index 0000000..013e180 --- /dev/null +++ b/kapi/include/kapi/boot.hpp @@ -0,0 +1,11 @@ +#ifndef TEACHOS_KAPI_BOOT_HPP +#define TEACHOS_KAPI_BOOT_HPP + +namespace teachos::boot +{ + struct information; + + extern "C" information const bootstrap_information; +} // namespace teachos::boot + +#endif |
