diff --git a/prototypes/base/Makefile b/prototypes/base/Makefile index 025e290..dc1c8a5 100644 --- a/prototypes/base/Makefile +++ b/prototypes/base/Makefile @@ -6,7 +6,7 @@ LD=ld IDT_DISPATCH = _ZN3IDT8dispatchEP8CpuState -FLAGS = -DIDT_DISPATCH=$(IDT_DISPATCH) -ffreestanding -m32 -Werror -Wall -iquote include -iquote lists -O3 -g +FLAGS = -mno-sse -DIDT_DISPATCH=$(IDT_DISPATCH) -ffreestanding -m32 -Werror -Wall -iquote include -iquote lists -O3 -g ASFLAGS = $(FLAGS) CFLAGS = $(FLAGS) CXXFLAGS = $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin @@ -47,7 +47,13 @@ kernel-base.ker: $(OBJS) run: - qemu-system-i386 -kernel kernel-base.ker -m 64 + qemu-system-i386 \ + -kernel kernel-base.ker \ + -m 64 \ + -d cpu_reset,int \ + -no-reboot \ + -no-shutdown \ + -serial stdio bnr: kernel-base.ker run diff --git a/prototypes/base/include/enums.hpp b/prototypes/base/include/enums.hpp index 3669f2f..a8b6035 100644 --- a/prototypes/base/include/enums.hpp +++ b/prototypes/base/include/enums.hpp @@ -8,4 +8,11 @@ static inline type operator & (type lhs, type rhs) { \ } \ static inline bool operator * (type lhs, type rhs) { \ return (static_cast(lhs) & static_cast(rhs)) != 0; \ -} +} \ +static inline type & operator |=(type & lhs, type rhs) { \ + reinterpret_cast(lhs) |= static_cast(rhs); \ + return lhs; \ +} + + + diff --git a/prototypes/base/include/pagedirectory.hpp b/prototypes/base/include/pagedirectory.hpp new file mode 100644 index 0000000..ef6f3fb --- /dev/null +++ b/prototypes/base/include/pagedirectory.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "pagetable.hpp" + +class PageDirectory +{ +private: + uint32_t tables[1024]; +public: + PageDirectory(); + ~PageDirectory(); + + uint32_t & table(uint32_t index) { + return this->tables[index]; + } +}; + +static_assert(sizeof(PageDirectory) == 4096, "PageDirectory must be 4096 bytes large"); \ No newline at end of file diff --git a/prototypes/base/include/pagetable.hpp b/prototypes/base/include/pagetable.hpp new file mode 100644 index 0000000..e7c4fc8 --- /dev/null +++ b/prototypes/base/include/pagetable.hpp @@ -0,0 +1,17 @@ +#pragma once + +class PageTable +{ +private: + uint32_t pages[1024]; +public: + PageTable(); + ~PageTable(); + + uint32_t & pageDescriptor(uint32_t pageIndex) + { + return this->pages[pageIndex]; + } +}; + +static_assert(sizeof(PageTable) == 4096, "PageDirectory must be 4096 bytes large"); \ No newline at end of file diff --git a/prototypes/base/include/vmm.hpp b/prototypes/base/include/vmm.hpp index 3f59c93..dc18277 100644 --- a/prototypes/base/include/vmm.hpp +++ b/prototypes/base/include/vmm.hpp @@ -1,2 +1,63 @@ #pragma once +#include "pmm.hpp" +#include "enums.hpp" +#include "pagedirectory.hpp" + +enum class VMMFlags +{ + None = 0, + Present = (1<<0), + Writable = (1<<1), + UserSpace = (1<<2), + SystemAllocated = (1<<3), +}; + +ENUM_CLASS_OPERATORS(VMMFlags) + +class VMMContext +{ + friend class VMM; +private: + PageDirectory *directory; + + /** + * Gets the uint32_t that describes the given virtual address + */ + uint32_t & getPageDescriptor(virtual_t virt); +public: + VMMContext(); + ~VMMContext(); + + /** + * Maps an arbitrary page into the virtual memory. + */ + void provide(virtual_t virt, VMMFlags flags); + + /** + * Maps a given page into the virtual memory. + */ + void map(virtual_t virt, physical_t phys, VMMFlags flags); + + /** + * Unmaps a given page from the virtual memory. + */ + void unmap(virtual_t virt); + +}; + +class VMM +{ +private: + VMM() = delete; +public: + /** + * Enables paging + */ + static void enable(); + + /** + * Sets the given context as the current context. + */ + static void activate(VMMContext & context); +}; diff --git a/prototypes/base/init.cpp b/prototypes/base/init.cpp index db4b31e..05cbf2d 100644 --- a/prototypes/base/init.cpp +++ b/prototypes/base/init.cpp @@ -9,6 +9,7 @@ #include "idt.hpp" #include "compat.h" #include "io.hpp" +#include "vmm.hpp" #include "driver/timer.hpp" #include "driver/keyboard.hpp" @@ -81,6 +82,8 @@ extern "C" void init(Structure const & data) PMM::markUsed(physical_t(ptr)); ptr += 0x1000; } + // nullptr is not valid. + PMM::markUsed(physical_t(nullptr)); auto freeMemory = PMM::getFreeMemory(); Console::main @@ -91,27 +94,43 @@ extern "C" void init(Structure const & data) << (freeMemory >> 12) << "Pages\n"; IDT::initialize(); + Console::main << "Interrupts set up.\n"; + + Console::main << "Creating VMM Context...\n"; + VMMContext kernelContext; + + + Console::main << "Mapping memory...\n"; + for(uint32_t addr = 0; addr < 4096 * 1024; addr += 0x1000) { + kernelContext.map( + virtual_t(addr), + physical_t(addr), + VMMFlags::Writable | VMMFlags::UserSpace); + } + Console::main << "Active Context...\n"; + VMM::activate(kernelContext); + + Console::main << "Active Paging...\n"; + VMM::enable(); + Console::main << "Virtual Memory Management ready.\n"; timer.install(); keyboardDriver.install(); scheduler.install(); + Console::main << "Drivers installed.\n"; - Console::main << "Interrupts set up.\n"; asm volatile("sti"); - asm volatile ("int $0x00"); + // asm volatile ("int $0x00"); - // Console::main << "Interrupts enabled.\n"; - - /* - for(int i = 0; i < 10; i++) { - bool success; - physical_t page = PMM::alloc(success); - Console::main << "allocated page " << i << " [" << success << "]: " << page << "\n"; - } - */ + Console::main << "Interrupts enabled.\n"; + uint32_t *invalidAddress = (uint32_t*)0xFF0000FF; + + Console::main << + "Value at " << invalidAddress << " = " << (*invalidAddress) << "\n"; + while(true); } diff --git a/prototypes/base/src/bsod.cpp b/prototypes/base/src/bsod.cpp index a8a25c4..1f20e6b 100644 --- a/prototypes/base/src/bsod.cpp +++ b/prototypes/base/src/bsod.cpp @@ -38,6 +38,13 @@ void BSOD::die(Error code, const char *msg, CpuState *cpu) asm volatile ("cli"); + uint32_t cr0 = 0xBADEAFFE, cr1 = 0xBADEAFFE, cr2 = 0xBADEAFFE, cr3 = 0xBADEAFFE; + + asm volatile("mov %%cr0, %0" : "=r" (cr0)); + // asm volatile("mov %%cr1, %0" : "=r" (cr1)); + asm volatile("mov %%cr2, %0" : "=r" (cr2)); + asm volatile("mov %%cr3, %0" : "=r" (cr3)); + Console::main << FColor(Color::White) << BColor(Color::Red); Console::main.clear(); @@ -68,6 +75,7 @@ void BSOD::die(Error code, const char *msg, CpuState *cpu) << W << "eax = " << Y << pad(hex(cpu->eax), 10) << W << " esi = " << Y << pad(hex(cpu->esi), 10) << W << " edx = " << Y << pad(hex(cpu->edx), 10) << W << " esp = " << Y << pad(hex(cpu->esp), 10) << "\n" << W << "ebx = " << Y << pad(hex(cpu->ebx), 10) << W << " edi = " << Y << pad(hex(cpu->edi), 10) << W << " eip = " << Y << pad(hex(cpu->eip), 10) << W << " flg = " << Y << bin(cpu->eflags) << "\n" << W << "ecx = " << Y << pad(hex(cpu->ecx), 10) << W << " ebp = " << Y << pad(hex(cpu->ebp), 10) << W << " cs = " << Y << pad(hex(cpu->cs), 10) << W << " ss = " << Y << pad(hex(cpu->ss), 10) << "\n" + << W << "cr0 = " << Y << pad(hex(cr0), 10) << W << " cr1 = " << Y << pad(hex(cr1), 10) << W << " cr2 = " << Y << pad(hex(cr2), 10) << W << " cr3 = " << Y << pad(hex(cr3), 10) << W << "\n" << W << "int = " << Y << pad(cpu->interrupt, 10) << W << " err = " << Y << pad(cpu->error, 10) << W << " " << toString(cpu->interrupt); asm volatile ("hlt"); diff --git a/prototypes/base/src/console.cpp b/prototypes/base/src/console.cpp index cabe1c0..7da4390 100644 --- a/prototypes/base/src/console.cpp +++ b/prototypes/base/src/console.cpp @@ -28,8 +28,20 @@ void Console::clear() this->updateCaret(); } +// Prüft, ob man bereits schreiben kann +static uint8_t is_transmit_empty(uint16_t base) { + return inb(base+5) & 0x20; +} + + // Byte senden +static void write_com(uint16_t base, uint8_t chr) { + while (is_transmit_empty(base)==0); + outb(base,chr); +} + void Console::put(char c) { + write_com(0x3F8, c); switch(c) { case '\0': return; case '\r': break; /* ignore \r */ diff --git a/prototypes/base/src/vmm.cpp b/prototypes/base/src/vmm.cpp index 1730d69..e529aa4 100644 --- a/prototypes/base/src/vmm.cpp +++ b/prototypes/base/src/vmm.cpp @@ -1,2 +1,132 @@ #include "vmm.hpp" +#include +#include "console.hpp" +void VMM::enable() +{ + uint32_t cr0; + asm volatile("mov %%cr0, %0" : "=r" (cr0)); + cr0 |= (1 << 31); + asm volatile("mov %0, %%cr0" : : "r" (cr0)); +} + +void VMM::activate(VMMContext & context) +{ + /* + Console::main + << "Activate PD " << context.directory << "\n"; + //*/ + asm volatile("mov %0, %%cr3" : : "r" (context.directory)); +} + +VMMContext::VMMContext() : + directory(PMM::alloc().data()) +{ + new (this->directory) PageDirectory(); +} + +VMMContext::~VMMContext() +{ + this->directory->~PageDirectory(); +} + + +uint32_t & VMMContext::getPageDescriptor(virtual_t v) +{ + uint32_t virt = v.numeric(); + uint32_t directoryIndex = (virt >> 12) / 1024; + uint32_t tableIndex = (virt >> 12) % 1024; + + uint32_t & tableDesc = this->directory->table(directoryIndex); + if((tableDesc & 0x01) == 0) + { + auto pageMemory = PMM::alloc(); + tableDesc = + pageMemory.numeric() | + static_cast( + VMMFlags::Present | + VMMFlags::Writable | + VMMFlags::UserSpace | + VMMFlags::SystemAllocated); + PageTable *table = reinterpret_cast(tableDesc & 0xFFFFF000); + new (table) PageTable(); + } + PageTable *table = reinterpret_cast(tableDesc & 0xFFFFF000); + auto & entry = table->pageDescriptor(tableIndex); + /* + Console::main << + v << " -> " << directoryIndex << "/" << tableIndex << ": " << tableDesc << "/" << entry << "\n"; + //*/ + return entry; +} + +/** + * Maps an arbitrary page into the virtual memory. + */ +void VMMContext::provide(virtual_t virt, VMMFlags flags) +{ + this->map(virt, PMM::alloc(), flags | VMMFlags::SystemAllocated); +} + +/** + * Maps a given page into the virtual memory. + */ +void VMMContext::map(virtual_t virt, physical_t phys, VMMFlags flags) +{ + using namespace console_tools; + + flags |= VMMFlags::Present; + + uint32_t & pageDesc = this->getPageDescriptor(virt); + pageDesc = + phys.numeric() | + static_cast(flags); + + /* + Console::main << + "Mapping " << virt << " -> " << phys << " [" << bin(static_cast(flags)) << "]: " << hex(pageDesc) << "\n"; + //*/ + asm volatile("invlpg %0" : : "m" (*(char*)phys.numeric())); +} + +/** + * Unmaps a given page from the virtual memory. + */ +void VMMContext::unmap(virtual_t virt) +{ + +} + + + +PageDirectory::PageDirectory() +{ + for(uint32_t i = 0; i < 1024; i++) { + this->tables[i] = 0; + } +} + +PageDirectory::~PageDirectory() +{ + for(uint32_t i = 0; i < 1024; i++) { + if(this->tables[i] & 0x01) { + PMM::free(physical_t(this->tables[i] & 0xFFFFF000)); + } + } +} + +PageTable::PageTable() +{ + for(uint32_t i = 0; i < 1024; i++) { + this->pages[i] = 0; + } +} + +PageTable::~PageTable() +{ + for(uint32_t i = 0; i < 1024; i++) { + if(this->pages[i] & static_cast(VMMFlags::SystemAllocated)) { + PMM::free(physical_t(this->pages[i] & 0xFFFFF000)); + } + } +} \ No newline at end of file