diff --git a/Kernel/Makefile b/Kernel/Makefile index 2a2f2e1dd6..92213cafaa 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -17,7 +17,8 @@ KERNEL_OBJS = \ panel.o \ Disk.o \ Userspace.o \ - IDEDiskDevice.o + IDEDiskDevice.o \ + MemoryManager.o VFS_OBJS = \ ../VirtualFileSystem/DiskDevice.o \ diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp new file mode 100644 index 0000000000..b9fccb577b --- /dev/null +++ b/Kernel/MemoryManager.cpp @@ -0,0 +1,90 @@ +#include "MemoryManager.h" +#include +#include +#include +#include "i386.h" +#include "StdLib.h" + +static MemoryManager* s_the; + +MemoryManager& MemoryManager::the() +{ + return *s_the; +} + +MemoryManager::MemoryManager() +{ + m_pageDirectory = (dword*)0x5000; + m_pageTableZero = (dword*)0x6000; + + initializePaging(); +} + +MemoryManager::~MemoryManager() +{ +} + +void MemoryManager::initializePaging() +{ + static_assert(sizeof(MemoryManager::PageDirectoryEntry) == 4); + static_assert(sizeof(MemoryManager::PageTableEntry) == 4); + memset(m_pageTableZero, 0, 4096); + memset(m_pageDirectory, 0, 4096); + + kprintf("MM: Page directory @ %p\n", m_pageDirectory); + kprintf("MM: Page table zero @ %p [0]=%x\n", m_pageTableZero, m_pageTableZero[0]); + // Build a basic PDB that identity maps the first 1MB. + identityMap(LinearAddress(0), 4 * MB); + + asm volatile("movl %%eax, %%cr3"::"a"(m_pageDirectory)); + asm volatile( + "movl %cr0, %eax\n" + "orl $0x80000001, %eax\n" + "movl %eax, %cr0\n" + ); +} + +auto MemoryManager::ensurePTE(LinearAddress linearAddress) -> PageTableEntry +{ + dword pageDirectoryIndex = (linearAddress.get() >> 22) & 0x3ff; + dword pageTableIndex = (linearAddress.get() >> 12) & 0x3ff; + + PageDirectoryEntry pde = PageDirectoryEntry(&m_pageDirectory[pageDirectoryIndex]); + if (!pde.isPresent()) { + kprintf("PDE %u !present, allocating\n", pageDirectoryIndex); + if (pageDirectoryIndex == 0) { + pde.setPageTableBase((dword)m_pageTableZero); + pde.setUserAllowed(true); + pde.setPresent(true); + pde.setWritable(true); + } else { + // FIXME: We need an allocator! + ASSERT_NOT_REACHED(); + } + } + return PageTableEntry(&pde.pageTableBase()[pageTableIndex]); +} + +void MemoryManager::identityMap(LinearAddress linearAddress, size_t length) +{ + // FIXME: ASSERT(linearAddress is 4KB aligned); + for (dword offset = 0; offset < length; offset += 4096) { + auto pteAddress = linearAddress.offset(offset); + auto pte = ensurePTE(pteAddress); + pte.setPhysicalPageBase(pteAddress.get()); + pte.setUserAllowed(true); + pte.setPresent(true); + pte.setWritable(true); + if (pteAddress.get() == 0x6023) { + kprintf("kek\n"); + HANG; + } + } +} + +void MemoryManager::initialize() +{ + s_the = new MemoryManager; +} + + diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h new file mode 100644 index 0000000000..603557deb8 --- /dev/null +++ b/Kernel/MemoryManager.h @@ -0,0 +1,131 @@ +#pragma once + +#include + +class PhysicalAddress { +public: + PhysicalAddress() { } + explicit PhysicalAddress(dword address) : m_address(address) { } + + dword get() const { return m_address; } + void set(dword address) { m_address = address; } + void mask(dword m) { m_address &= m; } + +private: + dword m_address { 0 }; +}; + +class LinearAddress { +public: + LinearAddress() { } + explicit LinearAddress(dword address) : m_address(address) { } + + LinearAddress offset(dword o) const { return LinearAddress(m_address + o); } + dword get() const { return m_address; } + void set(dword address) { m_address = address; } + void mask(dword m) { m_address &= m; } + + bool operator==(const LinearAddress& other) const { return m_address == other.m_address; } + +private: + dword m_address { 0 }; +}; + +class MemoryManager { +public: + static MemoryManager& the(); + + PhysicalAddress pageDirectoryBase() const { return PhysicalAddress(reinterpret_cast(m_pageDirectory)); } + + static void initialize(); +private: + MemoryManager(); + ~MemoryManager(); + + void initializePaging(); + + void identityMap(LinearAddress, size_t length); + + struct PageDirectoryEntry { + explicit PageDirectoryEntry(dword* pde) : m_pde(pde) { } + + dword* pageTableBase() { return reinterpret_cast(raw() & 0xfffff000u); } + void setPageTableBase(dword value) + { + *m_pde &= 0xfff; + *m_pde |= value & 0xfffff000; + } + + dword raw() const { return *m_pde; } + dword* ptr() { return m_pde; } + + enum Flags { + Present = 1 << 0, + ReadWrite = 1 << 1, + UserSupervisor = 1 << 2, + }; + + bool isPresent() const { return raw() & Present; } + void setPresent(bool b) { setBit(Present, b); } + + bool isUserAllowed() const { return raw() & UserSupervisor; } + void setUserAllowed(bool b) { setBit(UserSupervisor, b); } + + bool isWritable() const { return raw() & ReadWrite; } + void setWritable(bool b) { setBit(ReadWrite, b); } + + void setBit(byte bit, bool value) + { + if (value) + *m_pde |= bit; + else + *m_pde &= ~bit; + } + + dword* m_pde; + }; + + struct PageTableEntry { + explicit PageTableEntry(dword* pte) : m_pte(pte) { } + + dword* physicalPageBase() { return reinterpret_cast(raw() & 0xfffff000u); } + void setPhysicalPageBase(dword value) + { + *m_pte &= 0xfffu; + *m_pte |= value & 0xfffff000u; + } + + dword raw() const { return *m_pte; } + dword* ptr() { return m_pte; } + + enum Flags { + Present = 1 << 0, + ReadWrite = 1 << 1, + UserSupervisor = 1 << 2, + }; + + bool isPresent() const { return raw() & Present; } + void setPresent(bool b) { setBit(Present, b); } + + bool isUserAllowed() const { return raw() & UserSupervisor; } + void setUserAllowed(bool b) { setBit(UserSupervisor, b); } + + bool isWritable() const { return raw() & ReadWrite; } + void setWritable(bool b) { setBit(ReadWrite, b); } + + void setBit(byte bit, bool value) + { + if (value) + *m_pte |= bit; + else + *m_pte &= ~bit; + } + + dword* m_pte; + }; + + PageTableEntry ensurePTE(LinearAddress); + + dword* m_pageDirectory; + dword* m_pageTableZero; +}; diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 32f06d57e2..a8b14e34b9 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -6,6 +6,7 @@ #include "i386.h" #include "system.h" #include "FileSystem.h" +#include "MemoryManager.h" Task* current; Task* s_kernelTask; @@ -129,6 +130,8 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring) m_tss.ss = stackSegment; m_tss.cs = codeSegment; + m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get(); + m_tss.eip = (DWORD)m_entry; // NOTE: Each task gets 4KB of stack. diff --git a/Kernel/init.cpp b/Kernel/init.cpp index b30fdab381..7e4b3e964a 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "MemoryManager.h" #if 0 /* Keyboard LED disco task ;^) */ @@ -67,7 +68,7 @@ static void user_main() DO_SYSCALL_A3(0x3000, 2, 3, 4); // Crash ourselves! char* x = reinterpret_cast(0xbeefbabe); - *x = 1; + //*x = 1; //HANG; for (;;) { // nothing? @@ -103,6 +104,8 @@ void init() gdt_init(); idt_init(); + MemoryManager::initialize(); + // Anything that registers interrupts goes *after* PIC and IDT for obvious reasons. Syscall::initialize(); PIT::initialize();