/branches/network/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; |
324,8 → 309,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 → 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) |
{ |
431,7 → 416,7 |
uintptr_t b = node->key[node->keys - 1]; |
count_t c = |
(count_t) node->value[node->keys - 1]; |
int i = 0; |
unsigned int i = 0; |
if (overlaps(b, c * PAGE_SIZE, area->base, |
pages * PAGE_SIZE)) { |
526,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) |
{ |
561,7 → 546,7 |
for (cur = area->used_space.leaf_head.next; |
cur != &area->used_space.leaf_head; cur = cur->next) { |
btree_node_t *node; |
int i; |
unsigned int i; |
node = list_get_instance(cur, btree_node_t, leaf_link); |
for (i = 0; i < node->keys; i++) { |
626,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) |
698,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; |
756,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) |
{ |
775,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) |
{ |
835,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)) { |
891,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) |
{ |
963,9 → 1109,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 → 1139,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 → 1150,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 → 1170,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 → 1189,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,17 → 1218,17 |
* |
* 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) |
{ |
as_area_t *a; |
btree_node_t *leaf, *lnode; |
int i; |
unsigned int i; |
a = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf); |
if (a) { |
1143,19 → 1274,19 |
* |
* 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; |
int i; |
unsigned int i; |
/* |
* We don't want any area to have conflicts with NULL page. |
1240,7 → 1371,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,17 → 1385,17 |
* |
* 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) |
{ |
btree_node_t *leaf, *node; |
count_t pages; |
int i; |
unsigned int i; |
ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE)); |
ASSERT(count); |
1528,8 → 1659,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.\n", count, page); |
} |
/** Mark portion of address space area as unused. |
1536,17 → 1667,17 |
* |
* 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) |
{ |
btree_node_t *leaf, *node; |
count_t pages; |
int i; |
unsigned int i; |
ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE)); |
ASSERT(count); |
1707,8 → 1838,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.\n", count, page); |
} |
/** Remove reference to address space area share info. |
1715,7 → 1846,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) |
{ |
1734,7 → 1865,7 |
for (cur = sh_info->pagemap.leaf_head.next; |
cur != &sh_info->pagemap.leaf_head; cur = cur->next) { |
btree_node_t *node; |
int i; |
unsigned int i; |
node = list_get_instance(cur, btree_node_t, leaf_link); |
for (i = 0; i < node->keys; i++) |
1770,6 → 1901,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 → 1915,7 |
/** Print out information about address space. |
* |
* @param as Address space. |
* @param as Address space. |
*/ |
void as_print(as_t *as) |
{ |
1795,14 → 1932,14 |
node = list_get_instance(cur, btree_node_t, leaf_link); |
int i; |
unsigned int i; |
for (i = 0; i < node->keys; i++) { |
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/network/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; |
98,7 → 97,7 |
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf); |
if (!frame) { |
bool allocate = true; |
int i; |
unsigned int i; |
/* |
* Zero can be returned as a valid frame address. |
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); |
} |
/* |
193,13 → 190,13 |
for (cur = area->used_space.leaf_head.next; |
cur != &area->used_space.leaf_head; cur = cur->next) { |
btree_node_t *node; |
int i; |
unsigned int i; |
node = list_get_instance(cur, btree_node_t, leaf_link); |
for (i = 0; i < node->keys; i++) { |
uintptr_t base = node->key[i]; |
count_t count = (count_t) node->value[i]; |
int j; |
unsigned int j; |
for (j = 0; j < count; j++) { |
pte_t *pte; |
/branches/network/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) |
{ |
79,7 → 81,7 |
elf_header_t *elf = area->backend_data.elf; |
elf_segment_header_t *entry = area->backend_data.segment; |
btree_node_t *leaf; |
uintptr_t base, frame; |
uintptr_t base, frame, page, start_anon; |
index_t i; |
bool dirty = false; |
86,12 → 88,18 |
if (!as_area_check_access(area, access)) |
return AS_PF_FAULT; |
ASSERT((addr >= entry->p_vaddr) && |
ASSERT((addr >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) && |
(addr < entry->p_vaddr + entry->p_memsz)); |
i = (addr - entry->p_vaddr) >> PAGE_WIDTH; |
base = (uintptr_t) (((void *) elf) + entry->p_offset); |
ASSERT(ALIGN_UP(base, FRAME_SIZE) == base); |
i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH; |
base = (uintptr_t) |
(((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE)); |
/* Virtual address of faulting page*/ |
page = ALIGN_DOWN(addr, PAGE_SIZE); |
/* Virtual address of the end of initialized part of segment */ |
start_anon = entry->p_vaddr + entry->p_filesz; |
if (area->sh_info) { |
bool found = false; |
98,12 → 106,12 |
/* |
* The address space area is shared. |
*/ |
mutex_lock(&area->sh_info->lock); |
frame = (uintptr_t) btree_search(&area->sh_info->pagemap, |
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf); |
page - area->base, &leaf); |
if (!frame) { |
int i; |
unsigned int i; |
/* |
* Workaround for valid NULL address. |
110,8 → 118,7 |
*/ |
for (i = 0; i < leaf->keys; i++) { |
if (leaf->key[i] == |
ALIGN_DOWN(addr, PAGE_SIZE)) { |
if (leaf->key[i] == page - area->base) { |
found = true; |
break; |
} |
121,21 → 128,18 |
frame_reference_add(ADDR2PFN(frame)); |
page_mapping_insert(AS, addr, frame, |
as_area_get_flags(area)); |
if (!used_space_insert(area, |
ALIGN_DOWN(addr, PAGE_SIZE), 1)) |
if (!used_space_insert(area, page, 1)) |
panic("Could not insert used space.\n"); |
mutex_unlock(&area->sh_info->lock); |
return AS_PF_OK; |
} |
} |
/* |
* The area is either not shared or the pagemap does not contain the |
* mapping. |
*/ |
if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < |
entry->p_vaddr + entry->p_filesz) { |
if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) { |
/* |
* Initialized portion of the segment. The memory is backed |
* directly by the content of the ELF image. Pages are |
148,20 → 152,15 |
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; |
if (area->sh_info) { |
frame_reference_add(ADDR2PFN(frame)); |
btree_insert(&area->sh_info->pagemap, |
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, |
(void *) frame, leaf); |
} |
} else { |
frame = KA2PA(base + i*FRAME_SIZE); |
frame = KA2PA(base + i * FRAME_SIZE); |
} |
} else if (ALIGN_DOWN(addr, PAGE_SIZE) >= |
ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) { |
} else if (page >= start_anon) { |
/* |
* This is the uninitialized portion of the segment. |
* It is not physically present in the ELF image. |
169,44 → 168,52 |
* 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; |
if (area->sh_info) { |
frame_reference_add(ADDR2PFN(frame)); |
btree_insert(&area->sh_info->pagemap, |
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, |
(void *) frame, leaf); |
} |
} else { |
size_t size; |
size_t pad_lo, pad_hi; |
/* |
* The mixed case. |
* The lower part is backed by the ELF image and |
* the upper part is anonymous memory. |
* |
* The middle part is backed by the ELF image and |
* the lower and upper parts are anonymous memory. |
* (The segment can be and often is shorter than 1 page). |
*/ |
size = entry->p_filesz - (i<<PAGE_WIDTH); |
if (page < entry->p_vaddr) |
pad_lo = entry->p_vaddr - page; |
else |
pad_lo = 0; |
if (start_anon < page + PAGE_SIZE) |
pad_hi = page + PAGE_SIZE - start_anon; |
else |
pad_hi = 0; |
frame = (uintptr_t)frame_alloc(ONE_FRAME, 0); |
memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0); |
memcpy((void *) PA2KA(frame), (void *) (base + i * FRAME_SIZE), |
size); |
memcpy((void *) (PA2KA(frame) + pad_lo), |
(void *) (base + i * FRAME_SIZE + pad_lo), |
FRAME_SIZE - pad_lo - pad_hi); |
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; |
} |
if (area->sh_info) { |
frame_reference_add(ADDR2PFN(frame)); |
btree_insert(&area->sh_info->pagemap, |
ALIGN_DOWN(addr, PAGE_SIZE) - area->base, |
(void *) frame, leaf); |
} |
if (dirty && area->sh_info) { |
frame_reference_add(ADDR2PFN(frame)); |
btree_insert(&area->sh_info->pagemap, page - area->base, |
(void *) frame, leaf); |
} |
} |
if (area->sh_info) |
mutex_unlock(&area->sh_info->lock); |
page_mapping_insert(AS, addr, frame, as_area_get_flags(area)); |
if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1)) |
if (!used_space_insert(area, page, 1)) |
panic("Could not insert used space.\n"); |
return AS_PF_OK; |
216,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) |
225,17 → 233,17 |
{ |
elf_header_t *elf = area->backend_data.elf; |
elf_segment_header_t *entry = area->backend_data.segment; |
uintptr_t base; |
uintptr_t base, start_anon; |
index_t i; |
ASSERT((page >= entry->p_vaddr) && |
ASSERT((page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) && |
(page < entry->p_vaddr + entry->p_memsz)); |
i = (page - entry->p_vaddr) >> PAGE_WIDTH; |
base = (uintptr_t) (((void *) elf) + entry->p_offset); |
ASSERT(ALIGN_UP(base, FRAME_SIZE) == base); |
if (page + PAGE_SIZE < |
ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) { |
i = (page - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH; |
base = (uintptr_t) (((void *) elf) + |
ALIGN_DOWN(entry->p_offset, FRAME_SIZE)); |
start_anon = entry->p_vaddr + entry->p_filesz; |
if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) { |
if (entry->p_flags & PF_W) { |
/* |
* Free the frame with the copy of writable segment |
261,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) |
{ |
290,7 → 298,7 |
mutex_lock(&area->sh_info->lock); |
for (cur = &node->leaf_link; cur != &area->used_space.leaf_head; |
cur = cur->next) { |
int i; |
unsigned int i; |
node = list_get_instance(cur, btree_node_t, leaf_link); |
297,7 → 305,7 |
for (i = 0; i < node->keys; i++) { |
uintptr_t base = node->key[i]; |
count_t count = (count_t) node->value[i]; |
int j; |
unsigned int j; |
/* |
* Skip read-only areas of used space that are backed |
304,7 → 312,8 |
* by the ELF image. |
*/ |
if (!(area->flags & AS_AREA_WRITE)) |
if (base + count * PAGE_SIZE <= start_anon) |
if (base >= entry->p_vaddr && |
base + count * PAGE_SIZE <= start_anon) |
continue; |
for (j = 0; j < count; j++) { |
315,7 → 324,8 |
* ELF image. |
*/ |
if (!(area->flags & AS_AREA_WRITE)) |
if (base + (j + 1) * PAGE_SIZE <= |
if (base >= entry->p_vaddr && |
base + (j + 1) * PAGE_SIZE <= |
start_anon) |
continue; |
/branches/network/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 */ |
120,7 → 130,7 |
static inline int frame_index_valid(zone_t *zone, index_t index) |
{ |
return (index >= 0) && (index < zone->count); |
return (index < zone->count); |
} |
/** Compute pfn_t from frame_t pointer & zone pointer */ |
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; |
210,7 → 217,7 |
spinlock_lock(&zones.lock); |
if (hint >= zones.count || hint < 0) |
if (hint >= zones.count) |
hint = 0; |
i = hint; |
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("%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 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 |
719,10 → 735,10 |
ipl = interrupts_disable(); |
spinlock_lock(&zones.lock); |
if (z1 < 0 || z1 >= zones.count || z2 < 0 || z2 >= zones.count) |
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,14 → 857,14 |
} |
} |
/** 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 size = sizeof(zone_t) + count * sizeof(frame_t); |
int max_order; |
max_order = fnzb(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,53 → 1214,86 |
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"); |
#endif |
#ifdef __64_BITS__ |
printf("# base address 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"); |
} |
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); |
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); |
spinlock_unlock(&zones.lock); |
interrupts_restore(ipl); |
#ifdef __32_BITS__ |
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, 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); |
1205,26 → 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", 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); |
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/network/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,8 → 43,9 |
#include <arch/types.h> |
#include <debug.h> |
#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); |
52,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; |
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/network/kernel/generic/src/mm/slab.c |
---|
167,12 → 167,12 |
* 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; |
int i; |
unsigned int i; |
unsigned int zone = 0; |
data = frame_alloc_generic(cache->order, FRAME_KA | flags, &zone); |
179,7 → 179,7 |
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)); |
191,8 → 191,8 |
} |
/* Fill in slab structures */ |
for (i=0; i < (1 << cache->order); i++) |
frame_set_parent(ADDR2PFN(KA2PA(data))+i, slab, zone); |
for (i = 0; i < ((unsigned int) 1 << cache->order); i++) |
frame_set_parent(ADDR2PFN(KA2PA(data)) + i, slab, zone); |
slab->start = data; |
slab->available = cache->objects; |
199,8 → 199,8 |
slab->nextavail = 0; |
slab->cache = cache; |
for (i=0; i<cache->objects;i++) |
*((int *) (slab->start + i*cache->size)) = i+1; |
for (i = 0; i < cache->objects; i++) |
*((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,13 → 367,12 |
* |
* @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) |
{ |
int i; |
unsigned int i; |
count_t frames = 0; |
for (i=0;i < mag->busy; i++) { |
for (i = 0; i < mag->busy; i++) { |
frames += slab_obj_destroy(cache, mag->objs[i], NULL); |
atomic_dec(&cache->cached_objs); |
} |
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; |
527,25 → 525,26 |
/* Slab cache functions */ |
/** Return number of objects that fit in certain cache size */ |
static int comp_objects(slab_cache_t *cache) |
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; |
} |
/** Return wasted space in slab */ |
static int badness(slab_cache_t *cache) |
static unsigned int badness(slab_cache_t *cache) |
{ |
int objects; |
int ssize; |
unsigned int objects; |
unsigned int ssize; |
objects = comp_objects(cache); |
ssize = PAGE_SIZE << cache->order; |
if (cache->flags & SLAB_CACHE_SLINSIDE) |
ssize -= sizeof(slab_t); |
return ssize - objects*cache->size; |
return ssize - objects * cache->size; |
} |
/** |
553,33 → 552,29 |
*/ |
static void make_magcache(slab_cache_t *cache) |
{ |
int i; |
unsigned int i; |
ASSERT(_slab_initialized >= 2); |
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"); |
cache->mag_cache = malloc(sizeof(slab_mag_cache_t) * config.cpu_count, |
0); |
for (i = 0; i < config.cpu_count; i++) { |
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)) |
597,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. */ |
610,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; |
631,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; |
} |
654,7 → 647,7 |
*/ |
static count_t _slab_reclaim(slab_cache_t *cache, int flags) |
{ |
int i; |
unsigned int i; |
slab_magazine_t *mag; |
count_t frames = 0; |
int magcount; |
666,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; |
675,7 → 668,7 |
if (flags & SLAB_RECLAIM_ALL) { |
/* Free cpu-bound magazines */ |
/* Destroy CPU magazines */ |
for (i=0; i<config.cpu_count; i++) { |
for (i = 0; i < config.cpu_count; i++) { |
spinlock_lock(&cache->mag_cache[i].lock); |
mag = cache->mag_cache[i].current; |
719,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)) |
728,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; |
759,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); |
} |
788,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); |
} |
802,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) |
825,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; |
875,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; |
888,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)); |
901,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/network/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/network/kernel/generic/src/mm/tlb.c |
---|
81,7 → 81,7 |
void tlb_shootdown_start(tlb_invalidate_type_t type, asid_t asid, |
uintptr_t page, count_t count) |
{ |
int i; |
unsigned int i; |
CPU->tlb_active = 0; |
spinlock_lock(&tlblock); |
144,7 → 144,7 |
asid_t asid; |
uintptr_t page; |
count_t count; |
int i; |
unsigned int i; |
ASSERT(CPU); |