luxos/SysCore/memory/mmngr_ph.c

352 lines
11 KiB
C

/*********************************************************************
* (c) 2010 CTA Systems Inc. All rights reserved. Glory To God *
* *
* Physical Memory Manager *
* ======================= *
************************************************************ cta os */
// +==============================================+
// | HEADERS |
// +===================================== cta os =+
#include "mmngr_ph.h"
// +==============================================+
// | DEFINITIONS |
// +===================================== cta os =+
#define PMMNGR_BLOCK_SIZE 4096 // block size (4k)
#define PMMNGR_BLOCK_ALIGN PMMNGR_BLOCK_SIZE // block alignment
// +==============================================+
// | DATA DECLARATIONS |
// +===================================== cta os =+
static unsigned _mmngr_memory_size=0; // size of physical memory
static unsigned _mmngr_used_blocks=0; // number of blocks currently in use
static unsigned _mmngr_max_blocks=0; // maximum number of available memory blocks
static unsigned _mmngr_index = 0;
static mstack* _mmngr_memory_stack= 0; // memory stack
// +==============================================+
// | LOCAL FUNCTIONS |
// +===================================== cta os =+
inline mstack mstack_pop ()
{
mstack temp;
temp.low = _mmngr_memory_stack[--_mmngr_index].low;
temp.high = _mmngr_memory_stack[_mmngr_index].high;
_mmngr_used_blocks++;
_mmngr_memory_stack[_mmngr_index].low = 0xFFFF;
_mmngr_memory_stack[_mmngr_index].high = 0xFF;
return temp;
}
inline void mstack_push (const mstack *block)
{
if (block->low == 0 && block-> high == 0) return;
_mmngr_memory_stack[_mmngr_index].low = block->low;
_mmngr_memory_stack[_mmngr_index].high = block->high;
_mmngr_index++;
_mmngr_used_blocks--;
}
inline int mstack_test (const mstack *block)
{
unsigned i;
for (i = 0; i < _mmngr_index; i++)
if (_mmngr_memory_stack[i].low == block->low && _mmngr_memory_stack[i].high == block->high)
return (int) i;
return -1;
}
inline int mstack_qsort_cmp (mstack a, mstack b)
{
return (a.high == b.high) ? (int)a.low - (int)b.low : (int)a.high - (int)b.high;
}
void mstack_qsort(int beg, int end)
{
mstack piv; mstack tmp;
int l,r,p;
while (beg<end) // This while loop will avoid the second recursive call
{
l = beg; p = (beg+end)/2; r = end;
piv.low = _mmngr_memory_stack[p].low;
piv.high = _mmngr_memory_stack[p].high;
while (1)
{
while ((l<=r) && (mstack_qsort_cmp(_mmngr_memory_stack[l],piv) <= 0)) l++;
while ((l<=r) && (mstack_qsort_cmp(_mmngr_memory_stack[r],piv) > 0)) r--;
if (l>r) break;
tmp.low = _mmngr_memory_stack[l].low;
tmp.high = _mmngr_memory_stack[l].high;
_mmngr_memory_stack[l].low = _mmngr_memory_stack[r].low;
_mmngr_memory_stack[l].high = _mmngr_memory_stack[r].high;
_mmngr_memory_stack[r].low = tmp.low;
_mmngr_memory_stack[r].high = tmp.high;
if (p==r) p=l;
l++; r--;
}
_mmngr_memory_stack[p].low = _mmngr_memory_stack[r].low;
_mmngr_memory_stack[p].high = _mmngr_memory_stack[r].high;
_mmngr_memory_stack[r].low = piv.low;
_mmngr_memory_stack[r].high = piv.high;
r--;
// Recursion on the shorter side & loop (with new indexes) on the longer
if ((r-beg)<(end-l)) {
mstack_qsort(beg, r);
beg=l;
}
else {
mstack_qsort(l, end);
end=r;
}
}
}
// +==============================================+
// | DEBUGGING FUNCTIONS |
// +===================================== cta os =+
/*void print_stack()
{
int i;
for (i = 0; i < _mmngr_index; i++) \n\r (" %u", _mmngr_memory_stack[i].low);
}
extern char getch();*/
// +==============================================+
// | INITIALISATION FUNCTIONS |
// +===================================== cta os =+
void pmmngr_init (unsigned memSize, unsigned stack) {
_mmngr_memory_size = memSize;
_mmngr_memory_stack = (mstack*) stack;
_mmngr_max_blocks = (_mmngr_memory_size*1024) / PMMNGR_BLOCK_SIZE;
_mmngr_used_blocks = _mmngr_max_blocks;
_mmngr_index = 0;
// By default, all of memory is in use
}
void pmmngr_init_region (unsigned base, unsigned size) {
mstack block;
unsigned int count = size / PMMNGR_BLOCK_SIZE;
unsigned int start = base / PMMNGR_BLOCK_SIZE;
for (; count!=0; count--) {
block.low = (start + count) & 0xFFFF;
block.high = ((start + count) << 16) & 0xFF;
mstack_push(&block);
}
}
void pmmngr_deinit_region (unsigned base, unsigned size) {
unsigned int start = base / PMMNGR_BLOCK_SIZE;
unsigned int count = size / PMMNGR_BLOCK_SIZE;
int temp;
unsigned int i;
unsigned int j;
// Find free blocks in the area and zero them
for (i = 0; i < _mmngr_index; i++) {
temp = (_mmngr_memory_stack[i].high << 16) | _mmngr_memory_stack[i].low;
if (temp >=start && temp < start+count)
{ _mmngr_memory_stack[i].high = 0;
_mmngr_memory_stack[i].low = 0;
}
}
// Eliminate zero blocks
for (i = 0; i<_mmngr_index; i++)
if (_mmngr_memory_stack[i].high == 0 && _mmngr_memory_stack[i].low == 0)
{
// Find next non-zero
for (j = i; _mmngr_memory_stack[j].high == 0 && _mmngr_memory_stack[j].low == 0; j++)
if (j == _mmngr_index-1) {
j = 0; break; }
if (j == 0) {
_mmngr_index = i;
break;
}
_mmngr_memory_stack[i].high = _mmngr_memory_stack[j].high;
_mmngr_memory_stack[i].low = _mmngr_memory_stack[j].low;
_mmngr_memory_stack[j].high = 0;
_mmngr_memory_stack[j].low = 0;
}
}
// +==============================================+
// | MEMORY MANAGING FUNCTIONS |
// +===================================== cta os =+
unsigned char pmmngr_test_block (unsigned block)
{
mstack temp;
temp.low = block & 0xFFFF;
temp.high = (block>>16) & 0xFF;
return (mstack_test(&temp) == -1)? 0 : 1;
}
void pmmngr_free_block(void* address)
{
// Calculate block
mstack block;
unsigned temp = (unsigned)address / PMMNGR_BLOCK_SIZE;
block.low = temp & 0xFFFF;
block.high = (temp>>16) & 0xFF;
// Push it
mstack_push (&block);
}
void pmmngr_free_blocks (unsigned base, unsigned size)
{
mstack start, end, i;
// 4k align
base /= PMMNGR_BLOCK_SIZE;
size /= PMMNGR_BLOCK_SIZE;
// Calculate blocks
start.low = base & 0xFFFF;
start.high = (base >> 16) & 0xFF;
end.low = (base + size) & 0xFFFF;
end.high = ((base + size)>>16) & 0xFF;
for (i.low = start.low, i.high = start.high; // i = start
i.low < end.low || i.high < end.high;) // i != end
{
// only push if block is used
if (mstack_test(&i) == -1) mstack_push(&i);
// increment i.high
if (i.low == 0xFFFF) {
i.low = 0; i.high++;
}
else i.low++;
}
}
void* pmmngr_alloc_block()
{
if (_mmngr_index == 0) return 0;// Out of memory
// pop a block
mstack block = mstack_pop();
// Calculate and return address;
void* address;
unsigned temp = block.low | (block.high<<16);
address = (void *)(temp * PMMNGR_BLOCK_SIZE);
return address;
}
void* pmmngr_alloc_blocks (unsigned blocks)
{
// Less than 2 blocks requested
if (blocks == 0) return 0;
if (blocks == 1) return pmmngr_alloc_block();
// Sort the stack for the next step
mstack_qsort(0, (int)_mmngr_index);
int i = (int) _mmngr_index-1; // i = counter
int l = 1; // l = number of consecutive blocks
unsigned temp; // temp = temporary storage
unsigned prev = _mmngr_memory_stack[i].low | (_mmngr_memory_stack[i].high<<16); --i;
// Search consecutive blocks
for (i = 0; i < _mmngr_index; i++) {
temp = _mmngr_memory_stack[i].low | (_mmngr_memory_stack[i].high<<16);
if (temp == prev+1) l++;
else l = 1;
if (l == blocks) {
pmmngr_deinit_region (temp * PMMNGR_BLOCK_SIZE, blocks * PMMNGR_BLOCK_SIZE);
return (void*) ((temp-l+1) * PMMNGR_BLOCK_SIZE);
}
prev = temp;
}
return 0; // Could not find so many free blocks
}
// +==============================================+
// | GET DATA FUNCTIONS |
// +===================================== cta os =+
unsigned pmmngr_get_memory_size () {
return _mmngr_memory_size;
}
unsigned pmmngr_get_block_count () {
return _mmngr_max_blocks;
}
unsigned pmmngr_get_use_block_count () {
return _mmngr_used_blocks;
}
unsigned pmmngr_get_free_block_count () {
return _mmngr_index;
}
unsigned pmmngr_get_block_size () {
return PMMNGR_BLOCK_SIZE;
}
// +==============================================+
// | PAGING RELATED FUNCTIONS |
// +===================================== cta os =+
void pmmngr_paging_enable (unsigned char b) {
unsigned temp;
temp = read_cr0();
// Enable
if (b) temp |= 0x80000000;
else temp &= ~0x80000000;
write_cr0(temp);
}
unsigned char pmmngr_is_paging () {
unsigned temp = read_cr0();
return ((temp&0x80000000)>0);
}