From 1b964278762dde86b0b737bd9a34fec569339f54 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 10:29:30 +0200 Subject: x86_64: use p1204 project layout --- arch/x86_64/include/arch/boot/boot.hpp | 56 ----- arch/x86_64/include/arch/boot/ld.hpp | 61 ----- arch/x86_64/include/arch/bus/isa.hpp | 18 -- arch/x86_64/include/arch/cpu/control_register.hpp | 249 --------------------- .../include/arch/cpu/global_descriptor_table.hpp | 91 -------- arch/x86_64/include/arch/cpu/initialization.hpp | 12 - arch/x86_64/include/arch/cpu/interrupts.hpp | 116 ---------- arch/x86_64/include/arch/cpu/legacy_pic.hpp | 19 -- .../include/arch/cpu/model_specific_register.hpp | 151 ------------- arch/x86_64/include/arch/cpu/registers.hpp | 32 --- .../x86_64/include/arch/cpu/segment_descriptor.hpp | 61 ----- arch/x86_64/include/arch/cpu/segment_selector.hpp | 21 -- .../x86_64/include/arch/cpu/task_state_segment.hpp | 30 --- arch/x86_64/include/arch/debug/qemu_output.hpp | 43 ---- arch/x86_64/include/arch/device_io/port_io.hpp | 112 --------- arch/x86_64/include/arch/devices/init.hpp | 12 - arch/x86_64/include/arch/devices/legacy_pit.hpp | 29 --- arch/x86_64/include/arch/devices/local_apic.hpp | 37 --- .../include/arch/memory/higher_half_mapper.hpp | 44 ---- arch/x86_64/include/arch/memory/kernel_mapper.hpp | 35 --- arch/x86_64/include/arch/memory/mmu.hpp | 27 --- arch/x86_64/include/arch/memory/page_table.hpp | 232 ------------------- arch/x86_64/include/arch/memory/page_utilities.hpp | 29 --- .../include/arch/memory/region_allocator.hpp | 93 -------- arch/x86_64/include/arch/vga/crtc.hpp | 35 --- arch/x86_64/include/arch/vga/text.hpp | 10 - arch/x86_64/include/arch/vga/text/attribute.hpp | 30 --- arch/x86_64/include/arch/vga/text/buffer.hpp | 101 --------- arch/x86_64/include/arch/vga/text/color.hpp | 35 --- .../include/arch/vga/text/common_attributes.hpp | 37 --- arch/x86_64/include/arch/vga/text/device.hpp | 45 ---- arch/x86_64/include/arch/vga/text/flags.hpp | 38 ---- 32 files changed, 1941 deletions(-) delete mode 100644 arch/x86_64/include/arch/boot/boot.hpp delete mode 100644 arch/x86_64/include/arch/boot/ld.hpp delete mode 100644 arch/x86_64/include/arch/bus/isa.hpp delete mode 100644 arch/x86_64/include/arch/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/arch/cpu/global_descriptor_table.hpp delete mode 100644 arch/x86_64/include/arch/cpu/initialization.hpp delete mode 100644 arch/x86_64/include/arch/cpu/interrupts.hpp delete mode 100644 arch/x86_64/include/arch/cpu/legacy_pic.hpp delete mode 100644 arch/x86_64/include/arch/cpu/model_specific_register.hpp delete mode 100644 arch/x86_64/include/arch/cpu/registers.hpp delete mode 100644 arch/x86_64/include/arch/cpu/segment_descriptor.hpp delete mode 100644 arch/x86_64/include/arch/cpu/segment_selector.hpp delete mode 100644 arch/x86_64/include/arch/cpu/task_state_segment.hpp delete mode 100644 arch/x86_64/include/arch/debug/qemu_output.hpp delete mode 100644 arch/x86_64/include/arch/device_io/port_io.hpp delete mode 100644 arch/x86_64/include/arch/devices/init.hpp delete mode 100644 arch/x86_64/include/arch/devices/legacy_pit.hpp delete mode 100644 arch/x86_64/include/arch/devices/local_apic.hpp delete mode 100644 arch/x86_64/include/arch/memory/higher_half_mapper.hpp delete mode 100644 arch/x86_64/include/arch/memory/kernel_mapper.hpp delete mode 100644 arch/x86_64/include/arch/memory/mmu.hpp delete mode 100644 arch/x86_64/include/arch/memory/page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/page_utilities.hpp delete mode 100644 arch/x86_64/include/arch/memory/region_allocator.hpp delete mode 100644 arch/x86_64/include/arch/vga/crtc.hpp delete mode 100644 arch/x86_64/include/arch/vga/text.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/attribute.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/buffer.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/color.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/common_attributes.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/device.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/flags.hpp (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/arch/boot/boot.hpp b/arch/x86_64/include/arch/boot/boot.hpp deleted file mode 100644 index 7df61c4..0000000 --- a/arch/x86_64/include/arch/boot/boot.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef TEACHOS_X86_64_BOOT_BOOT_HPP -#define TEACHOS_X86_64_BOOT_BOOT_HPP - -#ifdef __ASSEMBLER__ -// clang-format off - -//! The number of huge pages to map during bootstrap. -#define HUGE_PAGES_TO_MAP (16) - -//! The magic value to be set in eax by the multiboot 2 loader. -#define MULTIBOOT2_MAGIC (0x36d76289) - -//! The "A" bit in a GDT entry. -#define GDT_ACCESSED (1 << 40) - -//! The "R/W" bit in a GDT entry -#define GDT_READ_WRITE (1 << 41) - -//! The "E" bit in a GDT entry. -#define GDT_EXECUTABLE (1 << 43) - -//! The "S" bit in a GDT entry. -#define GDT_DESCRIPTOR_TYPE (1 << 44) - -//! The "P" bit in a GDT entry. -#define GDT_PRESENT (1 << 47) - -//! The "L" bit in a GDT entry. -#define GDT_LONG_MODE (1 << 53) - -// clang-format on -#else - -#include // IWYU pragma: export - -#include - -#include - -namespace kapi::boot -{ - - struct information - { - //! A pointer to the loader provided Multiboot2 Information structure. - multiboot2::information_view const * mbi; - - //! The index of the next character to be written in the VGA text buffer after handoff. - std::size_t vga_buffer_index; - }; - -} // namespace kapi::boot - -#endif - -#endif diff --git a/arch/x86_64/include/arch/boot/ld.hpp b/arch/x86_64/include/arch/boot/ld.hpp deleted file mode 100644 index 988723d..0000000 --- a/arch/x86_64/include/arch/boot/ld.hpp +++ /dev/null @@ -1,61 +0,0 @@ -//! @file -//! The interface to linker script defined symbols. -//! -//! This header provides declarations for symbols that are defined in the linker script itself. The symbols declared -//! here provide important information, for example the start and end of the kernel image in virtual and physical -//! memory. -//! -//! Any variables defined in this file must not be read themselves, but rather their address shall be taken, yielding a -//! pointer to the memory location the represent. -//! -//! @note The symbols declared in this header are declared using C-language linkage in order to suppress name mangling. -//! -//! @see arch/x86_64/scripts/kernel.ld - -#ifndef TEACHOS_X86_64_BOOT_LD_HPP -#define TEACHOS_X86_64_BOOT_LD_HPP - -#include - -namespace arch::boot -{ - - extern "C" - { - //! The beginning of the kernel image in physical memory - //! - //! This symbol marks the start of the kernel image in physical memory. - //! - //! @see _end_physical - extern std::byte _start_physical; - - //! The first byte after the loaded kernel image. - //! - //! This symbol marks the end of the kernel image in physical memory. - //! - //! @see _start_physical - extern std::byte _end_physical; - - //! The first byte of the loaded kernel image in the virtual address space. - //! - //! This symbol and marks the start of the kernel image in virtual memory. - //! - //! @see _end_virtual - extern std::byte _start_virtual; - - //! The first byte after the loaded kernel image in the virtual address space. - //! - //! This symbol marks the end of the kernel image in virtual memory. - //! - //! @see _start_virtual - extern std::byte _end_virtual; - - //! The first byte of the kernel's virtual address space. - //! - //! This symbol marks beginning of the kernel virtual address space. - extern std::byte TEACHOS_VMA; - } - -} // namespace arch::boot - -#endif diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp deleted file mode 100644 index e56f56a..0000000 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_X86_64_BUS_ISA_HPP -#define TEACHOS_X86_64_BUS_ISA_HPP - -#include - -#include - -namespace arch::bus -{ - - struct isa final : public kapi::devices::bus - { - isa(std::size_t major); - }; - -} // namespace arch::bus - -#endif // TEACHOS_X86_64_BUS_ISA_HPP diff --git a/arch/x86_64/include/arch/cpu/control_register.hpp b/arch/x86_64/include/arch/cpu/control_register.hpp deleted file mode 100644 index 9cedc35..0000000 --- a/arch/x86_64/include/arch/cpu/control_register.hpp +++ /dev/null @@ -1,249 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP -#define TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP - -// IWYU pragma: private, include - -#include - -#include - -#include -#include -#include -#include - -namespace arch::cpu -{ - namespace impl - { - //! The assembler templates used to access (r/w) CR0; - constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; - - //! The assembler templates used to access (r/w) CR2; - constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; - - //! The assembler templates used to access (r/w) CR3; - constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; - } // namespace impl - - //! The flags that can be set on CR0 configuration register. - enum struct cr0_flags : uint64_t - { - //! Enable protected mode. - protection_enable = 1uz << 0, - //! Enable wait-monitoring of the coprocessor after task switching. - monitor_coprocessor = 1uz << 1, - //! Emulate floating point coprocessor. - emulation = 1uz << 2, - //! Marks that a task switch has occurred. - task_switched = 1uz << 3, - //! Marks Intel 387 DX math coprocessor as available - extension_type = 1uz << 4, - //! Numeric error handling mode. - numeric_error = 1uz << 5, - //! Disable writing to read-only marked memory. - write_protect = 1uz << 16, - //! Enable Ring-3 alignment checks - alignment_check = 1uz << 18, - //! Disable write through - not_write_through = 1uz << 29, - //! Disable caching of memory accesses - cache_disable = 1uz << 30, - //! Enable paging - paging = 1uz << 31 - }; - - enum struct cr3_flags : std::uint64_t - { - page_level_write_through = 1uz << 0, - page_level_cache_disable = 1uz << 1, - }; -} // namespace arch::cpu - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; - - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -namespace arch::cpu -{ - //! A mixin for flag-oriented control registers. - //! - //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A - //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct control_register_with_flags - { - private: - constexpr control_register_with_flags() noexcept = default; - friend Derived; - }; - - //! @copydoc control_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the control register - //! is an enum. - template - struct control_register_with_flags>> - { - //! The type of the flags used by this control register - using flags = ValueType; - - //! Set one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be set in the control register. - auto static set(ValueType value) -> void - { - auto current = Derived::read(); - current |= value; - Derived::write(current); - } - - //! Clear one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be cleared in the control register. - auto static clear(ValueType value) -> void - { - auto current = Derived::read(); - current &= ~value; - Derived::write(current); - } - }; - - //! A CPU control register. - //! - //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU - //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU - //! in an invalid/undefined state. - template - struct control_register : control_register_with_flags, ValueType> - { - //! Read the current value of the control register. - //! - //! @return The currently set value of the control register. - [[nodiscard]] auto static read() -> ValueType - { - auto value = ValueType{}; - asm volatile((AssemblerTemplates->first) : "=r"(value)); - return value; - } - - //! Write a new value to the control register. - //! - //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value The new value to write to the control register. - auto static write(ValueType value) -> void - { - asm volatile((AssemblerTemplates->second) : : "r"(value)); - } - }; - - //! The value type of the CR3 control register. - //! - //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the - //! page aligned physical address of the root page map, as well as the root paging configuration flags. - struct cr3_value - { - //! Contstruct a 0-value CR3 value. - constexpr cr3_value() = default; - - //! Construct a CR3 value using the given root page map address and flags. - //! - //! @param address The physical address of the root page map - //! @param flags The root configuration flags of the paging system. - constexpr cr3_value(kapi::memory::physical_address address, cr3_flags flags = static_cast(0)) - : m_flags{static_cast(flags)} - , m_address{static_cast(address.raw())} - {} - - //! Extract the physical address of the root page map from this value. - //! - //! @return The physical address of the root page map. - [[nodiscard]] constexpr auto address() const -> kapi::memory::physical_address - { - constexpr auto address_shift = 12uz; - return kapi::memory::physical_address{m_address << address_shift}; - } - - //! Encode the frame aligned physical address of the root page map into this value. - //! - //! @param frame The frame containing a PML4. - constexpr auto frame(kapi::memory::frame frame) -> void - { - m_address = static_cast(frame.number()); - } - - //! Extract the root paging configuration flags from this value. - //! - //! @return The root paging configuration flags. - [[nodiscard]] constexpr auto flags() const -> cr3_flags - { - return static_cast(m_flags); - } - - //! Encode the root paging configuration flags into this value. - //! - //! @param flags The root paging configuration flags. - constexpr auto flags(cr3_flags flags) -> void - { - m_flags = static_cast(flags); - } - - //! Add the given flags to the current set of encoded root configuration flags of this value. - //! - //! @param flags The root configuration flags to add. - //! @return A reference to this value. - constexpr auto operator|=(cr3_flags flags) -> cr3_value & - { - m_flags |= static_cast(flags); - return *this; - } - - //! Mask the root configuration flags of this value. - //! - //! @param mask The mask to apply to the root configuration flags. - //! @return A reference to this value. - constexpr auto operator&=(cr3_flags mask) -> cr3_value & - { - m_flags &= static_cast(mask); - return *this; - } - - private: - //! Reserved bits. - std::uint64_t : 3; - //! The root paging configuration flags. - std::uint64_t m_flags : 2 {}; - //! Reserved bits. - std::uint64_t : 7; - //! The page aligned physical address of the root page map. - std::uint64_t m_address : 52 {}; - }; - - static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp deleted file mode 100644 index b17c509..0000000 --- a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP -#define TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace arch::cpu -{ - - template - struct global_descriptor_table; - - struct [[gnu::packed]] global_descriptor_table_pointer - { - template - global_descriptor_table_pointer(global_descriptor_table const & gdt) - : size{GdtSize * sizeof(segment_descriptor) - 1} - , address{kapi::memory::physical_address{std::bit_cast(&gdt)}.raw()} - {} - - auto load() -> void - { - asm volatile("lgdt %0" : : "m"(*this)); - } - - std::uint16_t size{}; - std::uint64_t address{}; - }; - - static_assert(sizeof(global_descriptor_table_pointer) == sizeof(std::uint16_t) + sizeof(std::uint64_t)); - - template - struct global_descriptor_table - { - template... SegmentDescriptors> - constexpr global_descriptor_table(SegmentDescriptors const &... descriptors) - : m_descriptors{} - { - auto descriptor_data = std::array{ - std::pair{std::bit_cast(&descriptors), sizeof(descriptors)} - ... - }; - auto written_size = 0uz; - std::ranges::for_each(descriptor_data, [&written_size, this](auto entry) { - std::ranges::copy(entry.first, entry.first + entry.second, m_descriptors.begin() + written_size); - written_size += entry.second; - }); - } - - auto load(std::size_t code_segment_index, std::size_t data_segment_index) const -> void - { - auto pointer = global_descriptor_table_pointer{*this}; - pointer.load(); - - asm volatile("push %0\n" - "lea 1f(%%rip), %%rax\n" - "push %%rax\n" - "lretq\n" - "1:\n" - "mov %1, %%rax\n" - "mov %%rax, %%ss\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - : - : "X"(code_segment_index * sizeof(segment_descriptor)), - "X"(data_segment_index * sizeof(segment_descriptor)) - : "rax"); - } - - private: - std::array m_descriptors; - }; - - template... SegmentDescriptors> - global_descriptor_table(SegmentDescriptors const &... descriptors) - -> global_descriptor_table<(sizeof(SegmentDescriptors) + ...)>; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/initialization.hpp b/arch/x86_64/include/arch/cpu/initialization.hpp deleted file mode 100644 index 564c544..0000000 --- a/arch/x86_64/include/arch/cpu/initialization.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP -#define TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP - -namespace arch::cpu -{ - auto initialize_descriptors() -> void; - - auto initialize_legacy_interrupts() -> void; - -} // namespace arch::cpu - -#endif diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp deleted file mode 100644 index 6162f56..0000000 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP -#define TEACHOS_X86_64_CPU_INTERRUPTS_HPP - -#include - -#include - -#include -#include -#include - -namespace arch::cpu -{ - - //! The types of supported gates. - enum struct gate_type : std::uint8_t - { - //! A gate entered through the @p INT instruction. - interrupt_gate = 0b1110, - //! A gate entered via an exception. - trap_gate = 0b1111, - }; - - struct alignas(std::uint64_t) gate_descriptor - { - //! The lowest 16 bits of the address of this gate's handler function. - std::uint16_t offset_low : 16; - //! The code segment used when handling the respective interrupt. - segment_selector m_code_segment; - //! The index into the Interrupt Stack Table naming the stack to use. - std::uint8_t interrupt_stack_table_selector : 3; - //! Reserved - std::uint8_t : 5; - //! The type of this gate. - enum gate_type gate_type : 4; - //! Reserved - std::uint8_t : 1; - //! The privilege level required to enter through this gate. - std::uint8_t descriptor_privilege_level : 2; - //! Whether this gate is present or not. - std::uint8_t present : 1; - //! The middle 16 bits of the address of this gate's handler function. - std::uint16_t offset_middle : 16; - //! The highest 32 bits of the address of this gate's handler function. - std::uint32_t offset_high : 32; - //! Reserved - std::uint32_t : 32; - }; - - static_assert(sizeof(gate_descriptor) == 2 * sizeof(std::uint64_t)); - static_assert(std::is_aggregate_v); - - //! The stack frame as established by the low-level assembly interrupt stubs. - //! - //! @note The layout of this struct is reverse than what would reasonably be expected. The reason for this reversal is - //! that fact that it represents a stack frame. Stack frames on x86_64 grow towards lower addresses, meaning the first - //! item on the stack is the last item in C++ memory layout order. - struct interrupt_frame - { - struct - { - std::uint64_t r15{}; - std::uint64_t r14{}; - std::uint64_t r13{}; - std::uint64_t r12{}; - std::uint64_t r11{}; - std::uint64_t r10{}; - std::uint64_t r9{}; - std::uint64_t r8{}; - std::uint64_t rdi{}; - std::uint64_t rsi{}; - std::uint64_t rbp{}; - std::uint64_t rdx{}; - std::uint64_t rcx{}; - std::uint64_t rbx{}; - std::uint64_t rax{}; - } handler_saved; - - struct - { - std::uint64_t number{}; - std::uint64_t error_code{}; - } interrupt; - - struct - { - kapi::memory::linear_address rip{}; - std::uint64_t cs{}; - std::uint64_t rflags{}; - kapi::memory::linear_address rsp{}; - std::uint64_t ss{}; - } cpu_saved; - }; - - struct interrupt_descriptor_table - { - interrupt_descriptor_table() noexcept; - - auto load() const -> void; - - private: - std::array m_descriptors{}; - }; - - struct [[gnu::packed]] interrupt_descriptor_table_register - { - std::uint16_t limit; - gate_descriptor const * base; - - auto load() const -> void; - auto static read() -> interrupt_descriptor_table_register; - }; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/legacy_pic.hpp b/arch/x86_64/include/arch/cpu/legacy_pic.hpp deleted file mode 100644 index 56ca9c4..0000000 --- a/arch/x86_64/include/arch/cpu/legacy_pic.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP -#define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP - -#include - -#include - -namespace arch::cpu -{ - using pic_master_control_port = io::port<0x20, std::uint8_t, io::port_read, io::port_write>; - using pic_master_data_port = io::port<0x21, std::uint8_t, io::port_read, io::port_write>; - using pic_slave_control_port = io::port<0xa0, std::uint8_t, io::port_read, io::port_write>; - using pic_slave_data_port = io::port<0xa1, std::uint8_t, io::port_read, io::port_write>; - - constexpr auto pic_end_of_interrupt = std::uint8_t{0x20}; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/model_specific_register.hpp b/arch/x86_64/include/arch/cpu/model_specific_register.hpp deleted file mode 100644 index bd4aff9..0000000 --- a/arch/x86_64/include/arch/cpu/model_specific_register.hpp +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP -#define TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP - -// IWYU pragma: private, include - -#include - -#include -#include -#include - -namespace arch::cpu -{ - - //! The flags of the IA32_EFER (Extended Features Enable Register) MSR. - enum struct ia32_efer_flags : std::uint64_t - { - //! Enable the syscall and sysret instructions. - syscall_enable = 1uz << 0, - //! Enable IA-32e mode operation. - ia32e_mode_enable = 1uz << 8, - //! Indicates IA-32e mode is active (read-only) - ia32e_mode_active = 1uz << 10, - //! Enable the use of the NX page table bit. - execute_disable_bit_enable = 1uz << 11, - }; - -} // namespace arch::cpu - -namespace kstd::ext -{ - - template<> - struct is_bitfield_enum : std::true_type - { - }; - -} // namespace kstd::ext - -namespace arch::cpu -{ - //! The MSR number for the IA32_EFER MSR - constexpr auto ia32_efer_number = 0xC000'0080u; - - //! A mixin for flag-oriented model specific registers. - //! - //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific - //! register is flag-oriented, if it comprises a single field of bitfield. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct model_specific_register_with_flags - { - private: - constexpr model_specific_register_with_flags() noexcept = default; - friend Derived; - }; - - //! @copydoc model_specific_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the model specific - //! register is a bitfield enum. - template - struct model_specific_register_with_flags>> - { - //! The of the flags used by this model specific register. - using flags = ValueType; - - //! Set one or more flags in this model specific register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param flag One or a combination of flags to be set in the model specific register. - auto static set(flags flag) -> void - { - auto current = Derived::read(); - current |= flag; - Derived::write(current); - } - - //! Clear one or more flags in this model specific register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param flag One or a combination of flags to be cleared in the model specific register. - auto static clear(flags flag) -> void - { - auto current = Derived::read(); - current &= ~flag; - Derived::write(current); - } - - //! Test one or more flags in this model specific register - //! - //! @param flag One or a combination of flags to test for. - auto test(flags flag) -> flags - { - return Derived::read() & flag; - } - }; - - //! A model specific register (MSR) - //! - //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations. - //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in - //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in - //! an invalid/undefined state. - //! - //! @tparam Number The register number of this MSR - //! @tparam ValueType The value type of this MSR - template - struct model_specific_register - : model_specific_register_with_flags, ValueType> - { - //! A raw MSR value, comprising two halfs. - //! - //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs. - struct raw_value - { - std::uint32_t low_half; //!< The lower half of the register value - std::uint32_t high_half; //!< The upper half of the register value - }; - - //! Read the current value of this MSR. - //! - //! @return The current value of this MSR. - auto static read() -> ValueType - { - auto raw = raw_value{}; - asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); - return static_cast(std::bit_cast(raw)); - } - - //! Write a new value to this MSR. - //! - //! @param value The new value for this MSR. - auto static write(ValueType value) -> void - { - auto raw = std::bit_cast(static_cast(value)); - asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); - } - }; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/registers.hpp b/arch/x86_64/include/arch/cpu/registers.hpp deleted file mode 100644 index 58633f6..0000000 --- a/arch/x86_64/include/arch/cpu/registers.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP -#define TEACHOS_X86_64_CPU_REGISTERS_HPP - -#include // IWYU pragma: export -#include // IWYU pragma: export - -#include - -namespace arch::cpu -{ - - //! Configuration Register 0. - //! - //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. - using cr0 = control_register; - - //! Configuration Register 2. - //! - //! This configuration register holds the memory address the access to which has triggered the most recent page fault. - using cr2 = control_register; - - //! Configuration Register 3. - //! - //! This register holds the configuration of the virtual memory protection configuration. - using cr3 = control_register; - - //! The I32_EFER (Extended Feature Enable Register) MSR - using i32_efer = model_specific_register; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/segment_descriptor.hpp b/arch/x86_64/include/arch/cpu/segment_descriptor.hpp deleted file mode 100644 index 9570670..0000000 --- a/arch/x86_64/include/arch/cpu/segment_descriptor.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef TEACHOS_X86_64_SEGMENT_DESCRIPTOR_HPP -#define TEACHOS_X86_64_SEGMENT_DESCRIPTOR_HPP - -#include - -namespace arch::cpu -{ - - //! The type of segment described by a segment_descriptor. - enum struct segment_type : std::uint8_t - { - //! A system (TSS or LDT) segment - system = 0, - //! A code or data segment - code_or_data = 1, - }; - - //! The granularity of a segment described by a segment_descriptor - enum struct segment_granularity : std::uint8_t - { - //! The limit of the segment is defined in bytes. - byte = 0, - //! The limit of the segment is defined in pages (4KiB) - page = 1, - }; - - //! An entry in a segment descriptor table - struct segment_descriptor - { - std::uint64_t limit_low : 16; - std::uint64_t base_low : 24; - bool accessed : 1; - bool read_write : 1; - bool direction_or_conforming : 1; - bool executable : 1; - segment_type type : 1; - std::uint64_t privilege_level : 2; - bool present : 1; - std::uint64_t limit_high : 4; - std::uint64_t : 1; - bool long_mode : 1; - bool protected_mode : 1; - segment_granularity granularity : 1; - std::uint64_t base_high : 8; - }; - - static_assert(sizeof(segment_descriptor) == sizeof(std::uint64_t)); - static_assert(alignof(segment_descriptor) == alignof(std::uint64_t)); - - struct system_segment_descriptor : segment_descriptor - { - std::uint64_t base_extended : 32; - std::uint64_t : 32; - }; - - static_assert(sizeof(system_segment_descriptor) == 2 * sizeof(std::uint64_t)); - static_assert(alignof(system_segment_descriptor) == alignof(segment_descriptor)); - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/segment_selector.hpp b/arch/x86_64/include/arch/cpu/segment_selector.hpp deleted file mode 100644 index 1a78c47..0000000 --- a/arch/x86_64/include/arch/cpu/segment_selector.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TEACHOS_X86_64_SEGMENT_SELECTOR_HPP -#define TEACHOS_X86_64_SEGMENT_SELECTOR_HPP - -#include - -namespace arch::cpu -{ - - struct segment_selector - { - std::uint16_t request_privilege_level : 2; - bool use_local_descriptor_table : 1; - std::uint16_t table_index : 13; - }; - - static_assert(sizeof(segment_selector) == sizeof(std::uint16_t)); - static_assert(alignof(segment_selector) == alignof(std::uint16_t)); - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/task_state_segment.hpp b/arch/x86_64/include/arch/cpu/task_state_segment.hpp deleted file mode 100644 index 57729dd..0000000 --- a/arch/x86_64/include/arch/cpu/task_state_segment.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TEACHOS_X86_64_TASK_STATE_SEGMENT_HPP -#define TEACHOS_X86_64_TASK_STATE_SEGMENT_HPP - -#include - -namespace arch::cpu -{ - - struct [[gnu::packed]] task_state_segment - { - uint32_t : 32; - uint64_t rsp0 = {}; - uint64_t rsp1 = {}; - uint64_t rsp2 = {}; - uint64_t : 64; - uint64_t ist1 = {}; - uint64_t ist2 = {}; - uint64_t ist3 = {}; - uint64_t ist4 = {}; - uint64_t ist5 = {}; - uint64_t ist6 = {}; - uint64_t ist7 = {}; - uint64_t : 64; - uint16_t : 16; - uint16_t io_map_base_address = {}; - }; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/debug/qemu_output.hpp b/arch/x86_64/include/arch/debug/qemu_output.hpp deleted file mode 100644 index 5ddd4be..0000000 --- a/arch/x86_64/include/arch/debug/qemu_output.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP -#define TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP - -#include - -#include - -#include - -namespace arch::debug -{ - - //! A QEMU debug console output device. - //! - //! This device implements output to the port 0xE9 debug console present in QEMU in Bochs. It is designed to wrap a - //! different output device (e.g. a VGA text output device) and forwards the written data accordingly. - //! - //! @note Support for the device has to be enabled when the emulator is started. The device will try to detect if the - //! port is available. If the port is detected, any output to the device will be written to port before being - //! forwarded to the lower device. - struct qemu_output : kapi::cio::output_device - { - //! The port to write to. - using port = io::port<0xE9, unsigned char, io::port_write, io::port_read>; - - //! Construct a new debug device wrapper for the given output device. - //! - //! @param lower The device to forward the output to. - explicit qemu_output(output_device & lower); - - //! @copydoc kapi::cio::output_device - auto write(kapi::cio::output_stream stream, std::string_view text) -> void override; - - private: - //! The device to forward the output to. - output_device & m_lower; - //! Whether the device has been detected. - bool m_present; - }; - -} // namespace arch::debug - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/device_io/port_io.hpp b/arch/x86_64/include/arch/device_io/port_io.hpp deleted file mode 100644 index 4c8d66a..0000000 --- a/arch/x86_64/include/arch/device_io/port_io.hpp +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP -#define TEACHOS_X86_64_IO_PORT_IO_HPP - -#include -#include -#include -#include -#include -#include - -namespace arch::io -{ - - //! The requirements imposed on a type usable for port I/O. - template - concept port_io_type = requires { - requires sizeof(ValueType) == 1 || sizeof(ValueType) == 2 || sizeof(ValueType) == 4; - requires std::default_initializable; - std::bit_cast( - std::conditional_t>{}); - }; - - template - struct port_read - { - //! Read from the I/O port. - //! - //! @return The data read from the I/O port. - auto static read() noexcept - { - auto data = typename Derived::value_type{}; - asm volatile((code[Derived::size / 2]) - : [data] "=m"(data) - : [port] "i"(Derived::address) - : "dx", (Derived::data_register)); - return data; - } - - private: - constexpr port_read() noexcept = default; - friend Derived; - - //! The assembly templates used for reading from an I/O port. - constexpr auto static code = std::array{ - std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"}, - std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"}, - std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"}, - }; - }; - - template - struct port_write - { - //! Write data to the I/O port. - //! - //! @param data The data to write to the I/O port. - auto static write(std::same_as auto data) noexcept -> void - { - asm volatile((code[Derived::size / 2]) - : - : [port] "i"(Derived::address), [data] "im"(data) - : "dx", (Derived::data_register)); - } - - private: - constexpr port_write() noexcept = default; - friend Derived; - - //! The assembly templates used for writing to an I/O port. - constexpr auto static code = std::array{ - std::string_view{"mov %[port], %%dx\nmov %[data], %%al\nout %%al, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %[data], %%ax\nout %%ax, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %[data], %%eax\nout %%eax, %%dx"}, - }; - }; - - //! An I/O port of a given size at a given address. - //! - //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte - //! to double-word sized transfers. - //! - //! @tparam Address The address (port number) of the I/O port. - //! @tparam Size The size (in bytes) of the I/O port. - //! @tparam Features The features (readable, writeable) - template typename... Features> - requires(sizeof...(Features) > 0) - struct port : Features>... - { - //! The type of the data of this port. - using value_type = ValueType; - - //! The address of this I/O port. - constexpr auto static address = Address; - - //! The size of this I/O port. - constexpr auto static size = sizeof(value_type); - - //! The register clobbered by the I/O operation. - constexpr auto static data_register = size == 1 ? std::string_view{"al"} - : size == 2 ? std::string_view{"ax"} - : std::string_view{"eax"}; - }; - - auto inline wait() -> void - { - port<0x80, std::uint8_t, port_write>::write(0); - } - -} // namespace arch::io - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/devices/init.hpp b/arch/x86_64/include/arch/devices/init.hpp deleted file mode 100644 index c5fbf37..0000000 --- a/arch/x86_64/include/arch/devices/init.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP - -namespace arch::devices -{ - - auto init_acpi_devices() -> void; - auto init_legacy_devices() -> void; - -} // namespace arch::devices - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp deleted file mode 100644 index 356895c..0000000 --- a/arch/x86_64/include/arch/devices/legacy_pit.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP - -#include -#include - -#include -#include - -namespace arch::devices -{ - - struct legacy_pit : kapi::devices::device, kapi::interrupts::handler - { - legacy_pit(std::size_t major, std::uint32_t frequency_in_hz); - - auto init() -> bool override; - - auto handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status override; - - private: - std::uint32_t m_irq_number{}; - std::uint32_t m_frequency_in_hz{}; - std::uint64_t m_ticks{}; - }; - -} // namespace arch::devices - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp deleted file mode 100644 index f8f080d..0000000 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP - -#include -#include - -#include -#include - -namespace arch::devices -{ - - struct local_apic : kapi::devices::device - { - local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base, - bool is_bsp); - - auto init() -> bool override; - - private: - enum struct registers : std::ptrdiff_t; - - [[nodiscard]] auto read_register(registers id) const -> std::uint32_t; - auto write_register(registers id, std::uint32_t value) -> void; - - std::uint64_t m_hardware_id{}; - kapi::memory::physical_address m_base{}; - kapi::memory::mmio_region m_mapped_region{}; - bool m_is_bsp{}; - std::uint8_t m_version{}; - std::uint8_t m_highest_lvt_entry_index{}; - bool m_supports_eoi_broadcast_suppression{}; - }; - -} // namespace arch::devices - -#endif diff --git a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp b/arch/x86_64/include/arch/memory/higher_half_mapper.hpp deleted file mode 100644 index 9b02ee6..0000000 --- a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP -#define TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP - -#include - -#include - -#include - -namespace arch::memory -{ - - //! A simple page mapper making use of a Higher Half Direct Map (HHDM) to access and modify page tables. - struct higher_half_mapper : kapi::memory::page_mapper - { - //! Construct a new mapper for a hierarchy rooted in the given PML. - //! - //! @param root The root of the hierarchy to operate on. - explicit higher_half_mapper(page_table * root); - - //! @copydoc kapi::memory::page_mapper::map - auto map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte * override; - - //! @copydoc kapi::memory::page_mapper::unmap - auto unmap(kapi::memory::page page) -> void override; - - //! @copydoc kapi::memory::page_mapper::try_unmap - auto try_unmap(kapi::memory::page page) noexcept -> bool override; - - private: - //! Try to retrieve the the PML1 responsible for mapping this page, creating one if necessary. - //! - //! This function will create a page table hierarchy leading to the target PML1 if it doesn't exist. - //! - //! @param page The page to get the PML1 for. - //! @return The PML1 that manages the given page, nullptr it the system runs out of memory. - auto get_or_create_page_table(kapi::memory::page page) noexcept -> page_table *; - - page_table * m_root; - }; - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/kernel_mapper.hpp deleted file mode 100644 index adbf688..0000000 --- a/arch/x86_64/include/arch/memory/kernel_mapper.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP -#define TEACHOS_X86_64_KERNEL_MAPPER_HPP - -#include - -#include -#include - -#include - -#include -#include - -namespace arch::memory -{ - - struct kernel_mapper - { - using section_header_type = elf::section_header; - - explicit kernel_mapper(multiboot2::information_view const * mbi); - - auto remap_kernel(kapi::memory::page_mapper & mapper) -> void; - - private: - auto map_section(section_header_type const & section, std::string_view name, kapi::memory::page_mapper & mapper) - -> void; - - multiboot2::information_view const * m_mbi; - std::uintptr_t m_kernel_load_base; - }; - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/mmu.hpp b/arch/x86_64/include/arch/memory/mmu.hpp deleted file mode 100644 index 64373f4..0000000 --- a/arch/x86_64/include/arch/memory/mmu.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_MMU_HPP -#define TEACHOS_X86_64_MEMORY_MMU_HPP - -#include - -namespace arch::memory -{ - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - auto tlb_flush(kapi::memory::linear_address address) -> void; - - /** - * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. - * - * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because - * the system has to assume that the location of the level 4 page table moved. - */ - auto tlb_flush_all() -> void; - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp deleted file mode 100644 index ce3d3a1..0000000 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ /dev/null @@ -1,232 +0,0 @@ -#ifndef TEACHOS_X86_64_PAGE_TABLE_HPP -#define TEACHOS_X86_64_PAGE_TABLE_HPP - -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace arch::memory -{ - - //! A table containing page mapping entries. - //! - //! Page tables exist in a multi-level hierarchy and are used to map pages (virtual memory) onto frames (physical - //! memory). Conceptually, pages represent the data found in a virtual address space, while frames represent their - //! storage. In most cases, only a level 1 page table maps an actual page onto a frame. All other page tables on - //! higher levels do not map payload pages, but rather their subordinate page tables. The only exception to that rule - //! is the use of huge pages. - struct page_table - { - //! An entry in a page table. - //! - //! A page table entry is a combination of a frame number and a set of flags that determine the properties and - //! access rights to a mapped page. Entries at a higher level in the page hierarchy do not map a page directly, - //! unless that page is marked as huge on the relevant level, but rather map the next lower page table. - struct entry - { - //! Flags marking the state and configuration of an entry. - //! - //! An entry in a page table may have any combination of these flags active at the same time. The final flags of a - //! page are determined as the strictest combination (logical AND) of all flags along the hierarchy. - //! - //! @note This is a bitfield enum as defined by kstd::ext::bitfield_enum. - enum struct flags : std::uint64_t - { - empty = 0, - present = 1uz << 0, //!< The page is mapped. - writable = 1uz << 1, //!< The page is writable. - user_accessible = 1uz << 2, //!< The page is accessible in user mode. - write_through = 1uz << 3, //!< Any writes to the page must immediately hit memory. - disable_cache = 1uz << 4, //!< Any writes to the page must never be cached. - accessed = 1uz << 5, //!< The page was accessed. - dirty = 1uz << 6, //!< The page was written to. - huge_page = 1uz << 7, //!< The page is huge. - global = 1uz << 8, //!< The TLB entry for this page must not be flushed on context switches. - no_execute = 1uz << 63, //!< The data in this page must not be executed. - }; - - //! Construct an empty entry. - entry() = default; - - //! Clear this entry, ensuring all information is set to zero. - //! - //! This effectively marks the page represented by this entry as not present. In addition, it also removes any - //! information about the frame referenced by this entry. - auto clear() noexcept -> void; - - //! Check if the page represented by this entry is present. - //! - //! @note This function does not attempt to walk the page table hierarchy, but only performs a local check. This - //! means, that if the page is not mapped at a lower level, this will not be detected. - //! - //! @return @p true iff. the page is present at this level, @p false otherwise. - [[nodiscard]] auto present() const noexcept -> bool; - - //! Check if the page represented by this entry is a huge page. - //! - //! @note The effective size of the page depends on the level of the page table containing this entry. - //! - //! @return @p true iff. the page is marked as being huge, @p false otherwise. - [[nodiscard]] auto huge() const noexcept -> bool; - - //! Get all flags present in this entry. - //! - //! @return The flags that are currently set on this entry. - [[nodiscard]] auto all_flags() const noexcept -> flags; - - //! Set all flags of this entry. - //! - //! @param flags The flags to apply to this entry. - auto all_flags(flags flags) noexcept -> void; - - //! Add the given flags to the flags of this entry. - //! - //! @param rhs The flags to add to this entry's flags. - //! @return A reference to this entry. - auto operator|=(flags rhs) noexcept -> entry &; - - //! Get the frame number associated with this entry, if the referenced page is present. - //! - //! @return an engaged std::optional iff. this entry maps a page, std::nullopt otherwise. - [[nodiscard]] auto frame() const noexcept -> std::optional; - - //! Map this entry. - //! - //! @param frame The frame to map in this entry. - //! @param flags The flags to apply to this entry. - auto frame(kapi::memory::frame frame, flags flags) noexcept -> void; - - private: - //! A mask to retrieve, or exclude, the frame number from the raw entry. - //! - //! Page table entries in x86_64 are a compacted combination of the relevant flags and the frame number. This mask - //! represents the bits that make up the frame number in an entry. - constexpr auto static frame_number_mask{0x000f'ffff'ffff'f000uz}; - - //! The raw entry bytes. - //! - //! @see entry::frame_number_mask - std::uint64_t m_raw{}; - }; - - //! The maximum number of entries in this table. - constexpr auto static entry_count{kapi::memory::page::size / kstd::units::bytes{sizeof(entry)}}; - - //! Get the entry at the given index. - //! - //! @warning This function will panic if the entry index is out of bounds. - //! - //! @param index The index of the desired entry. - //! @return A reference to the entry at the given index. - [[nodiscard]] auto operator[](std::size_t index) -> entry &; - - //! @copydoc page_table::operator[] - [[nodiscard]] auto operator[](std::size_t index) const -> entry const &; - - //! Clear the entire page table. - //! - //! This function effectively marks the page table as not mapping any pages. - auto clear() noexcept -> void; - - //! Check if the page table is empty. - //! - //! @return @p true iff. this page table has no entries marked present, @p false otherwise. - [[nodiscard]] auto empty() const noexcept -> bool; - - private: - std::array m_entries{}; - }; - -} // namespace arch::memory - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -namespace arch::memory -{ - - constexpr auto to_mapper_flags(page_table::entry::flags flags) -> kapi::memory::page_mapper::flags - { - using table_flags = page_table::entry::flags; - using mapper_flags = kapi::memory::page_mapper::flags; - - auto result = mapper_flags{}; - - if ((flags & table_flags::no_execute) == table_flags::empty) - { - result |= mapper_flags::executable; - } - - if ((flags & table_flags::writable) != table_flags::empty) - { - result |= mapper_flags::writable; - } - - if ((flags & (table_flags::disable_cache | table_flags::write_through)) != table_flags::empty) - { - result |= mapper_flags::uncached; - } - - if ((flags & table_flags::user_accessible) == table_flags::empty) - { - result |= mapper_flags::supervisor_only; - } - - if ((flags & table_flags::global) != table_flags::empty) - { - result |= mapper_flags::global; - } - - return result; - } - - constexpr auto to_table_flags(kapi::memory::page_mapper::flags flags) -> page_table::entry::flags - { - using table_flags = page_table::entry::flags; - using mapper_flags = kapi::memory::page_mapper::flags; - - auto result = table_flags{}; - - if ((flags & mapper_flags::executable) == mapper_flags::empty) - { - result |= table_flags::no_execute; - } - - if ((flags & mapper_flags::writable) != mapper_flags::empty) - { - result |= table_flags::writable; - } - - if ((flags & mapper_flags::uncached) != mapper_flags::empty) - { - result |= (table_flags::disable_cache | table_flags::write_through); - } - - if ((flags & mapper_flags::supervisor_only) == mapper_flags::empty) - { - result |= table_flags::user_accessible; - } - - if ((flags & mapper_flags::global) != mapper_flags::empty) - { - result |= table_flags::global; - } - - return result; - } - -} // namespace arch::memory - -#endif diff --git a/arch/x86_64/include/arch/memory/page_utilities.hpp b/arch/x86_64/include/arch/memory/page_utilities.hpp deleted file mode 100644 index 068e824..0000000 --- a/arch/x86_64/include/arch/memory/page_utilities.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TEACHOS_X86_64_PAGE_UTILITIES_HPP -#define TEACHOS_X86_64_PAGE_UTILITIES_HPP - -#include - -#include - -namespace arch::memory -{ - - constexpr auto inline pml_index(std::size_t index, kapi::memory::page page) noexcept -> std::size_t - { - constexpr auto bits_per_level = 9; - auto shift_width = (index - 1) * bits_per_level; - constexpr auto index_mask = 0x1ffuz; - return page.number() >> shift_width & index_mask; - } - - template - [[nodiscard]] constexpr auto to_higher_half_pointer(kapi::memory::physical_address address) -> ValueType * - { - using namespace kapi::memory; - auto const higher_half_address = higher_half_direct_map_base + address.raw(); - return static_cast(higher_half_address); - } - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/region_allocator.hpp b/arch/x86_64/include/arch/memory/region_allocator.hpp deleted file mode 100644 index 5d9da2e..0000000 --- a/arch/x86_64/include/arch/memory/region_allocator.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP -#define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP - -#include -#include -#include - -#include - -#include -#include -#include - -namespace arch::memory -{ - //! A simple, memory-region based frame allocator. - //! - //! This frame allocator linearly allocates frames that are in available memory regions. It automatically skips any - //! frames occupied by the kernel image or any bootloader provided data. - //! - //! @note This allocator will never release frames. - struct region_allocator final : kapi::memory::frame_allocator - { - struct memory_information - { - //! The memory range occupied by the loaded kernel image. - //! - //! This includes all sections that are marked as occupying space in the kernel executable. The internal structure - //! of this area is more described in a more fine-grained manner by the ELF symbol information provided in the - //! Multiboot2 information by the loader. - std::pair image_range; - - //! The memory range occupied by the loader supplied Multiboot2 information structure. - //! - //! In general, this information is allocated somewhere in the range of the loaded image, but the loader protocol - //! does not guarantee this. It is thus imperative to be able to handle the cases where the loader chooses to - //! allocate the information structure outside of the image range. - std::pair mbi_range; - - //! The loader supplied map of memory regions. - //! - //! These include available, unavailable, and reclaimable regions. In general, only frames that are located in - //! non-reserved (as in available) regions should be allocated for page storage. - multiboot2::memory_map memory_map; - - //! The loader supplied Multiboot2 information structure. - //! - //! This is used to query boot module ranges so these frames can be excluded from early allocations. - multiboot2::information_view const * mbi; - }; - - using region = multiboot2::memory_map::region; - - //! Construct a new allocator using the provided memory information - //! - //! @param information The description of the detected memory regions as well as regions that are already occupied. - explicit region_allocator(memory_information const & information); - - //! @copydoc kapi::memory::frame_allocator::allocate_many - //! - //! @note As long as free frames are available, successive calls to this implementation are guaranteed to yield - //! frames in ascending order. - auto allocate_many(std::size_t count = 1) noexcept - -> std::optional> override; - - //! @copydoc kapi::memory::frame_allocator::mark_used - auto mark_used(kapi::memory::frame frame) -> void override; - - //! @copydoc kapi::memory::frame_allocator::release_many - //! - //! @note This implementation will never actually release any frames. - auto release_many(std::pair frame_set) -> void override; - - auto next_free_frame() noexcept -> std::optional; - - private: - //! Find the next memory area and write it into current_area. - auto choose_next_region() -> void; - auto find_next_frame() -> std::optional; - - kapi::memory::frame m_next_frame; //!< The next available frame. - std::optional m_current_region; //!< The memory region currently used for allocation - multiboot2::memory_map m_memory_map; //!< The boot loader supplied memory map. - kapi::memory::frame m_kernel_start; //!< The start of the kernel image in physical memory. - kapi::memory::frame m_kernel_end; //!< The end of the kernel image in physical memory. - kapi::memory::frame m_multiboot_start; //!< The start of the Multiboot2 information in physical memory. - kapi::memory::frame m_multiboot_end; //!< The end of the Multiboot2 information in physical memory. - multiboot2::information_view const * m_multiboot_information; //!< Source of Multiboot2 module ranges. - }; - -} // namespace arch::memory - -#endif diff --git a/arch/x86_64/include/arch/vga/crtc.hpp b/arch/x86_64/include/arch/vga/crtc.hpp deleted file mode 100644 index a8bec93..0000000 --- a/arch/x86_64/include/arch/vga/crtc.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_IO_HPP -#define TEACHOS_X86_64_VGA_IO_HPP - -#include - -#include - -namespace arch::vga::crtc -{ - /** - * @brief The address port of the CRT Controller. - */ - using address = io::port<0x3d4, std::byte, io::port_write>; - - /** - * @brief The data port of the CRT Controller. - */ - us