added paging to x86

This commit is contained in:
Morten Delenk 2017-09-03 09:56:58 +01:00
parent 4459db2f02
commit 3f83577f8f
12 changed files with 502 additions and 9 deletions

View file

@ -1,3 +1,3 @@
SET(PLATFORM_C_FLAGS "-I../../kernel/arch/arm/include") SET(ISA_C_FLAGS "-I../../kernel/arch/arm/include")
SET(PLATFORM_CXX_FLAGS "${PLATFORM_C_FLAGS}") SET(ISA_CXX_FLAGS "${ISA_C_FLAGS}")
SET(PLATFORM_ASM_FLAGS "${PLATFORM_C_FLAGS}") SET(ISA_ASM_FLAGS "${ISA_C_FLAGS}")

View file

@ -0,0 +1,52 @@
#pragma once
#include <stdint.h>
#include <pmm.hpp>
#include <regs.h>
#include <paging.hpp>
struct pagedir {
bool active:1;
bool writeable:1;
bool privileged:1;
bool no_write_cache:1;
bool no_read_cache:1;
bool accessed:1;
bool ignored:1;
bool size:1;
bool ignored2:1;
uint8_t ignored3:3;
phys_t pagetable:20;
}__attribute__((packed));
static_assert(sizeof(pagedir)==4);
struct pagetbl {
bool active:1;
bool writeable:1;
bool privileged:1;
bool no_write_cache:1;
bool no_read_cache:1;
bool accessed:1;
bool written:1;
bool pat:1;
bool no_flush_after_cr3:1;
uint8_t ignored:2;
bool lazy:1;
phys_t page:20;
}__attribute__((packed));
static_assert(sizeof(pagetbl)==4);
struct paging_context_x86: public paging_context {
phys_t pagedir_addr;
paging_context_x86();
virtual ~paging_context_x86();
virtual void switch_context();
virtual void map_pagetable(struct paging_context *);
virtual void *mmap(phys_t addr, void *dest, protection prot=protection::RW, bool lazy=true);
virtual void munmap(void *addr);
virtual bool is_mapped(void *addr);
virtual void mprotect(void *addr, protection prot);
virtual bool has_no_exec();
virtual void *get_exception_address(cpu_state *cpu);
virtual bool lazymap(void *addr, cpu_state *cpu);
pagedir * operator*();
pagetbl * operator[](phys_t);
};

347
kernel/arch/x86/paging.cpp Normal file
View file

@ -0,0 +1,347 @@
#include <paging.h>
#include <base.hpp>
extern int kernel_start;
extern int kernel_end;
paging_context_x86::paging_context_x86(): paging_context() {
*pmm >> pagedir_addr;
if(context_enabled) {
//Copy System section (first 256 entries) over to the new context
current_context->mmap(pagedir_addr, (void*)0x401000, protection::RW, false);
pagedir *src=(pagedir *)0x400000;
pagedir *dest=(pagedir *)0x401000;
for(int i=0;i<256;i++)
dest[i]=src[i];
for(int i=256;i<1024;i++)
dest[i].active=false;
//remap self-map correctly
dest[1].active=false;
dest[2].active=false;
dest[3].active=false;
phys_t selfmap_meta;
*pmm >> selfmap_meta;
dest[1].pagetable = selfmap_meta >> 12;
dest[1].writeable = true;
dest[1].privileged = false;
dest[1].no_write_cache = true;
dest[1].no_read_cache = false;
dest[1].size = false;
dest[1].active = true;
phys_t selfmap;
*pmm >> selfmap;
dest[2].pagetable = selfmap >> 12;
dest[2].writeable = true;
dest[2].privileged = false;
dest[2].no_write_cache = true;
dest[2].no_read_cache = false;
dest[2].size = false;
dest[2].active = true;
current_context->map_pagetable(this);
//Remap all parts of the system
for(int i=0;i<256;i++) {
if(!src[i].active)
continue;
if(i == 1 || i == 2 || i == 3)
continue;
pagetbl *pagetbl_start = (pagetbl *)(0x800000 + i << 22);
for(int j=0;j<1024;j++) {
if(!pagetbl_start[j].active)
continue;
mmap(pagetbl_start[j].page << 12, pagetbl_start+1024, protection::RW, false);
}
}
return;
}
//Map the entire kernel
pagedir *context=(pagedir *)pagedir_addr;
for(int i=0;i<1024;i++)
context[i].active=false;
phys_t kernel_tbl;
*pmm >> kernel_tbl;
context[0].pagetable=kernel_tbl >> 12;
context[0].writeable=true;
context[0].privileged=false;
context[0].no_write_cache=false;
context[0].no_read_cache=false;
context[0].size=false;
context[0].active=true;
pagetbl *kerneltbl = (pagetbl *)kernel_tbl;
for(int i=0;i<1024;i++)
kerneltbl[i].active=false;
for(phys_t i=((phys_t)&kernel_start)>>12,p = (phys_t)&kernel_start; p < (phys_t)&kernel_end; p+=0x1000, i++) {
kerneltbl[i].page=i;
kerneltbl[i].writeable=true;
kerneltbl[i].privileged=false;
kerneltbl[i].no_write_cache=false;
kerneltbl[i].no_read_cache=false;
kerneltbl[i].pat=false;
kerneltbl[i].no_flush_after_cr3=true;
kerneltbl[i].active=true;
}
//self-mapping page directory
phys_t pdir_selfmap_addr;
*pmm >> pdir_selfmap_addr;
context[1].pagetable = pdir_selfmap_addr >> 12;
context[1].writeable=true;
context[1].privileged=false;
context[1].no_write_cache=true;
context[1].no_read_cache=false;
context[1].size=false;
context[1].active=true;
pagetbl *pdir_selfmap=(pagetbl *)pdir_selfmap_addr;
for(int i=0;i<1024;i++) {
pdir_selfmap[i].active=false;
pdir_selfmap[i].lazy=false;
}
pdir_selfmap[0].page=pagedir_addr >> 12;
pdir_selfmap[0].writeable=true;
pdir_selfmap[0].privileged=false;
pdir_selfmap[0].no_write_cache=true;
pdir_selfmap[0].no_read_cache=false;
pdir_selfmap[0].pat=false;
pdir_selfmap[0].no_flush_after_cr3=false;
pdir_selfmap[0].active=true;
phys_t ptbl_selfmap_addr;
*pmm >> ptbl_selfmap_addr;
context[2].pagetable = ptbl_selfmap_addr>>12;
context[2].writeable=true;
context[2].privileged=false;
context[2].no_write_cache=true;
context[2].no_read_cache=false;
context[2].size=false;
context[2].active=true;
pagetbl *ptbl_selfmap=(pagetbl *)ptbl_selfmap_addr;
for(int i=0;i<1024;i++) {
ptbl_selfmap[i].active=false;
ptbl_selfmap[i].lazy=false;
}
//Create a self-map
for(int i=0;i<1024;i++) {
if(!context[i].active)
continue;
ptbl_selfmap[i].page = context[i].pagetable;
ptbl_selfmap[i].writeable=true;
ptbl_selfmap[i].privileged=false;
ptbl_selfmap[i].no_write_cache=true;
ptbl_selfmap[i].no_read_cache=false;
ptbl_selfmap[i].pat=false;
ptbl_selfmap[i].no_flush_after_cr3=false;
ptbl_selfmap[i].active=true;
}
}
paging_context_x86::~paging_context_x86() {
//Deallocate user space
pagedir *pd = (pagedir*)0x401000;
for(int i=256;i<1024;i++) {
if(!pd[i].active)
continue;
pagetbl *pt = (pagetbl*)(0xC00000+i<<12);
for(int j=0;j<1024;j++) {
if(!pt[j].active)
continue;
void * addr = (void *)((i<<22)+(j<<12));
munmap(addr);
}
munmap(pt);
*pmm << (pd[i].pagetable << 12);
}
//Deallocate selfmap
for(int i=1;i<3;i++) {
if(!pd[i].active)
continue;
pagetbl *pt = (pagetbl*)(0xC00000+i<<12);
for(int j=0;j<1024;j++) {
if(!pt[j].active)
continue;
void * addr = (void *)((i<<22)+(j<<12));
munmap(addr);
}
munmap(pt);
*pmm << (pd[i].pagetable << 12);
}
munmap(pd);
*pmm << pagedir_addr;
}
void paging_context_x86::switch_context() {
asm volatile("mov %0, %%cr3" :: "r"(pagedir_addr) : "memory");
if(!context_enabled) {
uint32_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= (1<<31);
asm volatile("mov %0, %%cr0" :: "r"(cr0) : "memory");
}
paging_context::switch_context();
}
void paging_context_x86::map_pagetable(struct paging_context *pc_t) {
paging_context_x86 *pc = (paging_context_x86*)pc_t;
mmap(pc->pagedir_addr, (void*)0x401000, protection::RW, false);
pagedir * pd = (pagedir*)0x401000;
for(int i=0;i<1024;i++) {
if(!pd[i].active)
continue;
mmap(pd[i].pagetable<<12, (void*)(0xC00000), protection::RW, false);
}
}
void *paging_context_x86::mmap(phys_t addr, void *dest, protection prot, bool lazy) {
if((!addr)&&(!lazy)) {
*pmm >> addr;
}
if(!dest) {
if(!lazy) {
for(phys_t i=16; i < 256; i++) {
if((**this)[i].active) {
for(phys_t j=0; j<1024; j++) {
if((*this)[i][j].active)
continue;
dest = (void*)((i<<22)|(j<<12));
}
continue;
}
dest = (void*)(i<<22);
}
} else {
for(phys_t i=256; i; i++) {
if((**this)[i].active) {
for(phys_t j=0; j<1024; j++) {
if((*this)[i][j].active)
continue;
if((*this)[i][j].lazy)
continue;
dest = (void*)((i<<22)|(j<<12));
}
continue;
}
dest = (void*)(i<<22);
}
}
}
if(!dest) {
panic("Not enough virtual memory is available for mmap()");
}
phys_t i=((phys_t)dest)>>22;
phys_t j=((phys_t)dest)>>12;
j&=0x3FF;
if(!(**this)[i].active) {
phys_t ptbl_addr;
*pmm >> ptbl_addr;
mmap(ptbl_addr, (*this)[i], protection::RW, false);
pagetbl *pent = (*this)[i];
for(int i=0;i<1024;i++)
pent[i].active=false;
pagedir *ptbl = &((**this)[i]);
ptbl->pagetable = ptbl_addr >> 12;
ptbl->writeable = true;
ptbl->privileged = (i < 256) ? false: true;
ptbl->no_write_cache = (i < 16) ? true : false;
ptbl->no_read_cache = false;
ptbl->size = false;
ptbl->active=true;
}
pagetbl *pent = (*this)[i] + j;
uint8_t p = (uint8_t)prot;
pent->page = addr >> 12;
pent->writeable = (p & 2)? true : false;
pent->privileged = (p & 4)? true : false;
pent->no_write_cache = (i < 16) ? true : false;
pent->no_read_cache = false;
pent->pat = false;
pent->no_flush_after_cr3 = false;
pent->lazy = lazy;
pent->active = !lazy;
if(current_context == this) {
asm volatile("invlpg %0" :: "m"(*(char*)dest) : "memory");
}
return dest;
}
void paging_context_x86::munmap(void *addr) {
phys_t i=((phys_t)addr)>>22;
phys_t j=((phys_t)addr)>>12;
j &= 0x3FF;
if(!(**this)[i].active)
return;
if(!(*this)[i][j].active)
(*this)[i][j].lazy = false;
*pmm << ((*this)[i][j].page << 12);
(*this)[i][j].active=false;
}
bool paging_context_x86::is_mapped(void *addr) {
phys_t i=((phys_t)addr)>>22;
phys_t j=((phys_t)addr)>>12;
j &= 0x3FF;
if(!(**this)[i].active)
return false;
return (*this)[i][j].active;
}
void paging_context_x86::mprotect(void *addr, protection prot) {
phys_t i=((phys_t)addr)>>22;
phys_t j=((phys_t)addr)>>12;
j &= 0x3FF;
if(!(**this)[i].active)
return;
if((!(*this)[i][j].active) && (!(*this)[i][j].lazy))
return;
pagetbl *pent= &((*this)[i][j]);
uint8_t p = (uint8_t)prot;
pent->writeable = (p & 2) ? true : false;
pent->privileged = (p & 4) ? true : false;
if(current_context == this)
asm volatile("invlpg %0" :: "m"(*(char*)addr) : "memory");
}
bool paging_context_x86::has_no_exec() {
return false;
}
void *paging_context_x86::get_exception_address(cpu_state *cpu) {
uint32_t cr2;
asm volatile("mov %%cr2, %0" : "=r"(cr2));
return (void*)cr2;
}
bool paging_context_x86::lazymap(void *addr, cpu_state *cpu) {
phys_t i=((phys_t)addr)>>22;
phys_t j=((phys_t)addr)>>12;
j &= 0x3FF;
if(!(**this)[i].active)
return false;
if((*this)[i][j].active)
return false;
if(!(*this)[i][j].lazy)
return false;
phys_t page;
*pmm >> page;
pagetbl *pent = &((*this)[i][j]);
pent->page = page >> 12;
pent->lazy = false;
pent->active = true;
return true;
}
pagedir * paging_context_x86::operator*() {
if(current_context == this)
return (pagedir*)0x400000;
return (pagedir*)0x401000;
}
pagetbl * paging_context_x86::operator[](phys_t i) {
if(current_context == this)
return (pagetbl *)(0x800000+(i<<12));
return (pagetbl *)(0xC00000+(i<<12));
}

View file

@ -1,3 +1,3 @@
SET(PLATFORM_C_FLAGS "-I../../kernel/arch/x86/pc/include -O2") SET(PLATFORM_C_FLAGS "-I../../kernel/arch/x86/pc/include -O0")
SET(PLATFORM_CXX_FLAGS "${PLATFORM_C_FLAGS}") SET(PLATFORM_CXX_FLAGS "${PLATFORM_C_FLAGS}")
SET(PLATFORM_ASM_FLAGS "${PLATFORM_C_FLAGS}") SET(PLATFORM_ASM_FLAGS "${PLATFORM_C_FLAGS}")

View file

@ -8,6 +8,7 @@
#include "../../../hw/pc/8259/pic.hpp" #include "../../../hw/pc/8259/pic.hpp"
#include "../../../hw/pc/idt/idt.hpp" #include "../../../hw/pc/idt/idt.hpp"
#include "../../../hw/pc/pmm/pmm.hpp" #include "../../../hw/pc/pmm/pmm.hpp"
#include <paging.h>
#include <base.hpp> #include <base.hpp>
static multiboot_info_t *mb_info; static multiboot_info_t *mb_info;
@ -17,6 +18,8 @@ CGATerm term;
VESAfb term(mb_info); VESAfb term(mb_info);
#endif #endif
PMM_MB lpmm(mb_info); PMM_MB lpmm(mb_info);
paging_context_x86 main_context;
void main(); void main();
extern "C" void start(int eax, multiboot_info_t *ebx) { extern "C" void start(int eax, multiboot_info_t *ebx) {
mb_info = ebx; mb_info = ebx;
@ -27,6 +30,13 @@ void drivers_init() {
setMainTTY(&term); setMainTTY(&term);
--term; --term;
initIDT(); initIDT();
main_context.switch_context();
main_context.mmap((phys_t)mb_info, mb_info, protection::RW, false);
phys_t start_fb = (phys_t)(mb_info->framebuffer_addr);
phys_t end_fb = start_fb + mb_info->framebuffer_height * mb_info->framebuffer_pitch;
for(phys_t i=start_fb; i<end_fb; i+=0x1000) {
main_context.mmap(i, (void*)i, protection::RW, false);
}
PIC::initPIC(0x20, 0x28); PIC::initPIC(0x20, 0x28);
asm volatile("sti"); asm volatile("sti");
} }

View file

@ -45,6 +45,7 @@ int_handler.write(" push %esp\n jmp panic2\n")
int_handler.write(".section .data\n"+data_section) int_handler.write(".section .data\n"+data_section)
print("Generating cpu_state struct") print("Generating cpu_state struct")
reg_struct.write("#pragma once\n")
reg_struct.write("#include <stdint.h>\n") reg_struct.write("#include <stdint.h>\n")
if config["ENABLE_FPU"] and not config["ENABLE_SSE"]: if config["ENABLE_FPU"] and not config["ENABLE_SSE"]:
reg_struct.write("struct fpu_state {\n") reg_struct.write("struct fpu_state {\n")

View file

@ -9,3 +9,4 @@ else:
add_driver(False, "8259") add_driver(False, "8259")
add_driver(False, "idt") add_driver(False, "idt")
add_driver(False, "pmm") add_driver(False, "pmm")

View file

@ -28,7 +28,7 @@ auto PMM_MB::isFree(phys_t addr) -> bool {
} }
if(!free) if(!free)
return false; return false;
if(addr == (phys_t)((uintptr_t)mb_info)) if((addr >= (phys_t)((uintptr_t)mb_info)) && (addr < (phys_t)((uintptr_t)mb_info)+0x1000))
return false; return false;
return PMM::isFree(addr); return PMM::isFree(addr);
} }

View file

@ -0,0 +1,32 @@
#pragma once
#include <stdint.h>
#include <pmm.hpp>
#include <regs.h>
enum class protection: uint8_t {
NONE=0,
X=1,
W=2,
WX=3,
R=4,
RX=5,
RW=6,
RWX=7
};
struct paging_context {
paging_context();
virtual ~paging_context();
virtual void switch_context();
virtual void map_pagetable(struct paging_context *);
virtual void* mmap(phys_t addr, void* dest, protection prot=protection::RW, bool lazy=true);
virtual void munmap(void* addr);
virtual bool is_mapped(void* addr);
virtual void mprotect(void* addr, protection prot);
virtual bool has_no_exec();
virtual void *get_exception_address(cpu_state *cpu);
virtual bool lazymap(void* addr, cpu_state *cpu);
};
extern paging_context *current_context;
extern bool context_enabled;

View file

@ -20,10 +20,11 @@ class PMM {
PMM(phys_t page_size); PMM(phys_t page_size);
virtual ~PMM(); virtual ~PMM();
virtual auto operator<<(phys_t page) -> PMM &; ///< Frees a page. O(1) virtual auto operator<<(phys_t page) -> PMM &; ///< Frees a page. O(1)
virtual auto operator>>(phys_t &page) -> PMM &; ///< Allocates a page. O(1) virtual auto operator>>(phys_t &page) -> PMM &; ///< Allocates a page. Probably O(log n)
virtual auto operator,(size_t no_pages) -> phys_t; ///< Allocates multiple pages. O(n²) virtual auto operator,(size_t no_pages) -> phys_t; ///< Allocates multiple pages. O(n)
virtual auto operator()(phys_t pages,size_t no_pages) -> void; ///< Deallocates multiple pages. O(n) virtual auto operator()(phys_t pages,size_t no_pages) -> void; ///< Deallocates multiple pages. O(n)
virtual auto operator&&(phys_t page) -> bool; //Returns true if this page is free. O(n). virtual auto operator&&(phys_t page) -> bool; //Returns true if this page is free. O(1).
virtual auto setUsed(phys_t page) -> void; //Marks a page as used. O(1).
}; };
/** /**
* This definition is for having a python-like syntax - like `page in pmm` * This definition is for having a python-like syntax - like `page in pmm`

36
kernel/src/paging.cpp Normal file
View file

@ -0,0 +1,36 @@
#include <paging.hpp>
paging_context *current_context(nullptr);
bool context_enabled=false;
paging_context::paging_context() {}
paging_context::~paging_context() {}
void paging_context::switch_context() {
current_context = this;
context_enabled = true;
}
void paging_context::map_pagetable(struct paging_context *) {}
void* paging_context::mmap(phys_t addr, void* dest, protection prot, bool lazy) {
return nullptr;
}
void paging_context::munmap(void *addr) {}
bool paging_context::is_mapped(void *addr) {
return false;
}
void paging_context::mprotect(void *addr, protection prot) {}
bool paging_context::has_no_exec() {
return false;
}
void *paging_context::get_exception_address(cpu_state *cpu) {
return nullptr;
}
bool paging_context::lazymap(void *addr, cpu_state *cpu) {
return false;
}

View file

@ -16,7 +16,12 @@ auto PMM::isFree(phys_t addr) -> bool {
return false; return false;
return true; return true;
} }
PMM::PMM(phys_t page_size): page_size(page_size), first_free(0), lowest_page(~0), highest_page(0) {} PMM::PMM(phys_t page_size): page_size(page_size), first_free(0), lowest_page(~0), highest_page(0) {
for(int i=0;i<32768;i++) {
pmm_bitmap[i]=0;
}
pmm = this;
}
void PMM::fill() { void PMM::fill() {
for(phys_t i=highest_page; i>=lowest_page && i; i-=page_size) { for(phys_t i=highest_page; i>=lowest_page && i; i-=page_size) {
if(isFree(i)) if(isFree(i))
@ -97,6 +102,8 @@ auto PMM::operator()(phys_t pages, size_t no_pages) -> void {
if(pages < first_free) if(pages < first_free)
first_free = pages; first_free = pages;
for(size_t i=0; i<no_pages; i++, pages+=page_size) { for(size_t i=0; i<no_pages; i++, pages+=page_size) {
if(!isFree(pages))
continue;
phys_t index = pageno >> 5; phys_t index = pageno >> 5;
phys_t bit = pageno & 31; phys_t bit = pageno & 31;
pmm_bitmap[index] |= 1<<bit; pmm_bitmap[index] |= 1<<bit;
@ -113,6 +120,12 @@ auto PMM::operator&&(phys_t page) -> bool {
return false; return false;
return true; return true;
} }
auto PMM::setUsed(phys_t page) -> void {
phys_t pageno = page / page_size;
phys_t index = pageno >> 5;
phys_t bit = pageno & 31;
pmm_bitmap[index] &= ~(1<<bit);
}
auto operator&&(phys_t a, PMM mm) -> bool { auto operator&&(phys_t a, PMM mm) -> bool {
return mm && a; return mm && a;
} }