161 lines
4.8 KiB
C++
161 lines
4.8 KiB
C++
#include "../memory/pageframealloc.h"
|
|
#include "../boot/multiboot/data.h"
|
|
#include "page.h"
|
|
#include "pageframe.h"
|
|
#include "../debug/output.h"
|
|
|
|
#include "../memory/config.h"
|
|
#include "../arch/lapic.h"
|
|
#include "../arch/apic.h"
|
|
|
|
//uint8_t PageFrameAllocator::bitmap[4294967296 / 4096 / 8];
|
|
PageFrame PageFrameAllocator::PageFrames[4294967296 / 4096];
|
|
Queue<PageFrame> user_memory_q;
|
|
Queue<PageFrame> kernel_memory_q;
|
|
|
|
void mark_pageframes(uintptr_t start, uintptr_t end, bool available){
|
|
// DBG << "start: " << hex << start << " end: " << end;
|
|
start = Page::floor(start);
|
|
end = Page::ceil(end);
|
|
if(start > 4294967296)
|
|
start = 4294967296;
|
|
if(end > 4294967296)
|
|
end = 4294967296;
|
|
|
|
if(start < 0x4000000 && end > 0x4000000){
|
|
mark_pageframes(start, 0x4000000, available);
|
|
mark_pageframes(0x4000000, end, available);
|
|
}
|
|
|
|
//DBG << " page start: " << hex << start << " end: " << end << endl;
|
|
Queue<PageFrame>* q = start<0x4000000?&kernel_memory_q:&user_memory_q;
|
|
|
|
for(uint64_t i = start; i < end; i += 4096){
|
|
uint64_t pg = i/4096;
|
|
|
|
PageFrameAllocator::PageFrames[pg].available = available;
|
|
|
|
if(available)
|
|
q->enqueue(PageFrameAllocator::PageFrames[pg]);
|
|
else
|
|
q->remove(&PageFrameAllocator::PageFrames[pg]);
|
|
}
|
|
}
|
|
|
|
void PageFrameAllocator::init(){
|
|
Multiboot::Memory* memory_map_start = Multiboot::getMemoryMap();
|
|
Multiboot::Memory* memory_map_entry = memory_map_start;
|
|
|
|
//mark as available
|
|
while(memory_map_entry != 0){
|
|
uintptr_t start = (uintptr_t)memory_map_entry->getStartAddress();
|
|
uintptr_t end = (uintptr_t)memory_map_entry->getEndAddress();
|
|
bool available = memory_map_entry->isAvailable();
|
|
|
|
if(available){
|
|
if(start < (uintptr_t)&___KERNEL_END___)
|
|
start = Page::ceil((uintptr_t)&___KERNEL_END___ +1);
|
|
|
|
mark_pageframes(start, end, available);
|
|
}
|
|
|
|
memory_map_entry = memory_map_entry->getNext();
|
|
}
|
|
|
|
//mark as unavailable
|
|
memory_map_entry = memory_map_start;
|
|
while(memory_map_entry != 0){
|
|
uintptr_t start = (uintptr_t)memory_map_entry->getStartAddress();
|
|
uintptr_t end = (uintptr_t)memory_map_entry->getEndAddress();
|
|
bool available = memory_map_entry->isAvailable();
|
|
|
|
if(!available){
|
|
mark_pageframes(start, end, available);
|
|
}
|
|
|
|
memory_map_entry = memory_map_entry->getNext();
|
|
}
|
|
|
|
for (size_t i = 0; i < Multiboot::getModuleCount(); ++i) {
|
|
Multiboot::Module* mod = Multiboot::getModule(i);
|
|
if (!mod) continue;
|
|
|
|
mark_pageframes((uintptr_t)mod, (uintptr_t)mod + 1, false);
|
|
mark_pageframes((uintptr_t)mod->getStartAddress(),
|
|
(uintptr_t)mod->getEndAddress(),
|
|
false);
|
|
}
|
|
|
|
|
|
|
|
|
|
//mark other known regions as unavailable
|
|
mark_pageframes((uintptr_t)&___KERNEL_START___, (uintptr_t)&___KERNEL_END___, false);
|
|
|
|
mark_pageframes(0x00F00000, 0x00FFFFFF, false);
|
|
|
|
mark_pageframes(0xfee00000, 0xfee003f0, false);
|
|
|
|
mark_pageframes(APIC::getIOAPICAddress(), APIC::getIOAPICAddress()+0x10, false);
|
|
|
|
}
|
|
|
|
void PageFrameAllocator::stats(){
|
|
Multiboot::Memory* memory_map_entry = Multiboot::getMemoryMap();
|
|
while(memory_map_entry != 0){
|
|
void* start = memory_map_entry->getStartAddress();
|
|
void* end = memory_map_entry->getEndAddress();
|
|
bool available = memory_map_entry->isAvailable();
|
|
DBG << "Memory: " << hex << start << " to " << end << " is available: " << available << "." << endl;
|
|
memory_map_entry = memory_map_entry->getNext();
|
|
}
|
|
|
|
uint64_t pages_available = 0;
|
|
for(uint64_t i=0; i<(sizeof(PageFrames)/sizeof(PageFrames[0]));i++){
|
|
if(PageFrames[i].available)
|
|
//if(bitmap[i/8] & (1<<i%8))
|
|
pages_available++;
|
|
}
|
|
for(uint64_t i=0; i < 0x8000000/4096/8; i+=4){
|
|
if(i%(64*4) == 0){
|
|
DBG << endl << hex << i * 8 * 4096 << " " << flush;
|
|
int x,y;
|
|
dout.getPos(x,y);
|
|
for(uint8_t j=x; j<10; j++){
|
|
DBG<<" ";
|
|
}
|
|
}
|
|
|
|
if(PageFrames[i].available)
|
|
DBG << '#';
|
|
else
|
|
DBG << '.';
|
|
}
|
|
DBG << "\npages available: " << dec << pages_available << endl;
|
|
|
|
}
|
|
|
|
void* PageFrameAllocator::alloc(bool kernel){
|
|
Queue<PageFrame>* q = kernel?&kernel_memory_q:&user_memory_q;
|
|
PageFrame* free_pageframe = q->dequeue();
|
|
|
|
if(!free_pageframe)
|
|
return 0;
|
|
|
|
free_pageframe->available = false;
|
|
|
|
uintptr_t addr = ((free_pageframe - &PageFrames[0]))<<12;
|
|
|
|
mark_pageframes(addr, addr+1, false);
|
|
return (void*)(addr);
|
|
}
|
|
|
|
void PageFrameAllocator::free(PageFrame* frame){
|
|
frame->available = true;
|
|
//TODO ref counter etc...
|
|
}
|
|
|
|
void PageFrameAllocator::free(uintptr_t addr){
|
|
free(&PageFrames[addr>>12]);
|
|
}
|