old-trainOS/src/pmm.c
2015-08-09 02:42:56 +02:00

142 lines
3.3 KiB
C

#include <inttypes.h>
#include "pmm.h"
#include "kernel.h"
#include "stdlib.h"
#include "console.h"
#define BITMAP_SIZE 32768
extern const void kernelStart;
extern const void kernelEnd;
/**
* Stores for every page in 4 GB RAM if it is free or not.
* A set bit indicates that the page is free.
*/
static uint32_t bitmap[BITMAP_SIZE];
static inline void resolve(void *pptr, uint32_t *idx, uint32_t *bit)
{
uintptr_t ptr = (uintptr_t)pptr;
ptr >>= 12; // Calculate page ID
*idx = ptr / 32; // B32 offset in bitmap.
*bit = ptr % 32; // Bit offset in bitmap
}
static inline void *rebuild(uint32_t idx, uint32_t bit)
{
uintptr_t ptr = 32 * idx + bit;
ptr <<= 12;
return (void*)ptr;
}
/**
* Marks an address used or free
* @param addr The address that will be marked
* @param used If != 0, the addr will be marked as used, else it will be marked as free.
*/
static inline void mark(uintptr_t addr, uint32_t used)
{
uint32_t bit, idx;
resolve((void*)addr, &idx, &bit);
if(used)
bitmap[idx] &= ~(1<<bit);
else
bitmap[idx] |= (1<<bit);
}
/**
* Marks a section in memory as used or free.
* @param start The start address of the section.
* @param end The end address of the section.
* @param used If 0 the section will be freed, else it will be marked as used.
*/
static inline void markSection(uintptr_t start, uintptr_t end, uint32_t used)
{
uintptr_t it = start;
while(it < end)
{
mark(it, used);
it += 0x1000;
}
}
void pmm_init(const MultibootStructure *mb)
{
if((mb->flags & MB_MEMORYMAP) == 0)
die("Multiboot header missing memory map. Cannot initialize PMM.");
// Make all memory used
memset(bitmap, 0, sizeof(bitmap));
// Free the memory map
{
uintptr_t it = mb->memoryMap;
for(size_t i = 0; i < mb->memoryMapLength; i++)
{
const MultibootMemoryMap *mmap = (const MultibootMemoryMap *)it;
if(mmap->type == 1)
{
markSection(mmap->base, mmap->base + mmap->length, 0);
}
it += mmap->entry_size + 4; // Stupid offset :P
}
}
// Mark the whole kernel as "used"
{
uintptr_t start = (uintptr_t)&kernelStart;
uintptr_t end = (uintptr_t)&kernelEnd;
markSection(start, end, 1);
}
// Mark all kernel modules as "used"
if(mb->flags & MB_MODULES)
{
const MultibootModule *mod = (const MultibootModule *)mb->modules;
for(size_t i = 0; i < mb->moduleCount; i++)
{
markSection(mod[i].start, mod[i].end, 1);
}
}
}
uint32_t pmm_calc_free(void)
{
uint32_t mem = 0;
for(uint32_t idx = 0; idx < BITMAP_SIZE; idx++)
{
for(uint32_t bit = 0; bit < 32; bit++)
{
if(bitmap[idx] & (1<<bit))
mem += 0x1000;
}
}
return mem;
}
void pmm_free(void *pptr)
{
mark((uintptr_t)pptr, 0);
}
void *pmm_alloc(void)
{
for(uint32_t idx = 0; idx < BITMAP_SIZE; idx++)
{
for(uint32_t bit = 0; bit < 32; bit++)
{
if(bitmap[idx] & (1<<bit))
{
// Allocate here
bitmap[idx] &= ~(1<<bit);
return rebuild(idx, bit);
}
}
}
die("out of physical memory");
return (void*)0xDEADBEEF;
}