diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c9280b5687..691a5ea5b7 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -26,6 +26,7 @@ set(KERNEL_SOURCES kernel/Input/PS2Keymap.cpp kernel/InterruptController.cpp kernel/kernel.cpp + kernel/Memory/Heap.cpp kernel/Memory/kmalloc.cpp kernel/PCI.cpp kernel/PIC.cpp diff --git a/kernel/include/kernel/Memory/Heap.h b/kernel/include/kernel/Memory/Heap.h new file mode 100644 index 0000000000..80f85d2549 --- /dev/null +++ b/kernel/include/kernel/Memory/Heap.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include + +#define PAGE_SIZE 4096 + +namespace Kernel::Memory +{ + + using paddr_t = uintptr_t; + + class PhysicalRange + { + public: + static constexpr paddr_t invalid = ~paddr_t(0); + + public: + PhysicalRange(paddr_t, size_t); + paddr_t reserve_page(); + void release_page(paddr_t); + + paddr_t start() const { return m_start + m_list_pages * PAGE_SIZE; } + paddr_t end() const { return m_start + m_total_pages * PAGE_SIZE; } + uint64_t pages() const { return m_reservable_pages; } + + private: + paddr_t page_address(uint64_t) const; + + private: + paddr_t m_start { 0 }; + size_t m_size { 0 }; + + uint64_t m_total_pages { 0 }; + uint64_t m_reservable_pages { 0 }; + uint64_t m_list_pages { 0 }; + + uint64_t* m_free_list { nullptr }; + uint64_t* m_used_list { nullptr }; + }; + + class Heap + { + BAN_NON_COPYABLE(Heap); + BAN_NON_MOVABLE(Heap); + + public: + static void initialize(); + static Heap& get(); + + private: + Heap() = default; + void initialize_impl(); + + private: + BAN::Vector m_physical_ranges; + }; + +} diff --git a/kernel/kernel/Memory/Heap.cpp b/kernel/kernel/Memory/Heap.cpp new file mode 100644 index 0000000000..812615ca5b --- /dev/null +++ b/kernel/kernel/Memory/Heap.cpp @@ -0,0 +1,103 @@ +#include +#include +#include + +extern uint8_t g_kernel_end[]; + +namespace Kernel::Memory +{ + + PhysicalRange::PhysicalRange(paddr_t start, size_t size) + { + ASSERT(start + size > (paddr_t)g_kernel_end); + + // Align start to page boundary and after the kernel memory + m_start = BAN::Math::max(start, (paddr_t)g_kernel_end); + if (auto rem = m_start % PAGE_SIZE) + m_start += PAGE_SIZE - rem; + + // Align size to page boundary + m_size = size - (m_start - start); + if (auto rem = m_size % PAGE_SIZE) + m_size -= rem; + + // FIXME: if total pages is just over multiple of (4096/sizeof(uint64_t)) we might make + // couple of pages unallocatable + m_total_pages = m_size / PAGE_SIZE; + m_list_pages = BAN::Math::div_round_up(m_total_pages * sizeof(uint64_t), PAGE_SIZE); + m_reservable_pages = m_total_pages - m_list_pages; + + MMU::get().allocate_range(m_start, m_list_pages * PAGE_SIZE, MMU::Flags::Present); + + // Initialize free list with every page pointing to the next one + uint64_t* list_ptr = (uint64_t*)m_start; + for (uint64_t i = 0; i < m_reservable_pages - 1; i++) + { + *list_ptr++ = i + 1; + //dprintln("{}/{}", i, m_reservable_pages); + } + + *list_ptr = invalid; + m_free_list = (uint64_t*)m_start; + + m_used_list = nullptr; + } + + paddr_t PhysicalRange::reserve_page() + { + ASSERT_NOT_REACHED(); + } + + void PhysicalRange::release_page(paddr_t) + { + ASSERT_NOT_REACHED(); + } + + paddr_t PhysicalRange::page_address(uint64_t page_index) const + { + ASSERT(page_index < m_reservable_pages); + return m_start + (page_index + m_list_pages) * PAGE_SIZE; + } + + + + static Heap* s_instance = nullptr; + + void Heap::initialize() + { + ASSERT(s_instance == nullptr); + s_instance = new Heap; + ASSERT(s_instance); + s_instance->initialize_impl(); + } + + Heap& Heap::get() + { + ASSERT(s_instance); + return *s_instance; + } + + void Heap::initialize_impl() + { + if (!(g_multiboot_info->flags & (1 << 6))) + Kernel::panic("Bootloader did not provide a memory map"); + + for (size_t i = 0; i < g_multiboot_info->mmap_length;) + { + multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)(g_multiboot_info->mmap_addr + i); + + if (mmmt->type == 1) + { + // We can't use the memory ovelapping with kernel + if (mmmt->base_addr + mmmt->length > (paddr_t)g_kernel_end) + MUST(m_physical_ranges.push_back({ mmmt->base_addr, mmmt->length })); + } + + i += mmmt->size + sizeof(uint32_t); + } + + for (auto& range : m_physical_ranges) + dprintln("RAM {8H}->{8H}, {} pages ({}.{} MB)", range.start(), range.end(), range.pages(), range.pages() * PAGE_SIZE / (1 << 20), range.pages() * PAGE_SIZE % (1 << 20) * 100 / (1 << 20)); + } + +} diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index b503722c4e..36b0e67047 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,9 @@ extern "C" void kernel_main() MMU::intialize(); dprintln("MMU initialized"); + Memory::Heap::initialize(); + dprintln("Heap initialzed"); + parse_command_line(); dprintln("command line parsed, root='{}'", cmdline.root);