Adds virtual memory management with paging :)

This commit is contained in:
Felix Queißner 2016-05-07 14:10:37 +02:00
parent e97921e246
commit 455a6db8b5
9 changed files with 292 additions and 14 deletions

View file

@ -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

View file

@ -8,4 +8,11 @@ static inline type operator & (type lhs, type rhs) { \
} \
static inline bool operator * (type lhs, type rhs) { \
return (static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)) != 0; \
}
} \
static inline type & operator |=(type & lhs, type rhs) { \
reinterpret_cast<uint32_t&>(lhs) |= static_cast<uint32_t>(rhs); \
return lhs; \
}

View file

@ -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");

View file

@ -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");

View file

@ -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);
};

View file

@ -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);
}

View file

@ -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");

View file

@ -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 */

View file

@ -1,2 +1,132 @@
#include "vmm.hpp"
#include <new>
#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<PageDirectory>())
{
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<uint32_t>(
VMMFlags::Present |
VMMFlags::Writable |
VMMFlags::UserSpace |
VMMFlags::SystemAllocated);
PageTable *table = reinterpret_cast<PageTable*>(tableDesc & 0xFFFFF000);
new (table) PageTable();
}
PageTable *table = reinterpret_cast<PageTable*>(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<uint32_t>(flags);
/*
Console::main <<
"Mapping " << virt << " -> " << phys << " [" << bin(static_cast<int>(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<uint32_t>(VMMFlags::SystemAllocated)) {
PMM::free(physical_t(this->pages[i] & 0xFFFFF000));
}
}
}