Adds virtual memory management with paging :)
This commit is contained in:
parent
e97921e246
commit
455a6db8b5
9 changed files with 292 additions and 14 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
18
prototypes/base/include/pagedirectory.hpp
Normal file
18
prototypes/base/include/pagedirectory.hpp
Normal 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");
|
17
prototypes/base/include/pagetable.hpp
Normal file
17
prototypes/base/include/pagetable.hpp
Normal 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");
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue