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; |
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, MUTEX_PASSIVE); |
(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; |
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) |
{ |
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) |
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,7 → 762,7 |
return true; |
} |
|
/** Change adress area flags. |
/** 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. |
778,11 → 769,11 |
* 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. |
* @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. |
* @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) |
{ |
887,9 → 878,14 |
tlb_shootdown_finalize(); |
|
/* |
* Set the new flags. |
*/ |
area->flags = flags; |
|
/* |
* Map pages back in with new flags. This step is kept separate |
* so that there's no instant when the memory area could be |
* accesed with both the old and the new flags at once. |
* so that the memory area could not be accesed with both the old and |
* the new flags at once. |
*/ |
frame_idx = 0; |
|
927,19 → 923,20 |
|
/** 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) |
{ |
985,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)) { |
1041,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) |
{ |
1113,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) |
{ |
1143,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) |
{ |
1154,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. |
1177,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. |
1200,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 |
} |
|
|
1237,11 → 1218,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) |
{ |
1293,15 → 1274,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; |
1390,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 { |
1404,11 → 1385,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) |
{ |
1678,8 → 1659,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. |
1686,11 → 1667,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) |
{ |
1857,8 → 1838,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. |
1865,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) |
{ |
1934,7 → 1915,7 |
|
/** Print out information about address space. |
* |
* @param as Address space. |
* @param as Address space. |
*/ |
void as_print(as_t *as) |
{ |
1956,9 → 1937,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); |
} |
} |