Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3424 → Rev 3425

/branches/tracing/kernel/generic/src/mm/slab.c
794,30 → 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);
int skip = 0;
 
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) {
 
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;
spinlock_unlock(&slab_cache_lock);
interrupts_restore(ipl);
printf("%-16s %8" PRIs " %6d %6u %6ld %6ld %9ld %-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");
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)
/branches/tracing/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;
}
114,7 → 113,6
if (allocate) {
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
dirty = true;
/*
* Insert the address of the newly allocated
145,7 → 143,6
*/
frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
dirty = true;
}
/*
/branches/tracing/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,10 → 141,8
{
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)
159,20 → 152,14
 
/** 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);
199,6 → 186,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 → 252,7
 
interrupts_restore(ipl);
 
#ifdef __OBJC__
[as free];
#else
slab_free(as_slab, as);
#endif
}
 
/** Create address space area of common attributes.
274,19 → 259,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 → 297,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;
338,13 → 323,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)
{
399,7 → 385,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.
409,7 → 395,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);
 
/*
452,8 → 438,10
cond = false; /* we are almost done */
i = (start_free - b) >> PAGE_WIDTH;
if (!used_space_remove(area, start_free, c - i))
panic("Could not remove used space.\n");
if (!used_space_remove(area, start_free,
c - i))
panic("Could not remove used "
"space.\n");
} else {
/*
* The interval of used space can be
460,7 → 448,8
* completely removed.
*/
if (!used_space_remove(area, b, c))
panic("Could not remove used space.\n");
panic("Could not remove used "
"space.\n");
}
for (; i < c; i++) {
522,10 → 511,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)
{
622,18 → 611,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)
694,7 → 684,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;
752,10 → 742,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)
{
771,21 → 762,181
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 withing 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)
{
831,9 → 982,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)) {
887,8 → 1037,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)
{
1159,9 → 1309,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)
{
1189,9 → 1339,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)
{
1200,23 → 1350,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.
1223,18 → 1370,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.
1246,36 → 1389,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
}
 
 
1283,11 → 1418,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)
{
1339,15 → 1474,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;
1436,7 → 1571,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 {
1450,11 → 1585,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)
{
1724,8 → 1859,8
}
}
 
panic("Inconsistency detected while adding %" PRIc " pages of used space at "
"%p.\n", count, page);
panic("Inconsistency detected while adding %" PRIc " pages of used "
"space at %p.\n", count, page);
}
 
/** Mark portion of address space area as unused.
1732,11 → 1867,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)
{
1903,8 → 2038,8
}
 
error:
panic("Inconsistency detected while removing %" PRIc " pages of used space "
"from %p.\n", count, page);
panic("Inconsistency detected while removing %" PRIc " pages of used "
"space from %p.\n", count, page);
}
 
/** Remove reference to address space area share info.
1911,7 → 2046,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)
{
1966,6 → 2101,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)
{
1974,7 → 2115,7
 
/** Print out information about address space.
*
* @param as Address space.
* @param as Address space.
*/
void as_print(as_t *as)
{
1996,9 → 2137,9
as_area_t *area = node->value[i];
mutex_lock(&area->lock);
printf("as_area: %p, base=%p, pages=%" PRIc " (%p - %p)\n",
area, area->base, area->pages, area->base,
area->base + FRAMES2SIZE(area->pages));
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/tracing/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>
46,7 → 45,7
#include <print.h>
#include <macros.h>
 
/** Return size needed for the buddy configuration data */
/** Return size needed for the buddy configuration data. */
size_t buddy_conf_size(int max_order)
{
return sizeof(buddy_system_t) + (max_order + 1) * sizeof(link_t);
53,21 → 52,20
}
 
 
/** 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;
 
81,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]);
93,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;
/*
107,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;
}
119,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)
{
135,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;
}
143,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);
 
161,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)
{
218,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)
{
268,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;
279,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("#%" PRIi "\t%5" PRIc "\t%7" PRIc "K\t%8" PRIi "K\t%6u\t",
i, cnt, SIZE2KB(cnt * (1 << i) * elem_size), SIZE2KB((1 << i) * elem_size), 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 %" PRIc " free elements (%" PRIc " blocks)\n" , elem_count, block_count);
}
 
/** @}
*/
/branches/tracing/kernel/generic/src/mm/frame.c
58,6 → 58,8
#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>
103,6 → 105,14
 
static zones_t zones;
 
/*
* Synchronization primitives used to sleep when there is no memory
* available.
*/
mutex_t mem_avail_mtx;
condvar_t mem_avail_cv;
unsigned long mem_avail_frames = 0; /**< Number of available frames. */
unsigned long mem_avail_gen = 0; /**< Generation counter. */
 
/********************/
/* Helper functions */
129,11 → 139,9
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)
{
145,11 → 153,10
/* Zoneinfo 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
* @param newzone New zone to be inserted into zone list.
* @return Zone number on success, -1 on error.
*/
static int zones_add_zone(zone_t *newzone)
{
171,7 → 178,8
for (i = 0; i < zones.count; i++) {
/* Check for overflow */
z = zones.info[i];
if (overlaps(newzone->base, newzone->count, z->base, z->count)) {
if (overlaps(newzone->base, newzone->count, z->base,
z->count)) {
printf("Zones overlap!\n");
return -1;
}
192,17 → 200,16
return i;
}
 
/**
* Try to find a zone where can we find the frame
/** Try to find a zone where can we find the frame.
*
* Assume interrupts are disabled.
*
* @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
* @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.
*/
static zone_t * find_zone_and_lock(pfn_t frame, unsigned int *pzone)
static zone_t *find_zone_and_lock(pfn_t frame, unsigned int *pzone)
{
unsigned int i;
unsigned int hint = pzone ? *pzone : 0;
229,7 → 236,7
i++;
if (i >= zones.count)
i = 0;
} while(i != hint);
} while (i != hint);
 
spinlock_unlock(&zones.lock);
return NULL;
245,16 → 252,21
*
* Assume interrupts are disabled.
*
* @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 pzone Pointer to preferred zone or NULL, on return contains
* zone number.
*/
static zone_t * find_free_zone_and_lock(uint8_t order, unsigned int *pzone)
static zone_t *
find_free_zone_and_lock(uint8_t order, int flags, unsigned int *pzone)
{
unsigned int i;
zone_t *z;
unsigned int hint = pzone ? *pzone : 0;
/* Mask off flags that are not applicable. */
flags &= FRAME_LOW_4_GiB;
 
spinlock_lock(&zones.lock);
if (hint >= zones.count)
hint = 0;
264,17 → 276,24
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;
/*
* Check whether the zone meets the search criteria.
*/
if ((z->flags & flags) == flags) {
/*
* 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 = 0;
} while(i != hint);
} while (i != hint);
spinlock_unlock(&zones.lock);
return NULL;
}
283,12 → 302,13
/* 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,
uint8_t order)
309,24 → 329,12
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("%" PRIi, 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 b 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)
{
345,9 → 353,11
 
ASSERT(is_left ^ is_right);
if (is_left) {
index = (frame_index(zone, frame)) + (1 << frame->buddy_order);
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);
}
if (frame_index_valid(zone, index)) {
360,14 → 370,15
return NULL;
}
 
/** Buddy system bisect implementation
/** Buddy system bisect implementation.
*
* @param b Buddy system.
* @param block Block to bisect
* @param b 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) {
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);
376,13 → 387,14
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 b 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)
395,39 → 407,41
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 b 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) {
uint8_t order)
{
frame_t *frame;
frame = list_get_instance(block, frame_t, buddy_link);
frame->buddy_order = order;
}
 
/** Buddy system get_order implementation
/** Buddy system get_order implementation.
*
* @param b Buddy system.
* @param block Buddy system block
* @param b 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) {
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;
}
 
/** Buddy system mark_busy implementation
/** Buddy system mark_busy implementation.
*
* @param b Buddy system
* @param block Buddy system block
*
* @param b Buddy system.
* @param block Buddy system block.
*/
static void zone_buddy_mark_busy(buddy_system_t *b, link_t * 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);
434,13 → 448,13
frame->refcount = 1;
}
 
/** Buddy system mark_available implementation
/** Buddy system mark_available implementation.
*
* @param b Buddy system
* @param block Buddy system block
*
* @param b Buddy system.
* @param block Buddy system block.
*/
static void zone_buddy_mark_available(buddy_system_t *b, link_t *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;
454,8 → 468,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,15 → 475,15
/* Zone functions */
/******************/
 
/** Allocate frame in particular zone
/** Allocate frame in particular zone.
*
* Assume zone is locked
* Assume zone is locked.
* Panics if allocation is impossible.
*
* @param zone Zone to allocate from.
* @param order Allocate exactly 2^order frames.
* @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)
496,12 → 509,12
return v;
}
 
/** Free frame from zone
/** Free frame from zone.
*
* Assume zone is locked
* Assume zone is locked.
*
* @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)
{
524,14 → 537,14
}
}
 
/** 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;
544,18 → 557,21
&frame->buddy_link);
ASSERT(link);
zone->free_count--;
 
mutex_lock(&mem_avail_mtx);
mem_avail_frames--;
mutex_unlock(&mem_avail_mtx);
}
 
/**
* Join 2 zones
/** Join two zones.
*
* Expect zone_t *z to point to space at least zone_conf_size large
* Expect zone_t *z to point to space at least zone_conf_size large.
*
* Assume z1 & z2 are locked
* Assume z1 & z2 are locked.
*
* @param z Target zone structure pointer
* @param z1 Zone to merge
* @param z2 Zone to merge
* @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)
{
629,7 → 645,7
}
}
 
/** 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??
636,9 → 652,9
* - the conf. data was created by zone_create or
* updated with 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 newzone The actual zone where freeing should occur.
* @param oldzone Pointer to old zone configuration data that should
* be freed from new zone.
*/
static void return_config_frames(zone_t *newzone, zone_t *oldzone)
{
662,7 → 678,7
}
}
 
/** 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
670,8 → 686,8
* you have to free every frame.
*
* @param zone
* @param frame_idx Index to block
* @param count Allocated space in block
* @param frame_idx Index to block.
* @param count Allocated space in block.
*/
static void zone_reduce_region(zone_t *zone, pfn_t frame_idx, count_t count)
{
698,7 → 714,7
}
}
 
/** 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
722,7 → 738,7
if ((z1 >= zones.count) || (z2 >= zones.count))
goto errout;
/* We can join only 2 zones with none existing inbetween */
if (z2-z1 != 1)
if (z2 - z1 != 1)
goto errout;
 
zone1 = zones.info[z1];
773,8 → 789,7
interrupts_restore(ipl);
}
 
/**
* Merge all zones into one big zone
/** Merge all 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).
784,21 → 799,19
int count = zones.count;
 
while (zones.count > 1 && --count) {
zone_merge(0,1);
zone_merge(0, 1);
break;
}
}
 
/** Create frame zone
/** Create new frame zone.
*
* Create new frame zone.
* @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 flags Zone flags.
*
* @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 flags Zone flags.
*
* @return Initialized zone.
* @return Initialized zone.
*/
static void zone_construct(pfn_t start, count_t count, zone_t *z, int flags)
{
808,7 → 821,15
spinlock_initialize(&z->lock, "zone_lock");
z->base = start;
z->count = count;
 
/* Mask off flags that are calculated automatically. */
flags &= ~FRAME_LOW_4_GiB;
/* Determine calculated flags. */
if (z->base + count < (1ULL << (32 - FRAME_WIDTH))) /* 4 GiB */
flags |= FRAME_LOW_4_GiB;
 
z->flags = flags;
 
z->free_count = count;
z->busy_count = 0;
 
819,8 → 840,7
z->buddy_system = (buddy_system_t *)&z[1];
buddy_system_create(z->buddy_system, max_order,
&zone_buddy_system_operations,
(void *) z);
&zone_buddy_system_operations, (void *) z);
/* Allocate frames _after_ the conframe */
/* Check sizes */
837,10 → 857,10
}
}
 
/** 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)
{
852,20 → 872,20
return size;
}
 
/** 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 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.
* @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.
*
* @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)
{
884,8 → 904,8
* it does not span kernel & init
*/
confcount = SIZE2FRAMES(zone_conf_size(count));
if (confframe >= start && confframe < start+count) {
for (;confframe < start + count; confframe++) {
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))
919,11 → 939,16
if (znum == -1)
return -1;
 
mutex_lock(&mem_avail_mtx);
mem_avail_frames += count;
mutex_unlock(&mem_avail_mtx);
 
/* 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);
}
return znum;
}
 
930,7 → 955,7
/***************************************/
/* Frame functions */
 
/** Set parent of frame */
/** Set parent of frame. */
void frame_set_parent(pfn_t pfn, void *data, unsigned int hint)
{
zone_t *zone = find_zone_and_lock(pfn, &hint);
937,7 → 962,7
 
ASSERT(zone);
 
zone_get_frame(zone, pfn-zone->base)->parent = data;
zone_get_frame(zone, pfn - zone->base)->parent = data;
spinlock_unlock(&zone->lock);
}
 
955,19 → 980,20
 
/** 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.
* @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, int flags, unsigned int *pzone)
{
ipl_t ipl;
int freed;
pfn_t v;
zone_t *zone;
unsigned long gen = 0;
loop:
ipl = interrupts_disable();
975,7 → 1001,7
/*
* First, find suitable frame zone.
*/
zone = find_free_zone_and_lock(order, pzone);
zone = find_free_zone_and_lock(order, flags, pzone);
/* If no memory, reclaim some slab memory,
if it does not help, reclaim all */
982,23 → 1008,51
if (!zone && !(flags & FRAME_NO_RECLAIM)) {
freed = slab_reclaim(0);
if (freed)
zone = find_free_zone_and_lock(order, pzone);
zone = find_free_zone_and_lock(order, flags, pzone);
if (!zone) {
freed = slab_reclaim(SLAB_RECLAIM_ALL);
if (freed)
zone = find_free_zone_and_lock(order, pzone);
zone = find_free_zone_and_lock(order, flags,
pzone);
}
}
if (!zone) {
/*
* TODO: Sleep until frames are available again.
* Sleep until some frames are available again.
*/
interrupts_restore(ipl);
 
if (flags & FRAME_ATOMIC)
if (flags & FRAME_ATOMIC) {
interrupts_restore(ipl);
return 0;
}
panic("Sleep not implemented.\n");
#ifdef CONFIG_DEBUG
unsigned long avail;
 
mutex_lock(&mem_avail_mtx);
avail = mem_avail_frames;
mutex_unlock(&mem_avail_mtx);
 
printf("Thread %" PRIu64 " waiting for %u frames, "
"%u available.\n", THREAD->tid, 1ULL << order, avail);
#endif
 
mutex_lock(&mem_avail_mtx);
while ((mem_avail_frames < (1ULL << order)) ||
gen == mem_avail_gen)
condvar_wait(&mem_avail_cv, &mem_avail_mtx);
gen = mem_avail_gen;
mutex_unlock(&mem_avail_mtx);
 
#ifdef CONFIG_DEBUG
mutex_lock(&mem_avail_mtx);
avail = mem_avail_frames;
mutex_unlock(&mem_avail_mtx);
 
printf("Thread %" PRIu64 " woken up, %u frames available.\n",
THREAD->tid, avail);
#endif
 
interrupts_restore(ipl);
goto loop;
}
1006,6 → 1060,11
v += zone->base;
 
spinlock_unlock(&zone->lock);
mutex_lock(&mem_avail_mtx);
mem_avail_frames -= (1ULL << order);
mutex_unlock(&mem_avail_mtx);
 
interrupts_restore(ipl);
 
if (flags & FRAME_KA)
1019,7 → 1078,7
* 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)
{
1028,16 → 1087,26
pfn_t pfn = ADDR2PFN(frame);
 
ipl = interrupts_disable();
 
/*
* First, find host frame zone for addr.
*/
zone = find_zone_and_lock(pfn,NULL);
zone = find_zone_and_lock(pfn, NULL);
ASSERT(zone);
zone_frame_free(zone, pfn-zone->base);
zone_frame_free(zone, pfn - zone->base);
spinlock_unlock(&zone->lock);
/*
* Signal that some memory has been freed.
*/
mutex_lock(&mem_avail_mtx);
mem_avail_frames++;
mem_avail_gen++;
condvar_broadcast(&mem_avail_cv);
mutex_unlock(&mem_avail_mtx);
 
interrupts_restore(ipl);
}
 
1046,7 → 1115,7
* Find respective frame structure for supplied PFN and
* increment frame reference count.
*
* @param pfn Frame number of the frame to be freed.
* @param pfn Frame number of the frame to be freed.
*/
void frame_reference_add(pfn_t pfn)
{
1059,10 → 1128,10
/*
* First, find host frame zone for addr.
*/
zone = find_zone_and_lock(pfn,NULL);
zone = find_zone_and_lock(pfn, NULL);
ASSERT(zone);
frame = &zone->frames[pfn-zone->base];
frame = &zone->frames[pfn - zone->base];
frame->refcount++;
spinlock_unlock(&zone->lock);
1069,7 → 1138,7
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;
1086,15 → 1155,14
}
}
 
/** 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();
1122,10 → 1190,9
}
 
 
/** Return total size of all zones
*
*/
uint64_t zone_total_size(void) {
/** Return total size of all zones. */
uint64_t zone_total_size(void)
{
zone_t *zone = NULL;
unsigned int i;
ipl_t ipl;
1147,19 → 1214,13
return total;
}
 
 
 
/** Prints list of zones
*
*/
void zone_print_list(void) {
/** 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 __32_BITS__
printf("# base address free frames busy frames\n");
printf("-- ------------ ------------ ------------\n");
1170,35 → 1231,69
printf("-- -------------------- ------------ ------------\n");
#endif
for (i = 0; i < zones.count; i++) {
/*
* 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++) {
uintptr_t base;
count_t free_count;
count_t busy_count;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
if (i >= zones.count) {
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
break;
}
 
zone = zones.info[i];
spinlock_lock(&zone->lock);
 
base = PFN2ADDR(zone->base);
free_count = zone->free_count;
busy_count = zone->busy_count;
 
spinlock_unlock(&zone->lock);
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
 
#ifdef __32_BITS__
printf("%-2u %10p %12" PRIc " %12" PRIc "\n", i, PFN2ADDR(zone->base),
zone->free_count, zone->busy_count);
printf("%-2u %10p %12" PRIc " %12" PRIc "\n", i, base,
free_count, busy_count);
#endif
 
#ifdef __64_BITS__
printf("%-2u %18p %12" PRIc " %12" PRIc "\n", i, PFN2ADDR(zone->base),
zone->free_count, zone->busy_count);
printf("%-2u %18p %12" PRIc " %12" PRIc "\n", i, base,
free_count, busy_count);
#endif
spinlock_unlock(&zone->lock);
}
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
}
 
/** Prints zone details.
*
* @param num Zone base address or zone number.
* @param num Zone base address or zone number.
*/
void zone_print_one(unsigned int num) {
void zone_print_one(unsigned int num)
{
zone_t *zone = NULL;
ipl_t ipl;
unsigned int i;
uintptr_t base;
count_t count;
count_t busy_count;
count_t free_count;
 
ipl = interrupts_disable();
spinlock_lock(&zones.lock);
1210,25 → 1305,28
}
}
if (!zone) {
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", PFN2ADDR(zone->base));
printf("Zone size: %" PRIc " frames (%" PRIs " KB)\n", zone->count,
SIZE2KB(FRAMES2SIZE(zone->count)));
printf("Allocated space: %" PRIc " frames (%" PRIs " KB)\n", zone->busy_count,
SIZE2KB(FRAMES2SIZE(zone->busy_count)));
printf("Available space: %" PRIc " frames (%" PRIs " KB)\n", zone->free_count,
SIZE2KB(FRAMES2SIZE(zone->free_count)));
buddy_system_structure_print(zone->buddy_system, FRAME_SIZE);
base = PFN2ADDR(zone->base);
count = zone->count;
busy_count = zone->busy_count;
free_count = zone->free_count;
spinlock_unlock(&zone->lock);
out:
spinlock_unlock(&zones.lock);
interrupts_restore(ipl);
 
printf("Zone base address: %p\n", base);
printf("Zone size: %" PRIc " frames (%" PRIs " KiB)\n", count,
SIZE2KB(FRAMES2SIZE(count)));
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/tracing/kernel/generic/src/mm/backend_elf.c
118,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;
}