started a bit of paging for x64

This commit is contained in:
Morten Delenk 2017-12-09 19:38:55 +00:00
parent 3f83577f8f
commit c061f9e30c
10 changed files with 456 additions and 131 deletions

View file

@ -2,6 +2,7 @@
#include <base.hpp>
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();
}

View file

@ -0,0 +1,91 @@
#pragma once
#include <stdint.h>
#include <pmm.hpp>
#include <regs.h>
#include <paging.hpp>
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);
};

View file

@ -0,0 +1,30 @@
#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) {
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;
}
}

View file

@ -17,9 +17,12 @@ CGATerm term;
VESAfb term(mb_info);
#endif
PMM_MB lpmm(mb_info);
#include<paging.hpp>
void main();
extern "C" void start(int eax, multiboot_info_t *ebx) {
mb_info = ebx;
context_enabled=false;
main();
}
void drivers_init() {

View file

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

View file

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

View file

@ -1,10 +1,14 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
class PMM;
#include <base.hpp>
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`
*/

View file

@ -1,131 +1,7 @@
#include <base.hpp>
#include <pmm.hpp>
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<<bit);
auto x = first_free;
first_free += page_size;
return x;
}
//Now we need to find a free page with n-1 free pages after it
phys_t linear_start = first_free;
phys_t length = (no_pages-1) * page_size;
while(true) {
bool found=true;
while(!(linear_start in *this)) {
linear_start += page_size;
if((linear_start > 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<<bit);
pageno++;
}
return linear_start;
}
}
auto PMM::operator()(phys_t pages, size_t no_pages) -> void {
phys_t pageno = pages / page_size;
if(pages < first_free)
first_free = pages;
for(size_t i=0; i<no_pages; i++, pages+=page_size) {
if(!isFree(pages))
continue;
phys_t index = pageno >> 5;
phys_t bit = pageno & 31;
pmm_bitmap[index] |= 1<<bit;
pageno++;
}
}
auto PMM::operator&&(phys_t page) -> 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<<bit)))
return false;
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 {
return mm && a;
}
#ifdef BITS == 64
#include "pmm64.hpp"
#else
#include "pmm32.hpp"
#endif

131
kernel/src/pmm32.hpp Normal file
View file

@ -0,0 +1,131 @@
#include <base.hpp>
#include <pmm.hpp>
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<<bit);
auto x = first_free;
first_free += page_size;
return x;
}
//Now we need to find a free page with n-1 free pages after it
phys_t linear_start = first_free;
phys_t length = (no_pages-1) * page_size;
while(true) {
bool found=true;
while(!(linear_start in *this)) {
linear_start += page_size;
if((linear_start > 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<<bit);
pageno++;
}
return linear_start;
}
}
auto PMM::operator()(phys_t pages, size_t no_pages) -> void {
phys_t pageno = pages / page_size;
if(pages < first_free)
first_free = pages;
for(size_t i=0; i<no_pages; i++, pages+=page_size) {
if(!isFree(pages))
continue;
phys_t index = pageno >> 5;
phys_t bit = pageno & 31;
pmm_bitmap[index] |= 1<<bit;
pageno++;
}
}
auto PMM::operator&&(phys_t page) -> 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<<bit)))
return false;
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 {
return mm && a;
}

143
kernel/src/pmm64.hpp Normal file
View file

@ -0,0 +1,143 @@
#include <pmm.hpp>
#include <paging.hpp>
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<i+no_pages*page_size; j+=page_size) {
if(not (j in self)) {
i+=(no_pages-1)*page_size;
goto outlbl;
}
}
//if we are here, we found it
for(phys_t j = i; j<=i+no_pages*page_size; j+=page_size) {
setUsed(j);
}
return i;
outlbl:
continue;
}
}
auto PMM::operator()(phys_t pages, size_t no_pages) -> 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;
}