summaryrefslogblamecommitdiff
path: root/Source/Kernel/MemoryManager/Mem.ns.cpp
blob: 1d1288e68056bb06c447b8aabb08f3a03bf7d7d5 (plain) (tree)
1
2
3
4
5
6
7
8
                            
                                     


               
                                                

                                   



                                                      
                                             
                                  





                                                       


                                                                                   


                           


















































































































































                                                                                                                              

                                                           







                                                                            
                                         


































                                                                                                                                                                                          
                       



































                                                                                                        


 
#include <Core/common.wtf.h>
#include <MemoryManager/PhysMem.ns.h>

namespace Mem {

bool kheapUsable = false, pagingEnabled = false;
u32int placementAddress, kheapFree;

heap_index_t heapIndex;
u32int heapStart, heapEnd;

//Placement malloc, used while heap is not initialized
void *kallocInternal(u32int sz, bool align) {
	if (kheapUsable) return 0;
	if (align && (placementAddress & 0xFFFFF000)) {
		placementAddress &= 0xFFFFF000;
		placementAddress += 0x1000;
	}
	u32int temp = placementAddress;
	placementAddress += sz;
	for (u32int i = temp; i < placementAddress; i += 0x1000) {
		if (pagingEnabled) kernelPageDirectory->allocFrame(i, true, false);
	}
	return (void*)temp;
}

//***************************************************************************
//***                      HEAP INDEX FUNCTIONS                           ***
//***************************************************************************
void insertIntoHeapIndex(heap_header_t *e) {
	//If index is full, return
	if ((heapIndex.size * sizeof(heap_header_t*) + (u32int)heapIndex.data) >= heapStart) return;

	u32int iterator = 0;
	while (iterator < heapIndex.size && heapIndex.data[iterator]->size < e->size) {
		if (heapIndex.data[iterator] == e) return;
		iterator++;
	}
	if (iterator == heapIndex.size) {
		heapIndex.data[heapIndex.size++] = e;
	} else {
		u32int pos = iterator;
		iterator = heapIndex.size;
		while (iterator > pos) {
			heapIndex.data[iterator] = heapIndex.data[iterator - 1];
			iterator--;
		}
		heapIndex.size++;
		heapIndex.data[pos] = e;
	}
}

u32int heapIndexFindEntry(heap_header_t *e) {
	for (u32int  i = 0; i < heapIndex.size; i++) {
		if (heapIndex.data[i] == e)
			return i;
	}
	return (u32int) - 1;
}

void removeFromHeapIndex(u32int idx) {
	heapIndex.size--;
	while (idx < heapIndex.size) {
		heapIndex.data[idx] = heapIndex.data[idx + 1];
		idx++;
	}
}

void removeFromHeapIndex(heap_header_t *e) {
	u32int i = heapIndexFindEntry(e);
	if (i != (u32int) - 1) {
		removeFromHeapIndex(i);
	}
}

//***************************************************************************
//***                      MEMORY MANAGMENT FUNCTIONS                     ***
//***************************************************************************
void createHeap() {
	u32int heapIndexSize = PhysMem::total() * 64 + 0x10000;
	heapStart = placementAddress + 0x10000; //Set initial heap start
	heapEnd = heapStart + HEAP_MIN_SIZE + heapIndexSize;							//Set heap end

	//Alocate frames for the heap
	for (u32int i = placementAddress; i < heapEnd; i += 0x1000) {
		kernelPageDirectory->allocFrame(i, true, false);
	}

	heapIndex.data = (heap_header_t **)heapStart;		//Set index start
	heapIndex.size = 0;
	heapStart += heapIndexSize;	//Set some of available memory to be the index
	
	heap_header_t *hole = (heap_header_t*) heapStart;
	hole->size = (heapEnd - heapStart);
	hole->magic = HEAP_MAGIC;
	hole->is_hole = true;

	heap_footer_t *hole_footer = (heap_footer_t*) (heapEnd - sizeof(heap_footer_t));
	hole_footer->header = hole;
	hole_footer->magic = HEAP_MAGIC;

	insertIntoHeapIndex(hole);

	kheapUsable = true;
	kheapFree = (heapEnd - heapStart);
}

void expandHeap(u32int quantity) {
	if (quantity & 0x00000FFF)
		quantity = (quantity & 0xFFFFF000) + 0x1000;

	u32int newEnd = heapEnd + quantity;

	for (u32int i = heapEnd; i < newEnd; i++) {
		kernelPageDirectory->allocFrame(i, true, false);
	}

	heap_footer_t *last_footer = (heap_footer_t*) (heapEnd - sizeof(heap_footer_t));
	heap_header_t *last_header = last_footer->header;
	if (last_header->is_hole) {	//Last block of heap is a hole, update its size
		removeFromHeapIndex(last_header);
		last_header->size += quantity;

		last_footer = (heap_footer_t*) (newEnd - sizeof(heap_footer_t));

		last_footer->magic = HEAP_MAGIC;
		last_footer->header = last_header;

		insertIntoHeapIndex(last_header);
	} else {		//Last block is not a hole. Just add a new hole at the end
		last_header = (heap_header_t*)heapEnd;
		last_footer = (heap_footer_t*) (newEnd - sizeof(heap_footer_t));

		last_header->is_hole = true;
		last_header->magic = HEAP_MAGIC;
		last_header->size = quantity;
		
		last_footer->magic = HEAP_MAGIC;
		last_footer->header = last_header;

		insertIntoHeapIndex(last_header);
	}

	heapEnd = newEnd;
}

void contractHeap() {	//Automatically work out how much we can contract
	heap_footer_t *last_footer = (heap_footer_t*) (heapEnd - sizeof(heap_footer_t));
	heap_header_t *last_header = last_footer->header;
	if (last_header->is_hole == false) return;	//We need a hole at end of heap

	u32int quantity = 0;
	while ((heapEnd - heapStart) - quantity > HEAP_MIN_SIZE and 
			(last_header->size - quantity) > 0x1000)	//Always keep at least 0x1000 free at end
		quantity += 0x1000;
	if (quantity == 0) return;

	u32int newEnd = heapEnd - quantity;

	removeFromHeapIndex(last_header);
	last_header->size -= quantity;
	last_footer = (heap_footer_t*)((u32int)last_footer - quantity);
	last_footer->magic = HEAP_MAGIC;
	last_footer->header = last_header;
	insertIntoHeapIndex(last_header);

	for (u32int i = newEnd; i < heapEnd; i += 0x1000) {
		kernelPageDirectory->freeFrame(i);
	}

	heapEnd = newEnd;
}

void *kalloc(u32int sz, bool align) {
	if (!kheapUsable) return kallocInternal(sz, align);
	if (align) return 0;

	u32int newsize = sz + sizeof(heap_header_t) + sizeof(heap_footer_t);
	u32int iterator = 0;
	while (iterator < heapIndex.size) {
		if (heapIndex.data[iterator]->size >= newsize) break;
		iterator++;
	}
	if (iterator == heapIndex.size) {
		expandHeap((sz & 0xFFFFF000) + 0x1000);
		return kalloc(sz);	//Recurse call
	}

	heap_header_t *loc = heapIndex.data[iterator];
	heap_footer_t *footer = (heap_footer_t*)((u32int)loc + loc->size - sizeof(heap_footer_t));
	loc->is_hole = false;	//Update current header

	removeFromHeapIndex(loc);


		//Here we create a new hole after currently allocated block, but only if we have enough space. If we don't, we simply allocate a bigger block so that we don't loose space
	if (loc->size > (newsize + sizeof(heap_header_t) + sizeof(heap_footer_t))) { 
		loc->size = newsize;	//Update header for return block

		heap_footer_t *newfooter = (heap_footer_t*)((u32int)loc + newsize - sizeof(heap_footer_t)); //Write footer for return block
		newfooter->header = loc;
		newfooter->magic = HEAP_MAGIC;

		heap_header_t *nextloc = (heap_header_t*)((u32int)loc + newsize); //Write header for new hole
		nextloc->is_hole = true;
		nextloc->magic = HEAP_MAGIC;
		nextloc->size = ((u32int)footer - (u32int)nextloc + sizeof(heap_footer_t));

		footer->header = nextloc;	//Write footer for new hole
		footer->magic = HEAP_MAGIC;

		insertIntoHeapIndex(nextloc);
	}
	
	kheapFree -= loc->size;

	return (void*)((u32int)loc + sizeof(heap_header_t));
}

void kfree(void *ptr) {
	if (ptr == 0) return;

	heap_header_t *header = (heap_header_t*) ((u32int)ptr - sizeof(heap_header_t));
	heap_footer_t *footer = (heap_footer_t*)((u32int)header + header->size - sizeof(heap_footer_t));
	if (header->magic != HEAP_MAGIC or footer->magic != HEAP_MAGIC) return;

	kheapFree += header->size;

	//Unify left
	heap_footer_t *prev_footer = (heap_footer_t*)((u32int)header - sizeof(heap_footer_t));
	if (prev_footer->magic == HEAP_MAGIC && prev_footer->header->is_hole) {
		header = prev_footer->header;
		removeFromHeapIndex(header);

		footer->header = header;
		header->size = ((u32int)footer - (u32int)header + sizeof(heap_footer_t));
	}

	//Unify right
	heap_header_t *next_header = (heap_header_t*)((u32int)footer + sizeof(heap_footer_t));
	if (next_header->magic == HEAP_MAGIC && next_header->is_hole) {
		removeFromHeapIndex(next_header);
		footer = (heap_footer_t*)((u32int)footer + next_header->size);
		
		footer->header = header;
		header->size = ((u32int)footer - (u32int)header + sizeof(heap_footer_t));
	}

	header->is_hole = true;

	insertIntoHeapIndex(header);

	if ((u32int)footer == (heapEnd - sizeof(heap_footer_t)) and
			header->size >= 0x2000 and (heapEnd - heapStart > HEAP_MIN_SIZE)) {
		contractHeap();
	}
}

}