diff options
Diffstat (limited to 'arch/x86_64')
102 files changed, 1511 insertions, 1611 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 41932c9..20a48f9 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -1,44 +1,69 @@ +#[============================================================================[ +# Library +#]============================================================================] + add_library("x86_64" OBJECT) -add_library("os::arch" ALIAS "x86_64") +add_library("arch::lib" ALIAS "x86_64") target_include_directories("x86_64" PUBLIC - "include" + "${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries("x86_64" PUBLIC - "os::kapi" - "libs::multiboot2" + "kapi::lib" + "multiboot2::lib" ) target_sources("x86_64" PRIVATE - # Platform-dependent KAPI implementation + "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" + "kapi/devices.cpp" + "kapi/interrupts.cpp" "kapi/memory.cpp" "kapi/system.cpp" +) + +target_sources("x86_64" PRIVATE + # CPU Initialization + "arch/cpu/initialization.cpp" + "arch/cpu/interrupts.cpp" + "arch/cpu/interrupts.S" + + # Bus Initialization + "arch/bus/isa.cpp" # Low-level bootstrap - "src/boot/boot32.S" - "src/boot/entry64.s" - "src/boot/initialize_runtime.cpp" - "src/boot/multiboot.s" + "arch/boot/boot32.S" + "arch/boot/entry64.s" + "arch/boot/initialize_runtime.cpp" + "arch/boot/multiboot.s" # Debug interfaces - "src/debug/qemu_output.cpp" + "arch/debug/qemu_output.cpp" + + # Devices + "arch/devices/init.cpp" + "arch/devices/legacy_pit.cpp" + "arch/devices/local_apic.cpp" # Memory management - "src/memory/kernel_mapper.cpp" - "src/memory/higher_half_mapper.cpp" - "src/memory/mmu.cpp" - "src/memory/page_table.cpp" - "src/memory/region_allocator.cpp" + "arch/memory/kernel_mapper.cpp" + "arch/memory/higher_half_mapper.cpp" + "arch/memory/mmu.cpp" + "arch/memory/page_table.cpp" + "arch/memory/region_allocator.cpp" # VGA text mode - "src/vga/text/buffer.cpp" - "src/vga/text/device.cpp" + "arch/vga/text/buffer.cpp" + "arch/vga/text/device.cpp" ) -file(GLOB_RECURSE ARCH_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") +file(GLOB_RECURSE ARCH_HEADERS + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS + "include/**.hpp" +) target_sources("x86_64" PUBLIC FILE_SET HEADERS @@ -46,7 +71,23 @@ target_sources("x86_64" PUBLIC FILES ${ARCH_HEADERS} ) +target_include_directories("x86_64" PUBLIC + "include" +) + +target_link_libraries("x86_64" PUBLIC + "acpi::lib" + "elf::lib" + "kapi::lib" + "kstd::lib" + "multiboot2::lib" +) + set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" PARENT_SCOPE ) + +set_target_properties("x86_64" PROPERTIES + VERIFY_INTERFACE_HEADER_SETS YES +) diff --git a/arch/x86_64/include/arch/boot/boot.hpp b/arch/x86_64/arch/boot/boot.hpp index 3a598f5..7df61c4 100644 --- a/arch/x86_64/include/arch/boot/boot.hpp +++ b/arch/x86_64/arch/boot/boot.hpp @@ -31,7 +31,7 @@ // clang-format on #else -#include "kapi/boot.hpp" // IWYU pragma: export +#include <kapi/boot.hpp> // IWYU pragma: export #include <multiboot2/information.hpp> diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/arch/boot/boot32.S index 1c2fdaf..e6fcd85 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/arch/boot/boot32.S @@ -1,4 +1,4 @@ -#include "arch/boot/boot.hpp" +#include <arch/boot/boot.hpp> /** * @brief Uninitialized data for the bootstrapping process. diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/arch/boot/entry64.s index 29fb778..29fb778 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/arch/boot/entry64.s diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/arch/boot/initialize_runtime.cpp index b08c13c..b08c13c 100644 --- a/arch/x86_64/src/boot/initialize_runtime.cpp +++ b/arch/x86_64/arch/boot/initialize_runtime.cpp diff --git a/arch/x86_64/include/arch/boot/ld.hpp b/arch/x86_64/arch/boot/ld.hpp index 988723d..988723d 100644 --- a/arch/x86_64/include/arch/boot/ld.hpp +++ b/arch/x86_64/arch/boot/ld.hpp diff --git a/arch/x86_64/src/boot/multiboot.s b/arch/x86_64/arch/boot/multiboot.s index 7ccca56..37d8afe 100644 --- a/arch/x86_64/src/boot/multiboot.s +++ b/arch/x86_64/arch/boot/multiboot.s @@ -18,6 +18,13 @@ multiboot_header_start: .long 3 .Lflags_end: .align 8 +.Linformation_request_start: + .word 1 + .word 0 + .long .Linformation_request_end - .Linformation_request_start + .long 3 +.Linformation_request_end: +.align 8 .Lend_start: .word 0 .word 0 diff --git a/arch/x86_64/arch/bus/isa.cpp b/arch/x86_64/arch/bus/isa.cpp new file mode 100644 index 0000000..f6cc72d --- /dev/null +++ b/arch/x86_64/arch/bus/isa.cpp @@ -0,0 +1,14 @@ +#include <arch/bus/isa.hpp> + +#include <kapi/devices.hpp> + +#include <cstddef> + +namespace arch::bus +{ + + isa::isa(std::size_t major) + : kapi::devices::bus{major, 0, "isa"} + {} + +} // namespace arch::bus
\ No newline at end of file diff --git a/arch/x86_64/arch/bus/isa.hpp b/arch/x86_64/arch/bus/isa.hpp new file mode 100644 index 0000000..e56f56a --- /dev/null +++ b/arch/x86_64/arch/bus/isa.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_X86_64_BUS_ISA_HPP +#define TEACHOS_X86_64_BUS_ISA_HPP + +#include <kapi/devices/bus.hpp> + +#include <cstddef> + +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/arch/cpu/control_register.hpp index fafbfc7..9cedc35 100644 --- a/arch/x86_64/include/arch/cpu/control_register.hpp +++ b/arch/x86_64/arch/cpu/control_register.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP #define TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP -// IWYU pragma: private, include "arch/cpu/registers.hpp" +// IWYU pragma: private, include <arch/cpu/registers.hpp> -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> #include <kstd/ext/bitfield_enum> diff --git a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/arch/cpu/global_descriptor_table.hpp index 402c87d..b17c509 100644 --- a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp +++ b/arch/x86_64/arch/cpu/global_descriptor_table.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP #define TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP -#include "kapi/memory.hpp" +#include <arch/cpu/segment_descriptor.hpp> -#include "arch/cpu/segment_descriptor.hpp" +#include <kapi/memory.hpp> #include <algorithm> #include <array> diff --git a/arch/x86_64/arch/cpu/initialization.cpp b/arch/x86_64/arch/cpu/initialization.cpp new file mode 100644 index 0000000..1be9c82 --- /dev/null +++ b/arch/x86_64/arch/cpu/initialization.cpp @@ -0,0 +1,164 @@ +#include <arch/cpu/initialization.hpp> + +#include <arch/cpu/global_descriptor_table.hpp> +#include <arch/cpu/interrupts.hpp> +#include <arch/cpu/legacy_pic.hpp> +#include <arch/cpu/segment_descriptor.hpp> +#include <arch/cpu/task_state_segment.hpp> + +#include <kstd/print> + +#include <bit> +#include <cstdint> + +namespace arch::cpu +{ + + namespace + { + constexpr auto gdt_null_descriptor = segment_descriptor{}; + + constexpr auto gdt_kernel_code_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = true, + .type = segment_type::code_or_data, + .privilege_level = 0, + .present = true, + .limit_high = 0xf, + .long_mode = true, + .protected_mode = false, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto gdt_kernel_data_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = true, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::code_or_data, + .privilege_level = 0, + .present = true, + .limit_high = 0xf, + .long_mode = false, + .protected_mode = true, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto gdt_user_code_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = true, + .type = segment_type::code_or_data, + .privilege_level = 3, + .present = true, + .limit_high = 0xf, + .long_mode = true, + .protected_mode = false, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto gdt_user_data_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = true, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::code_or_data, + .privilege_level = 3, + .present = true, + .limit_high = 0xf, + .long_mode = false, + .protected_mode = false, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto make_tss_descriptor(task_state_segment const * tss_ptr) -> system_segment_descriptor + { + auto const address = std::bit_cast<std::uintptr_t>(tss_ptr); + auto const limit = sizeof(task_state_segment) - 1; + + return system_segment_descriptor{ + { + .limit_low = limit & 0xffff, // NOLINT(readability-magic-numbers) + .base_low = address & 0xffffff, // NOLINT(readability-magic-numbers) + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::system, + .privilege_level = 0, + .present = true, + .limit_high = (limit >> 16) & 0xf, // NOLINT(readability-magic-numbers) + .long_mode = false, + .protected_mode = false, + .granularity = segment_granularity::byte, + .base_high = (address >> 24) & 0xff, // NOLINT(readability-magic-numbers) + }, + (address >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) + }; + } + } // namespace + + auto initialize_descriptors() -> void + { + auto static tss = task_state_segment{}; + auto static tss_descriptor = make_tss_descriptor(&tss); + + auto static gdt = global_descriptor_table{ + gdt_null_descriptor, gdt_kernel_code_descriptor, gdt_kernel_data_descriptor, + gdt_user_code_descriptor, gdt_user_data_descriptor, tss_descriptor, + }; + + kstd::println("[x86_64:SYS] Reloading Global Descriptor Table."); + gdt.load(1, 2); + + kstd::println("[x86_64:SYS] Initializing Interrupt Descriptor Table."); + auto static idt = interrupt_descriptor_table{}; + idt.load(); + } + + auto initialize_legacy_interrupts() -> void + { + constexpr auto pic_init_command = std::uint8_t{0x11}; + constexpr auto pic_master_offset = std::uint8_t{0x20}; + constexpr auto pic_slave_offset = std::uint8_t{0x28}; + constexpr auto pic_cascade_address = std::uint8_t{0x04}; + constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; + constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; + constexpr auto pic_master_mask = std::uint8_t{0x00}; + constexpr auto pic_slave_mask = std::uint8_t{0x00}; + + pic_master_control_port::write(pic_init_command); + pic_slave_control_port::write(pic_init_command); + + pic_master_data_port::write(pic_master_offset); + pic_slave_data_port::write(pic_slave_offset); + + pic_master_data_port::write(pic_cascade_address); + pic_slave_data_port::write(pic_cascade_slave_identity); + + pic_master_data_port::write(pic_use_8086_mode); + pic_slave_data_port::write(pic_use_8086_mode); + + pic_master_data_port::write(pic_master_mask); + pic_slave_data_port::write(pic_slave_mask); + + pic_master_data_port::write(pic_master_mask); + pic_slave_data_port::write(pic_slave_mask); + } + +} // namespace arch::cpu diff --git a/arch/x86_64/arch/cpu/initialization.hpp b/arch/x86_64/arch/cpu/initialization.hpp new file mode 100644 index 0000000..564c544 --- /dev/null +++ b/arch/x86_64/arch/cpu/initialization.hpp @@ -0,0 +1,12 @@ +#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/arch/cpu/interrupts.S b/arch/x86_64/arch/cpu/interrupts.S new file mode 100644 index 0000000..e59bdd2 --- /dev/null +++ b/arch/x86_64/arch/cpu/interrupts.S @@ -0,0 +1,112 @@ +.altmacro + +.macro ISR_WITHOUT_ERROR_CODE vector + .global isr\vector + isr\vector: + pushq $0 + pushq $\vector + jmp common_interrupt_handler +.endm + +.macro ISR_WITH_ERROR_CODE vector + .global isr\vector + isr\vector: + pushq $\vector + jmp common_interrupt_handler +.endm + +.macro ISR_TABLE_ENTRY vector + .quad isr\vector +.endm + +.section .rodata +.global isr_stub_table +.align 16 + +isr_stub_table: +.set i, 0 +.rept 256 + ISR_TABLE_ENTRY %i + .set i, i + 1 +.endr + + +.section .text + +common_interrupt_handler: + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + mov %rsp, %rdi + call interrupt_dispatch + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + + add $16, %rsp + iretq + +ISR_WITHOUT_ERROR_CODE 0 +ISR_WITHOUT_ERROR_CODE 1 +ISR_WITHOUT_ERROR_CODE 2 +ISR_WITHOUT_ERROR_CODE 3 +ISR_WITHOUT_ERROR_CODE 4 +ISR_WITHOUT_ERROR_CODE 5 +ISR_WITHOUT_ERROR_CODE 6 +ISR_WITHOUT_ERROR_CODE 7 +ISR_WITH_ERROR_CODE 8 +ISR_WITHOUT_ERROR_CODE 9 +ISR_WITH_ERROR_CODE 10 +ISR_WITH_ERROR_CODE 11 +ISR_WITH_ERROR_CODE 12 +ISR_WITH_ERROR_CODE 13 +ISR_WITH_ERROR_CODE 14 +ISR_WITHOUT_ERROR_CODE 15 +ISR_WITHOUT_ERROR_CODE 16 +ISR_WITH_ERROR_CODE 17 +ISR_WITHOUT_ERROR_CODE 18 +ISR_WITHOUT_ERROR_CODE 19 +ISR_WITHOUT_ERROR_CODE 20 +ISR_WITH_ERROR_CODE 21 +ISR_WITHOUT_ERROR_CODE 22 +ISR_WITHOUT_ERROR_CODE 23 +ISR_WITHOUT_ERROR_CODE 24 +ISR_WITHOUT_ERROR_CODE 25 +ISR_WITHOUT_ERROR_CODE 26 +ISR_WITHOUT_ERROR_CODE 27 +ISR_WITHOUT_ERROR_CODE 28 +ISR_WITH_ERROR_CODE 29 +ISR_WITH_ERROR_CODE 30 +ISR_WITHOUT_ERROR_CODE 31 + +.set i, 32 +.rept 256 - 32 + ISR_WITHOUT_ERROR_CODE %i + .set i, i + 1 +.endr diff --git a/arch/x86_64/arch/cpu/interrupts.cpp b/arch/x86_64/arch/cpu/interrupts.cpp new file mode 100644 index 0000000..f40422f --- /dev/null +++ b/arch/x86_64/arch/cpu/interrupts.cpp @@ -0,0 +1,203 @@ +#include <arch/cpu/interrupts.hpp> + +#include <arch/cpu/legacy_pic.hpp> +#include <arch/cpu/segment_selector.hpp> + +#include <kapi/cpu.hpp> +#include <kapi/interrupts.hpp> +#include <kapi/memory.hpp> + +#include <kstd/print> + +#include <cstdint> + +namespace arch::cpu +{ + + namespace + { + enum struct exception + { + divide_error, + debug_exception, + non_maskable_interrupt, + breakpoint, + overflow, + bound_range_exceeded, + invalid_opcode, + device_not_available, + double_fault, + coprocessor_segment_overrun, + invalid_tss, + segment_not_present, + stack_segment_fault, + general_protection_fault, + page_fault, + x87_fpu_floating_point_error = 16, + alignment_check, + machine_check, + simd_floating_point_error, + virtualization_exception, + control_protection_exception, + hypervisor_injection_exception = 28, + vmm_communication_exception, + security_exception, + }; + + constexpr auto number_of_exception_vectors = 32u; + + constexpr auto pic_master_irq_start = 0x20; + constexpr auto pic_master_irq_end = pic_master_irq_start + 8; + constexpr auto pic_slave_irq_start = pic_master_irq_end; + + constexpr auto to_exception_type(exception e) + { + switch (e) + { + case exception::divide_error: + case exception::x87_fpu_floating_point_error: + case exception::simd_floating_point_error: + return kapi::cpu::exception::type::arithmetic_error; + case exception::breakpoint: + return kapi::cpu::exception::type::breakpoint; + case exception::invalid_opcode: + return kapi::cpu::exception::type::illegal_instruction; + case exception::stack_segment_fault: + return kapi::cpu::exception::type::memory_access_fault; + case exception::general_protection_fault: + return kapi::cpu::exception::type::privilege_violation; + case exception::page_fault: + return kapi::cpu::exception::type::page_fault; + case exception::alignment_check: + return kapi::cpu::exception::type::alignment_fault; + default: + return kapi::cpu::exception::type::unknown; + } + } + + constexpr auto has_error_code(exception e) + { + switch (e) + { + case exception::double_fault: + case exception::invalid_tss: + case exception::segment_not_present: + case exception::stack_segment_fault: + case exception::general_protection_fault: + case exception::page_fault: + case exception::alignment_check: + case exception::control_protection_exception: + case exception::security_exception: + return true; + default: + return false; + } + } + + auto dispatch_exception(interrupt_frame * frame) -> bool + { + auto type = to_exception_type(static_cast<exception>(frame->interrupt.number)); + auto fault_address = kapi::memory::linear_address{}; + auto instruction_pointer = frame->cpu_saved.rip; + + switch (type) + { + case kapi::cpu::exception::type::page_fault: + { + asm volatile("mov %%cr2, %0" : "=r"(fault_address)); + auto present = (frame->interrupt.error_code & 0x1) != 0; + auto write = (frame->interrupt.error_code & 0x2) != 0; + auto user = (frame->interrupt.error_code & 0x4) != 0; + + return kapi::cpu::dispatch({type, instruction_pointer, fault_address, present, write, user}); + } + default: + return kapi::cpu::dispatch({type, instruction_pointer}); + } + } + + auto acknowledge_pic_interrupt(interrupt_frame * frame) -> void + { + if (frame->interrupt.number >= pic_slave_irq_start) + { + pic_slave_control_port::write(pic_end_of_interrupt); + } + pic_master_control_port::write(pic_end_of_interrupt); + } + } // namespace + + extern "C" + { + extern std::uintptr_t const isr_stub_table[256]; + + auto interrupt_dispatch(interrupt_frame * frame) -> void + { + auto [number, code] = frame->interrupt; + + if (number < number_of_exception_vectors) + { + if (!dispatch_exception(frame)) + { + if (has_error_code(static_cast<exception>(number))) + { + kstd::println(kstd::print_sink::stderr, + "[x86_64:CPU] Unhandled exception number {:#04x} received with code {:#04x}", number, code); + } + else + { + kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled exception number {:#04x} received", number); + } + } + } + else + { + auto irq_number = number - number_of_exception_vectors; + + if (kapi::interrupts::dispatch(irq_number) == kapi::interrupts::status::unhandled) + { + kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x} (IRQ{})", number, + irq_number); + } + + acknowledge_pic_interrupt(frame); + } + } + } + + interrupt_descriptor_table::interrupt_descriptor_table() noexcept + { + for (auto i = 0uz; i < 256; ++i) + { + m_descriptors[i] = gate_descriptor{ + .offset_low = static_cast<std::uint16_t>(isr_stub_table[i] & 0xffff), // NOLINT(readability-magic-numbers) + .m_code_segment = segment_selector{0, false, 1}, + .interrupt_stack_table_selector = 0, + .gate_type = (i < 32 && i != 2) ? gate_type::trap_gate : gate_type::interrupt_gate, + .descriptor_privilege_level = 0, + .present = true, + .offset_middle = + static_cast<std::uint16_t>((isr_stub_table[i] >> 16) & 0xffff), // NOLINT(readability-magic-numbers) + .offset_high = + static_cast<std::uint32_t>((isr_stub_table[i] >> 32) & 0xffff'ffff), // NOLINT(readability-magic-numbers) + }; + } + } + + auto interrupt_descriptor_table::load() const -> void + { + interrupt_descriptor_table_register{.limit = sizeof(m_descriptors) - 1, .base = m_descriptors.data()}.load(); + } + + auto interrupt_descriptor_table_register::load() const -> void + { + asm volatile("lidt %0" : : "m"(*this)); + } + + auto interrupt_descriptor_table_register::read() -> interrupt_descriptor_table_register + { + interrupt_descriptor_table_register idtr{}; + asm volatile("sidt %0" : : "m"(idtr)); + return idtr; + } + +} // namespace arch::cpu
\ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/arch/cpu/interrupts.hpp index 92c5824..6162f56 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/arch/cpu/interrupts.hpp @@ -1,7 +1,9 @@ #ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP #define TEACHOS_X86_64_CPU_INTERRUPTS_HPP -#include "arch/cpu/segment_selector.hpp" +#include <arch/cpu/segment_selector.hpp> + +#include <kapi/memory.hpp> #include <array> #include <cstdint> @@ -30,7 +32,7 @@ namespace arch::cpu //! Reserved std::uint8_t : 5; //! The type of this gate. - gate_type gate_type : 4; + enum gate_type gate_type : 4; //! Reserved std::uint8_t : 1; //! The privilege level required to enter through this gate. @@ -48,14 +50,67 @@ namespace arch::cpu static_assert(sizeof(gate_descriptor) == 2 * sizeof(std::uint64_t)); static_assert(std::is_aggregate_v<gate_descriptor>); + //! 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(); + interrupt_descriptor_table() noexcept; + + auto load() const -> void; private: std::array<gate_descriptor, 256> 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/arch/cpu/legacy_pic.hpp b/arch/x86_64/arch/cpu/legacy_pic.hpp new file mode 100644 index 0000000..56ca9c4 --- /dev/null +++ b/arch/x86_64/arch/cpu/legacy_pic.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP +#define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP + +#include <arch/device_io/port_io.hpp> + +#include <cstdint> + +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/arch/cpu/model_specific_register.hpp index 8539a24..bd4aff9 100644 --- a/arch/x86_64/include/arch/cpu/model_specific_register.hpp +++ b/arch/x86_64/arch/cpu/model_specific_register.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP #define TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP -// IWYU pragma: private, include "x86_64/cpu/registers.hpp" +// IWYU pragma: private, include <x86_64/cpu/registers.hpp> #include <kstd/ext/bitfield_enum> diff --git a/arch/x86_64/include/arch/cpu/registers.hpp b/arch/x86_64/arch/cpu/registers.hpp index d7def10..58633f6 100644 --- a/arch/x86_64/include/arch/cpu/registers.hpp +++ b/arch/x86_64/arch/cpu/registers.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include "kapi/memory.hpp" +#include <arch/cpu/control_register.hpp> // IWYU pragma: export +#include <arch/cpu/model_specific_register.hpp> // IWYU pragma: export -#include "arch/cpu/control_register.hpp" // IWYU pragma: export -#include "arch/cpu/model_specific_register.hpp" // IWYU pragma: export +#include <kapi/memory.hpp> namespace arch::cpu { diff --git a/arch/x86_64/include/arch/cpu/segment_descriptor.hpp b/arch/x86_64/arch/cpu/segment_descriptor.hpp index 9570670..9570670 100644 --- a/arch/x86_64/include/arch/cpu/segment_descriptor.hpp +++ b/arch/x86_64/arch/cpu/segment_descriptor.hpp diff --git a/arch/x86_64/include/arch/cpu/segment_selector.hpp b/arch/x86_64/arch/cpu/segment_selector.hpp index 1a78c47..1a78c47 100644 --- a/arch/x86_64/include/arch/cpu/segment_selector.hpp +++ b/arch/x86_64/arch/cpu/segment_selector.hpp diff --git a/arch/x86_64/include/arch/cpu/task_state_segment.hpp b/arch/x86_64/arch/cpu/task_state_segment.hpp index 57729dd..57729dd 100644 --- a/arch/x86_64/include/arch/cpu/task_state_segment.hpp +++ b/arch/x86_64/arch/cpu/task_state_segment.hpp diff --git a/arch/x86_64/src/debug/qemu_output.cpp b/arch/x86_64/arch/debug/qemu_output.cpp index 535017d..71acede 100644 --- a/arch/x86_64/src/debug/qemu_output.cpp +++ b/arch/x86_64/arch/debug/qemu_output.cpp @@ -1,6 +1,6 @@ -#include "arch/debug/qemu_output.hpp" +#include <arch/debug/qemu_output.hpp> -#include "kapi/cio.hpp" +#include <kapi/cio.hpp> #include <algorithm> #include <string_view> diff --git a/arch/x86_64/include/arch/debug/qemu_output.hpp b/arch/x86_64/arch/debug/qemu_output.hpp index e72eb39..5ddd4be 100644 --- a/arch/x86_64/include/arch/debug/qemu_output.hpp +++ b/arch/x86_64/arch/debug/qemu_output.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP #define TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP -#include "kapi/cio.hpp" +#include <arch/device_io/port_io.hpp> -#include "arch/device_io/port_io.hpp" +#include <kapi/cio.hpp> #include <string_view> diff --git a/arch/x86_64/include/arch/device_io/port_io.hpp b/arch/x86_64/arch/device_io/port_io.hpp index 65e58e3..4c8d66a 100644 --- a/arch/x86_64/include/arch/device_io/port_io.hpp +++ b/arch/x86_64/arch/device_io/port_io.hpp @@ -69,9 +69,9 @@ namespace arch::io //! The assembly templates used for writing to an I/O port. constexpr auto static code = std::array{ - std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%al, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%ax, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%eax, %%dx"}, + 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"}, }; }; @@ -102,6 +102,11 @@ namespace arch::io : std::string_view{"eax"}; }; + auto inline wait() -> void + { + port<0x80, std::uint8_t, port_write>::write<std::uint8_t>(0); + } + } // namespace arch::io #endif
\ No newline at end of file diff --git a/arch/x86_64/arch/devices/init.cpp b/arch/x86_64/arch/devices/init.cpp new file mode 100644 index 0000000..c30e8cf --- /dev/null +++ b/arch/x86_64/arch/devices/init.cpp @@ -0,0 +1,76 @@ +#include <arch/devices/init.hpp> + +#include <arch/boot/boot.hpp> +#include <arch/bus/isa.hpp> +#include <arch/devices/legacy_pit.hpp> + +#include <kapi/acpi.hpp> +#include <kapi/cpu.hpp> +#include <kapi/devices.hpp> + +#include <acpi/acpi.hpp> + +#include <kstd/memory> +#include <kstd/print> + +#include <cstdint> +#include <utility> + +namespace arch::devices +{ + + namespace + { + constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; + + auto get_acpi_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const> + { + auto const & mbi = kapi::boot::bootstrap_information.mbi; + auto system_description_pointer = static_cast<::acpi::rsdp const *>(nullptr); + + if (auto const & xsdp = mbi->maybe_acpi_xsdp()) + { + auto data = xsdp->pointer().data(); + + system_description_pointer = reinterpret_cast<::acpi::xsdp const *>(data); + } + else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) + { + auto data = rsdp->pointer().data(); + system_description_pointer = reinterpret_cast<::acpi::rsdp const *>(data); + } + + return kstd::make_observer(system_description_pointer); + } + } // namespace + + auto init_acpi_devices() -> void + { + auto acpi_root_pointer = get_acpi_root_pointer(); + if (acpi_root_pointer && acpi_root_pointer->validate()) + { + if (kapi::acpi::init(*acpi_root_pointer)) + { + kstd::println("[x86_64:DEV] ACPI subsystem initialized."); + } + } + + kapi::cpu::discover_topology(); + } + + auto init_legacy_devices() -> void + { + kstd::println("[x86_64:DEV] Initializing ISA bus..."); + + auto isa_major_number = kapi::devices::allocate_major_number(); + auto isa_bus = kstd::make_unique<arch::bus::isa>(isa_major_number); + + auto pit_major_number = kapi::devices::allocate_major_number(); + auto pit = kstd::make_unique<arch::devices::legacy_pit>(pit_major_number, pit_frequency_in_hz); + isa_bus->add_child(std::move(pit)); + + auto & root_bus = kapi::devices::get_root_bus(); + root_bus.add_child(std::move(isa_bus)); + } + +} // namespace arch::devices diff --git a/arch/x86_64/arch/devices/init.hpp b/arch/x86_64/arch/devices/init.hpp new file mode 100644 index 0000000..c5fbf37 --- /dev/null +++ b/arch/x86_64/arch/devices/init.hpp @@ -0,0 +1,12 @@ +#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/arch/devices/legacy_pit.cpp b/arch/x86_64/arch/devices/legacy_pit.cpp new file mode 100644 index 0000000..d542d47 --- /dev/null +++ b/arch/x86_64/arch/devices/legacy_pit.cpp @@ -0,0 +1,60 @@ +#include <arch/devices/legacy_pit.hpp> + +#include <arch/device_io/port_io.hpp> + +#include <kapi/devices.hpp> +#include <kapi/devices/device.hpp> +#include <kapi/interrupts.hpp> + +#include <cstddef> +#include <cstdint> + +namespace arch::devices +{ + + namespace + { + using command_port = io::port<0x43, std::uint8_t, io::port_write>; + using channel_0_port = io::port<0x40, std::uint8_t, io::port_write>; + using channel_1_port = io::port<0x41, std::uint8_t, io::port_write>; + using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; + + constexpr auto base_frequency = 1'193'182u; + constexpr auto square_wave_mode = 0x36; + } // namespace + + legacy_pit::legacy_pit(std::size_t major, std::uint32_t frequency_in_hz) + : kapi::devices::device{major, 0, "legacy_pit"} + , m_irq_number{0} + , m_frequency_in_hz{frequency_in_hz} + {} + + auto legacy_pit::init() -> bool + { + auto divisor = static_cast<std::uint16_t>(base_frequency / m_frequency_in_hz); + + kapi::interrupts::register_handler(m_irq_number, *this); + + command_port::write<std::uint8_t>(square_wave_mode); + io::wait(); + channel_0_port::write<std::uint8_t>(divisor & 0xff); + io::wait(); + channel_0_port::write<std::uint8_t>(divisor >> 8 & 0xff); + io::wait(); + + return true; + } + + auto legacy_pit::handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status + { + if (irq_number != m_irq_number) + { + return kapi::interrupts::status::unhandled; + } + + ++m_ticks; + + return kapi::interrupts::status::handled; + } + +} // namespace arch::devices
\ No newline at end of file diff --git a/arch/x86_64/arch/devices/legacy_pit.hpp b/arch/x86_64/arch/devices/legacy_pit.hpp new file mode 100644 index 0000000..356895c --- /dev/null +++ b/arch/x86_64/arch/devices/legacy_pit.hpp @@ -0,0 +1,29 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP + +#include <kapi/devices/device.hpp> +#include <kapi/interrupts.hpp> + +#include <cstddef> +#include <cstdint> + +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/arch/devices/local_apic.cpp b/arch/x86_64/arch/devices/local_apic.cpp new file mode 100644 index 0000000..660921b --- /dev/null +++ b/arch/x86_64/arch/devices/local_apic.cpp @@ -0,0 +1,134 @@ +#include <arch/devices/local_apic.hpp> + +#include <kapi/devices.hpp> +#include <kapi/memory.hpp> + +#include <kstd/print> + +#include <cstddef> +#include <cstdint> +#include <utility> + +namespace arch::devices +{ + + namespace + { + constexpr auto lapic_enable_bit = 0x100u; + constexpr auto spurious_interrupt_vector = 0xFFu; + + constexpr auto offset_of_version = 0u; + constexpr auto offset_of_max_lvt_entry = 16u; + constexpr auto offset_of_eoi_suppression = 24u; + + } // namespace + + enum struct local_apic::registers : std::ptrdiff_t + { + id = 0x020, + version = 0x030, + task_priority = 0x080, + arbitration_priority = 0x090, + processor_priority = 0x0a0, + eoi = 0x0b0, + remote_read = 0x0c0, + logical_destination = 0x0d0, + destination_format = 0x0e0, + spurious_interrupt_vector = 0x0f0, + in_service_0 = 0x100, + in_service_1 = 0x110, + in_service_2 = 0x120, + in_service_3 = 0x130, + in_service_4 = 0x140, + in_service_5 = 0x150, + in_service_6 = 0x160, + in_service_7 = 0x170, + trigger_mode_0 = 0x180, + trigger_mode_1 = 0x190, + trigger_mode_2 = 0x1a0, + trigger_mode_3 = 0x1b0, + trigger_mode_4 = 0x1c0, + trigger_mode_5 = 0x1d0, + trigger_mode_6 = 0x1e0, + trigger_mode_7 = 0x1f0, + interrupt_request_0 = 0x200, + interrupt_request_1 = 0x210, + interrupt_request_2 = 0x220, + interrupt_request_3 = 0x230, + interrupt_request_4 = 0x240, + interrupt_request_5 = 0x250, + interrupt_request_6 = 0x260, + interrupt_request_7 = 0x270, + error_status = 0x280, + lvt_corrected_machine_check_interrupt = 0x2f0, + interrupt_command_0 = 0x300, + interrupt_command_1 = 0x310, + lvt_timer = 0x320, + lvt_thermal_sensors = 0x330, + lvt_performance_monitoring_counters = 0x340, + lvt_local_interrupt_0 = 0x350, + lvt_local_interrupt_1 = 0x360, + lvt_error = 0x370, + initial_count = 0x380, + current_count = 0x390, + divide_configuration = 0x3e0, + }; + + local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, + kapi::memory::physical_address base, bool is_bsp) + : kapi::devices::device{major, minor, "lapic"} + , m_hardware_id{hardware_id} + , m_base{base} + , m_is_bsp{is_bsp} + {} + + auto local_apic::init() -> bool + { + auto static shared_virtual_base = kapi::memory::allocate_mmio_region(1); + auto static is_mapped = false; + + if (!is_mapped) + { + if (!kapi::memory::map_mmio_region(shared_virtual_base, m_base, kapi::memory::page_mapper::flags::writable)) + { + kstd::println("[x86_64:DEV] LAPIC {} MMIO mapping failed!", m_hardware_id); + return false; + } + is_mapped = true; + } + + m_mapped_region = shared_virtual_base; + + if (m_is_bsp) + { + auto raw_version = read_register(registers::version); + m_version = (raw_version >> offset_of_version) & 0xff; + m_highest_lvt_entry_index = (raw_version >> offset_of_max_lvt_entry) & 0xff; + m_supports_eoi_broadcast_suppression = (raw_version >> offset_of_eoi_suppression) & 0x1; + + write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); + + kstd::println("[x86_64:DEV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", + m_version, m_highest_lvt_entry_index, m_supports_eoi_broadcast_suppression); + } + else + { + kstd::println("[x86_64:DEV] LAPIC {} is not on the BSP, deferring initialization.", m_hardware_id); + } + + return true; + } + + auto local_apic::read_register(registers id) const -> std::uint32_t + { + auto reg = static_cast<std::uint32_t volatile *>(m_mapped_region.first + std::to_underlying(id)); + return *reg; + } + + auto local_apic::write_register(registers id, std::uint32_t value) -> void + { + auto reg = static_cast<std::uint32_t volatile *>(m_mapped_region.first + std::to_underlying(id)); + *reg = value; + } + +} // namespace arch::devices diff --git a/arch/x86_64/arch/devices/local_apic.hpp b/arch/x86_64/arch/devices/local_apic.hpp new file mode 100644 index 0000000..f8f080d --- /dev/null +++ b/arch/x86_64/arch/devices/local_apic.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP + +#include <kapi/devices/device.hpp> +#include <kapi/memory.hpp> + +#include <cstddef> +#include <cstdint> + +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/src/memory/higher_half_mapper.cpp b/arch/x86_64/arch/memory/higher_half_mapper.cpp index abb54a3..75adb3c 100644 --- a/arch/x86_64/src/memory/higher_half_mapper.cpp +++ b/arch/x86_64/arch/memory/higher_half_mapper.cpp @@ -1,10 +1,10 @@ -#include "arch/memory/higher_half_mapper.hpp" +#include <arch/memory/higher_half_mapper.hpp> -#include "kapi/memory.hpp" -#include "kapi/system.hpp" +#include <arch/memory/page_table.hpp> +#include <arch/memory/page_utilities.hpp> -#include "arch/memory/page_table.hpp" -#include "arch/memory/page_utilities.hpp" +#include <kapi/memory.hpp> +#include <kapi/system.hpp> #include <algorithm> #include <array> diff --git a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp b/arch/x86_64/arch/memory/higher_half_mapper.hpp index c8df40c..9b02ee6 100644 --- a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp +++ b/arch/x86_64/arch/memory/higher_half_mapper.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP #define TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP -#include "kapi/memory.hpp" +#include <arch/memory/page_table.hpp> -#include "arch/memory/page_table.hpp" +#include <kapi/memory.hpp> #include <cstddef> diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/arch/memory/kernel_mapper.cpp index 08c32c5..74272a0 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/arch/memory/kernel_mapper.cpp @@ -1,14 +1,16 @@ -#include "arch/memory/kernel_mapper.hpp" +#include <arch/memory/kernel_mapper.hpp> -#include "kapi/memory.hpp" -#include "kapi/system.hpp" +#include <arch/boot/ld.hpp> -#include "arch/boot/ld.hpp" - -#include <kstd/print> +#include <kapi/memory.hpp> +#include <kapi/system.hpp> #include <elf/format.hpp> #include <elf/section_header.hpp> + +#include <kstd/print> +#include <kstd/units> + #include <multiboot2/information.hpp> #include <algorithm> @@ -19,13 +21,14 @@ #include <string_view> #include <utility> +using namespace std::string_view_literals; +using namespace kstd::units_literals; + namespace arch::memory { namespace { - using namespace std::string_view_literals; - constexpr auto static ignored_section_prefixes = std::array{ ".boot_"sv, }; @@ -71,7 +74,8 @@ namespace arch::memory auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, kapi::memory::page_mapper & mapper) -> void { - auto number_of_pages = (section.size + (PLATFORM_PAGE_SIZE - 1)) / PLATFORM_PAGE_SIZE; + auto number_of_pages = + (kstd::units::bytes{section.size} + (kapi::memory::page::size - 1_B)) / kapi::memory::page::size; auto linear_start_address = kapi::memory::linear_address{section.virtual_load_address}; auto physical_start_address = kapi::memory::physical_address{section.virtual_load_address & ~m_kernel_load_base}; diff --git a/arch/x86_64/include/arch/memory/kernel_mapper.hpp b/arch/x86_64/arch/memory/kernel_mapper.hpp index 4329f1b..adbf688 100644 --- a/arch/x86_64/include/arch/memory/kernel_mapper.hpp +++ b/arch/x86_64/arch/memory/kernel_mapper.hpp @@ -1,10 +1,11 @@ #ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP #define TEACHOS_X86_64_KERNEL_MAPPER_HPP -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> #include <elf/format.hpp> #include <elf/section_header.hpp> + #include <multiboot2/information.hpp> #include <cstdint> diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/arch/memory/mmu.cpp index ea23278..2b53fa4 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/arch/memory/mmu.cpp @@ -1,8 +1,8 @@ -#include "arch/memory/mmu.hpp" +#include <arch/memory/mmu.hpp> -#include "kapi/memory.hpp" +#include <arch/cpu/registers.hpp> -#include "arch/cpu/registers.hpp" +#include <kapi/memory.hpp> namespace arch::memory { diff --git a/arch/x86_64/include/arch/memory/mmu.hpp b/arch/x86_64/arch/memory/mmu.hpp index 2d64184..64373f4 100644 --- a/arch/x86_64/include/arch/memory/mmu.hpp +++ b/arch/x86_64/arch/memory/mmu.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_MEMORY_MMU_HPP #define TEACHOS_X86_64_MEMORY_MMU_HPP -#include "kapi/memory/address.hpp" +#include <kapi/memory/address.hpp> namespace arch::memory { diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/arch/memory/page_table.cpp index 26cdd29..2180420 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/arch/memory/page_table.cpp @@ -1,6 +1,6 @@ -#include "arch/memory/page_table.hpp" +#include <arch/memory/page_table.hpp> -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> #include <algorithm> #include <bit> diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/arch/memory/page_table.hpp index 2889d38..ce3d3a1 100644 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ b/arch/x86_64/arch/memory/page_table.hpp @@ -1,9 +1,10 @@ #ifndef TEACHOS_X86_64_PAGE_TABLE_HPP #define TEACHOS_X86_64_PAGE_TABLE_HPP -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> #include <kstd/ext/bitfield_enum> +#include <kstd/units> #include <array> #include <cstddef> @@ -116,7 +117,7 @@ namespace arch::memory }; //! The maximum number of entries in this table. - constexpr auto static entry_count{kapi::memory::page::size / sizeof(entry)}; + constexpr auto static entry_count{kapi::memory::page::size / kstd::units::bytes{sizeof(entry)}}; //! Get the entry at the given index. //! @@ -173,7 +174,7 @@ namespace arch::memory result |= mapper_flags::writable; } - if ((flags & table_flags::disable_cache) != table_flags::empty) + if ((flags & (table_flags::disable_cache | table_flags::write_through)) != table_flags::empty) { result |= mapper_flags::uncached; } @@ -210,7 +211,7 @@ namespace arch::memory if ((flags & mapper_flags::uncached) != mapper_flags::empty) { - result |= table_flags::disable_cache; + result |= (table_flags::disable_cache | table_flags::write_through); } if ((flags & mapper_flags::supervisor_only) == mapper_flags::empty) @@ -228,4 +229,4 @@ namespace arch::memory } // namespace arch::memory -#endif
\ No newline at end of file +#endif diff --git a/arch/x86_64/include/arch/memory/page_utilities.hpp b/arch/x86_64/arch/memory/page_utilities.hpp index c48e74f..068e824 100644 --- a/arch/x86_64/include/arch/memory/page_utilities.hpp +++ b/arch/x86_64/arch/memory/page_utilities.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_PAGE_UTILITIES_HPP #define TEACHOS_X86_64_PAGE_UTILITIES_HPP -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> #include <cstddef> diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/arch/memory/region_allocator.cpp index facb1f2..4086a10 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/arch/memory/region_allocator.cpp @@ -1,7 +1,7 @@ -#include "arch/memory/region_allocator.hpp" +#include <arch/memory/region_allocator.hpp> -#include "kapi/memory/address.hpp" -#include "kapi/memory/frame.hpp" +#include <kapi/memory/address.hpp> +#include <kapi/memory/frame.hpp> #include <multiboot2/information.hpp> @@ -35,7 +35,7 @@ namespace arch::memory , m_kernel_end{kapi::memory::frame::containing(mem_info.image_range.second)} , m_multiboot_start{kapi::memory::frame::containing(mem_info.mbi_range.first)} , m_multiboot_end{kapi::memory::frame::containing(mem_info.mbi_range.second)} - // TODO BA-FS26: Protect MB2 boot modules + , m_multiboot_information{mem_info.mbi} { choose_next_region(); } @@ -76,19 +76,40 @@ namespace arch::memory } } - if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) + auto advanced = true; + while (advanced) { - m_next_frame = m_kernel_end + 1; - } + advanced = false; - if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) - { - m_next_frame = m_multiboot_end + 1; - } + if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) + { + m_next_frame = m_kernel_end + 1; + advanced = true; + continue; + } - if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) - { - m_next_frame = m_kernel_end + 1; + if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) + { + m_next_frame = m_multiboot_end + 1; + advanced = true; + continue; + } + + if (m_multiboot_information) + { + for (auto const & module : m_multiboot_information->modules()) + { + auto module_start = kapi::memory::frame::containing(kapi::memory::physical_address{module.start_address}); + auto module_end = kapi::memory::frame::containing(kapi::memory::physical_address{module.end_address}); + + if (falls_within(m_next_frame, module_start, module_end)) + { + m_next_frame = module_end + 1; + advanced = true; + break; + } + } + } } if (m_next_frame > last_frame(*m_current_region)) diff --git a/arch/x86_64/include/arch/memory/region_allocator.hpp b/arch/x86_64/arch/memory/region_allocator.hpp index 1c5885e..5d9da2e 100644 --- a/arch/x86_64/include/arch/memory/region_allocator.hpp +++ b/arch/x86_64/arch/memory/region_allocator.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP #define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP -#include "kapi/memory/address.hpp" -#include "kapi/memory/frame.hpp" -#include "kapi/memory/frame_allocator.hpp" +#include <kapi/memory/address.hpp> +#include <kapi/memory/frame.hpp> +#include <kapi/memory/frame_allocator.hpp> #include <multiboot2/information.hpp> @@ -42,6 +42,11 @@ namespace arch::memory //! 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; @@ -80,6 +85,7 @@ namespace arch::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 diff --git a/arch/x86_64/include/arch/vga/crtc.hpp b/arch/x86_64/arch/vga/crtc.hpp index dbdc365..a8bec93 100644 --- a/arch/x86_64/include/arch/vga/crtc.hpp +++ b/arch/x86_64/arch/vga/crtc.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_IO_HPP #define TEACHOS_X86_64_VGA_IO_HPP -#include "arch/device_io/port_io.hpp" +#include <arch/device_io/port_io.hpp> #include <cstddef> diff --git a/arch/x86_64/arch/vga/text.hpp b/arch/x86_64/arch/vga/text.hpp new file mode 100644 index 0000000..2e73dd2 --- /dev/null +++ b/arch/x86_64/arch/vga/text.hpp @@ -0,0 +1,10 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_HPP +#define TEACHOS_X86_64_VGA_TEXT_HPP + +#include <arch/vga/text/attribute.hpp> // IWYU pragma: export +#include <arch/vga/text/color.hpp> // IWYU pragma: export +#include <arch/vga/text/common_attributes.hpp> // IWYU pragma: export +#include <arch/vga/text/device.hpp> // IWYU pragma: export +#include <arch/vga/text/flags.hpp> // IWYU pragma: export + +#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP
\ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/attribute.hpp b/arch/x86_64/arch/vga/text/attribute.hpp index 6a0f995..6395aed 100644 --- a/arch/x86_64/include/arch/vga/text/attribute.hpp +++ b/arch/x86_64/arch/vga/text/attribute.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP #define TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include <arch/vga/text.hpp> -#include "arch/vga/text/color.hpp" -#include "arch/vga/text/flags.hpp" +#include <arch/vga/text/color.hpp> +#include <arch/vga/text/flags.hpp> namespace arch::vga::text { diff --git a/arch/x86_64/src/vga/text/buffer.cpp b/arch/x86_64/arch/vga/text/buffer.cpp index 7112573..498b9a3 100644 --- a/arch/x86_64/src/vga/text/buffer.cpp +++ b/arch/x86_64/arch/vga/text/buffer.cpp @@ -1,6 +1,6 @@ -#include "arch/vga/text/buffer.hpp" +#include <arch/vga/text/buffer.hpp> -#include "arch/vga/text/attribute.hpp" +#include <arch/vga/text/attribute.hpp> #include <algorithm> #include <bit> diff --git a/arch/x86_64/include/arch/vga/text/buffer.hpp b/arch/x86_64/arch/vga/text/buffer.hpp index 648d37a..8eb6645 100644 --- a/arch/x86_64/include/arch/vga/text/buffer.hpp +++ b/arch/x86_64/arch/vga/text/buffer.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP #define TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include <arch/vga/text.hpp> -#include "arch/vga/text/attribute.hpp" +#include <arch/vga/text/attribute.hpp> #include <cstddef> #include <span> diff --git a/arch/x86_64/include/arch/vga/text/color.hpp b/arch/x86_64/arch/vga/text/color.hpp index a541830..e0ad6df 100644 --- a/arch/x86_64/include/arch/vga/text/color.hpp +++ b/arch/x86_64/arch/vga/text/color.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_COLOR_HPP #define TEACHOS_X86_64_VGA_TEXT_COLOR_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include <arch/vga/text.hpp> #include <cstdint> diff --git a/arch/x86_64/include/arch/vga/text/common_attributes.hpp b/arch/x86_64/arch/vga/text/common_attributes.hpp index 9bd61a5..3d8929f 100644 --- a/arch/x86_64/include/arch/vga/text/common_attributes.hpp +++ b/arch/x86_64/arch/vga/text/common_attributes.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP #define TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include <arch/vga/text.hpp> -#include "arch/vga/text/attribute.hpp" -#include "arch/vga/text/color.hpp" -#include "arch/vga/text/flags.hpp" +#include <arch/vga/text/attribute.hpp> +#include <arch/vga/text/color.hpp> +#include <arch/vga/text/flags.hpp> namespace arch::vga::text { diff --git a/arch/x86_64/src/vga/text/device.cpp b/arch/x86_64/arch/vga/text/device.cpp index dcacd8c..8468358 100644 --- a/arch/x86_64/src/vga/text/device.cpp +++ b/arch/x86_64/arch/vga/text/device.cpp @@ -1,9 +1,9 @@ -#include "kapi/cio.hpp" +#include <arch/boot/boot.hpp> +#include <arch/boot/ld.hpp> +#include <arch/vga/crtc.hpp> +#include <arch/vga/text.hpp> -#include "arch/boot/boot.hpp" -#include "arch/boot/ld.hpp" -#include "arch/vga/crtc.hpp" -#include "arch/vga/text.hpp" +#include <kapi/cio.hpp> #include <bit> #include <cstddef> diff --git a/arch/x86_64/include/arch/vga/text/device.hpp b/arch/x86_64/arch/vga/text/device.hpp index 11b3281..0a0e017 100644 --- a/arch/x86_64/include/arch/vga/text/device.hpp +++ b/arch/x86_64/arch/vga/text/device.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP #define TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include <arch/vga/text.hpp> -#include "kapi/cio.hpp" +#include <arch/vga/text/buffer.hpp> -#include "arch/vga/text/buffer.hpp" +#include <kapi/cio.hpp> #include <string_view> diff --git a/arch/x86_64/include/arch/vga/text/flags.hpp b/arch/x86_64/arch/vga/text/flags.hpp index 67c6c11..7a29e33 100644 --- a/arch/x86_64/include/arch/vga/text/flags.hpp +++ b/arch/x86_64/arch/vga/text/flags.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP #define TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include <arch/vga/text.hpp> namespace arch::vga::text { diff --git a/arch/x86_64/include/arch/vga/text.hpp b/arch/x86_64/include/arch/vga/text.hpp deleted file mode 100644 index f81ab60..0000000 --- a/arch/x86_64/include/arch/vga/text.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_HPP -#define TEACHOS_X86_64_VGA_TEXT_HPP - -#include "text/attribute.hpp" // IWYU pragma: export -#include "text/color.hpp" // IWYU pragma: export -#include "text/common_attributes.hpp" // IWYU pragma: export -#include "text/device.hpp" // IWYU pragma: export -#include "text/flags.hpp" // IWYU pragma: export - -#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP
\ No newline at end of file diff --git a/arch/x86_64/kapi/boot_modules.cpp b/arch/x86_64/kapi/boot_modules.cpp new file mode 100644 index 0000000..fb6bf46 --- /dev/null +++ b/arch/x86_64/kapi/boot_modules.cpp @@ -0,0 +1,53 @@ +#include <kapi/boot_modules.hpp> + +#include <arch/boot/boot.hpp> +#include <arch/boot/ld.hpp> + +#include <kapi/boot.hpp> +#include <kapi/boot_module/boot_module.hpp> +#include <kapi/boot_module/boot_module_registry.hpp> +#include <kapi/memory.hpp> +#include <kapi/system.hpp> + +#include <kstd/print> + +#include <multiboot2/information.hpp> + +#include <algorithm> +#include <atomic> +#include <bit> +#include <cstdint> +#include <optional> + +namespace kapi::boot_modules +{ + namespace + { + auto constinit registry = std::optional<kapi::boot_modules::boot_module_registry>{}; + } // namespace + + auto init() -> void + { + auto static constinit is_initialized = std::atomic_flag{}; + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] Boot module registry has already been initialized."); + } + + kstd::println("[x86_64:BOOT_MODULES] Initializing boot module registry."); + + registry.emplace(kapi::boot_modules::boot_module_registry{}); + + auto modules = boot::bootstrap_information.mbi->modules(); + std::ranges::for_each(modules, [](auto const & module) { + registry->add_boot_module(kapi::boot_modules::boot_module{ + .name = module.string(), + .start_address = + memory::linear_address{module.start_address + std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}, + .size = module.end_address - module.start_address, + }); + }); + + set_boot_module_registry(*registry); + } +} // namespace kapi::boot_modules
\ No newline at end of file diff --git a/arch/x86_64/kapi/cio.cpp b/arch/x86_64/kapi/cio.cpp index 015cf5e..b33c6e0 100644 --- a/arch/x86_64/kapi/cio.cpp +++ b/arch/x86_64/kapi/cio.cpp @@ -1,7 +1,7 @@ -#include "kapi/cio.hpp" +#include <kapi/cio.hpp> -#include "arch/debug/qemu_output.hpp" -#include "arch/vga/text.hpp" +#include <arch/debug/qemu_output.hpp> +#include <arch/vga/text.hpp> #include <optional> diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 2a0f8f7..40dc228 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -1,12 +1,90 @@ -#include "kapi/cpu.hpp" +#include <kapi/cpu.hpp> + +#include <arch/cpu/initialization.hpp> +#include <arch/devices/local_apic.hpp> + +#include <kapi/acpi.hpp> +#include <kapi/devices.hpp> +#include <kapi/devices/cpu.hpp> +#include <kapi/memory.hpp> +#include <kapi/system.hpp> + +#include <acpi/acpi.hpp> + +#include <kstd/memory> +#include <kstd/print> + +#include <atomic> +#include <ranges> +#include <utility> namespace kapi::cpu { + namespace + { + constexpr auto candidate_flags = ::acpi::processor_local_apic_entry::flags::processor_enabled // + | ::acpi::processor_local_apic_entry::flags::online_capable; + } + + auto init() -> void + { + auto static constinit is_initialized = std::atomic_flag{}; + + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] CPU has already been initialized."); + } + + arch::cpu::initialize_descriptors(); + arch::cpu::initialize_legacy_interrupts(); + } + auto halt() -> void { asm volatile("1: hlt\njmp 1b"); __builtin_unreachable(); } + auto discover_topology() -> bool + { + auto static const cpu_major = kapi::devices::allocate_major_number(); + auto static const core_major = kapi::devices::allocate_major_number(); + auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); + + auto madt = kapi::acpi::get_table<::acpi::table_signature_v<::acpi::madt>>(); + if (!madt) + { + kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); + return false; + } + + auto lapic_entries = *madt | std::views::filter([](auto const & entry) { + return entry.type() == ::acpi::madt_entry::type::processor_local_apic; + }) | std::views::transform([](auto const & entry) { + return static_cast<::acpi::processor_local_apic_entry const &>(entry); + }) | std::views::filter([](auto const & entry) { return static_cast<bool>(entry.flags() & candidate_flags); }); + + auto bsp_found = false; + auto core_count = 0uz; + auto local_apic_address = memory::physical_address{madt->local_interrupt_controller_address()}; + auto cpu_bus = kstd::make_unique<devices::cpu>(cpu_major, 0); + + for (auto const & apic : lapic_entries) + { + auto is_bsp = !bsp_found; + bsp_found = true; + auto core = kstd::make_unique<devices::cpu::core>(core_major, core_count, apic.processor_id(), is_bsp); + core->add_child(kstd::make_unique<arch::devices::local_apic>(interrupt_controller_major, core_count, apic.id(), + local_apic_address, is_bsp)); + cpu_bus->add_child(std::move(core)); + ++core_count; + } + + devices::get_root_bus().add_child(std::move(cpu_bus)); + + kstd::println("[x86_64:PLT] Found {} CPU cores", core_count); + return core_count > 0; + } + } // namespace kapi::cpu diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp new file mode 100644 index 0000000..f188c92 --- /dev/null +++ b/arch/x86_64/kapi/devices.cpp @@ -0,0 +1,14 @@ +#include <kapi/devices.hpp> + +#include <arch/devices/init.hpp> + +namespace kapi::devices +{ + + auto init_platform_devices() -> void + { + arch::devices::init_acpi_devices(); + arch::devices::init_legacy_devices(); + } + +} // namespace kapi::devices
\ No newline at end of file diff --git a/arch/x86_64/kapi/interrupts.cpp b/arch/x86_64/kapi/interrupts.cpp new file mode 100644 index 0000000..85acc0f --- /dev/null +++ b/arch/x86_64/kapi/interrupts.cpp @@ -0,0 +1,16 @@ +#include <kapi/interrupts.hpp> + +namespace kapi::interrupts +{ + + auto enable() -> void + { + asm volatile("sti"); + } + + auto disable() -> void + { + asm volatile("cli"); + } + +} // namespace kapi::interrupts
\ No newline at end of file diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index a9e1216..5b870d5 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -1,18 +1,19 @@ -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> -#include "kapi/boot.hpp" -#include "kapi/system.hpp" +#include <arch/boot/boot.hpp> +#include <arch/boot/ld.hpp> +#include <arch/cpu/registers.hpp> +#include <arch/memory/higher_half_mapper.hpp> +#include <arch/memory/kernel_mapper.hpp> +#include <arch/memory/page_table.hpp> +#include <arch/memory/page_utilities.hpp> +#include <arch/memory/region_allocator.hpp> -#include "arch/boot/boot.hpp" -#include "arch/boot/ld.hpp" -#include "arch/cpu/registers.hpp" -#include "arch/memory/higher_half_mapper.hpp" -#include "arch/memory/kernel_mapper.hpp" -#include "arch/memory/page_table.hpp" -#include "arch/memory/page_utilities.hpp" -#include "arch/memory/region_allocator.hpp" +#include <kapi/boot.hpp> +#include <kapi/system.hpp> #include <kstd/print> +#include <kstd/units> #include <multiboot2/constants.hpp> #include <multiboot2/information.hpp> @@ -28,6 +29,8 @@ #include <span> #include <utility> +using namespace kstd::units_literals; + namespace kapi::memory { @@ -46,13 +49,14 @@ namespace kapi::memory } auto const & mbi = boot::bootstrap_information.mbi; - auto mbi_span = std::span{std::bit_cast<std::byte *>(mbi), mbi->size_bytes()}; + auto mbi_span = std::span{std::bit_cast<std::byte *>(mbi), static_cast<std::size_t>(mbi->size())}; auto image_span = std::span{&arch::boot::_start_physical, &arch::boot::_end_physical}; return arch::memory::region_allocator::memory_information{ .image_range = std::make_pair(physical_address{&image_span.front()}, physical_address{&image_span.back()}), .mbi_range = std::make_pair(physical_address{&mbi_span.front()}, physical_address{&mbi_span.back()}), .memory_map = *memory_map, + .mbi = mbi, }; } @@ -106,10 +110,10 @@ namespace kapi::memory [[maybe_unused]] auto remap_multiboot_information(page_mapper & mapper) -> void { auto mbi_base = std::bit_cast<std::uintptr_t>(boot::bootstrap_information.mbi); - auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); + auto mbi_size = boot::bootstrap_information.mbi->size(); auto mbi_physical_start = physical_address{mbi_base & ~std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}; auto mbi_virtual_start = linear_address{mbi_base}; - auto mbi_block_count = (mbi_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; + auto mbi_block_count = (mbi_size + frame::size - 1_B) / frame::size; for (auto i = 0uz; i < mbi_block_count; ++i) { @@ -119,6 +123,24 @@ namespace kapi::memory } } + [[maybe_unused]] auto remap_bootloader_modules(page_mapper & mapper) -> void + { + std::ranges::for_each(boot::bootstrap_information.mbi->modules(), [&mapper](auto const & module) { + auto module_physical_start = physical_address{module.start_address}; + auto module_virtual_start = + linear_address{module.start_address + std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}; + auto module_size = static_cast<kstd::units::bytes>(module.end_address - module.start_address); + auto module_block_count = (module_size + frame::size - 1_B) / frame::size; + + for (auto i = 0uz; i < module_block_count; ++i) + { + auto page = page::containing(module_virtual_start) + i; + auto frame = frame::containing(module_physical_start) + i; + mapper.map(page, frame, page_mapper::flags::writable | page_mapper::flags::supervisor_only); + } + }); + } + [[maybe_unused]] auto handoff_to_kernel_pmm(frame_allocator & new_allocator) -> void { auto memory_map = boot::bootstrap_information.mbi->memory_map(); @@ -128,7 +150,7 @@ namespace kapi::memory })) { auto start = frame::containing(physical_address{region.base}); - auto count = region.size_in_B / page::size; + auto count = kstd::units::bytes{region.size_in_B} / page::size; new_allocator.release_many({start, count}); } @@ -148,14 +170,22 @@ namespace kapi::memory [&](auto frame) { new_allocator.mark_used(frame); }); auto mbi_base = std::bit_cast<std::uintptr_t>(boot::bootstrap_information.mbi); - auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); + auto mbi_size = boot::bootstrap_information.mbi->size(); auto mbi_address = physical_address{mbi_base & ~std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}; auto mbi_start = frame::containing(mbi_address); auto mbi_end = frame::containing(mbi_address + mbi_size) + 1; - // TODO BA-FS26: Protect MB2 boot modules - std::ranges::for_each(std::views::iota(mbi_start, mbi_end), [&](auto frame) { new_allocator.mark_used(frame); }); + + std::ranges::for_each(boot::bootstrap_information.mbi->modules(), [&](auto const & module) { + auto module_physical_start = physical_address{module.start_address}; + auto module_size = module.end_address - module.start_address; + auto module_start = frame::containing(module_physical_start); + auto module_end = frame::containing(module_physical_start + module_size) + 1; + + std::ranges::for_each(std::views::iota(module_start, module_end), + [&](auto frame) { new_allocator.mark_used(frame); }); + }); } } // namespace @@ -196,6 +226,7 @@ namespace kapi::memory remap_kernel(*higher_half_mapper); remap_vga_text_mode_buffer(*higher_half_mapper); remap_multiboot_information(*higher_half_mapper); + remap_bootloader_modules(*higher_half_mapper); auto current_cr3 = arch::cpu::cr3::read(); auto old_pml4 = static_cast<arch::memory::page_table *>(current_cr3.address()); diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp index ca4418e..73a77e5 100644 --- a/arch/x86_64/kapi/system.cpp +++ b/arch/x86_64/kapi/system.cpp @@ -1,122 +1,8 @@ -#include "kapi/system.hpp" - -#include "arch/cpu/global_descriptor_table.hpp" -#include "arch/cpu/segment_descriptor.hpp" -#include "arch/cpu/task_state_segment.hpp" - -#include <kstd/print> - -#include <bit> -#include <cstdint> +#include <kapi/system.hpp> namespace kapi::system { - namespace - { - constexpr auto gdt_null_descriptor = arch::cpu::segment_descriptor{}; - - constexpr auto gdt_kernel_code_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = true, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 0, - .present = true, - .limit_high = 0xf, - .long_mode = true, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_kernel_data_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = true, - .direction_or_conforming = false, - .executable = false, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 0, - .present = true, - .limit_high = 0xf, - .long_mode = false, - .protected_mode = true, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_user_code_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = true, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 3, - .present = true, - .limit_high = 0xf, - .long_mode = true, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_user_data_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = true, - .direction_or_conforming = false, - .executable = false, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 3, - .present = true, - .limit_high = 0xf, - .long_mode = false, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - } // namespace - - auto memory_initialized() -> void - { - auto static tss = arch::cpu::task_state_segment{}; - auto static tss_descriptor = arch::cpu::system_segment_descriptor{ - { - .limit_low = (sizeof(tss) - 1) & 0xffff, // NOLINT(readability-magic-numbers) - .base_low = std::bit_cast<std::uintptr_t>(&tss) & 0xffffff, // NOLINT(readability-magic-numbers) - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = false, - .type = arch::cpu::segment_type::system, - .privilege_level = 0, - .present = true, - .limit_high = ((sizeof(tss) - 1) >> 16) & 0xf, // NOLINT(readability-magic-numbers) - .long_mode = false, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::byte, - .base_high = (std::bit_cast<std::uintptr_t>(&tss) >> 24) & 0xff, // NOLINT(readability-magic-numbers) - }, - (std::bit_cast<std::uintptr_t>(&tss) >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) - }; - - auto static gdt = arch::cpu::global_descriptor_table{ - gdt_null_descriptor, gdt_kernel_code_descriptor, gdt_kernel_data_descriptor, - gdt_user_code_descriptor, gdt_user_data_descriptor, tss_descriptor, - }; - - kstd::println("[x86_64:SYS] Reloading Global Descriptor Table."); - gdt.load(1, 2); - - kstd::println("[x86_64:SYS] TODO: initialize Interrupt Descriptor Table."); - } + auto memory_initialized() -> void {} } // namespace kapi::system
\ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp deleted file mode 100644 index 07110c8..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP - -#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" -#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - __extension__ typedef __int128 int128_t; - __extension__ typedef unsigned __int128 uint128_t; - - /** - * @brief Defines helper function for all states and the actual data the gate descriptor can have. - */ - struct [[gnu::packed]] gate_descriptor - { - /** - * @brief Default Constructor. - */ - gate_descriptor() = default; - - /** - * @brief Constructor. - * - * @note Created gate descriptor copies the given bytes into these components ending with a 32 bit reserved - * field that has to be used, because the 64-bit gate descriptor needs to be big enough for two 32-bit gate - * descriptor. - * - 16 bit Segment Selector - * - 3 bit Interrupt Stack Table Offset - * - 8 bit Type and Flags - * - 64 bit Offset - * - * @param flags Copies the bits set from the given data into the individual components of a gate - * descriptor. - */ - explicit gate_descriptor(uint128_t flags); - - /** - * @brief Constructor. - * - * @param selector, ist, flags, offset Copies the bits set from the given data into the individual components of - * a gate descriptor. - */ - gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset); - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(gate_descriptor const & other) const -> bool = default; - - private: - // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _offset_1 = {}; ///< Lower 16 bits of handler function address (0 - 15) - segment_selector _selector = {}; ///< Segment selector (16 - 31) - ist_offset _ist = {}; ///< Interrupt Stack Table offset (32 - 39) - idt_flags _flags = {}; ///< Gate Type and Flags (40 - 47) - uint64_t _offset_2 : 48 = {}; ///< Upper 48 bits of handler function address (48 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp deleted file mode 100644 index 5104c36..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp +++ /dev/null @@ -1,81 +0,0 @@ - -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Defines helper function for all states that the access byte field of a segment descriptor can - * have. - */ - struct [[gnu::packed]] idt_flags - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - INTERRUPT_GATE = 0b01110, ///< The actual type of gate segment is a interrupt gate. - TRAP_GATE = 0b01111, ///< The actual type of gate segment is a trap gate. - DESCRIPTOR_LEVEL_KERNEL = - 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. - DESCRIPTOR_LEVEL_ADMIN = - 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_PRIVILEGED_USER = - 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. - PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. - }; - - /** - * @brief Default Constructor. - */ - idt_flags() = default; - - /** - * @brief Constructor. - * - * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used - * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags - * are enabled or not using contains_flags method. - */ - idt_flags(uint8_t flags); - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<8U> other) const -> bool; - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(idt_flags const & other) const -> bool = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<8U> other) -> void; - - private: - uint8_t _flags = {}; ///< Underlying bits used to read the flags from. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP
\ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp deleted file mode 100644 index b388e0e..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Updates the IDTR with the created interrupt descriptor table. If it has not been created yet this - * method will create it. - */ - auto update_interrupt_descriptor_table_register() -> void; - - /** - * @brief Creates the interrupt descriptor table, with the minimum required configuration. If this method is called - * more than once, the previously created instance is returned instead. - * - * @return Reference to the created interrupt_descriptor_table. - */ - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &; - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp deleted file mode 100644 index 7fe933b..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP - -#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" -#include "arch/stl/vector.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - using interrupt_descriptor_table = stl::vector<gate_descriptor>; - - /** - * @brief Represents a pointer to the Interrupt Descriptor Table (IDT). - * - * This structure is used to store the base address and length of the IDT. - */ - struct [[gnu::packed]] interrupt_descriptor_table_pointer - { - /** - * @brief Default constructor. - */ - interrupt_descriptor_table_pointer() = default; - - /** - * @brief Constructor. - */ - interrupt_descriptor_table_pointer(uint16_t table_length, gate_descriptor * address); - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(interrupt_descriptor_table_pointer const & other) const -> std::strong_ordering = default; - - private: - uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - gate_descriptor * address = {}; ///< Non-owning pointer to the IDT base address. - }; - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp deleted file mode 100644 index e45bcf4..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Defines helper function for all states that the interrupt stack table offset field of a gate descriptor can - * have. Is automatically increased to one byte in size, to include the following 5 reserved bits in the gate - * descriptor. - */ - struct [[gnu::packed]] ist_offset - { - /** - * @brief Default Constructor. - */ - ist_offset() = default; - - /** - * @brief Constructor. - * - * @param offset Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, whereas 1 - 7 - * mean we switch to the n-th stack in the Interrupt Stack Table, contained in the TSS if the gate descriptor that - * contains this field is called. - */ - ist_offset(uint8_t offset); - - /** - * @brief Allows to compare the underlying set bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(ist_offset const & other) const -> bool = default; - - private: - uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, - ///< whereas 1 - 7 mean we switch to the n-th stack in the Interrupt Stack Table, contained - ///< in the TSS if the gate descriptor that contains this field is called. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp deleted file mode 100644 index ea8c145..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Represents a segment selector in the x86_64 architecture, which points to a valid code segment in the global - * descriptor table. - * - * A segment selector is a 16-bit identifier used to select a segment descriptor - * from the Global Descriptor Table (GDT) or the Local Descriptor Table (LDT). - * It contains an index, a table indicator (TI), and a requested privilege level (RPL). - */ - struct [[gnu::packed]] segment_selector - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - REQUEST_LEVEL_KERNEL = - 0U << 0U, ///< Highest privileged level used by the kernel to allow for full access of resources. - REQUEST_LEVEL_ADMIN = - 1U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - REQUEST_LEVEL_PRIVILEGED_USER = - 2U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - REQUEST_LEVEL_USER = 3U << 0U, ///< Restricts access to only application and their specific memory. - LOCAL_DESCRIPTOR_TABLE = 1U << 2U, ///< Wheter the index referes to an entry in the local or global descriptor - ///< table. If enabled the index points to a local descriptor table, if it is - ///< cleared it referes to a global descriptor table instead. - }; - - /** - * @brief Default constructor. - */ - segment_selector() = default; - - /** - * @brief Constructor. - * - * @param index Index into the local or global descriptor table. Processor multiplies the index value by 8 (number - * of bytes in 32-bit segment descriptor) and adds the result to the base GDT or LDT address. - * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to - * allow for direct integer conversion. - */ - constexpr segment_selector(uint16_t index, uint8_t flags) - : _flags(flags) - , _index(index) - { - // Nothing to do. - } - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<3U> other) const -> bool; - - /** - * @brief Gets the index into the global descriptor table or the local descriptor table this segment selector is - * pointing too. - * - * @return Underlying value of the index field, bit 3 - 16. - */ - [[gnu::section(".user_text")]] - auto get_index() const -> uint16_t; - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<3U> other) -> void; - - /** - * @brief Cast the underlying data into a combined 16-bit form, that contains all data. - * - * @return Underlying value combined into it's full size. - */ - operator uint16_t() const; - - private: - uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. - uint16_t _index - : 13 = {}; ///< Index into the local or global descriptor table. Processor multiplies the index value by 16 - ///< (number of bytes in segment descriptor) and adds the result to the base address. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/main.hpp b/arch/x86_64/pre/include/arch/context_switching/main.hpp deleted file mode 100644 index f8477ea..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/main.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" - -namespace teachos::arch::context_switching -{ - /** - * @brief Contains the references to the tables required for context switching - */ - struct descriptor_tables - { - segment_descriptor_table::global_descriptor_table & gdt; ///< Reference to the global descriptor table. - interrupt_descriptor_table::interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. - }; - - /** - * @brief Creates the Interrupt Descriptor Table and Global Descriptor Table as a static variable the first time this - * method is called and update IDTR and GDTR registers values. - * - * @note Subsequent calls after the first one, will simply return the previously created tables, but not update the - * registers again. - * - * @return References to the statically created Interrupt Descriptor and Global Descriptor Table. - */ - auto initialize_descriptor_tables() -> descriptor_tables; - - /** - * @brief Switches from the current Kernel Mode (Level 0) to User Mode (Level 3). Will simply use predefined Segment - * Selectors for the User Data and User Code Segment, which are Index 3 and 4 in the GDT respectively. - */ - auto switch_to_user_mode() -> void; - - /** - * @brief Switches from the current Code and Data Segment to the given Code and Data Segment. - * - * @note This method will additionally call initialize_descriptor_tables, to ensure the GDTR and IDTR have been setup - * correctly before attempting to switch the context. This switch is achieved using a far return, which will once - * executed call the given void function. - * - * @param data_segment Data Segment that the SS, DS; ES, FS and GS register will be set too. - * @param code_segment Code Segment that the CS register will be set too. - * @param return_function Function that will be called once the switch has been achieved. - */ - auto switch_context(interrupt_descriptor_table::segment_selector data_segment, - interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void; - -} // namespace teachos::arch::context_switching - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp deleted file mode 100644 index f507c61..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP - -#include <cstdint> - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Possible syscall implementation that should actually be called. - * - * @note Attempts to reflect the Linux interface partially. See https://filippo.io/linux-syscall-table/ for more - * information. - */ - enum class type : uint64_t - { - WRITE = 1U, ///< Loads the arg_0 parameter as an address pointing to a const char array, which will then be printed - ///< onto the VGA buffer screen. - EXPAND_HEAP = 2U, /// Expands the User Heap by additonally mapping 100 KiB of virtual page memory. Ignores the - /// parameters and uses them as out parameters instead, where arg_0 is the start of the newly - /// mapped heap area and arg_1 is the size of the entire area. Can be less than 100 KiB if less - /// space remains. - ASSERT = 3U, /// Loads the arg_0 parameter as a boolean which needs to be true or it will print the message in - /// arg_1 parameter onto the VGA buffer screen, keep it as a nullptr if it shouldn't print anything - /// and then it halts the further execution of the application. - }; - - /** - * @brief Possible error codes that can be returned by the different syscall methods called depending on the type - * enum. - */ - enum class error : uint8_t - { - OK = 0U, ///< No error occured in syscall. - OUT_OF_MEMORY = 1U, ///< Expanding heap failed because we have run out of mappable virtual address space. - }; - - /** - * @brief Allows to convert the error enum type into a boolean directly. Where any code besides 0 being no error, will - * return true. The remaining errors return true. - * - * @param e Error code that was returned by the syscall. - * @return Return true if there was no error and false otherwise. - */ - constexpr bool operator!(error e) - { - return e == error::OK; - } - - /** - * @brief Maximum amount of arguments that can be passed to a syscall. Default value is 0 and arguments are only ever - * used depending on the actual enum type and if the method requires thoose parameters. - */ - struct arguments - { - uint64_t arg_0{}; ///< First optional paramter to the syscall representing the RDI register. - uint64_t arg_1{}; ///< Second optional paramter to the syscall representing the RSI register. - uint64_t arg_2{}; ///< Third optional paramter to the syscall representing the RDX register. - uint64_t arg_3{}; ///< Fourth optional paramter to the syscall representing the R10 register. - uint64_t arg_4{}; ///< Fifth optional paramter to the syscall representing the R8 register. - uint64_t arg_5{}; ///< Sixth optional paramter to the syscall representing the R9 register. - }; - - /** - * @brief Response of a systemcall always containin an error code, signaling if the syscall even succeeded or not. - * Additionally it may contain up to 6 return values in the values struct. - */ - struct response - { - error error_code; ///< Error code returned by the syscall. If it failed all the values will be 0. - arguments values = {}; ///< Optional return values of the syscall implementation. - }; - - /** - * @brief Calls the method associated with the given syscall number and passes the given optional arguments to it, - * over the RDI, RSI, RDX, R10, R8 and R9 register. - * - * @param syscall_number Syscall method that should be called. See enum values in type for possible implemented - * methods. - * @param args Optional arguments passable to the different syscall methods, called depending on the syscall_number. - * Not passing the required parameters to the method, will result in passing 0 instead, which might make the fail or - * not function correctly. - * @return The syscall implementation always returns a bool-convertable error code converting to true if the syscall - * failed or false if it didn't. Additionally it might pase additional values besides the error code, they will be set - * in the arguments struct. So the value can be read and used for further processing. - */ - [[gnu::section(".user_text")]] - auto syscall(type syscall_number, arguments args = {}) -> response; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp deleted file mode 100644 index 8cb468a..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Enables and sets up internal CPU registers to allow for syscall to function correctly and switch context - * temporarily back to the kernel level. - * - * @note Configures the Model Specific Register required by syscall (LSTAR, FMASK, STAR) with the correct values so - * that the syscall_handler is called and sets the System Call Extension bit on the EFER flags to allow for syscall - * to be used. - */ - auto enable_syscall() -> void; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp deleted file mode 100644 index 2e7bcd1..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP - -#include <cstdint> - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Handler for SYSCALL instruction. Calls a specific implementation based - * on the register RAX. - * - * @return Returns with LEAVE, SYSRETQ - */ - auto syscall_handler() -> void; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP diff --git a/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp b/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp deleted file mode 100644 index 15b35c1..0000000 --- a/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP - -#include <cstdint> - -namespace teachos::arch::interrupt_handling -{ - /** - * @brief Represents the CPU state during an interrupt. - * - * Some interrupts push an error code, while others do not. The full list - * of which vector number contains the error code can be found here: https://wiki.osdev.org/Exceptions - */ - struct [[gnu::packed]] interrupt_frame - { - // uint64_t error_code; ///< Error code only pushed by some exceptions, therefore it is commented out. - uint64_t ip; ///< Instruction pointer at the time of the interrupt. - uint64_t cs; ///< Code segment selector indicating privilege level. - uint64_t flags; ///< CPU flags (RFLAGS) storing processor state. - uint64_t sp; ///< Stack pointer at the time of the interrupt. - uint64_t ss; ///< Stack segment selector, usually unused in 64-bit mode. - }; - - /** - * @brief Generic interrupt handler function. - * - * @param frame Pointer to the interrupt frame containing CPU state. - */ - [[gnu::interrupt]] - auto generic_interrupt_handler(interrupt_frame * frame) -> void; - -} // namespace teachos::arch::interrupt_handling - -#endif // TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp deleted file mode 100644 index 3c43304..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include <cstdint> - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Far Pointer. Address to function located in another code segment. - */ - struct far_pointer - { - void (*function)(); ///< Address of the function we want to call. (0-63) - context_switching::interrupt_descriptor_table::segment_selector - selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79) - }; - - /** - * @brief Far call - A call to an instruction located in a different segment than the current code segment but at the - * same privilege level. - * - * @param pointer 64-bit operand size far pointer that we want to call. - */ - auto call(far_pointer pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp deleted file mode 100644 index cb800d0..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Returns the value in the IDTR register. - * - * @return Value of IDTR register. - */ - auto store_interrupt_descriptor_table() - -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer; - - /** - * @brief Loads the interrupt_descriptor_table_pointer into the interrupt descriptor table register (IDTR). - */ - auto load_interrupt_descriptor_table( - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp deleted file mode 100644 index 48707dc..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Sets the interrupt flag (IF) in the EFLAGS register. - * This allows the processor to respond to maskable hardware interrupts. - */ - auto set_interrupt_flag() -> void; - - /** - * @brief Clears the interrupt flag (IF) in the EFLAGS register. - * This will stop the processor to respond to maskable hardware interrupts and needs to be done before changing the - * Interrupt Descriptor Table with lidt. - */ - auto clear_interrupt_flag() -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp deleted file mode 100644 index 99d6378..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). - * - * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions - * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for - * more information. - */ - enum class efer_flags : uint64_t - { - SCE = 1UL << 0UL, ///< System Call Extensions. - LME = 1UL << 8UL, ///< Long Mode Enabled. - LMA = 1UL << 10UL, ///< Long Mode Active. - NXE = 1UL << 11UL, ///< No-Execute Enable. - SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. - LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. - FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. - TCE = 1UL << 15UL, ///< Translation Cache Extension. - }; - - /** - * @brief Reads a 64-bit from the Model-Specific Register (MSR). - * - * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper - * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. - * - * @param msr The address of the MSR to read. - * @return The 64-bit value read from the MSR. - */ - auto read_msr(uint32_t msr) -> uint64_t; - - /** - * @brief Writes a 64-bit value to a Model-Specific Register (MSR). - * - * @note This function writes a 64-bit value to the MSR specified by the given address. - * It splits the 64-bit value into two 32-bit parts and writes them using the - * `wrmsr` instruction. - * - * @param msr The address of the MSR to write to. - * @param new_value The 64-bit value to write to the MSR. - */ - auto write_msr(uint32_t msr, uint64_t new_value) -> void; - - /** - * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register - * (MSR). - * - * @note This function reads the current value of the EFER register, ORs the specified - * bit with the current value, and writes the updated value back to the EFER register. - * - * @param flag The flag to set in the EFER register. - */ - auto set_efer_bit(efer_flags flag) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP
\ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp deleted file mode 100644 index 7c856f1..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP - -#include <bitset> -#include <cstdint> - -namespace teachos::arch::kernel::cpu -{ - - /** - * @brief Returns the value in the LTR register. - * - * @return Value of LTR register. - */ - auto store_task_register() -> uint16_t; - - /** - * @brief Loads the gdt offset to the tss segment descriptor into the task register (TR). - */ - auto load_task_register(uint16_t gdt_offset) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/halt.hpp b/arch/x86_64/pre/include/arch/kernel/halt.hpp deleted file mode 100644 index 377acc0..0000000 --- a/arch/x86_64/pre/include/arch/kernel/halt.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP - -namespace teachos::arch::kernel -{ - /** - * @brief Halts the kernel execution, meaning any code after a call to this will not run anymore. - */ - extern "C" [[noreturn]] auto halt() -> void; - -} // namespace teachos::arch::kernel - -#endif // TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/main.hpp b/arch/x86_64/pre/include/arch/kernel/main.hpp deleted file mode 100644 index a13e5f4..0000000 --- a/arch/x86_64/pre/include/arch/kernel/main.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP - -namespace teachos::arch::kernel -{ - /** - * @brief Initalizes the kernel system. - */ - auto main() -> void; - -} // namespace teachos::arch::kernel - -#endif // TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/user/main.hpp b/arch/x86_64/pre/include/arch/user/main.hpp deleted file mode 100644 index c168a1f..0000000 --- a/arch/x86_64/pre/include/arch/user/main.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_USER_MAIN_HPP -#define TEACHOS_ARCH_X86_64_USER_MAIN_HPP - -namespace teachos::arch::user -{ - /** - * @brief User Main method. If this method finishes there is no code left to run and the whole OS will shut down. - * Additionally this main method is executed at Ring 3 and accessing CPU Registers or Kernel level functionality can - * only be done over syscalls and not directly anymore. - */ - [[gnu::section(".user_text")]] - auto main() -> void; - -} // namespace teachos::arch::user - -#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp deleted file mode 100644 index 28f289c..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - gate_descriptor::gate_descriptor(uint128_t flags) - : _offset_1(flags) - , _selector(flags >> 19U, flags >> 16U) - , _ist(flags >> 32U) - , _flags(flags >> 40U) - , _offset_2(flags >> 48U) - { - // Nothing to do. - } - - gate_descriptor::gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset) - : _offset_1(offset) - , _selector(selector) - , _ist(ist) - , _flags(flags) - , _offset_2(offset >> 16U) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp deleted file mode 100644 index f3b9d5e..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - idt_flags::idt_flags(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto idt_flags::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } - - auto idt_flags::operator|=(std::bitset<8U> other) -> void - { - _flags |= other.to_ulong(); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp deleted file mode 100644 index 8640385..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/interrupt_handling/generic_interrupt_handler.hpp" -#include "arch/kernel/cpu/idtr.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - namespace - { - /// @brief Amount of currently reserved interrupt indicies. - /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. - constexpr uint16_t RESERVED_INTERRUPT_COUNT = 256U; - - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table - { - interrupt_descriptor_table interrupt_descriptor_table{RESERVED_INTERRUPT_COUNT}; - - uint64_t offset = reinterpret_cast<uint64_t>(interrupt_handling::generic_interrupt_handler); - segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - - for (std::size_t i = 0; i < interrupt_descriptor_table.size(); i++) - { - interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; - } - - return interrupt_descriptor_table; - } - } // namespace - - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & - { - // Interrupt Descriptor Table needs to be kept alive - interrupt_descriptor_table static idt = create_interrupt_descriptor_table(); - return idt; - } - - auto update_interrupt_descriptor_table_register() -> void - { - decltype(auto) idt = get_or_create_interrupt_descriptor_table(); - - interrupt_descriptor_table_pointer idt_pointer{static_cast<uint16_t>((idt.size() * sizeof(gate_descriptor)) - 1), - idt.data()}; - kernel::cpu::load_interrupt_descriptor_table(idt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); - arch::exception_handling::assert( - idt_pointer == stored_gdt_pointer, - "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp deleted file mode 100644 index 7bcbae6..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - gate_descriptor * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp deleted file mode 100644 index a70e75d..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - ist_offset::ist_offset(uint8_t index) - : _ist(index) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp deleted file mode 100644 index 25ba859..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool - { - return (std::bitset<3U>{_flags} & other) == other; - } - - auto segment_selector::get_index() const -> uint16_t - { - return _index; - } - - auto segment_selector::operator|=(std::bitset<3U> other) -> void - { - _flags |= other.to_ulong(); - } - - segment_selector::operator uint16_t() const - { - return *reinterpret_cast<uint16_t const *>(this); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/main.cpp b/arch/x86_64/pre/src/context_switching/main.cpp deleted file mode 100644 index 3eb6dae..0000000 --- a/arch/x86_64/pre/src/context_switching/main.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "arch/context_switching/main.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall/syscall_enable.hpp" -#include "arch/kernel/cpu/call.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/kernel/cpu/tr.hpp" -#include "arch/user/main.hpp" - -namespace teachos::arch::context_switching -{ - namespace - { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, - KERNEL_CODE_SEGMENT_SELECTOR}; - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ - 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - - auto reload_gdtr() -> void - { - kernel::cpu::call(KERNEL_CODE_POINTER); - } - } // namespace - - auto initialize_descriptor_tables() -> descriptor_tables - { - bool static initalized = false; - - if (!initalized) - { - kernel::cpu::clear_interrupt_flag(); - - segment_descriptor_table::update_gdtr(); - interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - - reload_gdtr(); - segment_descriptor_table::update_tss_register(); - - kernel::cpu::set_interrupt_flag(); - initalized = true; - } - - descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), - interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - return tables; - } - - auto switch_to_user_mode() -> void - { - syscall::enable_syscall(); - switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); - } - - auto switch_context(interrupt_descriptor_table::segment_selector data_segment, - interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void - { - (void)initialize_descriptor_tables(); - kernel::cpu::set_data_segment_registers(data_segment); - kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast<uint64_t>(return_function)); - } -} // namespace teachos::arch::context_switching diff --git a/arch/x86_64/pre/src/context_switching/syscall/main.cpp b/arch/x86_64/pre/src/context_switching/syscall/main.cpp deleted file mode 100644 index b4ab468..0000000 --- a/arch/x86_64/pre/src/context_switching/syscall/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/context_switching/syscall/main.hpp" - -namespace teachos::arch::context_switching::syscall -{ - auto syscall(type syscall_number, arguments args) -> response - { - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "m"(syscall_number) - : "memory"); - - asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); - asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); - asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); - asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); - asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); - asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); - - asm volatile("syscall"); - - arguments values{}; - asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); - - error error_code{}; - asm volatile("mov %%al, %[output]" : [output] "=m"(error_code)); - - return {error_code, values}; - } - -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp deleted file mode 100644 index dbb3ed9..0000000 --- a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "arch/context_switching/syscall/syscall_enable.hpp" - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/syscall/syscall_handler.hpp" -#include "arch/kernel/cpu/msr.hpp" - -namespace teachos::arch::context_switching::syscall -{ - namespace - { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - - constexpr auto IA32_STAR_ADDRESS = 0xC000'0081; - constexpr auto IA32_LSTAR_ADDRESS = 0xC000'0082; - constexpr auto IA32_FMASK_ADDRESS = 0xC000'0084; - - } // namespace - - auto enable_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast<uint64_t>(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp deleted file mode 100644 index c120f77..0000000 --- a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "arch/context_switching/syscall/syscall_handler.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/main.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::context_switching::syscall -{ - - namespace - { - auto write_to_vga_buffer(uint64_t buffer) -> response - { - video::vga::text::write(reinterpret_cast<char const *>(buffer), - video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - return {error::OK}; - } - - auto expand_user_heap() -> response - { - auto static current_heap_end = memory::heap::USER_HEAP_START; - uint64_t const heap_start = current_heap_end; - memory::remap_heap(heap_start, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); - current_heap_end += memory::heap::USER_HEAP_SIZE; - return { - error::OK, - {heap_start, memory::heap::USER_HEAP_SIZE} - }; - } - } // namespace - - auto syscall_handler() -> void - { - // Saving state of rcx and r11 because it is required by sysretq to function. - // Calls to other functions potentially overwrite these registers, because of - // callee saved calling convention. - uint64_t return_instruction_pointer, rflags = {}; - asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); - asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); - - uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; - asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); - - // RAX is read last, because paired with our type enum, we can use it to check - // if the register has been written by the compiled code between executing the syscall - // and now. - asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); - - response result; - switch (static_cast<type>(syscall_number)) - { - case type::WRITE: - result = write_to_vga_buffer(arg_0); - break; - case type::EXPAND_HEAP: - result = expand_user_heap(); - break; - case type::ASSERT: - teachos::arch::exception_handling::assert(arg_0, reinterpret_cast<char const *>(arg_1)); - break; - default: - teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); - break; - } - - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "m"(result.error_code) - : "memory"); - - asm volatile("mov %[input], %%rdi" - : /* no output from call */ - : [input] "m"(result.values.arg_0) - : "memory"); - asm volatile("mov %[input], %%rsi" - : /* no output from call */ - : [input] "m"(result.values.arg_1) - : "memory"); - asm volatile("mov %[input], %%rdx" - : /* no output from call */ - : [input] "m"(result.values.arg_2) - : "memory"); - asm volatile("mov %[input], %%r10" - : /* no output from call */ - : [input] "m"(result.values.arg_3) - : "memory"); - asm volatile("mov %[input], %%r8" - : /* no output from call */ - : [input] "m"(result.values.arg_4) - : "memory"); - asm volatile("mov %[input], %%r9" - : /* no output from call */ - : [input] "m"(result.values.arg_5) - : "memory"); - - asm volatile("mov %[input], %%rcx" - : /* no output from call */ - : [input] "m"(return_instruction_pointer) - : "memory"); - asm volatile("mov %[input], %%r11" - : /* no output from call */ - : [input] "m"(rflags) - : "memory"); - - // Additionally call leave, because x86 allocates stack space for the internal variables. If we do not clean up this - // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the - // method that originally called it, because the RIP has not been restored from the previous stack frame. - asm volatile("leave\n" - "sysretq"); - } - -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp deleted file mode 100644 index 9d061a8..0000000 --- a/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/interrupt_handling/generic_interrupt_handler.hpp" - -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::interrupt_handling -{ - auto generic_interrupt_handler(interrupt_frame * frame) -> void - { - (void)frame; - video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - } -} // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/pre/src/kernel/cpu/call.cpp b/arch/x86_64/pre/src/kernel/cpu/call.cpp deleted file mode 100644 index 98fa248..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/call.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "arch/kernel/cpu/call.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto call(far_pointer pointer) -> void - { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/idtr.cpp b/arch/x86_64/pre/src/kernel/cpu/idtr.cpp deleted file mode 100644 index 7aa20c1..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/idtr.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "arch/kernel/cpu/idtr.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_interrupt_descriptor_table() - -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer - { - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer current_value{}; - asm("sidt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto load_interrupt_descriptor_table( - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void - { - asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/if.cpp b/arch/x86_64/pre/src/kernel/cpu/if.cpp deleted file mode 100644 index 5d056fc..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/if.cpp +++ /dev/null @@ -1,13 +0,0 @@ -namespace teachos::arch::kernel::cpu -{ - auto set_interrupt_flag() -> void - { - asm volatile("sti"); - } - - auto clear_interrupt_flag() -> void - { - asm volatile("cli"); - } - -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/tr.cpp b/arch/x86_64/pre/src/kernel/cpu/tr.cpp deleted file mode 100644 index a435540..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/tr.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_task_register() -> uint16_t - { - uint16_t current_value{}; - asm("str %[output]" : [output] "=r"(current_value)); - return current_value; - } - - auto load_task_register(uint16_t gdt_offset) -> void - { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/main.cpp b/arch/x86_64/pre/src/kernel/main.cpp deleted file mode 100644 index 43b5f90..0000000 --- a/arch/x86_64/pre/src/kernel/main.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "arch/kernel/main.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/main.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/memory/heap/bump_allocator.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/main.hpp" -#include "arch/memory/multiboot/reader.hpp" -#include "arch/stl/vector.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::kernel -{ - auto stack_overflow_test(int count) -> int - { - int test[5000] = {}; - if (test[0] == 0xFFFF) - { - return count; - } - count = stack_overflow_test(count); - return count++; - } - - auto heap_test() -> void - { - auto test2 = new memory::multiboot::memory_information{}; - auto test3 = new memory::multiboot::memory_information{}; - auto test4 = *test2; - auto test5 = *test3; - test4.kernel_end = 5000; - test5.kernel_end = 3000; - auto test6 = test4.kernel_end; - auto test7 = test5.kernel_end; - auto test8 = memory::multiboot::read_multiboot2(); - if (test6 && test7 && test8.kernel_end) - { - video::vga::text::write("Heap test successful", video::vga::text::common_attributes::green_on_black); - } - test2->kernel_end = 2000; - test2->kernel_start = 1000; - test2->multiboot_start = 2000; - delete test2; - delete test3; - - auto test9 = new int(50); - delete test9; - } - - auto main() -> void - { - video::vga::text::clear(); - video::vga::text::cursor(false); - video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - - memory::initialize_memory_management(); - // stack_overflow_test(0); - - memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); - // heap_test(); - - auto address = memory::heap::global_heap_allocator::kmalloc(8U); - (void)address; - - context_switching::switch_to_user_mode(); - } -} // namespace teachos::arch::kernel diff --git a/arch/x86_64/pre/src/user/main.cpp b/arch/x86_64/pre/src/user/main.cpp deleted file mode 100644 index 8b07e4a..0000000 --- a/arch/x86_64/pre/src/user/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/user/main.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" - -#include <algorithm> -#include <array> -#include <atomic> -#include <ranges> - -namespace teachos::arch::user -{ - auto main() -> void - { - constexpr char syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - context_switching::syscall::syscall(context_switching::syscall::type::WRITE, - {reinterpret_cast<uint64_t>(&syscall_message)}); - - // Test C++ standard library - std::array<std::atomic<uint8_t>, 4> array_test = {std::atomic<uint8_t>{5}, std::atomic<uint8_t>{10}, - std::atomic<uint8_t>{15}, std::atomic<uint8_t>{20}}; - std::ranges::for_each(array_test, [](auto & item) { - auto value = item.load(); - uint8_t max_value = std::max(value, uint8_t{10}); - item.exchange(max_value + 2); - }); - - auto address = new uint64_t{10U}; - (void)address; - - for (;;) - { - } - } -} // namespace teachos::arch::user diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index a429570..dbb0f8f 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -72,6 +72,12 @@ SECTIONS .kernel_rodata ALIGN(4K) : AT (ADDR (.kernel_rodata) - TEACHOS_VMA) { *(.rodata*) + + . = ALIGN(8); + + PROVIDE(__start_fs_types = .); + KEEP(*(fs_types)); + PROVIDE(__stop_fs_types = .); } :kernel_rodata .kernel_data ALIGN(4K) : AT (ADDR (.kernel_data) - TEACHOS_VMA) diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 49f19ce..45c3356 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,5 +3,8 @@ default=0 menuentry "TeachOS" { multiboot2 /$<TARGET_FILE_NAME:kernel> + module2 /modules/ext2_4KB_fs.img + module2 /modules/ext2_1KB_fs.img + module2 /modules/ext2_2KB_fs.img boot }
\ No newline at end of file diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md new file mode 100644 index 0000000..6d235a7 --- /dev/null +++ b/arch/x86_64/support/modules/README.md @@ -0,0 +1,130 @@ +# Default images +The default images contain predefined data and structures that are specifically designed for testing purposes. +The ext2_4KB_fs image is intentionally fragmented, as some files were created and deleted before additional files were added, resulting in a non-contiguous layout. + +## ext2_1KB_fs +. +./lost+found +./archiv +./archiv/2024.img +./archiv/2025.img +./archiv/mnt +./closed.txt +./information +./information/info_1.txt +./information/info_2.txt +./symlinks +./symlinks/info_1_absolute -> /information/info_1.txt +./symlinks/info_1_relative -> ../information/info_1.txt +./symlinks/information_directory_absolute -> /information +./symlinks/information_directory_relative -> ../information +./symlinks/invalid_absolute -> /invalid/non_existant.txt +./symlinks/invalid_relative -> ../invalid/non_existant.txt +./symlinks/symloop_a -> ./symloop_b +./symlinks/symloop_b -> /symlinks/symloop_a +./symlinks/traverse_back_5_times -> ../../../../../ + +### 2024.img +(ext2 filesystem with 2KB Block size) +. +./lost+found +./sheep_1.txt +./sheep_2.txt +./stable/pig_1.txt +./stable/pig_2.txt +./stable/pig_3.txt +./symlinks +./symlinks/traverse_back_twice -> ../../ + +### 2025.img +(ext2 filesystem 4KB Block size) +. +./lost+found +./dev +./dev/image_1.txt +./dev/image_2.txt +./snake_1.txt +./snake_2.txt +./petting_zoo/goat_1.txt +./petting_zoo/goat_2.txt +./petting_zoo/chicken_coop +./petting_zoo/chicken_coop/chicken_1.txt +./petting_zoo/chicken_coop/chicken_2.txt +./petting_zoo/chicken_coop/chicken_3.txt + +## ext2_2KB_fs +. +./lost+found +./monkey_house +./monkey_house/infrastructure +./monkey_house/infrastructure/info.txt +./monkey_house/infrastructure/water.txt +./monkey_house/monkey_1.txt +./monkey_house/monkey_2.txt +./monkey_house/monkey_3.txt +./monkey_house/caretaker +./monkey_house/caretaker/isabelle.txt +./monkey_house/caretaker/peter.txt +./symlinks/leave_and_reenter_mount -> ../../archiv/../information/monkey_house + +## ext2_4KB_fs +. +./lost+found +./entrance +./entrance/tickets.txt +./entrance/map.txt +./enclosures +./enclosures/lion_house +./enclosures/lion_house/cage_a +./enclosures/lion_house/cage_a/history.txt +./enclosures/lion_house/cage_a/animals.txt +./enclosures/lion_house/cage_b +./enclosures/lion_house/cage_b/animals.txt +./enclosures/lion_house/cage_b/history.txt +./enclosures/lion_house/symlink_chain_2 -> /entrance/../enclosures/aquarium/symlink_chain_3 +./enclosures/elephant_house +./enclosures/elephant_house/elephant_1.txt +./enclosures/aquarium +./enclosures/aquarium/spawn_fish.sh +./enclosures/aquarium/symlink_chain_3 -> ../../entrance +./enclosures/aquarium/tank_1 +./enclosures/aquarium/tank_1/fish_1.txt +./enclosures/aquarium/tank_1/fish_2.txt +./enclosures/aquarium/tank_1/fish_3.txt +./enclosures/aquarium/tank_1/fish_4.txt +./enclosures/aquarium/tank_2 +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_1.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_2.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_3.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_4.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_5.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_6.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_7.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_8.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_9.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_10.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_11.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_12.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_13.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_14.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_15.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_16.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_17.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_18.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_19.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_20.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_21.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_22.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_23.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_24.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_25.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_26.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_27.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_28.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_29.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt +./enclosures/info.txt +./info.txt +./symlinks +./symlinks/symlink_chain_1 -> ../enclosures/lion_house/symlink_chain_2 +./symlinks/very_long_symlink -> ../enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt diff --git a/arch/x86_64/support/modules/ext2_1KB_fs.img b/arch/x86_64/support/modules/ext2_1KB_fs.img new file mode 100644 index 0000000..a5202ca --- /dev/null +++ b/arch/x86_64/support/modules/ext2_1KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98ac3c1be872806e25fb14eea168ca79a91959f4e6a5ac3d00c5d8224c1f73a3 +size 10485760 diff --git a/arch/x86_64/support/modules/ext2_2KB_fs.img b/arch/x86_64/support/modules/ext2_2KB_fs.img new file mode 100644 index 0000000..7f297f0 --- /dev/null +++ b/arch/x86_64/support/modules/ext2_2KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d9e872916e7d9107b321cc007e151899d5f19400a694666c0b24d482aef61ca +size 5242880 diff --git a/arch/x86_64/support/modules/ext2_4KB_fs.img b/arch/x86_64/support/modules/ext2_4KB_fs.img new file mode 100644 index 0000000..c3f6daf --- /dev/null +++ b/arch/x86_64/support/modules/ext2_4KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:026ca30269dbd80beb2dd74677c94676d1d4a7f6b5fe406c4ddb82836ba2dc00 +size 10485760 |
