Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4054 → Rev 4055

/branches/dd/kernel/generic/src/mm/slab.c
167,19 → 167,19
* Allocate frames for slab space and initialize
*
*/
static slab_t * slab_space_alloc(slab_cache_t *cache, int flags)
static slab_t *slab_space_alloc(slab_cache_t *cache, int flags)
{
void *data;
slab_t *slab;
size_t fsize;
unsigned int i;
unsigned int zone = 0;
count_t zone = 0;
data = frame_alloc_generic(cache->order, FRAME_KA | flags, &zone);
if (!data) {
return NULL;
}
if (! (cache->flags & SLAB_CACHE_SLINSIDE)) {
if (!(cache->flags & SLAB_CACHE_SLINSIDE)) {
slab = slab_alloc(slab_extern_cache, flags);
if (!slab) {
frame_free(KA2PA(data));
200,7 → 200,7
slab->cache = cache;
 
for (i = 0; i < cache->objects; i++)
*((int *) (slab->start + i*cache->size)) = i+1;
*((int *) (slab->start + i*cache->size)) = i + 1;
 
atomic_inc(&cache->allocated_slabs);
return slab;
239,8 → 239,7
*
* @return Number of freed pages
*/
static count_t slab_obj_destroy(slab_cache_t *cache, void *obj,
slab_t *slab)
static count_t slab_obj_destroy(slab_cache_t *cache, void *obj, slab_t *slab)
{
int freed = 0;
 
256,7 → 255,7
ASSERT(slab->available < cache->objects);
 
*((int *)obj) = slab->nextavail;
slab->nextavail = (obj - slab->start)/cache->size;
slab->nextavail = (obj - slab->start) / cache->size;
slab->available++;
 
/* Move it to correct list */
281,7 → 280,7
*
* @return Object address or null
*/
static void * slab_obj_create(slab_cache_t *cache, int flags)
static void *slab_obj_create(slab_cache_t *cache, int flags)
{
slab_t *slab;
void *obj;
301,7 → 300,8
return NULL;
spinlock_lock(&cache->slablock);
} else {
slab = list_get_instance(cache->partial_slabs.next, slab_t, link);
slab = list_get_instance(cache->partial_slabs.next, slab_t,
link);
list_remove(&slab->link);
}
obj = slab->start + slab->nextavail * cache->size;
332,8 → 332,7
*
* @param first If true, return first, else last mag
*/
static slab_magazine_t * get_mag_from_cache(slab_cache_t *cache,
int first)
static slab_magazine_t *get_mag_from_cache(slab_cache_t *cache, int first)
{
slab_magazine_t *mag = NULL;
link_t *cur;
368,8 → 367,7
*
* @return Number of freed pages
*/
static count_t magazine_destroy(slab_cache_t *cache,
slab_magazine_t *mag)
static count_t magazine_destroy(slab_cache_t *cache, slab_magazine_t *mag)
{
unsigned int i;
count_t frames = 0;
389,7 → 387,7
*
* Assume cpu_magazine lock is held
*/
static slab_magazine_t * get_full_current_mag(slab_cache_t *cache)
static slab_magazine_t *get_full_current_mag(slab_cache_t *cache)
{
slab_magazine_t *cmag, *lastmag, *newmag;
 
423,7 → 421,7
*
* @return Pointer to object or NULL if not available
*/
static void * magazine_obj_get(slab_cache_t *cache)
static void *magazine_obj_get(slab_cache_t *cache)
{
slab_magazine_t *mag;
void *obj;
458,7 → 456,7
* allocate new, exchange last & current
*
*/
static slab_magazine_t * make_empty_current_mag(slab_cache_t *cache)
static slab_magazine_t *make_empty_current_mag(slab_cache_t *cache)
{
slab_magazine_t *cmag,*lastmag,*newmag;
 
530,7 → 528,8
static unsigned int comp_objects(slab_cache_t *cache)
{
if (cache->flags & SLAB_CACHE_SLINSIDE)
return ((PAGE_SIZE << cache->order) - sizeof(slab_t)) / cache->size;
return ((PAGE_SIZE << cache->order) - sizeof(slab_t)) /
cache->size;
else
return (PAGE_SIZE << cache->order) / cache->size;
}
557,28 → 556,25
ASSERT(_slab_initialized >= 2);
 
cache->mag_cache = malloc(sizeof(slab_mag_cache_t)*config.cpu_count,0);
cache->mag_cache = malloc(sizeof(slab_mag_cache_t) * config.cpu_count,
0);
for (i = 0; i < config.cpu_count; i++) {
memsetb((uintptr_t)&cache->mag_cache[i],
sizeof(cache->mag_cache[i]), 0);
spinlock_initialize(&cache->mag_cache[i].lock, "slab_maglock_cpu");
memsetb(&cache->mag_cache[i], sizeof(cache->mag_cache[i]), 0);
spinlock_initialize(&cache->mag_cache[i].lock,
"slab_maglock_cpu");
}
}
 
/** Initialize allocated memory as a slab cache */
static void
_slab_cache_create(slab_cache_t *cache,
char *name,
size_t size,
size_t align,
int (*constructor)(void *obj, int kmflag),
int (*destructor)(void *obj),
int flags)
_slab_cache_create(slab_cache_t *cache, char *name, size_t size, size_t align,
int (*constructor)(void *obj, int kmflag), int (*destructor)(void *obj),
int flags)
{
int pages;
ipl_t ipl;
 
memsetb((uintptr_t)cache, sizeof(*cache), 0);
memsetb(cache, sizeof(*cache), 0);
cache->name = name;
 
if (align < sizeof(unative_t))
596,7 → 592,7
list_initialize(&cache->magazines);
spinlock_initialize(&cache->slablock, "slab_lock");
spinlock_initialize(&cache->maglock, "slab_maglock");
if (! (cache->flags & SLAB_CACHE_NOMAGAZINE))
if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
make_magcache(cache);
 
/* Compute slab sizes, object counts in slabs etc. */
609,7 → 605,7
if (pages == 1)
cache->order = 0;
else
cache->order = fnzb(pages-1)+1;
cache->order = fnzb(pages - 1) + 1;
 
while (badness(cache) > SLAB_MAX_BADNESS(cache)) {
cache->order += 1;
630,18 → 626,16
}
 
/** Create slab cache */
slab_cache_t * slab_cache_create(char *name,
size_t size,
size_t align,
int (*constructor)(void *obj, int kmflag),
int (*destructor)(void *obj),
int flags)
slab_cache_t *
slab_cache_create(char *name, size_t size, size_t align,
int (*constructor)(void *obj, int kmflag), int (*destructor)(void *obj),
int flags)
{
slab_cache_t *cache;
 
cache = slab_alloc(&slab_cache_cache, 0);
_slab_cache_create(cache, name, size, align, constructor, destructor,
flags);
flags);
return cache;
}
 
665,7 → 659,7
* endless loop
*/
magcount = atomic_get(&cache->magazine_counter);
while (magcount-- && (mag=get_mag_from_cache(cache,0))) {
while (magcount-- && (mag=get_mag_from_cache(cache, 0))) {
frames += magazine_destroy(cache,mag);
if (!(flags & SLAB_RECLAIM_ALL) && frames)
break;
718,8 → 712,8
_slab_reclaim(cache, SLAB_RECLAIM_ALL);
 
/* All slabs must be empty */
if (!list_empty(&cache->full_slabs) \
|| !list_empty(&cache->partial_slabs))
if (!list_empty(&cache->full_slabs) ||
!list_empty(&cache->partial_slabs))
panic("Destroying cache that is not empty.");
 
if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
727,9 → 721,8
slab_free(&slab_cache_cache, cache);
}
 
/** Allocate new object from cache - if no flags given, always returns
memory */
void * slab_alloc(slab_cache_t *cache, int flags)
/** Allocate new object from cache - if no flags given, always returns memory */
void *slab_alloc(slab_cache_t *cache, int flags)
{
ipl_t ipl;
void *result = NULL;
758,9 → 751,8
 
ipl = interrupts_disable();
 
if ((cache->flags & SLAB_CACHE_NOMAGAZINE) \
|| magazine_obj_put(cache, obj)) {
 
if ((cache->flags & SLAB_CACHE_NOMAGAZINE) ||
magazine_obj_put(cache, obj)) {
slab_obj_destroy(cache, obj, slab);
 
}
787,7 → 779,8
* memory allocation from interrupts can deadlock.
*/
 
for (cur = slab_cache_list.next;cur!=&slab_cache_list; cur=cur->next) {
for (cur = slab_cache_list.next; cur != &slab_cache_list;
cur = cur->next) {
cache = list_get_instance(cur, slab_cache_t, link);
frames += _slab_reclaim(cache, flags);
}
801,22 → 794,77
/* Print list of slabs */
void slab_print_list(void)
{
slab_cache_t *cache;
link_t *cur;
ipl_t ipl;
ipl = interrupts_disable();
spinlock_lock(&slab_cache_lock);
printf("slab name size pages obj/pg slabs cached allocated ctl\n");
printf("---------------- -------- ------ ------ ------ ------ --------- ---\n");
for (cur = slab_cache_list.next; cur != &slab_cache_list; cur = cur->next) {
int skip = 0;
 
printf("slab name size pages obj/pg slabs cached allocated"
" ctl\n");
printf("---------------- -------- ------ ------ ------ ------ ---------"
" ---\n");
 
while (true) {
slab_cache_t *cache;
link_t *cur;
ipl_t ipl;
int i;
 
/*
* We must not hold the slab_cache_lock spinlock when printing
* the statistics. Otherwise we can easily deadlock if the print
* needs to allocate memory.
*
* Therefore, we walk through the slab cache list, skipping some
* amount of already processed caches during each iteration and
* gathering statistics about the first unprocessed cache. For
* the sake of printing the statistics, we realese the
* slab_cache_lock and reacquire it afterwards. Then the walk
* starts again.
*
* This limits both the efficiency and also accuracy of the
* obtained statistics. The efficiency is decreased because the
* time complexity of the algorithm is quadratic instead of
* linear. The accuracy is impacted because we drop the lock
* after processing one cache. If there is someone else
* manipulating the cache list, we might omit an arbitrary
* number of caches or process one cache multiple times.
* However, we don't bleed for this algorithm for it is only
* statistics.
*/
 
ipl = interrupts_disable();
spinlock_lock(&slab_cache_lock);
 
for (i = 0, cur = slab_cache_list.next;
i < skip && cur != &slab_cache_list;
i++, cur = cur->next)
;
 
if (cur == &slab_cache_list) {
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
break;
}
 
skip++;
 
cache = list_get_instance(cur, slab_cache_t, link);
 
char *name = cache->name;
uint8_t order = cache->order;
size_t size = cache->size;
unsigned int objects = cache->objects;
long allocated_slabs = atomic_get(&cache->allocated_slabs);
long cached_objs = atomic_get(&cache->cached_objs);
long allocated_objs = atomic_get(&cache->allocated_objs);
int flags = cache->flags;
printf("%-16s %8zd %6zd %6zd %6zd %6zd %9zd %-3s\n", cache->name, cache->size, (1 << cache->order), cache->objects, atomic_get(&cache->allocated_slabs), atomic_get(&cache->cached_objs), atomic_get(&cache->allocated_objs), cache->flags & SLAB_CACHE_SLINSIDE ? "in" : "out");
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
printf("%-16s %8" PRIs " %6d %6u %6ld %6ld %9ld %-3s\n",
name, size, (1 << order), objects, allocated_slabs,
cached_objs, allocated_objs,
flags & SLAB_CACHE_SLINSIDE ? "in" : "out");
}
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
}
 
void slab_cache_init(void)
824,32 → 872,24
int i, size;
 
/* Initialize magazine cache */
_slab_cache_create(&mag_cache,
"slab_magazine",
sizeof(slab_magazine_t)+SLAB_MAG_SIZE*sizeof(void*),
sizeof(uintptr_t),
NULL, NULL,
SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
_slab_cache_create(&mag_cache, "slab_magazine",
sizeof(slab_magazine_t) + SLAB_MAG_SIZE * sizeof(void*),
sizeof(uintptr_t), NULL, NULL, SLAB_CACHE_NOMAGAZINE |
SLAB_CACHE_SLINSIDE);
/* Initialize slab_cache cache */
_slab_cache_create(&slab_cache_cache,
"slab_cache",
sizeof(slab_cache_cache),
sizeof(uintptr_t),
NULL, NULL,
SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
_slab_cache_create(&slab_cache_cache, "slab_cache",
sizeof(slab_cache_cache), sizeof(uintptr_t), NULL, NULL,
SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
/* Initialize external slab cache */
slab_extern_cache = slab_cache_create("slab_extern",
sizeof(slab_t),
0, NULL, NULL,
SLAB_CACHE_SLINSIDE | SLAB_CACHE_MAGDEFERRED);
slab_extern_cache = slab_cache_create("slab_extern", sizeof(slab_t), 0,
NULL, NULL, SLAB_CACHE_SLINSIDE | SLAB_CACHE_MAGDEFERRED);
 
/* Initialize structures for malloc */
for (i=0, size=(1<<SLAB_MIN_MALLOC_W);
i < (SLAB_MAX_MALLOC_W-SLAB_MIN_MALLOC_W+1);
i++, size <<= 1) {
malloc_caches[i] = slab_cache_create(malloc_names[i],
size, 0,
NULL,NULL, SLAB_CACHE_MAGDEFERRED);
for (i = 0, size = (1 << SLAB_MIN_MALLOC_W);
i < (SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1);
i++, size <<= 1) {
malloc_caches[i] = slab_cache_create(malloc_names[i], size, 0,
NULL, NULL, SLAB_CACHE_MAGDEFERRED);
}
#ifdef CONFIG_DEBUG
_slab_initialized = 1;
874,9 → 914,11
 
spinlock_lock(&slab_cache_lock);
for (cur=slab_cache_list.next; cur != &slab_cache_list;cur=cur->next){
for (cur = slab_cache_list.next; cur != &slab_cache_list;
cur = cur->next){
s = list_get_instance(cur, slab_cache_t, link);
if ((s->flags & SLAB_CACHE_MAGDEFERRED) != SLAB_CACHE_MAGDEFERRED)
if ((s->flags & SLAB_CACHE_MAGDEFERRED) !=
SLAB_CACHE_MAGDEFERRED)
continue;
make_magcache(s);
s->flags &= ~SLAB_CACHE_MAGDEFERRED;
887,7 → 929,7
 
/**************************************/
/* kalloc/kfree functions */
void * malloc(unsigned int size, int flags)
void *malloc(unsigned int size, int flags)
{
ASSERT(_slab_initialized);
ASSERT(size && size <= (1 << SLAB_MAX_MALLOC_W));
900,7 → 942,7
return slab_alloc(malloc_caches[idx], flags);
}
 
void * realloc(void *ptr, unsigned int size, int flags)
void *realloc(void *ptr, unsigned int size, int flags)
{
ASSERT(_slab_initialized);
ASSERT(size <= (1 << SLAB_MAX_MALLOC_W));
/branches/dd/kernel/generic/src/mm/tlb.c
173,7 → 173,7
tlb_invalidate_pages(asid, page, count);
break;
default:
panic("unknown type (%d)\n", type);
panic("Unknown type (%d).", type);
break;
}
if (type == TLB_INVL_ALL)
/branches/dd/kernel/generic/src/mm/backend_anon.c
78,7 → 78,6
int anon_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
{
uintptr_t frame;
bool dirty = false;
 
if (!as_area_check_access(area, access))
return AS_PF_FAULT;
106,7 → 105,7
*/
for (i = 0; i < leaf->keys; i++) {
if (leaf->key[i] ==
ALIGN_DOWN(addr, PAGE_SIZE)) {
ALIGN_DOWN(addr, PAGE_SIZE) - area->base) {
allocate = false;
break;
}
113,8 → 112,7
}
if (allocate) {
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
memsetb(PA2KA(frame), FRAME_SIZE, 0);
dirty = true;
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
/*
* Insert the address of the newly allocated
144,8 → 142,7
* the different causes
*/
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
memsetb(PA2KA(frame), FRAME_SIZE, 0);
dirty = true;
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
}
/*
155,7 → 152,7
*/
page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
panic("Could not insert used space.\n");
panic("Cannot insert used space.");
return AS_PF_OK;
}
/branches/dd/kernel/generic/src/mm/as.c
82,7 → 82,6
#include <arch/mm/cache.h>
#endif /* CONFIG_VIRT_IDX_DCACHE */
 
#ifndef __OBJC__
/**
* Each architecture decides what functions will be used to carry out
* address space operations such as creating or locking page tables.
93,7 → 92,6
* Slab for as_t objects.
*/
static slab_cache_t *as_slab;
#endif
 
/**
* This lock serializes access to the ASID subsystem.
113,13 → 111,11
/** Kernel address space. */
as_t *AS_KERNEL = NULL;
 
static int area_flags_to_page_flags(int aflags);
static as_area_t *find_area_and_lock(as_t *as, uintptr_t va);
static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
as_area_t *avoid_area);
static void sh_info_remove_reference(share_info_t *sh_info);
static int area_flags_to_page_flags(int);
static as_area_t *find_area_and_lock(as_t *, uintptr_t);
static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *);
static void sh_info_remove_reference(share_info_t *);
 
#ifndef __OBJC__
static int as_constructor(void *obj, int flags)
{
as_t *as = (as_t *) obj;
126,7 → 122,7
int rc;
 
link_initialize(&as->inactive_as_with_asid_link);
mutex_initialize(&as->lock);
mutex_initialize(&as->lock, MUTEX_PASSIVE);
rc = as_constructor_arch(as, flags);
139,7 → 135,6
 
return as_destructor_arch(as);
}
#endif
 
/** Initialize address space subsystem. */
void as_init(void)
146,33 → 141,29
{
as_arch_init();
 
#ifndef __OBJC__
as_slab = slab_cache_create("as_slab", sizeof(as_t), 0,
as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
#endif
AS_KERNEL = as_create(FLAG_AS_KERNEL);
if (!AS_KERNEL)
panic("can't create kernel address space\n");
panic("Cannot create kernel address space.");
/* Make sure the kernel address space
* reference count never drops to zero.
*/
atomic_set(&AS_KERNEL->refcount, 1);
}
 
/** Create address space.
*
* @param flags Flags that influence way in wich the address space is created.
* @param flags Flags that influence the way in wich the address space
* is created.
*/
as_t *as_create(int flags)
{
as_t *as;
 
#ifdef __OBJC__
as = [as_t new];
link_initialize(&as->inactive_as_with_asid_link);
mutex_initialize(&as->lock);
(void) as_constructor_arch(as, flags);
#else
as = (as_t *) slab_alloc(as_slab, 0);
#endif
(void) as_create_arch(as, 0);
btree_create(&as->as_area_btree);
189,7 → 180,7
#else
page_table_create(flags);
#endif
 
return as;
}
 
199,6 → 190,8
* zero), the address space can be destroyed.
*
* We know that we don't hold any spinlock.
*
* @param as Address space to be destroyed.
*/
void as_destroy(as_t *as)
{
263,11 → 256,7
 
interrupts_restore(ipl);
 
#ifdef __OBJC__
[as free];
#else
slab_free(as_slab, as);
#endif
}
 
/** Create address space area of common attributes.
274,19 → 263,19
*
* The created address space area is added to the target address space.
*
* @param as Target address space.
* @param flags Flags of the area memory.
* @param size Size of area.
* @param base Base address of area.
* @param attrs Attributes of the area.
* @param backend Address space area backend. NULL if no backend is used.
* @param backend_data NULL or a pointer to an array holding two void *.
* @param as Target address space.
* @param flags Flags of the area memory.
* @param size Size of area.
* @param base Base address of area.
* @param attrs Attributes of the area.
* @param backend Address space area backend. NULL if no backend is used.
* @param backend_data NULL or a pointer to an array holding two void *.
*
* @return Address space area on success or NULL on failure.
* @return Address space area on success or NULL on failure.
*/
as_area_t *
as_area_create(as_t *as, int flags, size_t size, uintptr_t base, int attrs,
mem_backend_t *backend, mem_backend_data_t *backend_data)
mem_backend_t *backend, mem_backend_data_t *backend_data)
{
ipl_t ipl;
as_area_t *a;
312,7 → 301,7
a = (as_area_t *) malloc(sizeof(as_area_t), 0);
 
mutex_initialize(&a->lock);
mutex_initialize(&a->lock, MUTEX_PASSIVE);
a->as = as;
a->flags = flags;
324,8 → 313,7
if (backend_data)
a->backend_data = *backend_data;
else
memsetb((uintptr_t) &a->backend_data, sizeof(a->backend_data),
0);
memsetb(&a->backend_data, sizeof(a->backend_data), 0);
 
btree_create(&a->used_space);
339,13 → 327,14
 
/** Find address space area and change it.
*
* @param as Address space.
* @param address Virtual address belonging to the area to be changed. Must be
* page-aligned.
* @param size New size of the virtual memory block starting at address.
* @param flags Flags influencing the remap operation. Currently unused.
* @param as Address space.
* @param address Virtual address belonging to the area to be changed.
* Must be page-aligned.
* @param size New size of the virtual memory block starting at
* address.
* @param flags Flags influencing the remap operation. Currently unused.
*
* @return Zero on success or a value from @ref errno.h otherwise.
* @return Zero on success or a value from @ref errno.h otherwise.
*/
int as_area_resize(as_t *as, uintptr_t address, size_t size, int flags)
{
400,7 → 389,7
if (pages < area->pages) {
bool cond;
uintptr_t start_free = area->base + pages*PAGE_SIZE;
uintptr_t start_free = area->base + pages * PAGE_SIZE;
 
/*
* Shrinking the area.
410,7 → 399,7
/*
* Start TLB shootdown sequence.
*/
tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base +
tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base +
pages * PAGE_SIZE, area->pages - pages);
 
/*
455,8 → 444,8
i = (start_free - b) >> PAGE_WIDTH;
if (!used_space_remove(area, start_free,
c - i))
panic("Could not remove used "
"space.\n");
panic("Cannot remove used "
"space.");
} else {
/*
* The interval of used space can be
463,8 → 452,8
* completely removed.
*/
if (!used_space_remove(area, b, c))
panic("Could not remove used "
"space.\n");
panic("Cannot remove used "
"space.");
}
for (; i < c; i++) {
526,10 → 515,10
 
/** Destroy address space area.
*
* @param as Address space.
* @param address Address withing the area to be deleted.
* @param as Address space.
* @param address Address within the area to be deleted.
*
* @return Zero on success or a value from @ref errno.h on failure.
* @return Zero on success or a value from @ref errno.h on failure.
*/
int as_area_destroy(as_t *as, uintptr_t address)
{
626,18 → 615,19
* sh_info of the source area. The process of duplicating the
* mapping is done through the backend share function.
*
* @param src_as Pointer to source address space.
* @param src_base Base address of the source address space area.
* @param acc_size Expected size of the source area.
* @param dst_as Pointer to destination address space.
* @param dst_base Target base address.
* @param src_as Pointer to source address space.
* @param src_base Base address of the source address space area.
* @param acc_size Expected size of the source area.
* @param dst_as Pointer to destination address space.
* @param dst_base Target base address.
* @param dst_flags_mask Destination address space area flags mask.
*
* @return Zero on success or ENOENT if there is no such task or if there is no
* such address space area, EPERM if there was a problem in accepting the area
* or ENOMEM if there was a problem in allocating destination address space
* area. ENOTSUP is returned if the address space area backend does not support
* sharing.
* @return Zero on success or ENOENT if there is no such task or if
* there is no such address space area, EPERM if there was
* a problem in accepting the area or ENOMEM if there was a
* problem in allocating destination address space area.
* ENOTSUP is returned if the address space area backend
* does not support sharing.
*/
int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
as_t *dst_as, uintptr_t dst_base, int dst_flags_mask)
698,7 → 688,7
sh_info = src_area->sh_info;
if (!sh_info) {
sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
mutex_initialize(&sh_info->lock);
mutex_initialize(&sh_info->lock, MUTEX_PASSIVE);
sh_info->refcount = 2;
btree_create(&sh_info->pagemap);
src_area->sh_info = sh_info;
756,10 → 746,11
*
* The address space area must be locked prior to this call.
*
* @param area Address space area.
* @param access Access mode.
* @param area Address space area.
* @param access Access mode.
*
* @return False if access violates area's permissions, true otherwise.
* @return False if access violates area's permissions, true
* otherwise.
*/
bool as_area_check_access(as_area_t *area, pf_access_t access)
{
775,21 → 766,183
return true;
}
 
/** Change adress space area flags.
*
* The idea is to have the same data, but with a different access mode.
* This is needed e.g. for writing code into memory and then executing it.
* In order for this to work properly, this may copy the data
* into private anonymous memory (unless it's already there).
*
* @param as Address space.
* @param flags Flags of the area memory.
* @param address Address within the area to be changed.
*
* @return Zero on success or a value from @ref errno.h on failure.
*
*/
int as_area_change_flags(as_t *as, int flags, uintptr_t address)
{
as_area_t *area;
uintptr_t base;
link_t *cur;
ipl_t ipl;
int page_flags;
uintptr_t *old_frame;
index_t frame_idx;
count_t used_pages;
/* Flags for the new memory mapping */
page_flags = area_flags_to_page_flags(flags);
 
ipl = interrupts_disable();
mutex_lock(&as->lock);
 
area = find_area_and_lock(as, address);
if (!area) {
mutex_unlock(&as->lock);
interrupts_restore(ipl);
return ENOENT;
}
 
if ((area->sh_info) || (area->backend != &anon_backend)) {
/* Copying shared areas not supported yet */
/* Copying non-anonymous memory not supported yet */
mutex_unlock(&area->lock);
mutex_unlock(&as->lock);
interrupts_restore(ipl);
return ENOTSUP;
}
 
base = area->base;
 
/*
* Compute total number of used pages in the used_space B+tree
*/
used_pages = 0;
 
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
used_pages += (count_t) node->value[i];
}
}
 
/* An array for storing frame numbers */
old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
 
/*
* Start TLB shootdown sequence.
*/
tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages);
 
/*
* Remove used pages from page tables and remember their frame
* numbers.
*/
frame_idx = 0;
 
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t b = node->key[i];
count_t j;
pte_t *pte;
for (j = 0; j < (count_t) node->value[i]; j++) {
page_table_lock(as, false);
pte = page_mapping_find(as, b + j * PAGE_SIZE);
ASSERT(pte && PTE_VALID(pte) &&
PTE_PRESENT(pte));
old_frame[frame_idx++] = PTE_GET_FRAME(pte);
 
/* Remove old mapping */
page_mapping_remove(as, b + j * PAGE_SIZE);
page_table_unlock(as, false);
}
}
}
 
/*
* Finish TLB shootdown sequence.
*/
 
tlb_invalidate_pages(as->asid, area->base, area->pages);
/*
* Invalidate potential software translation caches (e.g. TSB on
* sparc64).
*/
as_invalidate_translation_cache(as, area->base, area->pages);
tlb_shootdown_finalize();
 
/*
* Set the new flags.
*/
area->flags = flags;
 
/*
* Map pages back in with new flags. This step is kept separate
* so that the memory area could not be accesed with both the old and
* the new flags at once.
*/
frame_idx = 0;
 
for (cur = area->used_space.leaf_head.next;
cur != &area->used_space.leaf_head; cur = cur->next) {
btree_node_t *node;
unsigned int i;
node = list_get_instance(cur, btree_node_t, leaf_link);
for (i = 0; i < node->keys; i++) {
uintptr_t b = node->key[i];
count_t j;
for (j = 0; j < (count_t) node->value[i]; j++) {
page_table_lock(as, false);
 
/* Insert the new mapping */
page_mapping_insert(as, b + j * PAGE_SIZE,
old_frame[frame_idx++], page_flags);
 
page_table_unlock(as, false);
}
}
}
 
free(old_frame);
 
mutex_unlock(&area->lock);
mutex_unlock(&as->lock);
interrupts_restore(ipl);
 
return 0;
}
 
 
/** Handle page fault within the current address space.
*
* This is the high-level page fault handler. It decides
* whether the page fault can be resolved by any backend
* and if so, it invokes the backend to resolve the page
* fault.
* This is the high-level page fault handler. It decides whether the page fault
* can be resolved by any backend and if so, it invokes the backend to resolve
* the page fault.
*
* Interrupts are assumed disabled.
*
* @param page Faulting page.
* @param access Access mode that caused the fault (i.e. read/write/exec).
* @param istate Pointer to interrupted state.
* @param page Faulting page.
* @param access Access mode that caused the page fault (i.e.
* read/write/exec).
* @param istate Pointer to the interrupted state.
*
* @return AS_PF_FAULT on page fault, AS_PF_OK on success or AS_PF_DEFER if the
* fault was caused by copy_to_uspace() or copy_from_uspace().
* @return AS_PF_FAULT on page fault, AS_PF_OK on success or
* AS_PF_DEFER if the fault was caused by copy_to_uspace()
* or copy_from_uspace().
*/
int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
{
835,9 → 988,8
page_table_lock(AS, false);
/*
* To avoid race condition between two page faults
* on the same address, we need to make sure
* the mapping has not been already inserted.
* To avoid race condition between two page faults on the same address,
* we need to make sure the mapping has not been already inserted.
*/
if ((pte = page_mapping_find(AS, page))) {
if (PTE_PRESENT(pte)) {
891,8 → 1043,8
*
* When this function is enetered, no spinlocks may be held.
*
* @param old Old address space or NULL.
* @param new New address space.
* @param old Old address space or NULL.
* @param new New address space.
*/
void as_switch(as_t *old_as, as_t *new_as)
{
963,9 → 1115,9
 
/** Convert address space area flags to page flags.
*
* @param aflags Flags of some address space area.
* @param aflags Flags of some address space area.
*
* @return Flags to be passed to page_mapping_insert().
* @return Flags to be passed to page_mapping_insert().
*/
int area_flags_to_page_flags(int aflags)
{
993,9 → 1145,9
* The address space area must be locked.
* Interrupts must be disabled.
*
* @param a Address space area.
* @param a Address space area.
*
* @return Flags to be used in page_mapping_insert().
* @return Flags to be used in page_mapping_insert().
*/
int as_area_get_flags(as_area_t *a)
{
1004,23 → 1156,20
 
/** Create page table.
*
* Depending on architecture, create either address space
* private or global page table.
* Depending on architecture, create either address space private or global page
* table.
*
* @param flags Flags saying whether the page table is for kernel address space.
* @param flags Flags saying whether the page table is for the kernel
* address space.
*
* @return First entry of the page table.
* @return First entry of the page table.
*/
pte_t *page_table_create(int flags)
{
#ifdef __OBJC__
return [as_t page_table_create: flags];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_create);
return as_operations->page_table_create(flags);
#endif
}
 
/** Destroy page table.
1027,18 → 1176,14
*
* Destroy page table in architecture specific way.
*
* @param page_table Physical address of PTL0.
* @param page_table Physical address of PTL0.
*/
void page_table_destroy(pte_t *page_table)
{
#ifdef __OBJC__
return [as_t page_table_destroy: page_table];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_destroy);
as_operations->page_table_destroy(page_table);
#endif
}
 
/** Lock page table.
1050,36 → 1195,28
* prior to this call. Address space can be locked prior to this
* call in which case the lock argument is false.
*
* @param as Address space.
* @param lock If false, do not attempt to lock as->lock.
* @param as Address space.
* @param lock If false, do not attempt to lock as->lock.
*/
void page_table_lock(as_t *as, bool lock)
{
#ifdef __OBJC__
[as page_table_lock: lock];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_lock);
as_operations->page_table_lock(as, lock);
#endif
}
 
/** Unlock page table.
*
* @param as Address space.
* @param unlock If false, do not attempt to unlock as->lock.
* @param as Address space.
* @param unlock If false, do not attempt to unlock as->lock.
*/
void page_table_unlock(as_t *as, bool unlock)
{
#ifdef __OBJC__
[as page_table_unlock: unlock];
#else
ASSERT(as_operations);
ASSERT(as_operations->page_table_unlock);
as_operations->page_table_unlock(as, unlock);
#endif
}
 
 
1087,11 → 1224,11
*
* The address space must be locked and interrupts must be disabled.
*
* @param as Address space.
* @param va Virtual address.
* @param as Address space.
* @param va Virtual address.
*
* @return Locked address space area containing va on success or NULL on
* failure.
* @return Locked address space area containing va on success or
* NULL on failure.
*/
as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
{
1143,15 → 1280,15
*
* The address space must be locked and interrupts must be disabled.
*
* @param as Address space.
* @param va Starting virtual address of the area being tested.
* @param size Size of the area being tested.
* @param avoid_area Do not touch this area.
* @param as Address space.
* @param va Starting virtual address of the area being tested.
* @param size Size of the area being tested.
* @param avoid_area Do not touch this area.
*
* @return True if there is no conflict, false otherwise.
* @return True if there is no conflict, false otherwise.
*/
bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
as_area_t *avoid_area)
bool
check_area_conflicts(as_t *as, uintptr_t va, size_t size, as_area_t *avoid_area)
{
as_area_t *a;
btree_node_t *leaf, *node;
1240,7 → 1377,7
 
ipl = interrupts_disable();
src_area = find_area_and_lock(AS, base);
if (src_area){
if (src_area) {
size = src_area->pages * PAGE_SIZE;
mutex_unlock(&src_area->lock);
} else {
1254,11 → 1391,11
*
* The address space area must be already locked.
*
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
*
* @return 0 on failure and 1 on success.
* @return Zero on failure and non-zero on success.
*/
int used_space_insert(as_area_t *a, uintptr_t page, count_t count)
{
1528,8 → 1665,8
}
}
 
panic("Inconsistency detected while adding %d pages of used space at "
"%p.\n", count, page);
panic("Inconsistency detected while adding %" PRIc " pages of used "
"space at %p.", count, page);
}
 
/** Mark portion of address space area as unused.
1536,11 → 1673,11
*
* The address space area must be already locked.
*
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
* @param a Address space area.
* @param page First page to be marked.
* @param count Number of page to be marked.
*
* @return 0 on failure and 1 on success.
* @return Zero on failure and non-zero on success.
*/
int used_space_remove(as_area_t *a, uintptr_t page, count_t count)
{
1707,8 → 1844,8
}
 
error:
panic("Inconsistency detected while removing %d pages of used space "
"from %p.\n", count, page);
panic("Inconsistency detected while removing %" PRIc " pages of used "
"space from %p.", count, page);
}
 
/** Remove reference to address space area share info.
1715,7 → 1852,7
*
* If the reference count drops to 0, the sh_info is deallocated.
*
* @param sh_info Pointer to address space area share info.
* @param sh_info Pointer to address space area share info.
*/
void sh_info_remove_reference(share_info_t *sh_info)
{
1770,6 → 1907,12
return (unative_t) as_area_resize(AS, address, size, 0);
}
 
/** Wrapper for as_area_change_flags(). */
unative_t sys_as_area_change_flags(uintptr_t address, int flags)
{
return (unative_t) as_area_change_flags(AS, flags, address);
}
 
/** Wrapper for as_area_destroy(). */
unative_t sys_as_area_destroy(uintptr_t address)
{
1778,7 → 1921,7
 
/** Print out information about address space.
*
* @param as Address space.
* @param as Address space.
*/
void as_print(as_t *as)
{
1800,9 → 1943,9
as_area_t *area = node->value[i];
mutex_lock(&area->lock);
printf("as_area: %p, base=%p, pages=%d (%p - %p)\n",
area, area->base, area->pages, area->base,
area->base + area->pages*PAGE_SIZE);
printf("as_area: %p, base=%p, pages=%" PRIc
" (%p - %p)\n", area, area->base, area->pages,
area->base, area->base + FRAMES2SIZE(area->pages));
mutex_unlock(&area->lock);
}
}
/branches/dd/kernel/generic/src/mm/buddy.c
35,8 → 35,7
* @brief Buddy allocator framework.
*
* This file contains buddy system allocator framework.
* Specialized functions are needed for this abstract framework
* to be useful.
* Specialized functions are needed for this abstract framework to be useful.
*/
 
#include <mm/buddy.h>
44,29 → 43,29
#include <arch/types.h>
#include <debug.h>
#include <print.h>
#include <macros.h>
 
/** Return size needed for the buddy configuration data */
size_t buddy_conf_size(int max_order)
/** Return size needed for the buddy configuration data. */
size_t buddy_conf_size(size_t max_order)
{
return sizeof(buddy_system_t) + (max_order + 1) * sizeof(link_t);
}
 
 
/** Create buddy system
/** Create buddy system.
*
* Allocate memory for and initialize new buddy system.
*
* @param b Preallocated buddy system control data.
* @param max_order The biggest allocable size will be 2^max_order.
* @param op Operations for new buddy system.
* @param data Pointer to be used by implementation.
* @param b Preallocated buddy system control data.
* @param max_order The biggest allocable size will be 2^max_order.
* @param op Operations for new buddy system.
* @param data Pointer to be used by implementation.
*
* @return New buddy system.
* @return New buddy system.
*/
void buddy_system_create(buddy_system_t *b,
uint8_t max_order,
buddy_system_operations_t *op,
void *data)
void
buddy_system_create(buddy_system_t *b, uint8_t max_order,
buddy_system_operations_t *op, void *data)
{
int i;
 
80,7 → 79,7
ASSERT(op->mark_busy);
 
/*
* Use memory after our own structure
* Use memory after our own structure.
*/
b->order = (link_t *) (&b[1]);
92,14 → 91,15
b->data = data;
}
 
/** Check if buddy system can allocate block
/** Check if buddy system can allocate block.
*
* @param b Buddy system pointer
* @param i Size of the block (2^i)
* @param b Buddy system pointer.
* @param i Size of the block (2^i).
*
* @return True if block can be allocated
* @return True if block can be allocated.
*/
bool buddy_system_can_alloc(buddy_system_t *b, uint8_t i) {
bool buddy_system_can_alloc(buddy_system_t *b, uint8_t i)
{
uint8_t k;
/*
106,12 → 106,13
* If requested block is greater then maximal block
* we know immediatly that we cannot satisfy the request.
*/
if (i > b->max_order) return false;
if (i > b->max_order)
return false;
 
/*
* Check if any bigger or equal order has free elements
*/
for (k=i; k <= b->max_order; k++) {
for (k = i; k <= b->max_order; k++) {
if (!list_empty(&b->order[k])) {
return true;
}
118,12 → 119,11
}
return false;
}
 
/** Allocate PARTICULAR block from buddy system
/** Allocate PARTICULAR block from buddy system.
*
* @ return Block of data or NULL if no such block was found
* @return Block of data or NULL if no such block was found.
*/
link_t *buddy_system_alloc_block(buddy_system_t *b, link_t *block)
{
134,7 → 134,7
ASSERT(left);
list_remove(left);
while (1) {
if (! b->op->get_order(b,left)) {
if (!b->op->get_order(b, left)) {
b->op->mark_busy(b, left);
return left;
}
142,8 → 142,8
order = b->op->get_order(b, left);
 
right = b->op->bisect(b, left);
b->op->set_order(b, left, order-1);
b->op->set_order(b, right, order-1);
b->op->set_order(b, left, order - 1);
b->op->set_order(b, right, order - 1);
 
tmp = b->op->find_block(b, block, BUDDY_SYSTEM_INNER_BLOCK);
 
160,10 → 160,10
 
/** Allocate block from buddy system.
*
* @param b Buddy system pointer.
* @param i Returned block will be 2^i big.
* @param b Buddy system pointer.
* @param i Returned block will be 2^i big.
*
* @return Block of data represented by link_t.
* @return Block of data represented by link_t.
*/
link_t *buddy_system_alloc(buddy_system_t *b, uint8_t i)
{
217,13 → 217,12
buddy_system_free(b, hlp);
return res;
}
 
/** Return block to buddy system.
*
* @param b Buddy system pointer.
* @param block Block to return.
* @param b Buddy system pointer.
* @param block Block to return.
*/
void buddy_system_free(buddy_system_t *b, link_t *block)
{
267,7 → 266,8
b->op->set_order(b, hlp, i + 1);
 
/*
* Recursively add the coalesced block to the list of order i + 1.
* Recursively add the coalesced block to the list of
* order i + 1.
*/
buddy_system_free(b, hlp);
return;
278,46 → 278,7
* Insert block into the list of order i.
*/
list_append(block, &b->order[i]);
 
}
 
/** Prints out structure of buddy system
*
* @param b Pointer to buddy system
* @param elem_size Element size
*/
void buddy_system_structure_print(buddy_system_t *b, size_t elem_size) {
index_t i;
count_t cnt, elem_count = 0, block_count = 0;
link_t * cur;
 
printf("Order\tBlocks\tSize \tBlock size\tElems per block\n");
printf("-----\t------\t--------\t----------\t---------------\n");
for (i=0;i <= b->max_order; i++) {
cnt = 0;
if (!list_empty(&b->order[i])) {
for (cur = b->order[i].next; cur != &b->order[i]; cur = cur->next)
cnt++;
}
printf("#%zd\t%5zd\t%7zdK\t%8zdK\t%6zd\t", i, cnt, (cnt * (1 << i) * elem_size) >> 10, ((1 << i) * elem_size) >> 10, 1 << i);
if (!list_empty(&b->order[i])) {
for (cur = b->order[i].next; cur != &b->order[i]; cur = cur->next) {
b->op->print_id(b, cur);
printf(" ");
}
}
printf("\n");
block_count += cnt;
elem_count += (1 << i) * cnt;
}
printf("-----\t------\t--------\t----------\t---------------\n");
printf("Buddy system contains %zd free elements (%zd blocks)\n" , elem_count, block_count);
 
}
 
/** @}
*/
/branches/dd/kernel/generic/src/mm/backend_phys.c
77,7 → 77,7
page_mapping_insert(AS, addr, base + (addr - area->base),
as_area_get_flags(area));
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
panic("Could not insert used space.\n");
panic("Cannot insert used space.");
 
return AS_PF_OK;
}
/branches/dd/kernel/generic/src/mm/frame.c
1,6 → 1,7
/*
* Copyright (c) 2001-2005 Jakub Jermar
* Copyright (c) 2005 Sergey Bondari
* Copyright (c) 2009 Martin Decky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
33,7 → 34,7
 
/**
* @file
* @brief Physical frame allocator.
* @brief Physical frame allocator.
*
* This file contains the physical frame allocator and memory zone management.
* The frame allocator is built on top of the buddy allocator.
41,16 → 42,6
* @see buddy.c
*/
 
/*
* Locking order
*
* In order to access particular zone, the process must first lock
* the zones.lock, then lock the zone and then unlock the zones.lock.
* This insures, that we can fiddle with the zones in runtime without
* affecting the processes.
*
*/
 
#include <arch/types.h>
#include <mm/frame.h>
#include <mm/as.h>
57,7 → 48,8
#include <panic.h>
#include <debug.h>
#include <adt/list.h>
#include <synch/spinlock.h>
#include <synch/mutex.h>
#include <synch/condvar.h>
#include <arch/asm.h>
#include <arch.h>
#include <print.h>
67,43 → 59,17
#include <macros.h>
#include <config.h>
 
typedef struct {
count_t refcount; /**< tracking of shared frames */
uint8_t buddy_order; /**< buddy system block order */
link_t buddy_link; /**< link to the next free block inside one
order */
void *parent; /**< If allocated by slab, this points there */
} frame_t;
zones_t zones;
 
typedef struct {
SPINLOCK_DECLARE(lock); /**< this lock protects everything below */
pfn_t base; /**< frame_no of the first frame in the frames
array */
count_t count; /**< Size of zone */
 
frame_t *frames; /**< array of frame_t structures in this
zone */
count_t free_count; /**< number of free frame_t structures */
count_t busy_count; /**< number of busy frame_t structures */
buddy_system_t *buddy_system; /**< buddy system for the zone */
int flags;
} zone_t;
 
/*
* The zoneinfo.lock must be locked when accessing zoneinfo structure.
* Some of the attributes in zone_t structures are 'read-only'
* Synchronization primitives used to sleep when there is no memory
* available.
*/
mutex_t mem_avail_mtx;
condvar_t mem_avail_cv;
count_t mem_avail_req = 0; /**< Number of frames requested. */
count_t mem_avail_gen = 0; /**< Generation counter. */
 
typedef struct {
SPINLOCK_DECLARE(lock);
unsigned int count;
zone_t *info[ZONES_MAX];
} zones_t;
 
static zones_t zones;
 
 
/********************/
/* Helper functions */
/********************/
118,22 → 84,20
return (index_t) (frame - zone->frames) + zone->base;
}
 
static inline int frame_index_valid(zone_t *zone, index_t index)
static inline bool frame_index_valid(zone_t *zone, index_t index)
{
return (index < zone->count);
}
 
/** Compute pfn_t from frame_t pointer & zone pointer */
static index_t make_frame_index(zone_t *zone, frame_t *frame)
static inline index_t make_frame_index(zone_t *zone, frame_t *frame)
{
return (frame - zone->frames);
}
 
/** Initialize frame structure
/** Initialize frame structure.
*
* Initialize frame structure.
* @param frame Frame structure to be initialized.
*
* @param frame Frame structure to be initialized.
*/
static void frame_initialize(frame_t *frame)
{
141,142 → 105,145
frame->buddy_order = 0;
}
 
/**********************/
/* Zoneinfo functions */
/**********************/
/*******************/
/* Zones functions */
/*******************/
 
/**
* Insert-sort zone into zones list
/** Insert-sort zone into zones list.
*
* @param newzone New zone to be inserted into zone list
* @return zone number on success, -1 on error
* Assume interrupts are disabled and zones lock is
* locked.
*
* @param base Base frame of the newly inserted zone.
* @param count Number of frames of the newly inserted zone.
*
* @return Zone number on success, -1 on error.
*
*/
static int zones_add_zone(zone_t *newzone)
static count_t zones_insert_zone(pfn_t base, count_t count)
{
unsigned int i, j;
ipl_t ipl;
zone_t *z;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
/* Try to merge */
if (zones.count + 1 == ZONES_MAX) {
printf("Maximum zone count %u exceeded!\n", ZONES_MAX);
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return -1;
return (count_t) -1;
}
count_t i;
for (i = 0; i < zones.count; i++) {
/* Check for overflow */
z = zones.info[i];
if (overlaps(newzone->base, newzone->count, z->base, z->count)) {
/* Check for overlap */
if (overlaps(base, count,
zones.info[i].base, zones.info[i].count)) {
printf("Zones overlap!\n");
return -1;
return (count_t) -1;
}
if (newzone->base < z->base)
if (base < zones.info[i].base)
break;
}
/* Move other zones up */
for (j = i; j < zones.count; j++)
zones.info[j + 1] = zones.info[j];
count_t j;
for (j = zones.count; j > i; j--) {
zones.info[j] = zones.info[j - 1];
zones.info[j].buddy_system->data =
(void *) &zones.info[j - 1];
}
zones.info[i] = newzone;
zones.count++;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
 
return i;
}
 
/**
* Try to find a zone where can we find the frame
/** Get total available frames.
*
* Assume interrupts are disabled.
* Assume interrupts are disabled and zones lock is
* locked.
*
* @param frame Frame number contained in zone
* @param pzone If not null, it is used as zone hint. Zone index
* is filled into the variable on success.
* @return Pointer to locked zone containing frame
* @return Total number of available frames.
*
*/
static zone_t * find_zone_and_lock(pfn_t frame, unsigned int *pzone)
#ifdef CONFIG_DEBUG
static count_t total_frames_free(void)
{
unsigned int i;
unsigned int hint = pzone ? *pzone : 0;
zone_t *z;
count_t total = 0;
count_t i;
for (i = 0; i < zones.count; i++)
total += zones.info[i].free_count;
spinlock_lock(&zones.lock);
return total;
}
#endif
 
/** Find a zone with a given frames.
*
* Assume interrupts are disabled and zones lock is
* locked.
*
* @param frame Frame number contained in zone.
* @param count Number of frames to look for.
* @param hint Used as zone hint.
*
* @return Zone index or -1 if not found.
*
*/
count_t find_zone(pfn_t frame, count_t count, count_t hint)
{
if (hint >= zones.count)
hint = 0;
i = hint;
count_t i = hint;
do {
z = zones.info[i];
spinlock_lock(&z->lock);
if (z->base <= frame && z->base + z->count > frame) {
/* Unlock the global lock */
spinlock_unlock(&zones.lock);
if (pzone)
*pzone = i;
return z;
}
spinlock_unlock(&z->lock);
 
if ((zones.info[i].base <= frame)
&& (zones.info[i].base + zones.info[i].count >= frame + count))
return i;
i++;
if (i >= zones.count)
i = 0;
} while(i != hint);
 
spinlock_unlock(&zones.lock);
return NULL;
} while (i != hint);
return (count_t) -1;
}
 
/** @return True if zone can allocate specified order */
static int zone_can_alloc(zone_t *z, uint8_t order)
static bool zone_can_alloc(zone_t *zone, uint8_t order)
{
return buddy_system_can_alloc(z->buddy_system, order);
return (zone_flags_available(zone->flags)
&& buddy_system_can_alloc(zone->buddy_system, order));
}
 
/** Find and lock zone that can allocate order frames.
/** Find a zone that can allocate order frames.
*
* Assume interrupts are disabled.
* Assume interrupts are disabled and zones lock is
* locked.
*
* @param order Size (2^order) of free space we are trying to find
* @param pzone Pointer to preferred zone or NULL, on return contains zone
* number
* @param order Size (2^order) of free space we are trying to find.
* @param flags Required flags of the target zone.
* @param hind Preferred zone.
*
*/
static zone_t * find_free_zone_and_lock(uint8_t order, unsigned int *pzone)
static count_t find_free_zone(uint8_t order, zone_flags_t flags, count_t hint)
{
unsigned int i;
zone_t *z;
unsigned int hint = pzone ? *pzone : 0;
spinlock_lock(&zones.lock);
if (hint >= zones.count)
hint = 0;
i = hint;
count_t i = hint;
do {
z = zones.info[i];
/*
* Check whether the zone meets the search criteria.
*/
if ((zones.info[i].flags & flags) == flags) {
/*
* Check if the zone has 2^order frames area available.
*/
if (zone_can_alloc(&zones.info[i], order))
return i;
}
spinlock_lock(&z->lock);
 
/* Check if the zone has 2^order frames area available */
if (zone_can_alloc(z, order)) {
spinlock_unlock(&zones.lock);
if (pzone)
*pzone = i;
return z;
}
spinlock_unlock(&z->lock);
if (++i >= zones.count)
i++;
if (i >= zones.count)
i = 0;
} while(i != hint);
spinlock_unlock(&zones.lock);
return NULL;
} while (i != hint);
return (count_t) -1;
}
 
/**************************/
283,167 → 250,146
/* Buddy system functions */
/**************************/
 
/** Buddy system find_block implementation
/** Buddy system find_block implementation.
*
* Find block that is parent of current list.
* That means go to lower addresses, until such block is found
*
* @param order - Order of parent must be different then this parameter!!
* @param order Order of parent must be different then this
* parameter!!
*
*/
static link_t *zone_buddy_find_block(buddy_system_t *b, link_t *child,
static link_t *zone_buddy_find_block(buddy_system_t *buddy, link_t *child,
uint8_t order)
{
frame_t *frame;
zone_t *zone;
index_t index;
frame_t *frame = list_get_instance(child, frame_t, buddy_link);
zone_t *zone = (zone_t *) buddy->data;
frame = list_get_instance(child, frame_t, buddy_link);
zone = (zone_t *) b->data;
 
index = frame_index(zone, frame);
index_t index = frame_index(zone, frame);
do {
if (zone->frames[index].buddy_order != order) {
if (zone->frames[index].buddy_order != order)
return &zone->frames[index].buddy_link;
}
} while(index-- > 0);
} while (index-- > 0);
return NULL;
}
 
static void zone_buddy_print_id(buddy_system_t *b, link_t *block)
{
frame_t *frame;
zone_t *zone;
index_t index;
 
frame = list_get_instance(block, frame_t, buddy_link);
zone = (zone_t *) b->data;
index = frame_index(zone, frame);
printf("%zd", index);
}
 
/** Buddy system find_buddy implementation
/** Buddy system find_buddy implementation.
*
* @param b Buddy system.
* @param block Block for which buddy should be found
* @param buddy Buddy system.
* @param block Block for which buddy should be found.
*
* @return Buddy for given block if found
* @return Buddy for given block if found.
*
*/
static link_t *zone_buddy_find_buddy(buddy_system_t *b, link_t *block)
static link_t *zone_buddy_find_buddy(buddy_system_t *buddy, link_t *block)
{
frame_t *frame;
zone_t *zone;
index_t index;
bool is_left, is_right;
 
frame = list_get_instance(block, frame_t, buddy_link);
zone = (zone_t *) b->data;
frame_t *frame = list_get_instance(block, frame_t, buddy_link);
zone_t *zone = (zone_t *) buddy->data;
ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),
frame->buddy_order));
is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
 
ASSERT(is_left ^ is_right);
bool is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
index_t index;
if (is_left) {
index = (frame_index(zone, frame)) + (1 << frame->buddy_order);
} else { /* if (is_right) */
index = (frame_index(zone, frame)) - (1 << frame->buddy_order);
index = (frame_index(zone, frame)) +
(1 << frame->buddy_order);
} else { /* is_right */
index = (frame_index(zone, frame)) -
(1 << frame->buddy_order);
}
if (frame_index_valid(zone, index)) {
if (zone->frames[index].buddy_order == frame->buddy_order &&
zone->frames[index].refcount == 0) {
if ((zone->frames[index].buddy_order == frame->buddy_order) &&
(zone->frames[index].refcount == 0)) {
return &zone->frames[index].buddy_link;
}
}
 
return NULL;
return NULL;
}
 
/** Buddy system bisect implementation
/** Buddy system bisect implementation.
*
* @param b Buddy system.
* @param block Block to bisect
* @param buddy Buddy system.
* @param block Block to bisect.
*
* @return right block
* @return Right block.
*
*/
static link_t * zone_buddy_bisect(buddy_system_t *b, link_t *block) {
frame_t *frame_l, *frame_r;
 
frame_l = list_get_instance(block, frame_t, buddy_link);
frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
static link_t *zone_buddy_bisect(buddy_system_t *buddy, link_t *block)
{
frame_t *frame_l = list_get_instance(block, frame_t, buddy_link);
frame_t *frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
return &frame_r->buddy_link;
}
 
/** Buddy system coalesce implementation
/** Buddy system coalesce implementation.
*
* @param b Buddy system.
* @param block_1 First block
* @param block_2 First block's buddy
* @param buddy Buddy system.
* @param block_1 First block.
* @param block_2 First block's buddy.
*
* @return Coalesced block (actually block that represents lower address)
* @return Coalesced block (actually block that represents lower
* address).
*
*/
static link_t *zone_buddy_coalesce(buddy_system_t *b, link_t *block_1,
link_t *block_2)
static link_t *zone_buddy_coalesce(buddy_system_t *buddy, link_t *block_1,
link_t *block_2)
{
frame_t *frame1, *frame2;
frame_t *frame1 = list_get_instance(block_1, frame_t, buddy_link);
frame_t *frame2 = list_get_instance(block_2, frame_t, buddy_link);
frame1 = list_get_instance(block_1, frame_t, buddy_link);
frame2 = list_get_instance(block_2, frame_t, buddy_link);
return frame1 < frame2 ? block_1 : block_2;
return ((frame1 < frame2) ? block_1 : block_2);
}
 
/** Buddy system set_order implementation
/** Buddy system set_order implementation.
*
* @param b Buddy system.
* @param block Buddy system block
* @param order Order to set
* @param buddy Buddy system.
* @param block Buddy system block.
* @param order Order to set.
*
*/
static void zone_buddy_set_order(buddy_system_t *b, link_t *block,
uint8_t order) {
frame_t *frame;
frame = list_get_instance(block, frame_t, buddy_link);
frame->buddy_order = order;
static void zone_buddy_set_order(buddy_system_t *buddy, link_t *block,
uint8_t order)
{
list_get_instance(block, frame_t, buddy_link)->buddy_order = order;
}
 
/** Buddy system get_order implementation
/** Buddy system get_order implementation.
*
* @param b Buddy system.
* @param block Buddy system block
* @param buddy Buddy system.
* @param block Buddy system block.
*
* @return Order of block
* @return Order of block.
*
*/
static uint8_t zone_buddy_get_order(buddy_system_t *b, link_t *block) {
frame_t *frame;
frame = list_get_instance(block, frame_t, buddy_link);
return frame->buddy_order;
static uint8_t zone_buddy_get_order(buddy_system_t *buddy, link_t *block)
{
return list_get_instance(block, frame_t, buddy_link)->buddy_order;
}
 
/** Buddy system mark_busy implementation
/** Buddy system mark_busy implementation.
*
* @param b Buddy system
* @param block Buddy system block
* @param buddy Buddy system.
* @param block Buddy system block.
*
*/
static void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
frame_t * frame;
 
frame = list_get_instance(block, frame_t, buddy_link);
frame->refcount = 1;
static void zone_buddy_mark_busy(buddy_system_t *buddy, link_t * block)
{
list_get_instance(block, frame_t, buddy_link)->refcount = 1;
}
 
/** Buddy system mark_available implementation
/** Buddy system mark_available implementation.
*
* @param b Buddy system
* @param block Buddy system block
*
* @param buddy Buddy system.
* @param block Buddy system block.
*/
static void zone_buddy_mark_available(buddy_system_t *b, link_t *block) {
frame_t *frame;
frame = list_get_instance(block, frame_t, buddy_link);
frame->refcount = 0;
static void zone_buddy_mark_available(buddy_system_t *buddy, link_t *block)
{
list_get_instance(block, frame_t, buddy_link)->refcount = 0;
}
 
static buddy_system_operations_t zone_buddy_system_operations = {
454,8 → 400,7
.get_order = zone_buddy_get_order,
.mark_busy = zone_buddy_mark_busy,
.mark_available = zone_buddy_mark_available,
.find_block = zone_buddy_find_block,
.print_id = zone_buddy_print_id
.find_block = zone_buddy_find_block
};
 
/******************/
462,62 → 407,59
/* Zone functions */
/******************/
 
/** Allocate frame in particular zone
/** Allocate frame in particular zone.
*
* Assume zone is locked
* Assume zone is locked and is available for allocation.
* Panics if allocation is impossible.
*
* @param zone Zone to allocate from.
* @param order Allocate exactly 2^order frames.
*
* @return Frame index in zone
* @return Frame index in zone.
*
*/
static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
{
pfn_t v;
link_t *tmp;
frame_t *frame;
 
ASSERT(zone_flags_available(zone->flags));
/* Allocate frames from zone buddy system */
tmp = buddy_system_alloc(zone->buddy_system, order);
link_t *link = buddy_system_alloc(zone->buddy_system, order);
ASSERT(tmp);
ASSERT(link);
/* Update zone information. */
zone->free_count -= (1 << order);
zone->busy_count += (1 << order);
 
/* Frame will be actually a first frame of the block. */
frame = list_get_instance(tmp, frame_t, buddy_link);
frame_t *frame = list_get_instance(link, frame_t, buddy_link);
/* get frame address */
v = make_frame_index(zone, frame);
return v;
/* Get frame address */
return make_frame_index(zone, frame);
}
 
/** Free frame from zone
/** Free frame from zone.
*
* Assume zone is locked
* Assume zone is locked and is available for deallocation.
*
* @param zone Pointer to zone from which the frame is to be freed
* @param frame_idx Frame index relative to zone
* @param zone Pointer to zone from which the frame is to be freed.
* @param frame_idx Frame index relative to zone.
*
*/
static void zone_frame_free(zone_t *zone, index_t frame_idx)
{
frame_t *frame;
uint8_t order;
 
frame = &zone->frames[frame_idx];
ASSERT(zone_flags_available(zone->flags));
/* remember frame order */
order = frame->buddy_order;
 
frame_t *frame = &zone->frames[frame_idx];
/* Remember frame order */
uint8_t order = frame->buddy_order;
ASSERT(frame->refcount);
 
if (!--frame->refcount) {
buddy_system_free(zone->buddy_system, &frame->buddy_link);
/* Update zone information. */
zone->free_count += (1 << order);
zone->busy_count -= (1 << order);
524,521 → 466,643
}
}
 
/** Return frame from zone */
static frame_t * zone_get_frame(zone_t *zone, index_t frame_idx)
/** Return frame from zone. */
static frame_t *zone_get_frame(zone_t *zone, index_t frame_idx)
{
ASSERT(frame_idx < zone->count);
return &zone->frames[frame_idx];
}
 
/** Mark frame in zone unavailable to allocation */
/** Mark frame in zone unavailable to allocation. */
static void zone_mark_unavailable(zone_t *zone, index_t frame_idx)
{
frame_t *frame;
link_t *link;
 
frame = zone_get_frame(zone, frame_idx);
ASSERT(zone_flags_available(zone->flags));
frame_t *frame = zone_get_frame(zone, frame_idx);
if (frame->refcount)
return;
link_t *link __attribute__ ((unused));
link = buddy_system_alloc_block(zone->buddy_system,
&frame->buddy_link);
ASSERT(link);
zone->free_count--;
}
 
/**
* Join 2 zones
/** Merge two zones.
*
* Expect zone_t *z to point to space at least zone_conf_size large
* Expect buddy to point to space at least zone_conf_size large.
* Assume z1 & z2 are locked and compatible and zones lock is
* locked.
*
* Assume z1 & z2 are locked
* @param z1 First zone to merge.
* @param z2 Second zone to merge.
* @param old_z1 Original date of the first zone.
* @param buddy Merged zone buddy.
*
* @param z Target zone structure pointer
* @param z1 Zone to merge
* @param z2 Zone to merge
*/
static void _zone_merge(zone_t *z, zone_t *z1, zone_t *z2)
static void zone_merge_internal(count_t z1, count_t z2, zone_t *old_z1, buddy_system_t *buddy)
{
uint8_t max_order;
unsigned int i;
int z2idx;
pfn_t frame_idx;
frame_t *frame;
 
ASSERT(!overlaps(z1->base, z1->count, z2->base, z2->count));
ASSERT(z1->base < z2->base);
 
spinlock_initialize(&z->lock, "zone_lock");
z->base = z1->base;
z->count = z2->base + z2->count - z1->base;
z->flags = z1->flags & z2->flags;
 
z->free_count = z1->free_count + z2->free_count;
z->busy_count = z1->busy_count + z2->busy_count;
ASSERT(zone_flags_available(zones.info[z1].flags));
ASSERT(zone_flags_available(zones.info[z2].flags));
ASSERT(zones.info[z1].flags == zones.info[z2].flags);
ASSERT(zones.info[z1].base < zones.info[z2].base);
ASSERT(!overlaps(zones.info[z1].base, zones.info[z1].count,
zones.info[z2].base, zones.info[z2].count));
max_order = fnzb(z->count);
 
z->buddy_system = (buddy_system_t *) &z[1];
buddy_system_create(z->buddy_system, max_order,
&zone_buddy_system_operations, (void *) z);
 
z->frames = (frame_t *)((uint8_t *) z->buddy_system +
buddy_conf_size(max_order));
for (i = 0; i < z->count; i++) {
/* This marks all frames busy */
frame_initialize(&z->frames[i]);
}
/* Difference between zone bases */
pfn_t base_diff = zones.info[z2].base - zones.info[z1].base;
zones.info[z1].count = base_diff + zones.info[z2].count;
zones.info[z1].free_count += zones.info[z2].free_count;
zones.info[z1].busy_count += zones.info[z2].busy_count;
zones.info[z1].buddy_system = buddy;
uint8_t order = fnzb(zones.info[z1].count);
buddy_system_create(zones.info[z1].buddy_system, order,
&zone_buddy_system_operations, (void *) &zones.info[z1]);
zones.info[z1].frames =
(frame_t *) ((uint8_t *) zones.info[z1].buddy_system
+ buddy_conf_size(order));
/* This marks all frames busy */
count_t i;
for (i = 0; i < zones.info[z1].count; i++)
frame_initialize(&zones.info[z1].frames[i]);
/* Copy frames from both zones to preserve full frame orders,
* parents etc. Set all free frames with refcount=0 to 1, because
* we add all free frames to buddy allocator later again, clear
* order to 0. Don't set busy frames with refcount=0, as they
* parents etc. Set all free frames with refcount = 0 to 1, because
* we add all free frames to buddy allocator later again, clearing
* order to 0. Don't set busy frames with refcount = 0, as they
* will not be reallocated during merge and it would make later
* problems with allocation/free.
*/
for (i = 0; i < z1->count; i++)
z->frames[i] = z1->frames[i];
for (i = 0; i < z2->count; i++) {
z2idx = i + (z2->base - z1->base);
z->frames[z2idx] = z2->frames[i];
}
for (i = 0; i < old_z1->count; i++)
zones.info[z1].frames[i] = old_z1->frames[i];
for (i = 0; i < zones.info[z2].count; i++)
zones.info[z1].frames[base_diff + i]
= zones.info[z2].frames[i];
i = 0;
while (i < z->count) {
if (z->frames[i].refcount) {
/* skip busy frames */
i += 1 << z->frames[i].buddy_order;
} else { /* Free frames, set refcount=1 */
/* All free frames have refcount=0, we need not
* to check the order */
z->frames[i].refcount = 1;
z->frames[i].buddy_order = 0;
while (i < zones.info[z1].count) {
if (zones.info[z1].frames[i].refcount) {
/* Skip busy frames */
i += 1 << zones.info[z1].frames[i].buddy_order;
} else {
/* Free frames, set refcount = 1
* (all free frames have refcount == 0, we need not
* to check the order)
*/
zones.info[z1].frames[i].refcount = 1;
zones.info[z1].frames[i].buddy_order = 0;
i++;
}
}
/* Add free blocks from the 2 original zones */
while (zone_can_alloc(z1, 0)) {
frame_idx = zone_frame_alloc(z1, 0);
frame = &z->frames[frame_idx];
/* Add free blocks from the original zone z1 */
while (zone_can_alloc(old_z1, 0)) {
/* Allocate from the original zone */
pfn_t frame_idx = zone_frame_alloc(old_z1, 0);
/* Free the frame from the merged zone */
frame_t *frame = &zones.info[z1].frames[frame_idx];
frame->refcount = 0;
buddy_system_free(z->buddy_system, &frame->buddy_link);
buddy_system_free(zones.info[z1].buddy_system, &frame->buddy_link);
}
while (zone_can_alloc(z2, 0)) {
frame_idx = zone_frame_alloc(z2, 0);
frame = &z->frames[frame_idx + (z2->base - z1->base)];
/* Add free blocks from the original zone z2 */
while (zone_can_alloc(&zones.info[z2], 0)) {
/* Allocate from the original zone */
pfn_t frame_idx = zone_frame_alloc(&zones.info[z2], 0);
/* Free the frame from the merged zone */
frame_t *frame = &zones.info[z1].frames[base_diff + frame_idx];
frame->refcount = 0;
buddy_system_free(z->buddy_system, &frame->buddy_link);
buddy_system_free(zones.info[z1].buddy_system, &frame->buddy_link);
}
}
 
/** Return old configuration frames into the zone
/** Return old configuration frames into the zone.
*
* We have several cases
* - the conf. data is outside of zone -> exit, shall we call frame_free??
* - the conf. data was created by zone_create or
* updated with reduce_region -> free every frame
* We have two cases:
* - The configuration data is outside the zone
* -> do nothing (perhaps call frame_free?)
* - The configuration data was created by zone_create
* or updated by reduce_region -> free every frame
*
* @param newzone The actual zone where freeing should occur
* @param oldzone Pointer to old zone configuration data that should
* be freed from new zone
* @param znum The actual zone where freeing should occur.
* @param pfn Old zone configuration frame.
* @param count Old zone frame count.
*
*/
static void return_config_frames(zone_t *newzone, zone_t *oldzone)
static void return_config_frames(count_t znum, pfn_t pfn, count_t count)
{
pfn_t pfn;
frame_t *frame;
count_t cframes;
unsigned int i;
 
pfn = ADDR2PFN((uintptr_t)KA2PA(oldzone));
cframes = SIZE2FRAMES(zone_conf_size(oldzone->count));
ASSERT(zone_flags_available(zones.info[znum].flags));
if (pfn < newzone->base || pfn >= newzone->base + newzone->count)
count_t cframes = SIZE2FRAMES(zone_conf_size(count));
if ((pfn < zones.info[znum].base)
|| (pfn >= zones.info[znum].base + zones.info[znum].count))
return;
frame_t *frame __attribute__ ((unused));
 
frame = &newzone->frames[pfn - newzone->base];
frame = &zones.info[znum].frames[pfn - zones.info[znum].base];
ASSERT(!frame->buddy_order);
 
count_t i;
for (i = 0; i < cframes; i++) {
newzone->busy_count++;
zone_frame_free(newzone, pfn+i-newzone->base);
zones.info[znum].busy_count++;
zone_frame_free(&zones.info[znum],
pfn - zones.info[znum].base + i);
}
}
 
/** Reduce allocated block to count of order 0 frames
/** Reduce allocated block to count of order 0 frames.
*
* The allocated block need 2^order frames of space. Reduce all frames
* in block to order 0 and free the unneeded frames. This means, that
* when freeing the previously allocated block starting with frame_idx,
* The allocated block needs 2^order frames. Reduce all frames
* in the block to order 0 and free the unneeded frames. This means that
* when freeing the previously allocated block starting with frame_idx,
* you have to free every frame.
*
* @param zone
* @param frame_idx Index to block
* @param count Allocated space in block
* @param znum Zone.
* @param frame_idx Index the first frame of the block.
* @param count Allocated frames in block.
*
*/
static void zone_reduce_region(zone_t *zone, pfn_t frame_idx, count_t count)
static void zone_reduce_region(count_t znum, pfn_t frame_idx, count_t count)
{
count_t i;
uint8_t order;
frame_t *frame;
ASSERT(zone_flags_available(zones.info[znum].flags));
ASSERT(frame_idx + count < zones.info[znum].count);
ASSERT(frame_idx + count < zone->count);
 
order = zone->frames[frame_idx].buddy_order;
uint8_t order = zones.info[znum].frames[frame_idx].buddy_order;
ASSERT((count_t) (1 << order) >= count);
 
/* Reduce all blocks to order 0 */
count_t i;
for (i = 0; i < (count_t) (1 << order); i++) {
frame = &zone->frames[i + frame_idx];
frame_t *frame = &zones.info[znum].frames[i + frame_idx];
frame->buddy_order = 0;
if (!frame->refcount)
frame->refcount = 1;
ASSERT(frame->refcount == 1);
}
/* Free unneeded frames */
for (i = count; i < (count_t) (1 << order); i++) {
zone_frame_free(zone, i + frame_idx);
}
for (i = count; i < (count_t) (1 << order); i++)
zone_frame_free(&zones.info[znum], i + frame_idx);
}
 
/** Merge zones z1 and z2
/** Merge zones z1 and z2.
*
* - the zones must be 2 zones with no zone existing in between,
* which means that z2 = z1+1
* The merged zones must be 2 zones with no zone existing in between
* (which means that z2 = z1 + 1). Both zones must be available zones
* with the same flags.
*
* - When you create a new zone, the frame allocator configuration does
* not to be 2^order size. Once the allocator is running it is no longer
* possible, merged configuration data occupies more space :-/
* When you create a new zone, the frame allocator configuration does
* not to be 2^order size. Once the allocator is running it is no longer
* possible, merged configuration data occupies more space :-/
*
* The function uses
*
*/
void zone_merge(unsigned int z1, unsigned int z2)
bool zone_merge(count_t z1, count_t z2)
{
ipl_t ipl;
zone_t *zone1, *zone2, *newzone;
unsigned int cframes;
uint8_t order;
unsigned int i;
pfn_t pfn;
 
ipl = interrupts_disable();
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
 
if ((z1 >= zones.count) || (z2 >= zones.count))
bool ret = true;
/* We can join only 2 zones with none existing inbetween,
* the zones have to be available and with the same
* set of flags
*/
if ((z1 >= zones.count) || (z2 >= zones.count)
|| (z2 - z1 != 1)
|| (!zone_flags_available(zones.info[z1].flags))
|| (!zone_flags_available(zones.info[z2].flags))
|| (zones.info[z1].flags != zones.info[z2].flags)) {
ret = false;
goto errout;
/* We can join only 2 zones with none existing inbetween */
if (z2-z1 != 1)
goto errout;
 
zone1 = zones.info[z1];
zone2 = zones.info[z2];
spinlock_lock(&zone1->lock);
spinlock_lock(&zone2->lock);
 
cframes = SIZE2FRAMES(zone_conf_size(zone2->base + zone2->count -
zone1->base));
}
pfn_t cframes = SIZE2FRAMES(zone_conf_size(
zones.info[z2].base - zones.info[z1].base
+ zones.info[z2].count));
uint8_t order;
if (cframes == 1)
order = 0;
else
else
order = fnzb(cframes - 1) + 1;
 
/* Allocate zonedata inside one of the zones */
if (zone_can_alloc(zone1, order))
pfn = zone1->base + zone_frame_alloc(zone1, order);
else if (zone_can_alloc(zone2, order))
pfn = zone2->base + zone_frame_alloc(zone2, order);
else
goto errout2;
 
newzone = (zone_t *) PA2KA(PFN2ADDR(pfn));
 
_zone_merge(newzone, zone1, zone2);
 
/* Allocate merged zone data inside one of the zones */
pfn_t pfn;
if (zone_can_alloc(&zones.info[z1], order)) {
pfn = zones.info[z1].base + zone_frame_alloc(&zones.info[z1], order);
} else if (zone_can_alloc(&zones.info[z2], order)) {
pfn = zones.info[z2].base + zone_frame_alloc(&zones.info[z2], order);
} else {
ret = false;
goto errout;
}
/* Preserve original data from z1 */
zone_t old_z1 = zones.info[z1];
old_z1.buddy_system->data = (void *) &old_z1;
/* Do zone merging */
buddy_system_t *buddy = (buddy_system_t *) PA2KA(PFN2ADDR(pfn));
zone_merge_internal(z1, z2, &old_z1, buddy);
/* Free unneeded config frames */
zone_reduce_region(newzone, pfn - newzone->base, cframes);
zone_reduce_region(z1, pfn - zones.info[z1].base, cframes);
/* Subtract zone information from busy frames */
newzone->busy_count -= cframes;
 
/* Replace existing zones in zoneinfo list */
zones.info[z1] = newzone;
for (i = z2 + 1; i < zones.count; i++)
zones.info[z1].busy_count -= cframes;
/* Free old zone information */
return_config_frames(z1,
ADDR2PFN(KA2PA((uintptr_t) old_z1.frames)), old_z1.count);
return_config_frames(z1,
ADDR2PFN(KA2PA((uintptr_t) zones.info[z2].frames)),
zones.info[z2].count);
/* Move zones down */
count_t i;
for (i = z2 + 1; i < zones.count; i++) {
zones.info[i - 1] = zones.info[i];
zones.info[i - 1].buddy_system->data =
(void *) &zones.info[i - 1];
}
zones.count--;
 
/* Free old zone information */
return_config_frames(newzone, zone1);
return_config_frames(newzone, zone2);
errout2:
/* Nobody is allowed to enter to zone, so we are safe
* to touch the spinlocks last time */
spinlock_unlock(&zone1->lock);
spinlock_unlock(&zone2->lock);
errout:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return ret;
}
 
/**
* Merge all zones into one big zone
/** Merge all mergeable zones into one big zone.
*
* It is reasonable to do this on systems whose bios reports parts in chunks,
* so that we could have 1 zone (it's faster).
* It is reasonable to do this on systems where
* BIOS reports parts in chunks, so that we could
* have 1 zone (it's faster).
*
*/
void zone_merge_all(void)
{
int count = zones.count;
 
while (zones.count > 1 && --count) {
zone_merge(0,1);
break;
count_t i = 0;
while (i < zones.count) {
if (!zone_merge(i, i + 1))
i++;
}
}
 
/** Create frame zone
/** Create new frame zone.
*
* Create new frame zone.
*
* @param zone Zone to construct.
* @param buddy Address of buddy system configuration information.
* @param start Physical address of the first frame within the zone.
* @param count Count of frames in zone
* @param z Address of configuration information of zone
* @param count Count of frames in zone.
* @param flags Zone flags.
*
* @return Initialized zone.
*
*/
static void zone_construct(pfn_t start, count_t count, zone_t *z, int flags)
static void zone_construct(zone_t *zone, buddy_system_t *buddy, pfn_t start, count_t count, zone_flags_t flags)
{
unsigned int i;
uint8_t max_order;
 
spinlock_initialize(&z->lock, "zone_lock");
z->base = start;
z->count = count;
z->flags = flags;
z->free_count = count;
z->busy_count = 0;
 
/*
* Compute order for buddy system, initialize
*/
max_order = fnzb(count);
z->buddy_system = (buddy_system_t *)&z[1];
zone->base = start;
zone->count = count;
zone->flags = flags;
zone->free_count = count;
zone->busy_count = 0;
zone->buddy_system = buddy;
buddy_system_create(z->buddy_system, max_order,
&zone_buddy_system_operations,
(void *) z);
/* Allocate frames _after_ the conframe */
/* Check sizes */
z->frames = (frame_t *)((uint8_t *) z->buddy_system +
buddy_conf_size(max_order));
for (i = 0; i < count; i++) {
frame_initialize(&z->frames[i]);
}
/* Stuffing frames */
for (i = 0; i < count; i++) {
z->frames[i].refcount = 0;
buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);
}
if (zone_flags_available(flags)) {
/*
* Compute order for buddy system and initialize
*/
uint8_t order = fnzb(count);
buddy_system_create(zone->buddy_system, order,
&zone_buddy_system_operations, (void *) zone);
/* Allocate frames _after_ the confframe */
/* Check sizes */
zone->frames = (frame_t *) ((uint8_t *) zone->buddy_system +
buddy_conf_size(order));
count_t i;
for (i = 0; i < count; i++)
frame_initialize(&zone->frames[i]);
/* Stuffing frames */
for (i = 0; i < count; i++) {
zone->frames[i].refcount = 0;
buddy_system_free(zone->buddy_system, &zone->frames[i].buddy_link);
}
} else
zone->frames = NULL;
}
 
/** Compute configuration data size for zone
/** Compute configuration data size for zone.
*
* @param count Size of zone in frames
* @return Size of zone configuration info (in bytes)
* @param count Size of zone in frames.
*
* @return Size of zone configuration info (in bytes).
*
*/
uintptr_t zone_conf_size(count_t count)
{
int size = sizeof(zone_t) + count*sizeof(frame_t);
int max_order;
 
max_order = fnzb(count);
size += buddy_conf_size(max_order);
return size;
return (count * sizeof(frame_t) + buddy_conf_size(fnzb(count)));
}
 
/** Create and add zone to system
/** Create and add zone to system.
*
* @param start First frame number (absolute)
* @param count Size of zone in frames
* @param start First frame number (absolute).
* @param count Size of zone in frames.
* @param confframe Where configuration frames are supposed to be.
* Automatically checks, that we will not disturb the
* kernel and possibly init.
* If confframe is given _outside_ this zone, it is expected,
* that the area is already marked BUSY and big enough
* to contain zone_conf_size() amount of data.
* If the confframe is inside the area, the zone free frame
* information is modified not to include it.
* Automatically checks, that we will not disturb the
* kernel and possibly init. If confframe is given
* _outside_ this zone, it is expected, that the area is
* already marked BUSY and big enough to contain
* zone_conf_size() amount of data. If the confframe is
* inside the area, the zone free frame information is
* modified not to include it.
*
* @return Zone number or -1 on error
* @return Zone number or -1 on error.
*
*/
int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags)
count_t zone_create(pfn_t start, count_t count, pfn_t confframe, zone_flags_t flags)
{
zone_t *z;
uintptr_t addr;
count_t confcount;
unsigned int i;
int znum;
 
/* Theoretically we could have here 0, practically make sure
* nobody tries to do that. If some platform requires, remove
* the assert
*/
ASSERT(confframe);
/* If conframe is supposed to be inside our zone, then make sure
* it does not span kernel & init
*/
confcount = SIZE2FRAMES(zone_conf_size(count));
if (confframe >= start && confframe < start+count) {
for (;confframe < start + count; confframe++) {
addr = PFN2ADDR(confframe);
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(config.base), config.kernel_size))
continue;
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(config.stack_base), config.stack_size))
continue;
bool overlap = false;
count_t i;
for (i = 0; i < init.cnt; i++)
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (zone_flags_available(flags)) { /* Create available zone */
/* Theoretically we could have NULL here, practically make sure
* nobody tries to do that. If some platform requires, remove
* the assert
*/
ASSERT(confframe != NULL);
/* If confframe is supposed to be inside our zone, then make sure
* it does not span kernel & init
*/
count_t confcount = SIZE2FRAMES(zone_conf_size(count));
if ((confframe >= start) && (confframe < start + count)) {
for (; confframe < start + count; confframe++) {
uintptr_t addr = PFN2ADDR(confframe);
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(init.tasks[i].addr),
init.tasks[i].size)) {
overlap = true;
break;
}
if (overlap)
continue;
KA2PA(config.base), config.kernel_size))
continue;
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(config.stack_base), config.stack_size))
continue;
bool overlap = false;
count_t i;
for (i = 0; i < init.cnt; i++)
if (overlaps(addr, PFN2ADDR(confcount),
KA2PA(init.tasks[i].addr),
init.tasks[i].size)) {
overlap = true;
break;
}
if (overlap)
continue;
break;
}
break;
if (confframe >= start + count)
panic("Cannot find configuration data for zone.");
}
if (confframe >= start + count)
panic("Cannot find configuration data for zone.");
count_t znum = zones_insert_zone(start, count);
if (znum == (count_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return (count_t) -1;
}
buddy_system_t *buddy = (buddy_system_t *) PA2KA(PFN2ADDR(confframe));
zone_construct(&zones.info[znum], buddy, start, count, flags);
/* If confdata in zone, mark as unavailable */
if ((confframe >= start) && (confframe < start + count)) {
count_t i;
for (i = confframe; i < confframe + confcount; i++)
zone_mark_unavailable(&zones.info[znum],
i - zones.info[znum].base);
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return znum;
}
 
z = (zone_t *) PA2KA(PFN2ADDR(confframe));
zone_construct(start, count, z, flags);
znum = zones_add_zone(z);
if (znum == -1)
return -1;
 
/* If confdata in zone, mark as unavailable */
if (confframe >= start && confframe < start + count)
for (i = confframe; i < confframe + confcount; i++) {
zone_mark_unavailable(z, i - z->base);
}
/* Non-available zone */
count_t znum = zones_insert_zone(start, count);
if (znum == (count_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return (count_t) -1;
}
zone_construct(&zones.info[znum], NULL, start, count, flags);
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return znum;
}
 
/***************************************/
/*******************/
/* Frame functions */
/*******************/
 
/** Set parent of frame */
void frame_set_parent(pfn_t pfn, void *data, unsigned int hint)
/** Set parent of frame. */
void frame_set_parent(pfn_t pfn, void *data, count_t hint)
{
zone_t *zone = find_zone_and_lock(pfn, &hint);
 
ASSERT(zone);
 
zone_get_frame(zone, pfn-zone->base)->parent = data;
spinlock_unlock(&zone->lock);
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
count_t znum = find_zone(pfn, 1, hint);
ASSERT(znum != (count_t) -1);
zone_get_frame(&zones.info[znum],
pfn - zones.info[znum].base)->parent = data;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
}
 
void *frame_get_parent(pfn_t pfn, unsigned int hint)
void *frame_get_parent(pfn_t pfn, count_t hint)
{
zone_t *zone = find_zone_and_lock(pfn, &hint);
void *res;
 
ASSERT(zone);
res = zone_get_frame(zone, pfn - zone->base)->parent;
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
spinlock_unlock(&zone->lock);
count_t znum = find_zone(pfn, 1, hint);
ASSERT(znum != (count_t) -1);
void *res = zone_get_frame(&zones.info[znum],
pfn - zones.info[znum].base)->parent;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return res;
}
 
/** Allocate power-of-two frames of physical memory.
*
* @param order Allocate exactly 2^order frames.
* @param flags Flags for host zone selection and address processing.
* @param pzone Preferred zone
* @param order Allocate exactly 2^order frames.
* @param flags Flags for host zone selection and address processing.
* @param pzone Preferred zone.
*
* @return Physical address of the allocated frame.
*
*/
void * frame_alloc_generic(uint8_t order, int flags, unsigned int *pzone)
void *frame_alloc_generic(uint8_t order, frame_flags_t flags, count_t *pzone)
{
count_t size = ((count_t) 1) << order;
ipl_t ipl;
int freed;
pfn_t v;
zone_t *zone;
count_t hint = pzone ? (*pzone) : 0;
loop:
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
/*
* First, find suitable frame zone.
*/
zone = find_free_zone_and_lock(order, pzone);
count_t znum = find_free_zone(order,
FRAME_TO_ZONE_FLAGS(flags), hint);
/* If no memory, reclaim some slab memory,
if it does not help, reclaim all */
if (!zone && !(flags & FRAME_NO_RECLAIM)) {
freed = slab_reclaim(0);
if (freed)
zone = find_free_zone_and_lock(order, pzone);
if (!zone) {
if ((znum == (count_t) -1) && (!(flags & FRAME_NO_RECLAIM))) {
count_t freed = slab_reclaim(0);
if (freed > 0)
znum = find_free_zone(order,
FRAME_TO_ZONE_FLAGS(flags), hint);
if (znum == (count_t) -1) {
freed = slab_reclaim(SLAB_RECLAIM_ALL);
if (freed)
zone = find_free_zone_and_lock(order, pzone);
if (freed > 0)
znum = find_free_zone(order,
FRAME_TO_ZONE_FLAGS(flags), hint);
}
}
if (!zone) {
if (znum == (count_t) -1) {
if (flags & FRAME_ATOMIC) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
return NULL;
}
#ifdef CONFIG_DEBUG
count_t avail = total_frames_free();
#endif
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
/*
* TODO: Sleep until frames are available again.
* Sleep until some frames are available again.
*/
interrupts_restore(ipl);
 
if (flags & FRAME_ATOMIC)
return 0;
panic("Sleep not implemented.\n");
#ifdef CONFIG_DEBUG
printf("Thread %" PRIu64 " waiting for %" PRIc " frames, "
"%" PRIc " available.\n", THREAD->tid, size, avail);
#endif
mutex_lock(&mem_avail_mtx);
if (mem_avail_req > 0)
mem_avail_req = min(mem_avail_req, size);
else
mem_avail_req = size;
count_t gen = mem_avail_gen;
while (gen == mem_avail_gen)
condvar_wait(&mem_avail_cv, &mem_avail_mtx);
mutex_unlock(&mem_avail_mtx);
#ifdef CONFIG_DEBUG
printf("Thread %" PRIu64 " woken up.\n", THREAD->tid);
#endif
goto loop;
}
v = zone_frame_alloc(zone, order);
v += zone->base;
 
spinlock_unlock(&zone->lock);
pfn_t pfn = zone_frame_alloc(&zones.info[znum], order)
+ zones.info[znum].base;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
 
if (pzone)
*pzone = znum;
if (flags & FRAME_KA)
return (void *)PA2KA(PFN2ADDR(v));
return (void *)PFN2ADDR(v);
return (void *) PA2KA(PFN2ADDR(pfn));
return (void *) PFN2ADDR(pfn);
}
 
/** Free a frame.
*
* Find respective frame structure for supplied physical frame address.
* Decrement frame reference count.
* If it drops to zero, move the frame structure to free list.
* Decrement frame reference count. If it drops to zero, move the frame
* structure to free list.
*
* @param Frame Physical Address of of the frame to be freed.
* @param frame Physical Address of of the frame to be freed.
*
*/
void frame_free(uintptr_t frame)
{
ipl_t ipl;
zone_t *zone;
pfn_t pfn = ADDR2PFN(frame);
 
ipl = interrupts_disable();
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
/*
* First, find host frame zone for addr.
*/
zone = find_zone_and_lock(pfn,NULL);
ASSERT(zone);
pfn_t pfn = ADDR2PFN(frame);
count_t znum = find_zone(pfn, 1, NULL);
zone_frame_free(zone, pfn-zone->base);
ASSERT(znum != (count_t) -1);
spinlock_unlock(&zone->lock);
zone_frame_free(&zones.info[znum], pfn - zones.info[znum].base);
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
/*
* Signal that some memory has been freed.
*/
mutex_lock(&mem_avail_mtx);
if (mem_avail_req > 0)
mem_avail_req--;
if (mem_avail_req == 0) {
mem_avail_gen++;
condvar_broadcast(&mem_avail_cv);
}
mutex_unlock(&mem_avail_mtx);
}
 
/** Add reference to frame.
1047,55 → 1111,56
* increment frame reference count.
*
* @param pfn Frame number of the frame to be freed.
*
*/
void frame_reference_add(pfn_t pfn)
{
ipl_t ipl;
zone_t *zone;
frame_t *frame;
 
ipl = interrupts_disable();
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
/*
* First, find host frame zone for addr.
*/
zone = find_zone_and_lock(pfn,NULL);
ASSERT(zone);
count_t znum = find_zone(pfn, 1, NULL);
frame = &zone->frames[pfn-zone->base];
frame->refcount++;
ASSERT(znum != (count_t) -1);
spinlock_unlock(&zone->lock);
zones.info[znum].frames[pfn - zones.info[znum].base].refcount++;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
}
 
/** Mark given range unavailable in frame zones */
/** Mark given range unavailable in frame zones. */
void frame_mark_unavailable(pfn_t start, count_t count)
{
unsigned int i;
zone_t *zone;
unsigned int prefzone = 0;
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
count_t i;
for (i = 0; i < count; i++) {
zone = find_zone_and_lock(start + i, &prefzone);
if (!zone) /* PFN not found */
count_t znum = find_zone(start + i, 1, 0);
if (znum == (count_t) -1) /* PFN not found */
continue;
zone_mark_unavailable(zone, start + i - zone->base);
 
spinlock_unlock(&zone->lock);
zone_mark_unavailable(&zones.info[znum],
start + i - zones.info[znum].base);
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
}
 
/** Initialize physical memory management
*
* Initialize physical memory managemnt.
*/
/** Initialize physical memory management. */
void frame_init(void)
{
if (config.cpu_active == 1) {
zones.count = 0;
spinlock_initialize(&zones.lock, "zones.lock");
mutex_initialize(&mem_avail_mtx, MUTEX_ACTIVE);
condvar_initialize(&mem_avail_cv);
}
/* Tell the architecture to create some memory */
frame_arch_init();
if (config.cpu_active == 1) {
1110,36 → 1175,28
frame_mark_unavailable(pfn,
SIZE2FRAMES(init.tasks[i].size));
}
 
if (ballocs.size)
frame_mark_unavailable(ADDR2PFN(KA2PA(ballocs.base)),
SIZE2FRAMES(ballocs.size));
 
/* Black list first frame, as allocating NULL would
* fail in some places */
* fail in some places
*/
frame_mark_unavailable(0, 1);
}
}
 
 
/** Return total size of all zones
*
*/
uint64_t zone_total_size(void) {
zone_t *zone = NULL;
unsigned int i;
ipl_t ipl;
uint64_t total = 0;
 
ipl = interrupts_disable();
/** Return total size of all zones. */
uint64_t zone_total_size(void)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
for (i = 0; i < zones.count; i++) {
zone = zones.info[i];
spinlock_lock(&zone->lock);
total += (uint64_t) FRAMES2SIZE(zone->count);
spinlock_unlock(&zone->lock);
}
uint64_t total = 0;
count_t i;
for (i = 0; i < zones.count; i++)
total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
1147,86 → 1204,128
return total;
}
 
/** Prints list of zones. */
void zone_print_list(void)
{
#ifdef __32_BITS__
printf("# base address frames flags free frames busy frames\n");
printf("-- ------------ ------------ -------- ------------ ------------\n");
#endif
 
 
/** Prints list of zones
*
*/
void zone_print_list(void) {
zone_t *zone = NULL;
unsigned int i;
ipl_t ipl;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
#ifdef __64_BITS__
printf("# base address frames flags free frames busy frames\n");
printf("-- -------------------- ------------ -------- ------------ ------------\n");
#endif
if (sizeof(void *) == 4) {
printf("# base address free frames busy frames\n");
printf("-- ------------ ------------ ------------\n");
} else {
printf("# base address free frames busy frames\n");
printf("-- -------------------- ------------ ------------\n");
}
/*
* Because printing may require allocation of memory, we may not hold
* the frame allocator locks when printing zone statistics. Therefore,
* we simply gather the statistics under the protection of the locks and
* print the statistics when the locks have been released.
*
* When someone adds/removes zones while we are printing the statistics,
* we may end up with inaccurate output (e.g. a zone being skipped from
* the listing).
*/
for (i = 0; i < zones.count; i++) {
zone = zones.info[i];
spinlock_lock(&zone->lock);
count_t i;
for (i = 0;; i++) {
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (sizeof(void *) == 4)
printf("%-2d %#10zx %12zd %12zd\n", i, PFN2ADDR(zone->base),
zone->free_count, zone->busy_count);
else
printf("%-2d %#18zx %12zd %12zd\n", i, PFN2ADDR(zone->base),
zone->free_count, zone->busy_count);
if (i >= zones.count) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
break;
}
spinlock_unlock(&zone->lock);
uintptr_t base = PFN2ADDR(zones.info[i].base);
count_t count = zones.info[i].count;
zone_flags_t flags = zones.info[i].flags;
count_t free_count = zones.info[i].free_count;
count_t busy_count = zones.info[i].busy_count;
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
bool available = zone_flags_available(flags);
printf("%-2" PRIc, i);
#ifdef __32_BITS__
printf(" %10p", base);
#endif
#ifdef __64_BITS__
printf(" %18p", base);
#endif
printf(" %12" PRIc " %c%c%c ", count,
available ? 'A' : ' ',
(flags & ZONE_RESERVED) ? 'R' : ' ',
(flags & ZONE_FIRMWARE) ? 'F' : ' ');
if (available)
printf("%12" PRIc " %12" PRIc,
free_count, busy_count);
printf("\n");
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
}
 
/** Prints zone details.
*
* @param num Zone base address or zone number.
*
*/
void zone_print_one(unsigned int num) {
zone_t *zone = NULL;
ipl_t ipl;
unsigned int i;
 
ipl = interrupts_disable();
void zone_print_one(count_t num)
{
ipl_t ipl = interrupts_disable();
spinlock_lock(&zones.lock);
 
count_t znum = (count_t) -1;
count_t i;
for (i = 0; i < zones.count; i++) {
if ((i == num) || (PFN2ADDR(zones.info[i]->base) == num)) {
zone = zones.info[i];
if ((i == num) || (PFN2ADDR(zones.info[i].base) == num)) {
znum = i;
break;
}
}
if (!zone) {
if (znum == (count_t) -1) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
printf("Zone not found.\n");
goto out;
return;
}
spinlock_lock(&zone->lock);
printf("Memory zone information\n");
printf("Zone base address: %#.*p\n", sizeof(uintptr_t) * 2,
PFN2ADDR(zone->base));
printf("Zone size: %zd frames (%zd KB)\n", zone->count,
SIZE2KB(FRAMES2SIZE(zone->count)));
printf("Allocated space: %zd frames (%zd KB)\n", zone->busy_count,
SIZE2KB(FRAMES2SIZE(zone->busy_count)));
printf("Available space: %zd frames (%zd KB)\n", zone->free_count,
SIZE2KB(FRAMES2SIZE(zone->free_count)));
buddy_system_structure_print(zone->buddy_system, FRAME_SIZE);
spinlock_unlock(&zone->lock);
uintptr_t base = PFN2ADDR(zones.info[i].base);
zone_flags_t flags = zones.info[i].flags;
count_t count = zones.info[i].count;
count_t free_count = zones.info[i].free_count;
count_t busy_count = zones.info[i].busy_count;
out:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
bool available = zone_flags_available(flags);
printf("Zone number: %" PRIc "\n", znum);
printf("Zone base address: %p\n", base);
printf("Zone size: %" PRIc " frames (%" PRIs " KiB)\n", count,
SIZE2KB(FRAMES2SIZE(count)));
printf("Zone flags: %c%c%c\n",
available ? 'A' : ' ',
(flags & ZONE_RESERVED) ? 'R' : ' ',
(flags & ZONE_FIRMWARE) ? 'F' : ' ');
if (available) {
printf("Allocated space: %" PRIc " frames (%" PRIs " KiB)\n",
busy_count, SIZE2KB(FRAMES2SIZE(busy_count)));
printf("Available space: %" PRIc " frames (%" PRIs " KiB)\n",
free_count, SIZE2KB(FRAMES2SIZE(free_count)));
}
}
 
/** @}
*/
 
/branches/dd/kernel/generic/src/mm/page.c
40,11 → 40,28
* They however, define the single interface.
*/
 
/*
* Note on memory prefetching and updating memory mappings, also described in:
* AMD x86-64 Architecture Programmer's Manual, Volume 2, System Programming,
* 7.2.1 Special Coherency Considerations.
*
* The processor which modifies a page table mapping can access prefetched data
* from the old mapping. In order to prevent this, we place a memory barrier
* after a mapping is updated.
*
* We assume that the other processors are either not using the mapping yet
* (i.e. during the bootstrap) or are executing the TLB shootdown code. While
* we don't care much about the former case, the processors in the latter case
* will do an implicit serialization by virtue of running the TLB shootdown
* interrupt handler.
*/
 
#include <mm/page.h>
#include <arch/mm/page.h>
#include <arch/mm/asid.h>
#include <mm/as.h>
#include <mm/frame.h>
#include <arch/barrier.h>
#include <arch/types.h>
#include <arch/asm.h>
#include <memstr.h>
65,8 → 82,8
* considering possible crossings
* of page boundaries.
*
* @param s Address of the structure.
* @param size Size of the structure.
* @param s Address of the structure.
* @param size Size of the structure.
*/
void map_structure(uintptr_t s, size_t size)
{
76,8 → 93,11
cnt = length / PAGE_SIZE + (length % PAGE_SIZE > 0);
 
for (i = 0; i < cnt; i++)
page_mapping_insert(AS_KERNEL, s + i * PAGE_SIZE, s + i * PAGE_SIZE, PAGE_NOT_CACHEABLE | PAGE_WRITE);
page_mapping_insert(AS_KERNEL, s + i * PAGE_SIZE,
s + i * PAGE_SIZE, PAGE_NOT_CACHEABLE | PAGE_WRITE);
 
/* Repel prefetched accesses to the old mapping. */
memory_barrier();
}
 
/** Insert mapping of page to frame.
87,10 → 107,11
*
* The page table must be locked and interrupts must be disabled.
*
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be mapped.
* @param frame Physical address of memory frame to which the mapping is done.
* @param flags Flags to be used for mapping.
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be mapped.
* @param frame Physical address of memory frame to which the mapping is
* done.
* @param flags Flags to be used for mapping.
*/
void page_mapping_insert(as_t *as, uintptr_t page, uintptr_t frame, int flags)
{
98,6 → 119,9
ASSERT(page_mapping_operations->mapping_insert);
page_mapping_operations->mapping_insert(as, page, frame, flags);
/* Repel prefetched accesses to the old mapping. */
memory_barrier();
}
 
/** Remove mapping of page.
108,8 → 132,8
*
* The page table must be locked and interrupts must be disabled.
*
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be demapped.
* @param as Address space to wich page belongs.
* @param page Virtual address of the page to be demapped.
*/
void page_mapping_remove(as_t *as, uintptr_t page)
{
117,6 → 141,9
ASSERT(page_mapping_operations->mapping_remove);
page_mapping_operations->mapping_remove(as, page);
 
/* Repel prefetched accesses to the old mapping. */
memory_barrier();
}
 
/** Find mapping for virtual page
125,10 → 152,11
*
* The page table must be locked and interrupts must be disabled.
*
* @param as Address space to wich page belongs.
* @param page Virtual page.
* @param as Address space to wich page belongs.
* @param page Virtual page.
*
* @return NULL if there is no such mapping; requested mapping otherwise.
* @return NULL if there is no such mapping; requested mapping
* otherwise.
*/
pte_t *page_mapping_find(as_t *as, uintptr_t page)
{
/branches/dd/kernel/generic/src/mm/backend_elf.c
48,6 → 48,7
#include <memstr.h>
#include <macros.h>
#include <arch.h>
#include <arch/barrier.h>
 
#ifdef CONFIG_VIRT_IDX_DCACHE
#include <arch/mm/cache.h>
67,12 → 68,13
*
* The address space area and page tables must be already locked.
*
* @param area Pointer to the address space area.
* @param addr Faulting virtual address.
* @param access Access mode that caused the fault (i.e. read/write/exec).
* @param area Pointer to the address space area.
* @param addr Faulting virtual address.
* @param access Access mode that caused the fault (i.e.
* read/write/exec).
*
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e.
* serviced).
* @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK
* on success (i.e. serviced).
*/
int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
{
116,7 → 118,7
*/
 
for (i = 0; i < leaf->keys; i++) {
if (leaf->key[i] == page) {
if (leaf->key[i] == page - area->base) {
found = true;
break;
}
127,7 → 129,7
page_mapping_insert(AS, addr, frame,
as_area_get_flags(area));
if (!used_space_insert(area, page, 1))
panic("Could not insert used space.\n");
panic("Cannot insert used space.");
mutex_unlock(&area->sh_info->lock);
return AS_PF_OK;
}
150,6 → 152,10
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
memcpy((void *) PA2KA(frame),
(void *) (base + i * FRAME_SIZE), FRAME_SIZE);
if (entry->p_flags & PF_X) {
smc_coherence_block((void *) PA2KA(frame),
FRAME_SIZE);
}
dirty = true;
} else {
frame = KA2PA(base + i * FRAME_SIZE);
162,7 → 168,7
* and cleared.
*/
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
memsetb(PA2KA(frame), FRAME_SIZE, 0);
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
dirty = true;
} else {
size_t pad_lo, pad_hi;
187,8 → 193,13
memcpy((void *) (PA2KA(frame) + pad_lo),
(void *) (base + i * FRAME_SIZE + pad_lo),
FRAME_SIZE - pad_lo - pad_hi);
memsetb(PA2KA(frame), pad_lo, 0);
memsetb(PA2KA(frame) + FRAME_SIZE - pad_hi, pad_hi, 0);
if (entry->p_flags & PF_X) {
smc_coherence_block((void *) (PA2KA(frame) + pad_lo),
FRAME_SIZE - pad_lo - pad_hi);
}
memsetb((void *) PA2KA(frame), pad_lo, 0);
memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
0);
dirty = true;
}
 
203,7 → 214,7
 
page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
if (!used_space_insert(area, page, 1))
panic("Could not insert used space.\n");
panic("Cannot insert used space.");
 
return AS_PF_OK;
}
212,9 → 223,10
*
* The address space area and page tables must be already locked.
*
* @param area Pointer to the address space area.
* @param page Page that is mapped to frame. Must be aligned to PAGE_SIZE.
* @param frame Frame to be released.
* @param area Pointer to the address space area.
* @param page Page that is mapped to frame. Must be aligned to
* PAGE_SIZE.
* @param frame Frame to be released.
*
*/
void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
257,7 → 269,7
*
* The address space and address space area must be locked prior to the call.
*
* @param area Address space area.
* @param area Address space area.
*/
void elf_share(as_area_t *area)
{