diff --git a/arch/amd64/cpu/gdt.cpp b/arch/amd64/cpu/gdt.cpp index a329a2d..38784db 100644 --- a/arch/amd64/cpu/gdt.cpp +++ b/arch/amd64/cpu/gdt.cpp @@ -151,7 +151,7 @@ namespace GlobalDescriptorTable "movw %%ax, %%es\n" :: : "memory", "rax"); - CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); + CPUStackPointer[Core] = StackManager.Allocate(STACK_SIZE); memset(CPUStackPointer[Core], 0, STACK_SIZE); debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core, CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE, @@ -183,8 +183,7 @@ namespace GlobalDescriptorTable for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++) { - void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); - + void *NewStack = StackManager.Allocate(STACK_SIZE); tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE; memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE); debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE); diff --git a/arch/i386/cpu/gdt.cpp b/arch/i386/cpu/gdt.cpp index d231040..7f3de24 100644 --- a/arch/i386/cpu/gdt.cpp +++ b/arch/i386/cpu/gdt.cpp @@ -216,7 +216,7 @@ namespace GlobalDescriptorTable "movw %%ax, %%es\n" :: : "memory", "eax"); - CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); + CPUStackPointer[Core] = StackManager.Allocate(STACK_SIZE); memset(CPUStackPointer[Core], 0, STACK_SIZE); debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core, CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE, @@ -242,7 +242,7 @@ namespace GlobalDescriptorTable for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++) { - void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); + void *NewStack = StackManager.Allocate(STACK_SIZE); tss[Core].InterruptStackTable[i] = (uint32_t)NewStack + STACK_SIZE; memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE); diff --git a/core/interrupts_manager.cpp b/core/interrupts_manager.cpp index 1b1e533..74ea796 100644 --- a/core/interrupts_manager.cpp +++ b/core/interrupts_manager.cpp @@ -123,7 +123,7 @@ namespace Interrupts CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, (uint64_t)CoreData); CoreData->ID = Core; CoreData->IsActive = true; - CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE; + CoreData->Stack = (uintptr_t)StackManager.Allocate(STACK_SIZE) + STACK_SIZE; if (CoreData->Checksum != CPU_DATA_CHECKSUM) { KPrint("CPU %d checksum mismatch! %x != %x", @@ -142,7 +142,7 @@ namespace Interrupts CPU::x32::wrmsr(CPU::x32::MSR_SHADOW_GS_BASE, (uint64_t)CoreData); CoreData->ID = Core; CoreData->IsActive = true; - CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE; + CoreData->Stack = (uintptr_t)StackManager.Allocate(STACK_SIZE) + STACK_SIZE; if (CoreData->Checksum != CPU_DATA_CHECKSUM) { KPrint("CPU %d checksum mismatch! %x != %x", diff --git a/core/memory/kstack.cpp b/core/memory/kstack.cpp new file mode 100644 index 0000000..a5678f5 --- /dev/null +++ b/core/memory/kstack.cpp @@ -0,0 +1,75 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include "../../kernel.h" + +namespace Memory +{ + KernelStackManager::StackAllocation KernelStackManager::DetailedAllocate(size_t Size) + { + SmartLock(StackLock); + Size += 0x10; + + size_t pagesNeeded = TO_PAGES(Size); + size_t stackSize = pagesNeeded * PAGE_SIZE; + + assert((CurrentStackTop - stackSize) > KERNEL_STACK_BASE); + + void *physicalMemory = KernelAllocator.RequestPages(pagesNeeded); + void *virtualAddress = (void *)(CurrentStackTop - stackSize); + + Memory::Virtual vmm(KernelPageTable); + vmm.Map(virtualAddress, physicalMemory, stackSize, Memory::RW | Memory::G); + + AllocatedStacks.push_back({physicalMemory, virtualAddress, stackSize}); + CurrentStackTop -= stackSize; + TotalSize += stackSize; + return {physicalMemory, virtualAddress, stackSize}; + } + + void *KernelStackManager::Allocate(size_t Size) + { + return this->DetailedAllocate(Size).VirtualAddress; + } + + void KernelStackManager::Free(void *Address) + { + SmartLock(StackLock); + + auto it = std::find_if(AllocatedStacks.begin(), AllocatedStacks.end(), + [Address](const StackAllocation &stack) + { + return stack.VirtualAddress == Address; + }); + + if (it == AllocatedStacks.end()) + return; + + size_t pagesToFree = TO_PAGES(it->Size); + Memory::Virtual vmm(KernelPageTable); + vmm.Unmap(Address, it->Size); + KernelAllocator.FreePages(it->PhysicalAddress, pagesToFree); + + TotalSize -= it->Size; + AllocatedStacks.erase(it); + } + + KernelStackManager::KernelStackManager() {} + KernelStackManager::~KernelStackManager() {} +} diff --git a/core/memory/memory.cpp b/core/memory/memory.cpp index db2b470..298c208 100644 --- a/core/memory/memory.cpp +++ b/core/memory/memory.cpp @@ -42,6 +42,7 @@ using namespace Memory; Physical KernelAllocator; +Memory::KernelStackManager StackManager; PageTable *KernelPageTable = nullptr; bool Page1GBSupport = false; bool PSESupport = false; diff --git a/core/memory/stack_guard.cpp b/core/memory/stack_guard.cpp index e645392..e05e85a 100644 --- a/core/memory/stack_guard.cpp +++ b/core/memory/stack_guard.cpp @@ -128,10 +128,11 @@ namespace Memory } else { - this->StackBottom = vma->RequestPages(TO_PAGES(STACK_SIZE)); + Memory::KernelStackManager::StackAllocation sa = StackManager.DetailedAllocate(STACK_SIZE); + this->StackBottom = sa.VirtualAddress; this->StackTop = (void *)((uintptr_t)this->StackBottom + STACK_SIZE); - this->StackPhysicalBottom = this->StackBottom; - this->StackPhysicalTop = this->StackTop; + this->StackPhysicalBottom = sa.PhysicalAddress; + this->StackPhysicalTop = (void *)((uintptr_t)this->StackPhysicalBottom + STACK_SIZE); this->Size = STACK_SIZE; debug("StackBottom: %#lx", this->StackBottom); @@ -139,7 +140,7 @@ namespace Memory for (size_t i = 0; i < TO_PAGES(STACK_SIZE); i++) { AllocatedPages pa = { - .PhysicalAddress = (void *)((uintptr_t)this->StackBottom + (i * PAGE_SIZE)), + .PhysicalAddress = (void *)((uintptr_t)this->StackPhysicalBottom + (i * PAGE_SIZE)), .VirtualAddress = (void *)((uintptr_t)this->StackBottom + (i * PAGE_SIZE)), }; AllocatedPagesList.push_back(pa); @@ -152,6 +153,12 @@ namespace Memory StackGuard::~StackGuard() { + if (!this->UserMode) + { + for (auto Page : this->AllocatedPagesList) + StackManager.Free(Page.VirtualAddress); + } + /* VMA will free the stack */ } } diff --git a/include/memory.hpp b/include/memory.hpp index 7ae3849..61d4a97 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -63,6 +63,7 @@ namespace Memory #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ void InitializeMemoryManagement(); void CreatePageTable(Memory::PageTable *pt); extern Memory::Physical KernelAllocator; +extern Memory::KernelStackManager StackManager; extern Memory::PageTable *KernelPageTable; #endif // __cplusplus diff --git a/include/memory/kstack.hpp b/include/memory/kstack.hpp new file mode 100644 index 0000000..9a7b1c1 --- /dev/null +++ b/include/memory/kstack.hpp @@ -0,0 +1,69 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifndef __FENNIX_KERNEL_MEMORY_KERNEL_STACK_MANAGER_H__ +#define __FENNIX_KERNEL_MEMORY_KERNEL_STACK_MANAGER_H__ + +#include + +namespace Memory +{ + class KernelStackManager + { + public: + struct StackAllocation + { + void *PhysicalAddress; + void *VirtualAddress; + size_t Size; + }; + + private: + NewLock(StackLock); + std::list AllocatedStacks; + size_t TotalSize = 0; + uintptr_t CurrentStackTop = KERNEL_STACK_END; + + public: + /** + * Allocate a new stack with detailed information + * + * @param Size Size in bytes to allocate + * @return {PhysicalAddress, VirtualAddress, Size} + */ + StackAllocation DetailedAllocate(size_t Size); + + /** + * Allocate a new stack + * + * @param Size Size in bytes to allocate + * @return Pointer to the BASE of the stack + */ + void *Allocate(size_t Size); + + /** + * Free a previously allocated stack + * + * @param Address Virtual Address + */ + void Free(void *Address); + KernelStackManager(); + ~KernelStackManager(); + }; +} + +#endif // !__FENNIX_KERNEL_MEMORY_KERNEL_STACK_MANAGER_H__ diff --git a/include/memory/macro.hpp b/include/memory/macro.hpp index 741f203..b82f502 100644 --- a/include/memory/macro.hpp +++ b/include/memory/macro.hpp @@ -50,17 +50,23 @@ #if defined(a64) || defined(aa64) #define KERNEL_VMA_OFFSET 0xFFFFFFFF80000000 -#define USER_ALLOC_BASE 0xFFFFA00000000000 /* 256 GiB */ -#define USER_ALLOC_END 0xFFFFB00000000000 +#define USER_ALLOC_BASE 0xFFFFA00000000000 /* 256 GiB */ +#define USER_ALLOC_END 0xFFFFB00000000000 -#define USER_STACK_END 0xFFFFEFFF00000000 /* 256 MiB */ -#define USER_STACK_BASE 0xFFFFEFFFFFFF0000 +#define KERNEL_STACK_BASE 0xFFFFB00000000000 /* 256 GiB */ +#define KERNEL_STACK_END 0xFFFFC00000000000 + +#define USER_STACK_END 0xFFFFEFFF00000000 /* 256 MiB */ +#define USER_STACK_BASE 0xFFFFEFFFFFFF0000 #elif defined(a32) #define KERNEL_VMA_OFFSET 0xC0000000 #define USER_ALLOC_BASE 0x80000000 #define USER_ALLOC_END 0xA0000000 +#define KERNEL_STACK_BASE 0xA0000000 +#define KERNEL_STACK_END 0xB0000000 + #define USER_STACK_BASE 0xEFFFFFFF #define USER_STACK_END 0xE0000000 #endif diff --git a/kernel.cpp b/kernel.cpp index 50bd47f..d9296f5 100644 --- a/kernel.cpp +++ b/kernel.cpp @@ -324,6 +324,7 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info) InitializeMemoryManagement(); void *KernelStackAddress = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE)); + // void *KernelStackAddress = StackManager.Allocate(STACK_SIZE); /* FIXME: This breaks stl tests, how? */ uintptr_t KernelStack = (uintptr_t)KernelStackAddress + STACK_SIZE - 0x10; debug("Kernel stack: %#lx-%#lx", KernelStackAddress, KernelStack); #if defined(a64)