diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index 76a9f533..b9ed26fb 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -137,6 +137,21 @@ namespace IDT extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, const Registers* regs) { + if (isr == ISR::PageFault) + { + using namespace Kernel; + + vaddr_t vaddr = regs->cr2 & PAGE_ADDR_MASK; + + if (!PageTable::kernel().is_page_free(vaddr)) + { + auto paddr = kmalloc_paddr_of(vaddr); + ASSERT(paddr.has_value()); + PageTable::current().map_page_at(paddr.value(), vaddr, PageTable::Flags::ReadWrite | PageTable::Flags::Present); + return; + } + } + pid_t tid = Kernel::Scheduler::current_tid(); pid_t pid = tid ? Kernel::Process::current().pid() : 0; diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index 071d3355..36e36e6d 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -65,7 +65,7 @@ namespace Kernel static uint64_t* allocate_page_aligned_page() { - void* page = kmalloc(PAGE_SIZE, PAGE_SIZE); + void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true); ASSERT(page); memset(page, 0, PAGE_SIZE); return (uint64_t*)page; diff --git a/kernel/include/kernel/Memory/kmalloc.h b/kernel/include/kernel/Memory/kmalloc.h index ba7d288e..2f330a2d 100644 --- a/kernel/include/kernel/Memory/kmalloc.h +++ b/kernel/include/kernel/Memory/kmalloc.h @@ -1,10 +1,15 @@ #pragma once +#include +#include + #include void kmalloc_initialize(); void kmalloc_dump_info(); -void* kmalloc(size_t); -void* kmalloc(size_t, size_t); +void* kmalloc(size_t size); +void* kmalloc(size_t size, size_t align, bool force_identity_map = false); void kfree(void*); + +BAN::Optional kmalloc_paddr_of(Kernel::vaddr_t); diff --git a/kernel/kernel/Memory/kmalloc.cpp b/kernel/kernel/Memory/kmalloc.cpp index 83781d28..5e859f18 100644 --- a/kernel/kernel/Memory/kmalloc.cpp +++ b/kernel/kernel/Memory/kmalloc.cpp @@ -1,16 +1,21 @@ #include #include #include +#include #include #include #define MB (1 << 20) +extern uint8_t g_kernel_end[]; + static constexpr size_t s_kmalloc_min_align = alignof(max_align_t); static uint8_t s_kmalloc_storage[2 * MB]; +static BAN::UniqPtr s_general_allocator; + struct kmalloc_node { void set_align(ptrdiff_t align) { m_align = align; } @@ -277,7 +282,7 @@ static void* kmalloc_impl(size_t size, size_t align) void* kmalloc(size_t size) { - return kmalloc(size, s_kmalloc_min_align); + return kmalloc(size, s_kmalloc_min_align, false); } static constexpr bool is_power_of_two(size_t value) @@ -287,16 +292,30 @@ static constexpr bool is_power_of_two(size_t value) return (value & (value - 1)) == 0; } -void* kmalloc(size_t size, size_t align) +void* kmalloc(size_t size, size_t align, bool force_indentity_map) { const kmalloc_info& info = s_kmalloc_info; ASSERT(is_power_of_two(align)); if (align < s_kmalloc_min_align) align = s_kmalloc_min_align; - + ASSERT(align <= PAGE_SIZE); + Kernel::CriticalScope critical; + // FIXME: this is a hack to make more dynamic kmalloc memory + if (size > PAGE_SIZE && !force_indentity_map) + { + using namespace Kernel; + + if (!s_general_allocator) + s_general_allocator = MUST(GeneralAllocator::create(PageTable::kernel(), (vaddr_t)g_kernel_end)); + + auto vaddr = s_general_allocator->allocate(size); + if (vaddr) + return (void*)vaddr; + } + if (size == 0 || size >= info.size) goto no_memory; @@ -331,6 +350,9 @@ void kfree(void* address) Kernel::CriticalScope critical; + if (s_general_allocator && s_general_allocator->deallocate((Kernel::vaddr_t)address)) + return; + if (s_kmalloc_fixed_info.base <= address_uint && address_uint < s_kmalloc_fixed_info.end) { auto& info = s_kmalloc_fixed_info; @@ -386,4 +408,21 @@ void kfree(void* address) Kernel::panic("Trying to free a pointer {8H} outsize of kmalloc memory", address); } -} \ No newline at end of file +} + +BAN::Optional kmalloc_paddr_of(Kernel::vaddr_t vaddr) +{ + using namespace Kernel; + + if (s_general_allocator) + { + auto paddr = s_general_allocator->paddr_of(vaddr); + if (paddr.has_value()) + return paddr.value(); + } + + if ((vaddr_t)s_kmalloc_storage <= vaddr && vaddr < (vaddr_t)s_kmalloc_storage + sizeof(s_kmalloc_storage)) + return V2P(vaddr); + + return {}; +} diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index ec587636..ef625b78 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -133,6 +133,9 @@ extern "C" void kernel_main() PageTable::initialize(); dprintln("PageTable initialized"); + Heap::initialize(); + dprintln("Heap initialzed"); + TerminalDriver* terminal_driver = VesaTerminalDriver::create(); ASSERT(terminal_driver); dprintln("VESA initialized"); @@ -141,9 +144,6 @@ extern "C" void kernel_main() ASSERT(tty1); dprintln("TTY initialized"); - Heap::initialize(); - dprintln("Heap initialzed"); - parse_command_line(); dprintln("command line parsed, root='{}'", cmdline.root);