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)