From 051307f49f4cdfb86c527a475ab21feea4a664d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 4 Mar 2025 18:01:49 +0000 Subject: Add more methods to vector to mimic stl interface partially. --- arch/x86_64/src/memory/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a6f91d9..08308db 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -7,6 +7,9 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" +#include "arch/stl/shared_pointer.hpp" +#include "arch/stl/unique_pointer.hpp" +#include "arch/stl/vector.hpp" namespace teachos::arch::memory { @@ -49,5 +52,11 @@ namespace teachos::arch::memory remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); + + auto test2 = stl::make_unique(0); + auto test3 = stl::make_shared(0); + if (test2 && test3) + { + } } } // namespace teachos::arch::memory -- cgit v1.2.3 From 06d5e5872838bd1528493b62b4dc28d44b54aa47 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 9 Mar 2025 09:30:01 +0000 Subject: add doxygen comments to shared and unique pointer --- arch/x86_64/src/memory/main.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 08308db..15e89c0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -52,11 +52,5 @@ namespace teachos::arch::memory remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - - auto test2 = stl::make_unique(0); - auto test3 = stl::make_shared(0); - if (test2 && test3) - { - } } -} // namespace teachos::arch::memory +} // namespace teachos::arch::memory \ No newline at end of file -- cgit v1.2.3 From 1a6d41362447531a2ea5ee344c15b9aaa6c2090a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 9 Mar 2025 16:52:17 +0000 Subject: Adjust comments and implement remaining interface for STL classes. --- arch/x86_64/src/memory/main.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 15e89c0..a6f91d9 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -7,9 +7,6 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -#include "arch/stl/shared_pointer.hpp" -#include "arch/stl/unique_pointer.hpp" -#include "arch/stl/vector.hpp" namespace teachos::arch::memory { @@ -53,4 +50,4 @@ namespace teachos::arch::memory video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -} // namespace teachos::arch::memory \ No newline at end of file +} // namespace teachos::arch::memory -- cgit v1.2.3 From 2e4cbd473ff3bb7ac7371af39becf830b4fb753b Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 14:05:45 +0000 Subject: IN_PROGRESS implement gdt initialization --- arch/x86_64/src/memory/cpu/control_register.cpp | 72 ------------------------- arch/x86_64/src/memory/cpu/msr.cpp | 31 ----------- arch/x86_64/src/memory/cpu/tlb.cpp | 16 ------ arch/x86_64/src/memory/main.cpp | 4 +- 4 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 arch/x86_64/src/memory/cpu/control_register.cpp delete mode 100644 arch/x86_64/src/memory/cpu/msr.cpp delete mode 100644 arch/x86_64/src/memory/cpu/tlb.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/cpu/control_register.cpp b/arch/x86_64/src/memory/cpu/control_register.cpp deleted file mode 100644 index 7ee88b5..0000000 --- a/arch/x86_64/src/memory/cpu/control_register.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "arch/memory/cpu/control_register.hpp" - -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::memory::cpu -{ - auto read_control_register(control_register cr) -> uint64_t - { - uint64_t current_value; - switch (cr) - { - case control_register::CR0: - asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR2: - asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR3: - asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR4: - asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); - break; - default: - exception_handling::panic("[Control Register] Attempted to read non-existent or reserved control register"); - break; - } - return current_value; - } - - auto write_control_register(control_register cr, uint64_t new_value) -> void - { - switch (cr) - { - case control_register::CR0: - asm volatile("mov %[input], %%cr0" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR2: - asm volatile("mov %[input], %%cr2" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR3: - asm volatile("mov %[input], %%cr3" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR4: - asm volatile("mov %[input], %%cr4" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - default: - exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); - break; - } - } - - auto set_cr0_bit(cr0_flags flag) -> void - { - auto const cr0 = read_control_register(control_register::CR0); - write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/msr.cpp b/arch/x86_64/src/memory/cpu/msr.cpp deleted file mode 100644 index b83f902..0000000 --- a/arch/x86_64/src/memory/cpu/msr.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "arch/memory/cpu/msr.hpp" - -namespace teachos::arch::memory::cpu -{ - namespace - { - auto constexpr IA32_EFER_ADDRESS = 0xC0000080; - } - - auto read_msr(uint32_t msr) -> uint64_t - { - uint32_t low, high; - asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); - return (static_cast(high) << 32) | low; - } - - auto write_msr(uint32_t msr, uint64_t value) -> void - { - uint32_t low = value & 0xFFFFFFFF; - uint32_t high = value >> 32; - asm volatile("wrmsr" - : /* no output from call */ - : "c"(msr), "a"(low), "d"(high)); - } - - auto set_efer_bit(efer_flags flag) -> void - { - auto const efer = read_msr(IA32_EFER_ADDRESS); - write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/tlb.cpp b/arch/x86_64/src/memory/cpu/tlb.cpp deleted file mode 100644 index 591d9fc..0000000 --- a/arch/x86_64/src/memory/cpu/tlb.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/memory/cpu/tlb.hpp" - -#include "arch/memory/cpu/control_register.hpp" - -namespace teachos::arch::memory::cpu -{ - auto tlb_flush(paging::virtual_address address) -> void - { - asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); - } - - auto tlb_flush_all() -> void - { - write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a6f91d9..abc7431 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -1,9 +1,9 @@ #include "arch/memory/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/control_register.hpp" +#include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/cpu/control_register.hpp" -#include "arch/memory/cpu/msr.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -- cgit v1.2.3 From 11db9338dac611ea32e202add5ce5055b54ebb58 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 15:46:16 +0000 Subject: fixup typing and continue adding gdt --- arch/x86_64/src/memory/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index abc7431..a920a20 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -38,8 +38,8 @@ namespace teachos::arch::memory auto const memory_information = multiboot::read_multiboot2(); allocator::area_frame_allocator allocator(memory_information); - cpu::set_cr0_bit(memory::cpu::cr0_flags::WRITE_PROTECT); - cpu::set_efer_bit(memory::cpu::efer_flags::NXE); + kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); auto & active_table = kernel.remap_kernel(); -- cgit v1.2.3 From 2b8e6e7e10f084a9a9ba5c0b79a041f4d1ac459b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 15 Mar 2025 11:29:26 +0000 Subject: implement loading of gdtr register --- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index a824c8a..5101ab2 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -11,7 +11,7 @@ namespace teachos::arch::memory::heap : heap_start(heap_start) , heap_end(heap_end) , first(nullptr) - , mutex{shared::mutex{}} + , mutex{stl::mutex{}} { auto const heap_size = heap_end - heap_start; exception_handling::assert( -- cgit v1.2.3 From e6a9d939ed5e9f89e69efdacc60a1ce6edd1061c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 15 Mar 2025 12:38:11 +0000 Subject: temporarily make all page table entries user accessible --- arch/x86_64/src/memory/paging/page_entry.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 5aa0982..3a0f03f 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging } // namespace entry::entry(uint64_t flags) - : flags(flags) + : flags(flags | entry::USER_ACCESSIBLE) // TODO: Temporarily make all entries user accessible { // Nothing to do. } @@ -21,14 +21,19 @@ namespace teachos::arch::memory::paging { flags |= entry::PRESENT; } + if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) { flags |= entry::WRITABLE; } + if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) { flags |= entry::EXECUTING_CODE_FORBIDDEN; } + + // TODO: Temporarily make all entries user accessible + flags |= entry::USER_ACCESSIBLE; } auto entry::is_unused() const -> bool { return flags == 0U; } @@ -51,7 +56,9 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = frame.start_address() | additional_flags.to_ulong(); + + // TODO: Temporarily make all entries user accessible + flags = frame.start_address() | additional_flags.to_ulong() | entry::USER_ACCESSIBLE; } auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } -- cgit v1.2.3 From eafe8533bb5ccbe15bd8ffbc917b38122b04a157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Apr 2025 15:21:52 +0000 Subject: Add stack frame allocator. Fix stl vector bug and create stl stack implementation --- .../src/memory/allocator/area_frame_allocator.cpp | 2 +- .../src/memory/allocator/stack_frame_allocator.cpp | 105 +++++++++++++++++++++ arch/x86_64/src/memory/main.cpp | 20 +++- 3 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index cb4fefa..a5a1b49 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::allocator { area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) - : next_free_frame(0U) + : next_free_frame() , current_area(std::nullopt) , memory_areas(mem_info.areas) , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) diff --git a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp new file mode 100644 index 0000000..0fa277a --- /dev/null +++ b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp @@ -0,0 +1,105 @@ +#include "arch/memory/allocator/stack_frame_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include +#include + +namespace teachos::arch::memory::allocator +{ + stack_frame_allocator::stack_frame_allocator(multiboot::memory_information const & mem_info) + : free_frames() + , next_free_frame() + , current_area(std::nullopt) + , memory_areas(mem_info.areas) + , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) + , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) + , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) + , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) + { + load_free_physical_frames(); + } + + auto stack_frame_allocator::load_free_physical_frames() -> void + { + choose_next_area(); + if (!current_area.has_value()) + { + return; + } + + auto const address = current_area.value().base_address + current_area.value().area_length - 1; + physical_frame const current_area_last_frame = physical_frame::containing_address(address); + + // Only try to allocate memory if current_area is not null, because + // the current_area is null if there is no more available memory. + while (next_free_frame <= current_area_last_frame) + { + if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; + } + else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; + } + else + { + // Frame is unused, increment `next_free_frame` and return it. + next_free_frame.frame_number += 1; + // TODO: Fix using heap like structure to initalize paging allocator used by heap does not work + // free_frames.push(next_free_frame); + static uint32_t count = 0U; + count++; + } + } + } + + auto stack_frame_allocator::choose_next_area() -> void + { + current_area = std::nullopt; + auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { + auto address = area.base_address + area.area_length - 1; + return physical_frame::containing_address(address) >= next_free_frame; + }); + + auto const lowest_area_with_free_frames = std::ranges::min_element( + next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); + + if (lowest_area_with_free_frames != next_area_with_free_frames.end()) + { + current_area = *lowest_area_with_free_frames; + // Update the `next_free_frame` according to the new memory area + auto const start_frame = physical_frame::containing_address(current_area.value().base_address); + if (next_free_frame < start_frame) + { + next_free_frame = start_frame; + } + } + } + + auto stack_frame_allocator::allocate_frame() -> std::optional + { + // If the underlying stack is empty that are no free frames left to allocate. + if (free_frames.empty()) + { + load_free_physical_frames(); + if (free_frames.empty()) + { + return std::nullopt; + } + } + + decltype(auto) top = free_frames.top(); + free_frames.pop(); + return top; + } + + auto stack_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void + { + free_frames.push(physical_frame); + } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a920a20..3041a75 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -4,6 +4,8 @@ #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/allocator/stack_frame_allocator.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -12,7 +14,21 @@ namespace teachos::arch::memory { namespace { - auto remap_heap(allocator::area_frame_allocator allocator, paging::active_page_table & active_table) -> void + template + auto create_frame_allocator(multiboot::memory_information const & memory_information) -> T + { + return allocator::area_frame_allocator{memory_information}; + } + + template<> + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::stack_frame_allocator + { + return allocator::stack_frame_allocator{memory_information}; + } + + template + auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); auto const end_page = @@ -36,7 +52,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - allocator::area_frame_allocator allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 5dc0e92a7211b44429c1a2e7efe19c146f5c4f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Apr 2025 10:52:30 +0000 Subject: Remove deque --- arch/x86_64/src/memory/main.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 3041a75..bd094e0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -5,7 +5,6 @@ #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/allocator/stack_frame_allocator.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -20,13 +19,6 @@ namespace teachos::arch::memory return allocator::area_frame_allocator{memory_information}; } - template<> - auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::stack_frame_allocator - { - return allocator::stack_frame_allocator{memory_information}; - } - template auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { @@ -52,7 +44,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 5f149faeb9d41bb56733075b0e56908b3731d38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 09:32:59 +0000 Subject: Move gnu function attributes to header file --- arch/x86_64/src/memory/heap/bump_allocator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index df95346..525f45c 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -24,11 +24,13 @@ namespace teachos::arch::memory::heap auto bump_allocator::allocate(std::size_t size) -> void * { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time // causing the value to differ and the calculation to have to be redone. for (;;) { - auto alloc_start = next.load(std::memory_order::relaxed); auto const alloc_end = saturating_add(alloc_start, size); arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another -- cgit v1.2.3 From 7d2e8bc16e6c1bacb3c676d21ea2245d8132218f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 11:27:29 +0000 Subject: Remove the addition of USER_ACCESSIBLE flag to every entry created --- arch/x86_64/src/memory/main.cpp | 3 ++- arch/x86_64/src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 10 ++++------ arch/x86_64/src/memory/paging/temporary_page.cpp | 10 +++++----- 4 files changed, 12 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index bd094e0..4cccabb 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -31,7 +31,8 @@ namespace teachos::arch::memory for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, + paging::entry::WRITABLE | paging::entry::USER_ACCESSIBLE); } } } // namespace diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 4e0610e..780f12c 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::memory::paging { auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); temporary_page.unmap_page(active_page_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 3a0f03f..c76c673 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging } // namespace entry::entry(uint64_t flags) - : flags(flags | entry::USER_ACCESSIBLE) // TODO: Temporarily make all entries user accessible + : flags(flags) { // Nothing to do. } @@ -31,15 +31,14 @@ namespace teachos::arch::memory::paging { flags |= entry::EXECUTING_CODE_FORBIDDEN; } - - // TODO: Temporarily make all entries user accessible - flags |= entry::USER_ACCESSIBLE; } auto entry::is_unused() const -> bool { return flags == 0U; } auto entry::set_unused() -> void { flags = 0U; } + auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) @@ -57,8 +56,7 @@ namespace teachos::arch::memory::paging exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - // TODO: Temporarily make all entries user accessible - flags = frame.start_address() | additional_flags.to_ulong() | entry::USER_ACCESSIBLE; + flags = frame.start_address() | additional_flags.to_ulong(); } auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 152241d..9946f36 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -4,21 +4,21 @@ namespace teachos::arch::memory::paging { - auto temporary_page::map_table_frame(allocator::physical_frame frame, - active_page_table & active_table) -> page_table_handle + auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) + -> page_table_handle { page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), page_table_handle::LEVEL1}; return handle; } - auto temporary_page::map_to_frame(allocator::physical_frame frame, - active_page_table & active_table) -> virtual_address + auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table) + -> virtual_address { exception_handling::assert(!active_table.translate_page(page).has_value(), "[Temporary page] Page is already mapped"); - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE | entry::USER_ACCESSIBLE); return page.start_address(); } -- cgit v1.2.3 From c9f46f3773e7943ce114af888a44f50061c2ac1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 6 May 2025 13:40:42 +0000 Subject: Remove user Mode Access to VGA / Heap and Kernel Methods. --- arch/x86_64/src/memory/main.cpp | 3 +-- arch/x86_64/src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/temporary_page.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 4cccabb..bd094e0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -31,8 +31,7 @@ namespace teachos::arch::memory for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, - paging::entry::WRITABLE | paging::entry::USER_ACCESSIBLE); + active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); } } } // namespace diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 780f12c..4e0610e 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::memory::paging { auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); temporary_page.unmap_page(active_page_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 9946f36..8e73523 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -18,7 +18,7 @@ namespace teachos::arch::memory::paging exception_handling::assert(!active_table.translate_page(page).has_value(), "[Temporary page] Page is already mapped"); - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE | entry::USER_ACCESSIBLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); return page.start_address(); } -- cgit v1.2.3 From be32189323ba8c46091d6deaf091cf41147426b4 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 7 May 2025 14:06:25 +0000 Subject: wip custom heap allocation functions for user mode --- .../src/memory/heap/global_heap_allocator.cpp | 54 +++++++++++++++------- arch/x86_64/src/memory/main.cpp | 6 +-- 2 files changed, 40 insertions(+), 20 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index c1ca160..51f6261 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -6,15 +6,20 @@ namespace teachos::arch::memory::heap { - heap_allocator * global_heap_allocator::allocator_instance = nullptr; + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; + heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; - auto global_heap_allocator::allocate(std::size_t size) -> void * { return get().allocate(size); } + auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } - auto global_heap_allocator::deallocate(void * pointer) noexcept -> void { get().deallocate(pointer); } + auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); } + + auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); } + + auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); } auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void { - exception_handling::assert(allocator_instance == nullptr, + exception_handling::assert(kernel_allocator_instance == nullptr, "Calling register_heap_allocator_type can only be done once."); switch (new_type) @@ -23,56 +28,71 @@ namespace teachos::arch::memory::heap // Nothing to do break; case heap_allocator_type::BUMP: { - static bump_allocator allocator{HEAP_START, HEAP_START + HEAP_SIZE}; - allocator_instance = &allocator; + static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + + static bump_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; break; } case heap_allocator_type::LINKED_LIST: { - static linked_list_allocator allocator{HEAP_START, HEAP_START + HEAP_SIZE}; - allocator_instance = &allocator; + static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + + static linked_list_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; break; } } } - auto global_heap_allocator::get() -> heap_allocator & + auto global_heap_allocator::kernel() -> heap_allocator & + { + exception_handling::assert(kernel_allocator_instance != nullptr, + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."); + + return *kernel_allocator_instance; + } + + auto global_heap_allocator::user() -> heap_allocator & { - exception_handling::assert(allocator_instance != nullptr, + exception_handling::assert(user_allocator_instance != nullptr, "Attempted to allocate or deallocate using the global_heap_allocator before " "register_heap_allocation_type was called."); - return *allocator_instance; + return *user_allocator_instance; } } // namespace teachos::arch::memory::heap auto operator new(std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::allocate(size); + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); } auto operator delete(void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator delete(void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator new[](std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::allocate(size); + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); } auto operator delete[](void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator delete[](void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index bd094e0..558fbce 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -5,7 +5,7 @@ #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/heap/heap_allocator.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -22,9 +22,9 @@ namespace teachos::arch::memory template auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { - auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); + auto const start_page = paging::virtual_page::containing_address(heap::KERNEL_HEAP_START); auto const end_page = - ++(paging::virtual_page::containing_address(memory::heap::HEAP_START + memory::heap::HEAP_SIZE - 1)); + ++(paging::virtual_page::containing_address(heap::KERNEL_HEAP_START + heap::KERNEL_HEAP_SIZE - 1)); paging::page_container::iterator const begin{start_page}; paging::page_container::iterator const end{end_page}; paging::page_container const pages{begin, end}; -- cgit v1.2.3 From 0b62fdb3fe657d056a42d7567b67951ba3468738 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 8 May 2025 08:51:52 +0000 Subject: wip allocating heap memory in user mode --- .../src/memory/heap/global_heap_allocator.cpp | 20 ++++---- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 55 ++++++++++++++++++++++ arch/x86_64/src/memory/main.cpp | 18 ++++--- 3 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 arch/x86_64/src/memory/heap/user_heap_allocator.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index 51f6261..acba02d 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -3,11 +3,12 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/linked_list_allocator.hpp" +#include "arch/memory/heap/user_heap_allocator.hpp" namespace teachos::arch::memory::heap { heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; - heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; + user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } @@ -30,20 +31,17 @@ namespace teachos::arch::memory::heap case heap_allocator_type::BUMP: { static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; - - static bump_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; - user_allocator_instance = &user_allocator; break; } case heap_allocator_type::LINKED_LIST: { static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; - - static linked_list_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; - user_allocator_instance = &user_allocator; break; } } + + static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; } auto global_heap_allocator::kernel() -> heap_allocator & @@ -55,11 +53,11 @@ namespace teachos::arch::memory::heap return *kernel_allocator_instance; } - auto global_heap_allocator::user() -> heap_allocator & + auto global_heap_allocator::user() -> user_heap_allocator & { - exception_handling::assert(user_allocator_instance != nullptr, - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."); + // exception_handling::assert(user_allocator_instance != nullptr, + // "Attempted to allocate or deallocate using the global_heap_allocator before " + // "register_heap_allocation_type was called."); return *user_allocator_instance; } diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp new file mode 100644 index 0000000..f09811d --- /dev/null +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -0,0 +1,55 @@ +#include "arch/memory/heap/user_heap_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include + +namespace teachos::arch::memory::heap +{ + namespace + { + template + [[gnu::section(".user_text")]] + auto saturating_add(T x, T y) -> T + requires std::is_unsigned_v + { + if (x > std::numeric_limits::max() - y) + { + return std::numeric_limits::max(); + } + T result = x + y; + return result; + } + } // namespace + + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); + // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time + // causing the value to differ and the calculation to have to be redone. + for (;;) + { + auto const alloc_end = saturating_add(alloc_start, size); + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); + // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another + // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation + // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. + auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); + if (updated) + { + return reinterpret_cast(alloc_start); + } + } + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + { + if (pointer) + { + } + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 558fbce..4cdfa80 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -20,18 +20,23 @@ namespace teachos::arch::memory } template - auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void + auto remap_heap(T & allocator, paging::active_page_table & active_table, bool is_user_heap = false) -> void { - auto const start_page = paging::virtual_page::containing_address(heap::KERNEL_HEAP_START); - auto const end_page = - ++(paging::virtual_page::containing_address(heap::KERNEL_HEAP_START + heap::KERNEL_HEAP_SIZE - 1)); + auto const heap_start = is_user_heap ? heap::USER_HEAP_START : heap::KERNEL_HEAP_START; + auto const heap_size = is_user_heap ? heap::USER_HEAP_SIZE : heap::KERNEL_HEAP_SIZE; + + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); paging::page_container::iterator const begin{start_page}; paging::page_container::iterator const end{end_page}; paging::page_container const pages{begin, end}; + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = is_user_heap ? base_flags | paging::entry::USER_ACCESSIBLE : base_flags; + for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, flags); } } } // namespace @@ -54,7 +59,8 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - remap_heap(allocator, active_table); + remap_heap(allocator, active_table); // Remap kernel heap + remap_heap(allocator, active_table, true); // Remap user heap video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From d80ecf29baada6242c5181adaec0d1500707cad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 9 May 2025 12:00:23 +0000 Subject: Move necessary code into user text --- arch/x86_64/src/memory/heap/global_heap_allocator.cpp | 3 +++ arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index acba02d..23e2458 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -40,6 +40,7 @@ namespace teachos::arch::memory::heap } } + [[gnu::section(".user_data")]] static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; user_allocator_instance = &user_allocator; } @@ -55,6 +56,8 @@ namespace teachos::arch::memory::heap auto global_heap_allocator::user() -> user_heap_allocator & { + // TODO: Assert Method does not exist in .user_text meaning this causes a Page Fault when accessed, Make it into a + // syscall instead // exception_handling::assert(user_allocator_instance != nullptr, // "Attempted to allocate or deallocate using the global_heap_allocator before " // "register_heap_allocation_type was called."); diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index f09811d..eefcab5 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -25,7 +25,10 @@ namespace teachos::arch::memory::heap auto user_heap_allocator::allocate(std::size_t size) -> void * { - // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // TODO: .load() crashes because it is only in the kernel .text section and not the user one? How would you fix + // Similarly assert cause a crash here it is easier though simply create a syscall for the assert method. + + // that? Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the // exchange failed, becuase the value was not the expected one. auto alloc_start = next.load(std::memory_order::relaxed); // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time -- cgit v1.2.3 From a5812be4fa8ecc208219682204b14969d7b718b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 9 May 2025 13:15:58 +0000 Subject: Switch uer heap to linked list allocator --- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 186 +++++++++++++++++---- 1 file changed, 154 insertions(+), 32 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index eefcab5..6843d66 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,58 +1,180 @@ #include "arch/memory/heap/user_heap_allocator.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" -#include -#include +#include namespace teachos::arch::memory::heap { - namespace + user_heap_allocator::user_heap_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start(heap_start) + , heap_end(heap_end) + , first(nullptr) + , mutex{stl::mutex{}} { - template - [[gnu::section(".user_text")]] - auto saturating_add(T x, T y) -> T - requires std::is_unsigned_v + auto const heap_size = heap_end - heap_start; + exception_handling::assert( + heap_size > min_allocatable_size(), + "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " + "atleast one memory hole entry"); + first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) { - if (x > std::numeric_limits::max() - y) + // TODO: Can not access current pointer. Results in a General Protection Fault? + if (current->size == total_size) { - return std::numeric_limits::max(); + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); } - T result = x + y; - return result; + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + + previous = current; + current = current->next; } - } // namespace - auto user_heap_allocator::allocate(std::size_t size) -> void * + exception_handling::panic("[Linked List Allocator] Out of memory"); + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void { - // TODO: .load() crashes because it is only in the kernel .text section and not the user one? How would you fix - // Similarly assert cause a crash here it is easier though simply create a syscall for the assert method. - - // that? Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the - // exchange failed, becuase the value was not the expected one. - auto alloc_start = next.load(std::memory_order::relaxed); - // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time - // causing the value to differ and the calculation to have to be redone. - for (;;) + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) { - auto const alloc_end = saturating_add(alloc_start, size); - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); - // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another - // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation - // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. - auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); - if (updated) + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) { - return reinterpret_cast(alloc_start); + break; } + + previous = current; + current = current->next; } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); } - auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * { - if (pointer) + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean + // that the block has already been deallocated and we therefore attempted a double free. + exception_handling::assert(previous_block == nullptr || + start_address >= + (reinterpret_cast(previous_block) + previous_block->size), + "[Linked List Allocator] Attempted double free detected"); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) { + first = new_block; + return; } + previous_block->next = new_block; } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From f3a976be198d97573b630242c0f833c290c62d81 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 10 May 2025 10:33:26 +0000 Subject: experiment with globally available linker sections and page table entry flags --- arch/x86_64/src/memory/paging/page_entry.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index c76c673..57e33f7 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -39,6 +39,8 @@ namespace teachos::arch::memory::paging auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_global() -> void { flags |= entry::GLOBAL; } + auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) -- cgit v1.2.3 From 955ab48fe6329b2cbc8c5855a8ba7290185d0ea3 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 11 May 2025 07:20:54 +0000 Subject: rename page table entry function --- arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 57e33f7..a5b44fa 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -37,7 +37,7 @@ namespace teachos::arch::memory::paging auto entry::set_unused() -> void { flags = 0U; } - auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } auto entry::set_global() -> void { flags |= entry::GLOBAL; } -- cgit v1.2.3 From 833cd6446d9981a262959749c0e248e33b54c174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 11 May 2025 08:48:57 +0000 Subject: Adjust user heap allocator with expanding heap functionality --- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 41 +++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index 6843d66..ce8b0fa 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,5 +1,6 @@ #include "arch/memory/heap/user_heap_allocator.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" @@ -18,7 +19,7 @@ namespace teachos::arch::memory::heap heap_size > min_allocatable_size(), "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " "atleast one memory hole entry"); - first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + // first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); } auto user_heap_allocator::allocate(std::size_t size) -> void * @@ -57,6 +58,30 @@ namespace teachos::arch::memory::heap current = current->next; } + current = expand_heap_if_full(); + + if (current != nullptr) + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + } + exception_handling::panic("[Linked List Allocator] Out of memory"); } @@ -91,6 +116,20 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto user_heap_allocator::expand_heap_if_full() -> memory_block * + { + context_switching::syscall::arguments args{}; + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args); + + if (!result.error_code) + { + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + return nullptr; + } + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void * { -- cgit v1.2.3 From ef156dd6430855434b54275b22cd43ee3cedcfdc Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 11 May 2025 09:29:56 +0000 Subject: make frame_allocator and active_page_table statically available --- arch/x86_64/src/memory/heap/memory_block.cpp | 1 + arch/x86_64/src/memory/main.cpp | 59 +++++++++++++++++----------- 2 files changed, 37 insertions(+), 23 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 446cd96..9f1fea8 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -6,6 +6,7 @@ namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) { + // TODO: Figure out why this memset fails memset(static_cast(this), 0, size); this->size = size; this->next = next; diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 4cdfa80..595cb0d 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -9,37 +9,47 @@ #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" +#include + namespace teachos::arch::memory { namespace { - template - auto create_frame_allocator(multiboot::memory_information const & memory_information) -> T + static std::optional frame_allocator; + + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::area_frame_allocator { - return allocator::area_frame_allocator{memory_information}; + frame_allocator.emplace(memory_information); + return frame_allocator.value(); } - template - auto remap_heap(T & allocator, paging::active_page_table & active_table, bool is_user_heap = false) -> void + auto get_frame_allocator() -> allocator::area_frame_allocator { - auto const heap_start = is_user_heap ? heap::USER_HEAP_START : heap::KERNEL_HEAP_START; - auto const heap_size = is_user_heap ? heap::USER_HEAP_SIZE : heap::KERNEL_HEAP_SIZE; + exception_handling::assert(frame_allocator.has_value(), "[Memory main] Frame allocator has not been created yet"); + return frame_allocator.value(); + } + } // namespace + + auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void + { + auto allocator = get_frame_allocator(); + decltype(auto) active_table = paging::active_page_table::create_or_get(); + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - auto const start_page = paging::virtual_page::containing_address(heap_start); - auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - paging::page_container::iterator const begin{start_page}; - paging::page_container::iterator const end{end_page}; - paging::page_container const pages{begin, end}; + paging::page_container::iterator const begin{start_page}; + paging::page_container::iterator const end{end_page}; + paging::page_container const pages{begin, end}; - constexpr auto base_flags = paging::entry::WRITABLE; - auto const flags = is_user_heap ? base_flags | paging::entry::USER_ACCESSIBLE : base_flags; + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = base_flags | additional_flags; - for (auto const & page : pages) - { - active_table.map_page_to_next_free_frame(allocator, page, flags); - } + for (auto const & page : pages) + { + active_table.map_page_to_next_free_frame(allocator, page, flags); } - } // namespace + } auto initialize_memory_management() -> void { @@ -49,18 +59,21 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); - auto & active_table = kernel.remap_kernel(); + kernel.remap_kernel(); video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - remap_heap(allocator, active_table); // Remap kernel heap - remap_heap(allocator, active_table, true); // Remap user heap + // Remap kernel heap + remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + // Remap user heap + remap_heap(heap::USER_HEAP_SIZE, heap::USER_HEAP_SIZE, paging::entry::USER_ACCESSIBLE); + video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From ee4c61f7313fedd23d01c69ea5036fa38ef6248a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 12 May 2025 08:50:12 +0000 Subject: Adjust user heap to lazy allocate heap --- arch/x86_64/src/memory/heap/global_heap_allocator.cpp | 2 +- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 4 +--- arch/x86_64/src/memory/heap/memory_block.cpp | 4 ++-- arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 14 -------------- arch/x86_64/src/memory/main.cpp | 4 ---- 5 files changed, 4 insertions(+), 24 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index 23e2458..e6c268a 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -41,7 +41,7 @@ namespace teachos::arch::memory::heap } [[gnu::section(".user_data")]] - static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + static user_heap_allocator user_allocator{}; user_allocator_instance = &user_allocator; } diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index 5101ab2..63a6111 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -8,9 +8,7 @@ namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start(heap_start) - , heap_end(heap_end) - , first(nullptr) + : first(nullptr) , mutex{stl::mutex{}} { auto const heap_size = heap_end - heap_start; diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 9f1fea8..6ee675a 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -7,10 +7,10 @@ namespace teachos::arch::memory::heap memory_block::memory_block(std::size_t size, memory_block * next) { // TODO: Figure out why this memset fails - memset(static_cast(this), 0, size); + // memset(static_cast(this), 0, size); this->size = size; this->next = next; } - memory_block::~memory_block() { memset(static_cast(this), 0, sizeof(memory_block)); } + memory_block::~memory_block() { /*memset(static_cast(this), 0, sizeof(memory_block));*/ } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index ce8b0fa..9cb6c17 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -8,20 +8,6 @@ namespace teachos::arch::memory::heap { - user_heap_allocator::user_heap_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start(heap_start) - , heap_end(heap_end) - , first(nullptr) - , mutex{stl::mutex{}} - { - auto const heap_size = heap_end - heap_start; - exception_handling::assert( - heap_size > min_allocatable_size(), - "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " - "atleast one memory hole entry"); - // first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - auto user_heap_allocator::allocate(std::size_t size) -> void * { // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 595cb0d..5e671ac 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -69,11 +69,7 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - // Remap kernel heap remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - // Remap user heap - remap_heap(heap::USER_HEAP_SIZE, heap::USER_HEAP_SIZE, paging::entry::USER_ACCESSIBLE); - video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From 29e067867e7a437d12351b481024d4bab431b202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 12 May 2025 13:51:12 +0000 Subject: Fix crashes because of are frame allocator copy --- arch/x86_64/src/memory/heap/memory_block.cpp | 5 ++--- arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 13 ++++--------- arch/x86_64/src/memory/main.cpp | 11 ++++++----- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 6ee675a..bc97bd6 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -6,11 +6,10 @@ namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) { - // TODO: Figure out why this memset fails - // memset(static_cast(this), 0, size); + memset(static_cast(this), 0U, size); this->size = size; this->next = next; } - memory_block::~memory_block() { /*memset(static_cast(this), 0, sizeof(memory_block));*/ } + memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index 9cb6c17..f3fe1c2 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -104,16 +104,11 @@ namespace teachos::arch::memory::heap auto user_heap_allocator::expand_heap_if_full() -> memory_block * { - context_switching::syscall::arguments args{}; - auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args); + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); - if (!result.error_code) - { - uint64_t const heap_start = result.values.arg_0; - uint64_t const heap_size = result.values.arg_1; - return new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - return nullptr; + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; } auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 5e671ac..2746a71 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -18,22 +18,23 @@ namespace teachos::arch::memory static std::optional frame_allocator; auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::area_frame_allocator + -> allocator::area_frame_allocator & { frame_allocator.emplace(memory_information); return frame_allocator.value(); } - auto get_frame_allocator() -> allocator::area_frame_allocator + auto get_frame_allocator() -> allocator::area_frame_allocator & { - exception_handling::assert(frame_allocator.has_value(), "[Memory main] Frame allocator has not been created yet"); + exception_handling::assert(frame_allocator.has_value(), + "[Initialization] Frame allocator has not been created yet"); return frame_allocator.value(); } } // namespace auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void { - auto allocator = get_frame_allocator(); + decltype(auto) allocator = get_frame_allocator(); decltype(auto) active_table = paging::active_page_table::create_or_get(); auto const start_page = paging::virtual_page::containing_address(heap_start); auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); @@ -59,7 +60,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + decltype(auto) allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 5c314eef566df2732973e8cb35974ec49748adba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 16 May 2025 13:27:16 +0000 Subject: Fix bug where level 4 to level 2 entries are not mapped user accesible. --- arch/x86_64/src/memory/paging/page_entry.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index a5b44fa..57045ca 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -39,8 +39,6 @@ namespace teachos::arch::memory::paging auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } - auto entry::set_global() -> void { flags |= entry::GLOBAL; } - auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) -- cgit v1.2.3 From 8d39f3f67734bf39cada370c39243e6ef33bf4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 18 May 2025 14:45:05 +0000 Subject: Make new usable for both kernel and user calls --- .../src/memory/heap/global_heap_allocator.cpp | 66 +++++++++++++++++----- 1 file changed, 51 insertions(+), 15 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index e6c268a..35cd623 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -1,12 +1,29 @@ #include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/linked_list_allocator.hpp" #include "arch/memory/heap/user_heap_allocator.hpp" namespace teachos::arch::memory::heap { + namespace + { + constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."; + constexpr uint16_t KERNEL_CODE_INDEX = 1U; + + [[gnu::section(".user_text")]] + auto os_in_kernel_mode() -> bool + { + auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); + return cs.get_index() == KERNEL_CODE_INDEX; + } + } // namespace + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; @@ -47,53 +64,72 @@ namespace teachos::arch::memory::heap auto global_heap_allocator::kernel() -> heap_allocator & { - exception_handling::assert(kernel_allocator_instance != nullptr, - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."); + exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); return *kernel_allocator_instance; } auto global_heap_allocator::user() -> user_heap_allocator & { - // TODO: Assert Method does not exist in .user_text meaning this causes a Page Fault when accessed, Make it into a - // syscall instead - // exception_handling::assert(user_allocator_instance != nullptr, - // "Attempted to allocate or deallocate using the global_heap_allocator before " - // "register_heap_allocation_type was called."); - + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); return *user_allocator_instance; } } // namespace teachos::arch::memory::heap auto operator new(std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); } auto operator delete(void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator delete(void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator new[](std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); } auto operator delete[](void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator delete[](void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } -- cgit v1.2.3 From 8a6a9a3a159ce1b960721eb921b8e8d81b15b718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 20 May 2025 12:29:09 +0000 Subject: Improve syscalls and user heap allocator --- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 80 +++++++++++----------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index f3fe1c2..427a68a 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,8 +1,6 @@ #include "arch/memory/heap/user_heap_allocator.hpp" #include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" #include @@ -20,24 +18,10 @@ namespace teachos::arch::memory::heap while (current != nullptr) { - // TODO: Can not access current pointer. Results in a General Protection Fault? - if (current->size == total_size) + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + return memory.value(); } previous = current; @@ -48,27 +32,17 @@ namespace teachos::arch::memory::heap if (current != nullptr) { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + return memory.value(); } } - exception_handling::panic("[Linked List Allocator] Out of memory"); + char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; + context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, + {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); + return nullptr; } auto user_heap_allocator::deallocate(void * pointer) noexcept -> void @@ -102,6 +76,30 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, + std::size_t total_size) -> std::optional + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + return std::nullopt; + } + auto user_heap_allocator::expand_heap_if_full() -> memory_block * { auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); @@ -180,10 +178,12 @@ namespace teachos::arch::memory::heap // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean // that the block has already been deallocated and we therefore attempted a double free. - exception_handling::assert(previous_block == nullptr || - start_address >= - (reinterpret_cast(previous_block) + previous_block->size), - "[Linked List Allocator] Attempted double free detected"); + char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {previous_block == nullptr || + start_address >= (reinterpret_cast(previous_block) + previous_block->size), + reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); auto const new_block = new (pointer) memory_block(block_size, next_block); // If we want to deallocate the first block that is before any other free block, then there exists no previous free -- cgit v1.2.3 From 9f2e780030e2101d5f7f01f42df805db9a5fa809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 30 May 2025 12:48:57 +0000 Subject: Clean up files --- .../src/memory/allocator/stack_frame_allocator.cpp | 105 --------------------- 1 file changed, 105 deletions(-) delete mode 100644 arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp (limited to 'arch/x86_64/src/memory') diff --git a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp deleted file mode 100644 index 0fa277a..0000000 --- a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "arch/memory/allocator/stack_frame_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::allocator -{ - stack_frame_allocator::stack_frame_allocator(multiboot::memory_information const & mem_info) - : free_frames() - , next_free_frame() - , current_area(std::nullopt) - , memory_areas(mem_info.areas) - , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) - , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) - , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) - , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) - { - load_free_physical_frames(); - } - - auto stack_frame_allocator::load_free_physical_frames() -> void - { - choose_next_area(); - if (!current_area.has_value()) - { - return; - } - - auto const address = current_area.value().base_address + current_area.value().area_length - 1; - physical_frame const current_area_last_frame = physical_frame::containing_address(address); - - // Only try to allocate memory if current_area is not null, because - // the current_area is null if there is no more available memory. - while (next_free_frame <= current_area_last_frame) - { - if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; - } - else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; - } - else - { - // Frame is unused, increment `next_free_frame` and return it. - next_free_frame.frame_number += 1; - // TODO: Fix using heap like structure to initalize paging allocator used by heap does not work - // free_frames.push(next_free_frame); - static uint32_t count = 0U; - count++; - } - } - } - - auto stack_frame_allocator::choose_next_area() -> void - { - current_area = std::nullopt; - auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { - auto address = area.base_address + area.area_length - 1; - return physical_frame::containing_address(address) >= next_free_frame; - }); - - auto const lowest_area_with_free_frames = std::ranges::min_element( - next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); - - if (lowest_area_with_free_frames != next_area_with_free_frames.end()) - { - current_area = *lowest_area_with_free_frames; - // Update the `next_free_frame` according to the new memory area - auto const start_frame = physical_frame::containing_address(current_area.value().base_address); - if (next_free_frame < start_frame) - { - next_free_frame = start_frame; - } - } - } - - auto stack_frame_allocator::allocate_frame() -> std::optional - { - // If the underlying stack is empty that are no free frames left to allocate. - if (free_frames.empty()) - { - load_free_physical_frames(); - if (free_frames.empty()) - { - return std::nullopt; - } - } - - decltype(auto) top = free_frames.top(); - free_frames.pop(); - return top; - } - - auto stack_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void - { - free_frames.push(physical_frame); - } -} // namespace teachos::arch::memory::allocator -- cgit v1.2.3