#include "mem.h"
#include <core/sys.h>
#include <core/monitor.h>
#include "paging.h"
#include <config.h>
#include "_dlmalloc.h"
#include "mem.h"
#define FREEPAGESTOKEEP 5
#define KHEAP_IDXSIZE 0x4000 // only used with heap.std.h
#define KHEAP_INITSIZE 0x00080000
#define KHEAP_MAXSIZE 0x08000000
size_t mem_placementAddr;
bool _no_more_ksbrk = false;
// ******************************
// PAGE ALLOCATION
// ****************************
static struct freepage {
size_t virt, phys;
} freepages[FREEPAGESTOKEEP];
uint32_t freepagecount = 0;
/* For internal use only. Populates the cache of pages that can be given to requesters. */
static void get_free_pages() {
static uint32_t locked = 0;
uint32_t i;
if (locked) return;
locked = 1;
while (freepagecount < FREEPAGESTOKEEP) {
if (_no_more_ksbrk) {
for (i = 0xFFFFF000; i >= 0xF0000000; i -= 0x1000) {
if (pagedir_getPage(kernel_pagedir, i, 1)->frame == 0) break;
}
freepages[freepagecount].virt = i;
uint32_t frame = frame_alloc();
freepages[freepagecount].phys = frame * 0x1000;
page_map(pagedir_getPage(kernel_pagedir, i, 0), freepages[freepagecount].phys / 0x1000, 0, 0);
freepagecount++;
} else {
if (mem_placementAddr & 0xFFFFF000) {
mem_placementAddr &= 0xFFFFF000;
mem_placementAddr += 0x1000;
}
freepages[freepagecount].virt = (size_t)ksbrk(0x1000);
freepages[freepagecount].phys = freepages[freepagecount].virt - K_HIGHHALF_ADDR;
freepagecount++;
}
}
locked = 0;
}
/* Gives one page from the cache to someone requesting it. */
void* kmalloc_page(size_t *phys) {
cli();
get_free_pages();
freepagecount--;
*phys = freepages[freepagecount].phys;
size_t tmp = freepages[freepagecount].virt;
sti();
return (void*)tmp;
}
void kfree_page(void* ptr) {
size_t addr = (size_t)ptr;
if (_no_more_ksbrk) {
page_unmapFree(pagedir_getPage(kernel_pagedir, addr, 0));
}
}
//***********************************
// MEMORY ALLOCATION FOR DLMALLOC
// *************************
void* ksbrk(size_t size) {
if (!_no_more_ksbrk) { // ksbrk is NOT being called by dlmalloc
if (size & 0x0FFF) {
size = (size & 0xFFFFF000) + 0x1000;
}
}
size_t tmp = mem_placementAddr;
size_t er_begin, er_end, i;
/* (DBG) monitor_write("<ksbrk ");
monitor_writeHex(size);
monitor_write(":");
monitor_writeHex(tmp);
monitor_write("> "); */
mem_placementAddr += size;
if (_no_more_ksbrk) { // paging enabled, we must allocate these pages
if (tmp < mem_placementAddr) {
er_begin = tmp;
if (er_begin & 0x0FFF) er_begin = (er_begin & 0xFFFFF000) + 0x1000;
er_end = mem_placementAddr;
if (er_end & 0x0FFF) er_end = (er_end & 0xFFFFF000) + 0x1000;
for (i = er_begin; i < er_end; i += 0x1000) {
page *p = pagedir_getPage(kernel_pagedir, i, 1);
size_t f = frame_alloc();
page_map(p, f, 0, 0);
/* (DBG) monitor_write("<map "); monitor_writeHex(i); monitor_write(" ");
monitor_writeHex(f); monitor_write("> "); */
}
} else if (tmp > mem_placementAddr) {
er_begin = (size_t)mem_placementAddr;
if (er_begin & 0x0FFF) er_begin = (er_begin & 0xFFFFF000) + 0x1000;
er_end = tmp;
if (er_end & 0x0FFF) er_end = (er_end & 0xFFFFF000) + 0x1000;
for (i = er_end - 0x1000; i >= er_begin; i -= 0x1000) {
// (DBG) monitor_write("<unmap:"); monitor_writeHex(i); monitor_write("> ");
page_unmapFree(pagedir_getPage(kernel_pagedir, i, 0));
}
}
}
return (void*)tmp;
}
void kbrk(void* ptr) {
monitor_write("<kbrk ");
monitor_writeHex((uint32_t)ptr);
monitor_write(">\n");
if ((size_t)ptr > (size_t)&end) {
ksbrk((size_t)ptr - (size_t)mem_placementAddr);
} else {
PANIC("INVALID KBRK.");
}
}