kolibrios/kernel/branches/kolibri_pe/core/frame.c
Sergey Semyonov (Serge) a20b1c888d kolibri_pe: the latest 32-bit version
git-svn-id: svn://kolibrios.org@2971 a494cfbc-eb01-0410-851d-a64ba20cac60
2012-09-04 22:16:57 +00:00

446 lines
9.2 KiB
C

#include <types.h>
#include <core.h>
#include <spinlock.h>
#include <link.h>
#include <mm.h>
extern u32_t pg_balloc;
extern u32_t mem_amount;
void __fastcall *balloc(size_t size);
static zone_t z_core;
#include "buddy.inc"
typedef struct
{
link_t link;
SPINLOCK_DECLARE(lock);
u32_t state;
void *parent;
count_t avail;
addr_t base;
index_t next;
int list[512];
}pslab_t;
typedef struct
{
SPINLOCK_DECLARE(lock);
count_t partial_count;
link_t full_slabs; /**< List of full slabs */
link_t partial_slabs; /**< List of partial slabs */
}pcache_t;
static pcache_t page_cache;
static pslab_t *create_page_slab();
void init_mm()
{
int i;
u32_t base;
u32_t size;
count_t pages;
size_t conf_size;
size_t core_size;
pslab_t *slab;
pages = mem_amount >> PAGE_WIDTH;
DBG("last page = %x total pages = %x\n",mem_amount, pages);
conf_size = pages*sizeof(frame_t);
DBG("conf_size = %x free mem start =%x\n",conf_size, pg_balloc);
zone_create(&z_core, 0, pages);
zone_release(&z_core, 0, pages);
zone_reserve(&z_core, 0, pg_balloc >> PAGE_WIDTH);
list_initialize(&page_cache.full_slabs);
list_initialize(&page_cache.partial_slabs);
slab = create_page_slab();
ASSERT(slab);
slab->parent = &page_cache;
page_cache.partial_count++;
list_prepend(&slab->link, &page_cache.partial_slabs);
};
/** Return wasted space in slab */
static unsigned int badness(index_t order, size_t size)
{
unsigned int objects;
unsigned int ssize;
ssize = PAGE_SIZE << order;
objects = (PAGE_SIZE << order) / size;
return ssize - objects * size;
}
#define SLAB_MAX_BADNESS(order) (((size_t) PAGE_SIZE << (order)) >> 2)
static pslab_t *create_page_slab()
{
pslab_t *slab;
link_t *tmp;
spinlock_lock(&z_core.lock);
tmp = buddy_alloc(9);
if( tmp != 0 )
{
frame_t *frame;
int i;
addr_t v;
/* Update zone information. */
z_core.free_count -= 512;
z_core.busy_count += 512;
spinlock_unlock(&z_core.lock);
/* Frame will be actually a first frame of the block. */
frame = (frame_t*)tmp;
frame->parent = 0;
v = (z_core.base + (index_t)(frame - z_core.frames)) << PAGE_WIDTH;
slab = (pslab_t*)PA2KA(v);
for(i = 1; i < 512; i++)
frame[i].parent = slab;
slab->base = v + PAGE_SIZE;
slab->avail = 511;
slab->next = 0;
for(i = 0; i < 511; i++)
slab->list[i] = i + 1;
}
else
{
spinlock_unlock(&z_core.lock);
slab = NULL;
};
DBG("create page slab at %x\n", slab);
return slab;
}
static void destroy_page_slab(pslab_t *slab)
{
u32_t order;
count_t idx;
frame_t *frame;
idx = (KA2PA(slab) >> PAGE_WIDTH)-z_core.base;
frame = &z_core.frames[idx];
/* remember frame order */
order = frame->buddy_order;
ASSERT(frame->refcount);
if (!--frame->refcount)
{
spinlock_lock(&z_core.lock);
buddy_system_free(&frame->buddy_link);
/* Update zone information. */
z_core.free_count += (1 << order);
z_core.busy_count -= (1 << order);
spinlock_unlock(&z_core.lock);
}
}
#if 0
fslab_t *create_slab(index_t order, size_t size)
{
fslab_t *slab;
slab = (fslab_t*)PA2KA(frame_alloc(0));
if( slab )
{
link_t *tmp;
spinlock_lock(&z_core.lock);
tmp = buddy_alloc(order);
ASSERT(tmp);
if( tmp )
{
frame_t *frame;
count_t objects;
count_t i;
addr_t v;
/* Update zone information. */
z_core.free_count -= (1 << order);
z_core.busy_count += (1 << order);
spinlock_unlock(&z_heap.lock);
/* Frame will be actually a first frame of the block. */
frame = (frame_t*)tmp;
for(i = 0; i < (1U<<order); i++)
frame[i].parent = slab;
/* get frame address */
v = z_core.base + (index_t)(frame - z_core.frames);
slab->base = (v << PAGE_WIDTH);
slab->avail = (PAGE_SIZE << order) / size;
slab->next = 0;
objects = (PAGE_SIZE << order) / size;
for(i = 0; i < objects; i++)
slab->list[i] = i + 1;
}
else
{
spinlock_unlock(&z_core.lock);
frame_free(KA2PA(slab));
slab = NULL;
};
};
return slab;
}
static void destroy_slab(fslab_t *slab)
{
u32_t order;
count_t idx;
frame_t *frame;
idx = (slab->base >> PAGE_WIDTH)-z_core.base;
frame = &z_core.frames[idx];
/* remember frame order */
order = frame->buddy_order;
ASSERT(frame->refcount);
if (!--frame->refcount)
{
spinlock_lock(&z_core.lock);
buddy_system_free(&frame->buddy_link);
/* Update zone information. */
z_core.free_count += (1 << order);
z_core.busy_count -= (1 << order);
spinlock_unlock(&z_core.lock);
}
// slab_free(fslab, slab);
};
#endif
addr_t alloc_page(void)
{
eflags_t efl;
pslab_t *slab;
addr_t frame;
efl = safe_cli();
spinlock_lock(&page_cache.lock);
if (list_empty(&page_cache.partial_slabs))
{
slab = create_page_slab();
if (!slab)
{
spinlock_unlock(&page_cache.lock);
safe_sti(efl);
return 0;
}
slab->parent = &page_cache;
slab->state = 1;
page_cache.partial_count++;
list_prepend(&slab->link, &page_cache.partial_slabs);
}
else
slab = (pslab_t*)page_cache.partial_slabs.next;
frame = slab->base + (slab->next << PAGE_WIDTH);
slab->next = slab->list[slab->next];
slab->avail--;
if( slab->avail == 0 )
{
slab->state = 0;
list_remove(&slab->link);
list_prepend(&slab->link, &page_cache.full_slabs);
page_cache.partial_count--;
DBG("%s insert empty page slab\n", __FUNCTION__);
};
spinlock_unlock(&page_cache.lock);
// DBG("alloc_page: %x remain %d\n", frame, slab->avail);
safe_sti(efl);
return frame;
}
addr_t __fastcall frame_alloc(count_t count)
{
addr_t frame;
if ( count > 1)
{
eflags_t efl;
index_t order;
frame_t *tmp;
count_t i;
order = fnzb(count-1)+1;
efl = safe_cli();
spinlock_lock(&z_core.lock);
tmp = (frame_t*)buddy_alloc( order );
ASSERT(tmp);
z_core.free_count -= (1 << order);
z_core.busy_count += (1 << order);
for(i = 0; i < (1 << order); i++)
tmp[i].parent = NULL;
spinlock_unlock(&z_core.lock);
safe_sti(efl);
frame = (z_core.base +
(index_t)(tmp - z_core.frames)) << PAGE_WIDTH;
DBG("%s %x order %d remain %d\n", __FUNCTION__,
frame, order, z_core.free_count);
}
else
frame = alloc_page();
return frame;
}
size_t __fastcall frame_free(addr_t addr)
{
eflags_t efl;
index_t idx;
frame_t *frame;
size_t frame_size;
idx = addr >> PAGE_WIDTH;
if( (idx < z_core.base) ||
(idx >= z_core.base+z_core.count)) {
DBG("%s: invalid address %x\n", __FUNCTION__, addr);
return 0;
}
efl = safe_cli();
frame = &z_core.frames[idx-z_core.base];
if( frame->parent != NULL )
{
pslab_t *slab;
slab = frame->parent;
spinlock_lock(&page_cache.lock);
idx = (addr - slab->base) >> PAGE_WIDTH;
ASSERT(idx < 512);
slab->list[idx] = slab->next;
slab->next = idx;
slab->avail++;
if( (slab->state == 0 ) &&
(slab->avail >= 4))
{
slab->state = 1;
list_remove(&slab->link);
list_prepend(&slab->link, &page_cache.partial_slabs);
page_cache.partial_count++;
DBG("%s: insert partial page slab\n", __FUNCTION__);
}
spinlock_unlock(&page_cache.lock);
frame_size = 1;
}
else
{
count_t order;
order = frame->buddy_order;
DBG("%s %x order %d\n", __FUNCTION__, addr, order);
ASSERT(frame->refcount);
spinlock_lock(&z_core.lock);
if (!--frame->refcount)
{
buddy_system_free(&frame->buddy_link);
/* Update zone information. */
z_core.free_count += (1 << order);
z_core.busy_count -= (1 << order);
}
spinlock_unlock(&z_core.lock);
frame_size = 1 << order;
};
safe_sti(efl);
return frame_size;
}
count_t get_free_mem()
{
return z_core.free_count;
}