From c061f9e30c767a314c399548a621f5355fe78ded Mon Sep 17 00:00:00 2001 From: Morten Delenk Date: Sat, 9 Dec 2017 19:38:55 +0000 Subject: [PATCH] started a bit of paging for x64 --- kernel/arch/x86/paging.cpp | 13 +++ kernel/arch/x86_64/include/paging.h | 91 ++++++++++++++++++ kernel/arch/x86_64/paging.cpp | 30 ++++++ kernel/arch/x86_64/pc/start.cpp | 3 + kernel/hw/pmm/pmm.cpp | 4 +- kernel/src/include/base.hpp | 6 ++ kernel/src/include/pmm.hpp | 32 +++++++ kernel/src/pmm.cpp | 134 +------------------------- kernel/src/pmm32.hpp | 131 +++++++++++++++++++++++++ kernel/src/pmm64.hpp | 143 ++++++++++++++++++++++++++++ 10 files changed, 456 insertions(+), 131 deletions(-) create mode 100644 kernel/arch/x86_64/include/paging.h create mode 100644 kernel/arch/x86_64/paging.cpp create mode 100644 kernel/src/pmm32.hpp create mode 100644 kernel/src/pmm64.hpp diff --git a/kernel/arch/x86/paging.cpp b/kernel/arch/x86/paging.cpp index 2c77eda..5dec4d3 100644 --- a/kernel/arch/x86/paging.cpp +++ b/kernel/arch/x86/paging.cpp @@ -2,6 +2,7 @@ #include extern int kernel_start; extern int kernel_end; +pagedir global_kernel[256]; paging_context_x86::paging_context_x86(): paging_context() { *pmm >> pagedir_addr; if(context_enabled) { @@ -175,12 +176,24 @@ paging_context_x86::~paging_context_x86() { } void paging_context_x86::switch_context() { + pagedir* p = (pagedir*)pagedir_addr; + if(context_enabled) + p=(pagedir*)0x400000; + for(int i = 0; i < 256; i++) { + global_kernel[i]=p[i]; + } 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"); + } else { + for(int i=0;i<256;i++) + if((i>=1)&&(i<=3)) + continue; + else + p[i]=global_kernel[i]; } paging_context::switch_context(); } diff --git a/kernel/arch/x86_64/include/paging.h b/kernel/arch/x86_64/include/paging.h new file mode 100644 index 0000000..601c03f --- /dev/null +++ b/kernel/arch/x86_64/include/paging.h @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include +#include +typedef phys_t virt_t; +struct pagemap_tbl { + bool active:1; + bool writable:1; + bool unprivileged:1; + bool no_write_cache:1; + bool no_read_cache:1; + bool accessed:1; + uint8_t sbz:3; + uint8_t ignored:3; + phys_t pagemap:40; + uint16_t ignored2:11; + bool executable:1; + +}__attribute__((packed)); +static_assert(sizeof(pagemap_tbl)==8); + +struct pagemap { + bool active:1; + bool writable:1; + bool unprivileged:1; + bool no_write_cache:1; + bool no_read_cache:1; + bool accessed:1; + bool sbz:1; + bool _1G_page:1; + bool global:1; + uint8_t ignored:3; + phys_t pagedir:40; + uint16_t ignored2:11; + bool executable:1; +}__attribute__((packed)); +static_assert(sizeof(pagemap)==8); + +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 sbz:1; + bool _2M_page:1; + bool global:1; + uint8_t ignored:3; + phys_t pagetbl:40; + uint16_t ignored2:11; + bool executable:1; +}__attribute__((packed)); +static_assert(sizeof(pagedir)==8); + +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 sbz:1; + bool pat:1; + bool global:1; + uint8_t ignored:2; + bool lazy:1; + phys_t page:40; + uint16_t ignored2:11; + bool executable:1; +} +}__attribute__((packed)); + + +struct paging_context_x86: public paging_context { + phys_t pagemaptbl_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); +}; diff --git a/kernel/arch/x86_64/paging.cpp b/kernel/arch/x86_64/paging.cpp new file mode 100644 index 0000000..a7acf48 --- /dev/null +++ b/kernel/arch/x86_64/paging.cpp @@ -0,0 +1,30 @@ +#include +#include +extern int kernel_start; +extern int kernel_end; + + + +paging_context_x86::paging_context_x86(): paging_context() { + *pmm >> pagedir_addr; + if(context_enabled) { + current_context->mmap(pagedir_addr, (void*)0x800000, protection::RW, false); + pagemap *src=(pagemap *)0x400000; + pagemap *dest=(pagedir*)0x600000; + for(int i=0;i<256;i++) + dest[i]=src[i]; + for(int i=256;i<512;i++) + dest[i].active=false; + dest[0].active=false; + phys_t first_pagedir; + *pmm >> first_pagedir; + dest[0].pagetable = first_pagedir >> 12; + dest[0].writeable=true; + dest[0].unprivileged=false; + dest[0].no_write_cache=true; + dest[0].no_read_cache=false; + dest[0].sbz=0; + dest[0].active=true; + + } +} diff --git a/kernel/arch/x86_64/pc/start.cpp b/kernel/arch/x86_64/pc/start.cpp index ff3a5a4..6771cd2 100644 --- a/kernel/arch/x86_64/pc/start.cpp +++ b/kernel/arch/x86_64/pc/start.cpp @@ -17,9 +17,12 @@ CGATerm term; VESAfb term(mb_info); #endif PMM_MB lpmm(mb_info); + +#include void main(); extern "C" void start(int eax, multiboot_info_t *ebx) { mb_info = ebx; + context_enabled=false; main(); } void drivers_init() { diff --git a/kernel/hw/pmm/pmm.cpp b/kernel/hw/pmm/pmm.cpp index 4d26da6..e5407f7 100644 --- a/kernel/hw/pmm/pmm.cpp +++ b/kernel/hw/pmm/pmm.cpp @@ -58,7 +58,7 @@ union MMAPTag { uint8_t id; uint8_t size; uint8_t value; - }__attribute__((packed)) BITS; + }__attribute__((packed)) BITSi; struct { uint8_t id; uint8_t size; @@ -108,7 +108,7 @@ PMM_MMAP::PMM_MMAP(): PMM(0x1000) { ; break; case 4: - bits = tag.BITS.value; + bits = tag.BITSi.value; break; case 5: if(tag.REGION.permission != PERM::RWX) diff --git a/kernel/src/include/base.hpp b/kernel/src/include/base.hpp index f6862c6..b665804 100644 --- a/kernel/src/include/base.hpp +++ b/kernel/src/include/base.hpp @@ -21,3 +21,9 @@ extern "C" void panic(const char* s); #define __BIG_ENDIAN__ #endif #endif + +#ifdef __x86_64__ +#define BITS 64 +#else +#define BITS 32 +#endif diff --git a/kernel/src/include/pmm.hpp b/kernel/src/include/pmm.hpp index 5327b4b..3a33b46 100644 --- a/kernel/src/include/pmm.hpp +++ b/kernel/src/include/pmm.hpp @@ -1,10 +1,14 @@ #pragma once #include #include +class PMM; +#include typedef uintptr_t phys_t; ///< Type used for physical addresses /** * A single entry in the PMM list */ + +#if BITS == 32 /** * Physical memory manager. It stores the free memory in a linked list */ @@ -26,6 +30,34 @@ class PMM { 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). }; + +#else + +struct pmm_entry { + phys_t next; + phys_t last; +}; + +class PMM { + protected: + phys_t head; + virtual auto isFree(phys_t address) -> bool; + auto fill() -> void; + phys_t page_size, lowest_page, highest_page; + void push(phys_t); + phys_t pop(); + public: + PMM(phys_t page_size); + virtual ~PMM(); + virtual auto operator<<(phys_t page) -> PMM &; + virtual auto operator>>(phys_t &page) -> PMM &; + virtual auto operator,(size_t no_pages) -> phys_t; + virtual auto operator()(phys_t pages, size_t no_pages) -> void; + virtual auto operator&&(phys_t page) -> bool; + virtual auto setUsed(phys_t page) -> void; +}; + +#endif /** * This definition is for having a python-like syntax - like `page in pmm` */ diff --git a/kernel/src/pmm.cpp b/kernel/src/pmm.cpp index f0e85df..dca798b 100644 --- a/kernel/src/pmm.cpp +++ b/kernel/src/pmm.cpp @@ -1,131 +1,7 @@ #include -#include -extern "C" int kernel_start; -extern "C" int kernel_end; - -uint32_t pmm_bitmap[32768]; - - -auto PMM::isFree(phys_t addr) -> bool { - if(addr == 0) - return false; - phys_t start = (phys_t)(&kernel_start); - phys_t end = (phys_t)(&kernel_end); - if((addr >= start) && (addr < end)) - return false; - return true; -} -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() { - for(phys_t i=highest_page; i>=lowest_page && i; i-=page_size) { - if(isFree(i)) - *this << i; - } -} -PMM::~PMM() {} - -auto PMM::operator<<(phys_t page) -> PMM & { - (*this)(page,1); - return *this; -} -auto PMM::operator>>(phys_t &page) -> PMM & { - page = (*this, 1); - return *this; -} - -auto PMM::operator,(size_t no_pages) -> phys_t { - if(first_free > highest_page) - panic("No free physical memory is available."); - if(no_pages == 1) { - while(!(first_free in *this)) { - first_free += page_size; - if(first_free > highest_page) - panic("No free physical memory is available."); - } - phys_t pageno = first_free / page_size; - phys_t index = pageno >> 5; - phys_t bit = pageno & 31; - pmm_bitmap[index] &= ~(1< highest_page)||(linear_start+length > highest_page)) - panic("No free physical memory is available."); - } - if(!((linear_start + length) in *this)) { - linear_start += no_pages * page_size; - } - //We're on to something - phys_t i; - for(i=linear_start; i < linear_start + length; i+=page_size) { - if(!(i in *this)) { - found=false; - break; - } - } - if(!found) { - linear_start=i+page_size; - continue; - } - //Set the first_free variable correctly when the first page was a hit - if(linear_start == first_free) - first_free += length + page_size; - - phys_t pageno = linear_start / page_size; - - for(i=linear_start; i <= linear_start + length; i+= page_size) { - phys_t index = pageno >> 5; - phys_t bit = pageno & 31; - pmm_bitmap[index] &= ~(1< void { - phys_t pageno = pages / page_size; - if(pages < first_free) - first_free = pages; - for(size_t i=0; i> 5; - phys_t bit = pageno & 31; - pmm_bitmap[index] |= 1< bool { - phys_t pageno = page / page_size; - phys_t index = pageno >> 5; - if(!pmm_bitmap[index]) - return false; - phys_t bit = pageno & 31; - if(!(pmm_bitmap[index] & (1< void { - phys_t pageno = page / page_size; - phys_t index = pageno >> 5; - phys_t bit = pageno & 31; - pmm_bitmap[index] &= ~(1< bool { - return mm && a; -} +#ifdef BITS == 64 +#include "pmm64.hpp" +#else +#include "pmm32.hpp" +#endif diff --git a/kernel/src/pmm32.hpp b/kernel/src/pmm32.hpp new file mode 100644 index 0000000..f0e85df --- /dev/null +++ b/kernel/src/pmm32.hpp @@ -0,0 +1,131 @@ +#include +#include +extern "C" int kernel_start; +extern "C" int kernel_end; + + +uint32_t pmm_bitmap[32768]; + + +auto PMM::isFree(phys_t addr) -> bool { + if(addr == 0) + return false; + phys_t start = (phys_t)(&kernel_start); + phys_t end = (phys_t)(&kernel_end); + if((addr >= start) && (addr < end)) + return false; + return true; +} +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() { + for(phys_t i=highest_page; i>=lowest_page && i; i-=page_size) { + if(isFree(i)) + *this << i; + } +} +PMM::~PMM() {} + +auto PMM::operator<<(phys_t page) -> PMM & { + (*this)(page,1); + return *this; +} +auto PMM::operator>>(phys_t &page) -> PMM & { + page = (*this, 1); + return *this; +} + +auto PMM::operator,(size_t no_pages) -> phys_t { + if(first_free > highest_page) + panic("No free physical memory is available."); + if(no_pages == 1) { + while(!(first_free in *this)) { + first_free += page_size; + if(first_free > highest_page) + panic("No free physical memory is available."); + } + phys_t pageno = first_free / page_size; + phys_t index = pageno >> 5; + phys_t bit = pageno & 31; + pmm_bitmap[index] &= ~(1< highest_page)||(linear_start+length > highest_page)) + panic("No free physical memory is available."); + } + if(!((linear_start + length) in *this)) { + linear_start += no_pages * page_size; + } + //We're on to something + phys_t i; + for(i=linear_start; i < linear_start + length; i+=page_size) { + if(!(i in *this)) { + found=false; + break; + } + } + if(!found) { + linear_start=i+page_size; + continue; + } + //Set the first_free variable correctly when the first page was a hit + if(linear_start == first_free) + first_free += length + page_size; + + phys_t pageno = linear_start / page_size; + + for(i=linear_start; i <= linear_start + length; i+= page_size) { + phys_t index = pageno >> 5; + phys_t bit = pageno & 31; + pmm_bitmap[index] &= ~(1< void { + phys_t pageno = pages / page_size; + if(pages < first_free) + first_free = pages; + for(size_t i=0; i> 5; + phys_t bit = pageno & 31; + pmm_bitmap[index] |= 1< bool { + phys_t pageno = page / page_size; + phys_t index = pageno >> 5; + if(!pmm_bitmap[index]) + return false; + phys_t bit = pageno & 31; + if(!(pmm_bitmap[index] & (1< void { + phys_t pageno = page / page_size; + phys_t index = pageno >> 5; + phys_t bit = pageno & 31; + pmm_bitmap[index] &= ~(1< bool { + return mm && a; +} diff --git a/kernel/src/pmm64.hpp b/kernel/src/pmm64.hpp new file mode 100644 index 0000000..20d7d96 --- /dev/null +++ b/kernel/src/pmm64.hpp @@ -0,0 +1,143 @@ +#include +#include +extern "C" int kernel_start; +extern "C" int kernel_end; + +static inline void * map(phys_t addr) { + if(__builtin_expect(context_enabled, true)) + return current_context->mmap(addr, (void*)1, protection::RW, false); + return (void*)addr; +} +static inline void unmap(void* addr) { +/* if(__builtin_expect(context_enabled, true)) + current_context->munmap(addr);*/ +} + +auto PMM::isFree(phys_t addr) -> bool { + if(!addr) + return false; + auto start = (phys_t)(&kernel_start); + auto end = (phys_t)(&kernel_end); + if((addr >= start) && (addr < end)) + return false; + return true; +} + +void PMM::push(phys_t p) { + phys_t h=head; + auto ent=(pmm_entry*)map(p); + ent->next=head; + ent->last=0; + head=p; + unmap(ent); + ent=(pmm_entry*)map(h); + ent->last=p; + unmap(ent); +} +phys_t PMM::pop() { + phys_t p = head; + if(!p) + panic("oom"); + auto ent=(pmm_entry*)map(p); + head=ent->next; + unmap(ent); + ent=(pmm_entry*)map(head); + ent->last=0; + unmap(ent); + return p; +} + +PMM::PMM(phys_t page_size): page_size(page_size), head(0), lowest_page(~0), highest_page(0) { + pmm=this; +} +void PMM::fill() { + for(phys_t i=highest_page; i>=lowest_page && i; i-=page_size) { + if(isFree(i)) + *this << i; + } +} + +PMM::~PMM() {} + +auto PMM::operator<<(phys_t page) -> PMM & { + push(page); + return *this; +} +auto PMM::operator>>(phys_t &page) -> PMM& { + page=pop(); + return *this; +} +#define self (*this) +auto PMM::operator,(size_t no_pages) -> phys_t { + if(no_pages == 1) + return pop(); + for(phys_t i = lowest_page; i < highest_page; i+=page_size) { + if(not (i in self)) + continue; + if(not ((i+no_pages*page_size) in self)) { + i+=(no_pages-1)*page_size; + continue; + } + //we found something + for(phys_t j = i+page_size; j void { + for(phys_t i=pages; i<=pages+no_pages*page_size; i+=page_size) { + if(!isFree(i)) + continue; + push(i); + } +} + +auto PMM::operator&&(phys_t page) -> bool { + phys_t curr = head; + while(curr) { + if(curr == page) + return true; + auto ent = (pmm_entry *)map(curr); + curr = ent->next; + unmap(ent); + } + return false; +} + +auto PMM::setUsed(phys_t page) -> void { + if(head == page) { + pop(); + return; + } + if(not (page in self)) + return; + phys_t next, last; + auto ent = (pmm_entry*)map(page); + next=ent->next; + last=ent->last; + unmap(ent); + if(next) { + ent=(pmm_entry*)map(next); + ent->last=last; + unmap(ent); + } + if(last) { + ent=(pmm_entry*)map(last); + ent->next=next; + } +} + +auto operator&&(phys_t a, PMM mm) -> bool{ + return mm in a; +}