aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-04-16 10:29:30 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-29 09:05:04 +0200
commit1b964278762dde86b0b737bd9a34fec569339f54 (patch)
tree7fe0f4707e05f46461f03744d178f413b7bbca28 /arch/x86_64/src
parentd906d70c94c2a40d5fc6fd26056c7bc57d540002 (diff)
downloadkernel-1b964278762dde86b0b737bd9a34fec569339f54.tar.xz
kernel-1b964278762dde86b0b737bd9a34fec569339f54.zip
x86_64: use p1204 project layout
Diffstat (limited to 'arch/x86_64/src')
-rw-r--r--arch/x86_64/src/boot/boot32.S443
-rw-r--r--arch/x86_64/src/boot/entry64.s62
-rw-r--r--arch/x86_64/src/boot/initialize_runtime.cpp22
-rw-r--r--arch/x86_64/src/boot/multiboot.s33
-rw-r--r--arch/x86_64/src/bus/isa.cpp14
-rw-r--r--arch/x86_64/src/cpu/initialization.cpp164
-rw-r--r--arch/x86_64/src/cpu/interrupt_stubs.S112
-rw-r--r--arch/x86_64/src/cpu/interrupts.cpp203
-rw-r--r--arch/x86_64/src/debug/qemu_output.cpp25
-rw-r--r--arch/x86_64/src/devices/init.cpp76
-rw-r--r--arch/x86_64/src/devices/legacy_pit.cpp60
-rw-r--r--arch/x86_64/src/devices/local_apic.cpp134
-rw-r--r--arch/x86_64/src/memory/higher_half_mapper.cpp119
-rw-r--r--arch/x86_64/src/memory/kernel_mapper.cpp117
-rw-r--r--arch/x86_64/src/memory/mmu.cpp19
-rw-r--r--arch/x86_64/src/memory/page_table.cpp82
-rw-r--r--arch/x86_64/src/memory/region_allocator.cpp165
-rw-r--r--arch/x86_64/src/vga/text/buffer.cpp101
-rw-r--r--arch/x86_64/src/vga/text/device.cpp60
19 files changed, 0 insertions, 2011 deletions
diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S
deleted file mode 100644
index e6fcd85..0000000
--- a/arch/x86_64/src/boot/boot32.S
+++ /dev/null
@@ -1,443 +0,0 @@
-#include <arch/boot/boot.hpp>
-
-/**
- * @brief Uninitialized data for the bootstrapping process.
- */
-.section .boot_bss, "aw", @nobits
-
-page_maps_start:
-page_map_level_4: .skip 512 * 8
-page_map_level_3_high: .skip 512 * 8
-page_map_level_3_low: .skip 512 * 8
-page_map_level_2: .skip 512 * 8
-page_maps_end = .
-page_maps_size = page_maps_end - page_maps_start
-
-/**
- * @brief Storage for the multiboot2 information pointer.
- */
-.global multiboot_information_pointer
-multiboot_information_pointer: .skip 8
-
-/**
- * @brief Storage for the bootstrap stack.
- */
-.section .boot_stack, "aw", @nobits
-.align 16
-
-early_stack_bottom: .skip 1 << 8
-early_stack_top:
-early_stack_size = early_stack_top - early_stack_bottom
-
-/**
- * @brief Constants for the bootstrapping process.
- */
-.section .boot_rodata, "a", @progbits
-
-.global global_descriptor_table_data
-
-/**
- * @brief A basic GDT for long mode.
- */
-global_descriptor_table:
-global_descriptor_table_null = . - global_descriptor_table
-.quad 0
-global_descriptor_table_code = . - global_descriptor_table
-.quad GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE | (1 << 55)
-global_descriptor_table_data = . - global_descriptor_table
-.quad GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | (1 << 54) | (1 << 55)
-global_descriptor_table_end:
-
-message_prefix_panic: .string "Panic: "
-message_not_loaded_by_multiboot2: .string "The operating system was not loaded by a Multiboot 2 loader."
-message_cpuid_instruction_no_supported: .string "The 'cpuid' instruction is not supported on this platform."
-message_long_mode_not_supported: .string "Long mode is not supported by this platform."
-message_return_from_kernel_main: .string "Execution returned from kernel main."
-
-/**
- * @brief Initialized data for the bootstrapping process.
- */
-.section .boot_data, "aw", @progbits
-
-/**
- * @brief A pointer to the current position within the VGA text buffer.
- */
-.global vga_buffer_pointer
-vga_buffer_pointer: .quad 0xb8000
-
-/**
- * @brief Code for the bootstrapping process.
- */
-.section .boot_text, "ax", @progbits
-.align 16
-.code32
-
-.macro pie_base
- push %esi
- call 0f
- 0:
- pop %esi
-.endm
-
-.macro function_start
- push %ebp
- mov %esp, %ebp
-.endm
-
-.macro function_end
- leave
- ret
-.endm
-
-.macro pie_function_start
- function_start
- pie_base
-.endm
-
-.macro pie_function_end
- pop %esi
- function_end
-.endm
-
-/**
- * @brief Prepare the environment and start the kernel.
- *
- * This function performs all necessary checks to ensure the system was loaded
- * by the expected loader and supports all features required to run the kernel.
- * If successful, it prepares the system by setting up memory virtualization
- * and then start the kernel proper.
- *
- * @param %eax The Multiboot 2 magic marker.
- * @param %ebx The Multiboot 2 information pointer.
- * @return void This function does not return.
- */
-.global _start
-_start:
- call 0f
-0:
- pop %esi
-
- lea (early_stack_top - 0b)(%esi), %ecx
-
- mov %ecx, %esp
- mov %esp, %ebp
-
- call _assert_loaded_by_multiboot2_loader
- call _save_multiboot_information_pointer
-
- call _assert_cpuid_instruction_is_supported
- call _assert_cpu_supports_long_mode
-
- push $HUGE_PAGES_TO_MAP
- call _prepare_page_maps
- add $4, %esp
-
- call _enable_paging
- call _enable_sse
- call _reload_gdt
-
- lea (_entry64 - 0b)(%esi), %eax
- pushl $global_descriptor_table_code
- pushl %eax
- lret
-
-/**
- * @brief Halt the system.
- *
- * This function will instruct the CPU to halt. It will try to keep the CPU
- * halted, even if interrupts occur.
- *
- * @return This function never returns.
- */
-_halt:
- function_start
-
-1:
- hlt
- jmp 1b
-
- function_end
-
-/**
- * @brief Print a message via the VGA text buffer.
- *
- * @param ebp+12 The message to print.
- * @param ebp+8 The color to print the message in.
- */
-_print:
- pie_function_start
-
- push %edi
- push %ebx
-
- mov 8(%ebp), %al
- mov 12(%ebp), %edx
- mov $0, %ecx
- lea (vga_buffer_pointer - 0b)(%esi), %edi
- mov (%edi), %edi
-
-1:
- mov (%edx, %ecx), %bl
- test %bl, %bl
- je 2f
- mov %bl, (%edi, %ecx, 2)
- mov %al, 1(%edi, %ecx, 2)
- inc %ecx
- jmp 1b
-
-2:
- shl $1, %ecx
- add %ecx, %edi
- lea (vga_buffer_pointer - 0b)(%esi), %ecx
- mov %edi, (%ecx)
-
- pop %ebx
- pop %edi
-
- pie_function_end
-
-/**
- * @brief Print a given panic message and then halt the machine as if by calling ::halt()
- *
- * @param ebp+4 A message to print.
- * @return This function does not return.
- */
-_panic:
- pie_function_start
-
- lea (message_prefix_panic - 0b)(%esi), %eax
-
- push %eax
- push $0x4f
- call _print
-
- mov 8(%ebp), %eax
- mov %eax, 4(%esp)
- call _print
- add $8, %esp
-
- call _halt
-
- pie_function_end
-
-/**
- * Assert that we were loaded by a Multiboot 2 compliant bootloader.
- *
- * This assertion will panic the system if the magic signature was not found.
- * If we were loaded my an appropriate bootloader, this function also saves
- * the provided MBI pointer to `multiboot_information_pointer`.
- */
-_assert_loaded_by_multiboot2_loader:
- pie_function_start
-
- cmp $MULTIBOOT2_MAGIC, %eax
- je 1f
- lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax
- push %eax
- call _panic
-1:
- pie_function_end
-
-/**
- * @brief Store the multiboot 2 information pointer in the global memory.
- *
- * @return void
- */
-_save_multiboot_information_pointer:
- pie_function_start
-
- lea (multiboot_information_pointer - 0b)(%esi), %eax
- mov %ebx, (%eax)
-
- pie_function_end
-
-/**
- * @brief Assert that the CPU supports the CPUID instruction.
- *
- * The primary way to check for support of the instruction is to flip the ID
- * bin in EFLAGS and then check if this changed was accepted. If so, the CPU
- * supports the CPUID instruction, otherwise it most-likely doesn't.
- */
-_assert_cpuid_instruction_is_supported:
- pie_function_start
-
- pushfl
- pop %eax
- mov %eax, %ecx
-
- xor $(1 << 21), %eax /* Flip the ID bit */
- push %eax /* Move the new bitset on the stack for loading */
- popfl /* Load the flags with ID set back into EFLAGS */
- pushfl /* Copy the flags back onto the stack */
- pop %eax /* Load the flags for further checking */
-
- push %ecx
- popfl
-
- cmp %ecx, %eax
- jne 1f
- lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax
- push %eax
- call _panic
-
-1:
- pie_function_end
-
-/**
- * @brief Assert that the CPU supports going into long mode.
- */
-_assert_cpu_supports_long_mode:
- pie_function_start
-
- mov $0x80000000, %eax
- cpuid
- cmp $0x80000001, %eax
- jb 1f
-
- mov $0x80000001, %eax
- cpuid
- test $(1 << 29), %edx
- jnz 2f
-1:
- lea (message_long_mode_not_supported - 0b)(%esi), %eax
- push %eax
- call _panic
-2:
- pie_function_end
-
-/**
- * @brief Prepare a basic page map hierarchy
- *
- * @param ebp+8 The number of huge pages to map
- * @return void
- */
-_prepare_page_maps:
- pie_function_start
-
- push %edi
-
- call _clear_page_map_memory
-
- lea (page_map_level_4 - 0b)(%esi), %edi
- lea (page_map_level_3_low - 0b)(%esi), %eax
- or $0b11, %eax
- mov %eax, (%edi)
-
- lea (page_map_level_3_high - 0b)(%esi), %eax
- or $0b11, %eax
- mov %eax, (511 * 8)(%edi)
-
- lea (page_map_level_3_low - 0b)(%esi), %edi
- lea (page_map_level_2 - 0b)(%esi), %eax
- or $0b11, %eax
- mov %eax, (%edi)
-
- lea (page_map_level_3_high - 0b)(%esi), %edi
- lea (page_map_level_2 - 0b)(%esi), %eax
- or $0b11, %eax
- mov %eax, (510 * 8)(%edi)
-
- lea (page_map_level_2 - 0b)(%esi), %edi
- mov 8(%ebp), %ecx
-
-1:
- dec %ecx
- mov $(1 << 21), %eax
- mul %ecx
- or $0b10000011, %eax
- mov %eax, (%edi, %ecx, 8)
-
- test %ecx, %ecx
- jnz 1b
-
- pop %edi
-
- pie_function_end
-
-/**
- * @brief Clear all page map memory by filling it with 0s.
- *
- * @return void
- */
-_clear_page_map_memory:
- pie_function_start
-
- push %edi
-
- xor %eax, %eax
- mov $page_maps_size, %ecx
- shr $2, %ecx
- lea (page_maps_start - 0b)(%esi), %edi
- rep stosl
-
- pop %edi
-
- pie_function_end
-
-/**
- * @p Enable memory virtualization via paging.
- *
- * Note: This routine expects for there to be a valid set of page maps already
- * set up for use.
- *
- * @return void
- */
-_enable_paging:
- pie_function_start
-
- lea (page_map_level_4 - 0b)(%esi), %eax
- mov %eax, %cr3
-
- /* Enable Physical Address Extension */
- mov %cr4, %eax
- or $(1 << 5), %eax
- mov %eax, %cr4
-
- /* Enable long mode support */
- mov $0xC0000080, %ecx
- rdmsr
- or $(1 << 8), %eax
- wrmsr
-
- /* Enable paging */
- mov %cr0, %eax
- or $(1 << 31), %eax
- mov %eax, %cr0
-
- pie_function_end
-
-/**
- * @brief Enable use of SSE instructions.
- */
-_enable_sse:
- function_start
-
- mov %cr0, %eax
- and $0xfffffffb, %eax
- or $0x00000002, %eax
- mov %eax, %cr0
-
- mov %cr4, %eax
- or $(3 << 9), %eax
- mov %eax, %cr4
-
- function_end
-
-/**
- * @brief Prepare a new GTD and load make it active.
- *
- * @return void
- */
-_reload_gdt:
- pie_function_start
-
- sub $10, %esp
- lea (global_descriptor_table - 0b)(%esi), %eax
- movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp)
- mov %eax, 2(%esp)
- movl $0, 6(%esp)
-
- lgdt (%esp)
- add $10, %esp
-
- pie_function_end
diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s
deleted file mode 100644
index 29fb778..0000000
--- a/arch/x86_64/src/boot/entry64.s
+++ /dev/null
@@ -1,62 +0,0 @@
-.section .stack, "aw", @nobits
-
-.align 16
-.global stack_top
-stack_bottom: .skip 1 << 20
-stack_top:
-stack_size = stack_top - stack_bottom
-
-.section .bss, "aw", @nobits
-
-//! A structure containing information gathered during the bootstrap process.
-//! Expected layout (as described by teachos::boot::information):
-//!
-//! struct
-//! {
-//! multiboot2::information_view const * mbi;
-//! std::size_t vga_buffer_index;
-//! }
-.global bootstrap_information
-bootstrap_information: .skip 16
-
-.section .boot_text, "ax", @progbits
-.code64
-
-.global _entry64
-_entry64:
- mov $global_descriptor_table_data, %rax
- mov %rax, %ss
- mov %rax, %ds
- mov %rax, %es
- mov %rax, %fs
- mov %rax, %gs
-
- mov $stack_top, %rsp
- mov %rsp, %rbp
-
- mov multiboot_information_pointer, %rax
- or $TEACHOS_VMA, %rax
- mov vga_buffer_pointer, %rdx
- sub $0xb8000, %rdx
- mov %rax, (bootstrap_information)
- mov %rdx, (bootstrap_information + 8)
-
- call invoke_global_constructors
-
- xor %rax, %rax
- mov %rax, %rbp
- mov %rax, %rdx
- mov %rax, %rsi
-
- mov $stack_size, %rcx
- shr $3, %rcx
- lea (stack_bottom), %rdi
- rep stosq
-
- mov %rax, %rdi
-
- call main
-
-1:
- hlt
- jmp 1b
diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp
deleted file mode 100644
index b08c13c..0000000
--- a/arch/x86_64/src/boot/initialize_runtime.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <algorithm>
-#include <functional>
-#include <span>
-
-namespace arch::boot
-{
-
- extern "C"
- {
- using global_initializer = auto (*)() -> void;
-
- extern global_initializer __init_array_start;
- extern global_initializer __init_array_end;
-
- auto invoke_global_constructors() -> void
- {
- auto initializers = std::span{&__init_array_start, &__init_array_end};
- std::ranges::for_each(initializers, [](auto invokable) { std::invoke(invokable); });
- }
- }
-
-} // namespace arch::boot \ No newline at end of file
diff --git a/arch/x86_64/src/boot/multiboot.s b/arch/x86_64/src/boot/multiboot.s
deleted file mode 100644
index 37d8afe..0000000
--- a/arch/x86_64/src/boot/multiboot.s
+++ /dev/null
@@ -1,33 +0,0 @@
-.section .boot_mbh, "a"
-.align 8
-
-multiboot_header_start:
-.Lmagic:
- .long 0xe85250d6
-.Larch:
- .long 0
-.Llength:
- .long multiboot_header_end - multiboot_header_start
-.Lchecksum:
- .long 0x100000000 - (0xe85250d6 + 0 + (multiboot_header_end - multiboot_header_start))
-.align 8
-.Lflags_start:
- .word 4
- .word 1
- .long .Lflags_end - .Lflags_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
- .long .Lend_end - .Lend_start
-.Lend_end:
-multiboot_header_end:
diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp
deleted file mode 100644
index f6cc72d..0000000
--- a/arch/x86_64/src/bus/isa.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#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/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp
deleted file mode 100644
index 1be9c82..0000000
--- a/arch/x86_64/src/cpu/initialization.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-#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/src/cpu/interrupt_stubs.S b/arch/x86_64/src/cpu/interrupt_stubs.S
deleted file mode 100644
index e59bdd2..0000000
--- a/arch/x86_64/src/cpu/interrupt_stubs.S
+++ /dev/null
@@ -1,112 +0,0 @@
-.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/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp
deleted file mode 100644
index f40422f..0000000
--- a/arch/x86_64/src/cpu/interrupts.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-#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/src/debug/qemu_output.cpp b/arch/x86_64/src/debug/qemu_output.cpp
deleted file mode 100644
index 71acede..0000000
--- a/arch/x86_64/src/debug/qemu_output.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <arch/debug/qemu_output.hpp>
-
-#include <kapi/cio.hpp>
-
-#include <algorithm>
-#include <string_view>
-
-namespace arch::debug
-{
-
- qemu_output::qemu_output(output_device & lower)
- : m_lower{lower}
- , m_present{port::read() == port::address}
- {}
-
- auto qemu_output::write(kapi::cio::output_stream stream, std::string_view text) -> void
- {
- if (m_present)
- {
- std::ranges::for_each(text, port::write<port::value_type>);
- }
- m_lower.write(stream, text);
- }
-
-} // namespace arch::debug
diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp
deleted file mode 100644
index c30e8cf..0000000
--- a/arch/x86_64/src/devices/init.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#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/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp
deleted file mode 100644
index d542d47..0000000
--- a/arch/x86_64/src/devices/legacy_pit.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#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/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp
deleted file mode 100644
index 660921b..0000000
--- a/arch/x86_64/src/devices/local_apic.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-#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/src/memory/higher_half_mapper.cpp b/arch/x86_64/src/memory/higher_half_mapper.cpp
deleted file mode 100644
index 75adb3c..0000000
--- a/arch/x86_64/src/memory/higher_half_mapper.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-#include <arch/memory/higher_half_mapper.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>
-#include <cstddef>
-#include <memory>
-#include <ranges>
-#include <utility>
-
-namespace arch::memory
-{
-
- higher_half_mapper::higher_half_mapper(page_table * root)
- : m_root{root}
- {}
-
- auto higher_half_mapper::map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte *
- {
- auto table = get_or_create_page_table(page);
- if (!table)
- {
- return nullptr;
- }
-
- auto const index = pml_index(1, page);
- auto & entry = (*table)[index];
-
- if (entry.present())
- {
- kapi::system::panic("[x86_64:MEM] Tried to map a page that is already mapped!");
- }
-
- entry.frame(frame, to_table_flags(flags) | page_table::entry::flags::present);
-
- return static_cast<std::byte *>(page.start_address());
- }
-
- auto higher_half_mapper::unmap(kapi::memory::page page) -> void
- {
- if (!try_unmap(page))
- {
- kapi::system::panic("[x86_64:MEM] Tried to unmap a page that is not mapped!");
- }
- }
-
- auto higher_half_mapper::try_unmap(kapi::memory::page page) noexcept -> bool
- {
- auto table_path = std::array<std::pair<page_table *, std::size_t>, 4>{};
- table_path[0] = std::pair{m_root, pml_index(4, page)};
-
- for (auto level = 4uz; level > 1uz; --level)
- {
- auto [table, index] = table_path[4 - level];
- auto & entry = (*table)[index];
-
- if (!entry.present())
- {
- return false;
- }
-
- auto next_table = to_higher_half_pointer<page_table>(entry.frame()->start_address());
- auto next_index = pml_index(4 - level - 1, page);
- table_path[4 - level - 1] = std::pair{next_table, next_index};
- }
-
- std::ranges::for_each(std::views::reverse(table_path), [previous_was_empty = true](auto & step) mutable {
- auto [table, index] = step;
- auto & entry = (*table)[index];
- auto frame = entry.frame();
-
- if (previous_was_empty)
- {
- entry.clear();
- previous_was_empty = table->empty();
- kapi::memory::get_frame_allocator().release(*frame);
- }
- });
-
- return true;
- }
-
- auto higher_half_mapper::get_or_create_page_table(kapi::memory::page page) noexcept -> page_table *
- {
- auto table = m_root;
-
- for (auto level = 4uz; level > 1uz; --level)
- {
- auto index = pml_index(level, page);
- auto & entry = (*table)[index];
-
- if (!entry.present())
- {
- auto table_frame = kapi::memory::allocate_frame();
- if (!table_frame)
- {
- return nullptr;
- }
-
- auto new_table = to_higher_half_pointer<page_table>(table_frame->start_address());
- std::construct_at(new_table);
-
- auto const flags = page_table::entry::flags::present | page_table::entry::flags::writable |
- page_table::entry::flags::user_accessible;
- entry.frame(*table_frame, flags);
- }
-
- table = to_higher_half_pointer<page_table>(entry.frame()->start_address());
- }
-
- return table;
- }
-
-} // namespace arch::memory \ No newline at end of file
diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp
deleted file mode 100644
index 74272a0..0000000
--- a/arch/x86_64/src/memory/kernel_mapper.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-#include <arch/memory/kernel_mapper.hpp>
-
-#include <arch/boot/ld.hpp>
-
-#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>
-#include <array>
-#include <bit>
-#include <cstdint>
-#include <ranges>
-#include <string_view>
-#include <utility>
-
-using namespace std::string_view_literals;
-using namespace kstd::units_literals;
-
-namespace arch::memory
-{
-
- namespace
- {
- constexpr auto static ignored_section_prefixes = std::array{
- ".boot_"sv,
- };
-
- constexpr auto static user_accessible_prefixes = std::array{
- ".user"sv,
- ".stl"sv,
- };
-
- } // namespace
-
- kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi)
- : m_mbi{std::move(mbi)}
- , m_kernel_load_base{std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}
- {}
-
- auto kernel_mapper::remap_kernel(kapi::memory::page_mapper & mapper) -> void
- {
- auto elf_information = m_mbi->maybe_elf_symbols<elf::format::elf64>();
- if (!elf_information)
- {
- kapi::system::panic("[x86_64:MEM] ELF section information is not available.");
- }
-
- auto sections = *elf_information;
- auto allocated_sections =
- std::views::all(sections) | std::views::filter(&elf::section_header<elf::format::elf64>::allocated) |
- std::views::filter([&](auto const & section) -> auto {
- auto name = sections.name(section);
- return !std::ranges::any_of(ignored_section_prefixes,
- [&](auto const & prefix) -> auto { return name.starts_with(prefix); });
- });
-
- if (allocated_sections.empty())
- {
- kapi::system::panic("[x86_64:MEM] No allocated ELF sections were found.");
- }
-
- std::ranges::for_each(allocated_sections,
- [&](auto const & section) -> auto { map_section(section, sections.name(section), mapper); });
- }
-
- auto kernel_mapper::map_section(section_header_type const & section, std::string_view name,
- kapi::memory::page_mapper & mapper) -> void
- {
- 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};
-
- kstd::println("[x86_64:MEM] mapping {}"
- "\n {} bytes -> page count: {}"
- "\n {} @ {}",
- name, section.size, number_of_pages, linear_start_address, physical_start_address);
-
- auto first_page = kapi::memory::page::containing(linear_start_address);
- auto first_frame = kapi::memory::frame::containing(physical_start_address);
-
- auto page_flags = kapi::memory::page_mapper::flags::empty;
-
- if (section.writable())
- {
- page_flags |= kapi::memory::page_mapper::flags::writable;
- }
-
- if (section.executable())
- {
- page_flags |= kapi::memory::page_mapper::flags::executable;
- }
-
- auto is_prefix_of_name = [=](auto prefix) -> bool {
- return name.starts_with(prefix);
- };
-
- if (!std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name))
- {
- page_flags |= kapi::memory::page_mapper::flags::supervisor_only;
- }
-
- for (auto i = 0uz; i < number_of_pages; ++i)
- {
- mapper.map(first_page + i, first_frame + i, page_flags);
- }
- }
-
-} // namespace arch::memory \ No newline at end of file
diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp
deleted file mode 100644
index 2b53fa4..0000000
--- a/arch/x86_64/src/memory/mmu.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <arch/memory/mmu.hpp>
-
-#include <arch/cpu/registers.hpp>
-
-#include <kapi/memory.hpp>
-
-namespace arch::memory
-{
- auto tlb_flush(kapi::memory::linear_address address) -> void
- {
- asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory");
- }
-
- auto tlb_flush_all() -> void
- {
- auto paging_root = cpu::cr3::read();
- cpu::cr3::write(paging_root);
- }
-} // namespace arch::memory
diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp
deleted file mode 100644
index 2180420..0000000
--- a/arch/x86_64/src/memory/page_table.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#include <arch/memory/page_table.hpp>
-
-#include <kapi/memory.hpp>
-
-#include <algorithm>
-#include <bit>
-#include <cstddef>
-#include <cstdint>
-#include <optional>
-#include <utility>
-
-namespace arch::memory
-{
-
- auto page_table::entry::clear() noexcept -> void
- {
- m_raw = 0;
- }
-
- auto page_table::entry::present() const noexcept -> bool
- {
- return (all_flags() & flags::present) != flags::empty;
- }
-
- auto page_table::entry::huge() const noexcept -> bool
- {
- return (all_flags() & flags::huge_page) != flags::empty;
- }
-
- auto page_table::entry::all_flags() const noexcept -> flags
- {
- return std::bit_cast<flags>(m_raw & ~frame_number_mask);
- }
-
- auto page_table::entry::all_flags(flags flags) noexcept -> void
- {
- m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags);
- }
-
- auto page_table::entry::operator|=(flags rhs) noexcept -> page_table::entry &
- {
- auto raw_flags = std::to_underlying(rhs) & ~frame_number_mask;
- m_raw |= raw_flags;
- return *this;
- }
-
- auto page_table::entry::frame() const noexcept -> std::optional<kapi::memory::frame>
- {
- if (present())
- {
- return kapi::memory::frame::containing(kapi::memory::physical_address{m_raw & frame_number_mask});
- }
- return std::nullopt;
- }
-
- auto page_table::entry::frame(kapi::memory::frame frame, flags flags) noexcept -> void
- {
- m_raw = (frame.start_address().raw() | static_cast<std::uint64_t>(flags));
- };
-
- auto page_table::operator[](std::size_t index) -> entry &
- {
- return m_entries.at(index);
- }
-
- auto page_table::operator[](std::size_t index) const -> entry const &
- {
- return m_entries.at(index);
- }
-
- auto page_table::clear() noexcept -> void
- {
- std::ranges::for_each(m_entries, &page_table::entry::clear);
- }
-
- auto page_table::empty() const noexcept -> bool
- {
- return std::ranges::all_of(m_entries,
- [](auto const & entry) -> auto { return entry.all_flags() == entry::flags::empty; });
- }
-
-} // namespace arch::memory
diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp
deleted file mode 100644
index 4086a10..0000000
--- a/arch/x86_64/src/memory/region_allocator.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-#include <arch/memory/region_allocator.hpp>
-
-#include <kapi/memory/address.hpp>
-#include <kapi/memory/frame.hpp>
-
-#include <multiboot2/information.hpp>
-
-#include <algorithm>
-#include <cstddef>
-#include <optional>
-#include <ranges>
-#include <utility>
-
-namespace arch::memory
-{
- namespace
- {
- constexpr auto last_frame(multiboot2::memory_map::region const & region)
- {
- return kapi::memory::frame::containing(kapi::memory::physical_address{region.base + region.size_in_B - 1});
- }
-
- constexpr auto falls_within(kapi::memory::frame const & candidate, kapi::memory::frame const & start,
- kapi::memory::frame const & end)
- {
- return candidate >= start && candidate <= end;
- }
- } // namespace
-
- region_allocator::region_allocator(memory_information const & mem_info)
- : m_next_frame{}
- , m_current_region{}
- , m_memory_map{mem_info.memory_map}
- , m_kernel_start{kapi::memory::frame::containing(mem_info.image_range.first)}
- , 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)}
- , m_multiboot_information{mem_info.mbi}
- {
- choose_next_region();
- }
-
- auto region_allocator::choose_next_region() -> void
- {
- m_current_region.reset();
-
- auto remaining_regions =
- m_memory_map | //
- std::views::filter(&multiboot2::memory_map::region::available) |
- std::views::filter([this](auto const & region) -> bool { return last_frame(region) >= m_next_frame; });
-
- auto lowest_region =
- std::ranges::min_element(remaining_regions, [](auto lhs, auto rhs) -> bool { return lhs.base < rhs.base; });
-
- if (lowest_region == remaining_regions.end())
- {
- return;
- }
-
- m_current_region = *lowest_region;
- if (auto start_of_region = kapi::memory::frame::containing(kapi::memory::physical_address{m_current_region->base});
- start_of_region > m_next_frame)
- {
- m_next_frame = start_of_region;
- }
- }
-
- auto region_allocator::find_next_frame() -> std::optional<kapi::memory::frame>
- {
- if (!m_current_region || m_next_frame > last_frame(*m_current_region))
- {
- choose_next_region();
- if (!m_current_region)
- {
- return std::nullopt;
- }
- }
-
- auto advanced = true;
- while (advanced)
- {
- advanced = false;
-
- 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_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))
- {
- choose_next_region();
- }
-
- return m_current_region.transform([this](auto) -> auto { return m_next_frame; });
- }
-
- auto region_allocator::allocate_many(std::size_t count) noexcept
- -> std::optional<std::pair<kapi::memory::frame, std::size_t>>
- {
- while (m_current_region)
- {
- auto result = find_next_frame();
-
- if (result)
- {
- auto region_end = last_frame(*m_current_region);
- if ((region_end.number() - result->number()) >= count)
- {
- m_next_frame = m_next_frame + count;
- return std::make_pair(*result, count);
- }
- else
- {
- m_next_frame = region_end + 1;
- choose_next_region();
- }
- }
- }
-
- return std::nullopt;
- }
-
- auto region_allocator::mark_used(kapi::memory::frame frame) -> void
- {
- if (frame < m_next_frame)
- {
- m_next_frame = frame;
- find_next_frame();
- }
- }
-
- auto region_allocator::release_many(std::pair<kapi::memory::frame, std::size_t>) -> void {}
-
- auto region_allocator::next_free_frame() noexcept -> std::optional<kapi::memory::frame>
- {
- return find_next_frame();
- }
-
-} // namespace arch::memory
diff --git a/arch/x86_64/src/vga/text/buffer.cpp b/arch/x86_64/src/vga/text/buffer.cpp
deleted file mode 100644
index 498b9a3..0000000
--- a/arch/x86_64/src/vga/text/buffer.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-#include <arch/vga/text/buffer.hpp>
-
-#include <arch/vga/text/attribute.hpp>
-
-#include <algorithm>
-#include <bit>
-#include <cstddef>
-#include <span>
-#include <string_view>
-#include <utility>
-
-namespace arch::vga::text
-{
- buffer::buffer(std::size_t width, std::size_t height, cell * start, std::size_t position)
- : m_width{width}
- , m_height{height}
- , m_buffer{start, m_width * m_height}
- , m_position{position}
- {}
-
- auto buffer::clear() -> void
- {
- m_position = 0;
- std::ranges::fill(m_buffer, std::pair{'\0', static_cast<std::byte>(0x00)});
- }
-
- auto buffer::write(std::string_view code_points, attribute attribute) -> void
- {
- std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); });
- }
-
- auto buffer::write(char code_point, attribute attribute) -> void
- {
- if (m_position + 1 > m_height * m_width)
- {
- scroll();
- }
-
- if (!handle_special_code_point(code_point, attribute))
- {
- do_write(code_point, attribute);
- }
- };
-
- auto buffer::newline() -> void
- {
- auto free_glyphs_in_line = m_width - column();
- m_position += free_glyphs_in_line;
- }
-
- auto buffer::scroll(std::size_t nof_lines) -> void
- {
- auto scroll_count = std::min(nof_lines, m_height);
-
- auto scroll_start = m_buffer.begin() + (scroll_count * m_width);
- std::ranges::move(scroll_start, m_buffer.end(), m_buffer.begin());
-
- auto clear_start = m_buffer.begin() + (m_height - scroll_count) * m_width;
- std::ranges::fill(clear_start, m_buffer.end(), cell{});
-
- m_position = (line() - scroll_count) * m_width;
- }
-
- auto buffer::column() const noexcept -> std::ptrdiff_t
- {
- return m_position % m_width;
- }
-
- auto buffer::line() const noexcept -> std::ptrdiff_t
- {
- return m_position / m_width;
- }
- auto buffer::handle_special_code_point(char code_point, attribute attribute) -> bool
- {
- switch (code_point)
- {
- case '\n':
- newline();
- return true;
- case '\r':
- m_position -= column();
- return true;
- case '\t':
- do_write(" ", attribute);
- return true;
- default:
- return false;
- }
- }
-
- auto buffer::do_write(std::string_view code_points, attribute attribute) -> void
- {
- std::ranges::for_each(code_points, [&](auto code_point) -> void { do_write(code_point, attribute); });
- }
-
- auto buffer::do_write(char code_point, attribute attribute) -> void
- {
- m_buffer[m_position++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)};
- }
-
-} // namespace arch::vga::text
diff --git a/arch/x86_64/src/vga/text/device.cpp b/arch/x86_64/src/vga/text/device.cpp
deleted file mode 100644
index 8468358..0000000
--- a/arch/x86_64/src/vga/text/device.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#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>
-#include <cstdint>
-#include <string_view>
-
-namespace arch::vga::text
-{
- namespace
- {
- constexpr auto default_buffer_address = std::uintptr_t{0xb8000};
- constexpr auto default_buffer_width = 80z;
- constexpr auto default_buffer_height = 25z;
-
- constexpr auto bit_cursor_enabled = 5U;
- } // namespace
-
- device::device()
- : m_buffer{
- default_buffer_width, default_buffer_height,
- std::bit_cast<buffer::cell *>(default_buffer_address + std::bit_cast<std::uintptr_t>(&boot::TEACHOS_VMA)),
- kapi::boot::bootstrap_information.vga_buffer_index}
- {
- clear();
- }
-
- auto device::clear() -> void
- {
- m_buffer.clear();
- }
-
- auto device::cursor(bool enabled) -> void
- {
- auto cursor_disable_byte = std::byte{!enabled} << bit_cursor_enabled;
-
- crtc::address::write(crtc::registers::cursor_start);
- crtc::data::write(crtc::data::read() | cursor_disable_byte);
- }
-
- auto device::write(kapi::cio::output_stream stream, std::string_view text) -> void
- {
- auto attributes = [&] -> attribute {
- switch (stream)
- {
- case kapi::cio::output_stream::stderr:
- return red_on_black;
- default:
- return green_on_black;
- }
- }();
- m_buffer.write(text, attributes);
- }
-
-} // namespace arch::vga::text