95,10 → 95,13 |
#endif |
|
/** |
* This lock protects inactive_as_with_asid_head list. It must be acquired |
* before as_t mutex. |
* This lock serializes access to the ASID subsystem. |
* It protects: |
* - inactive_as_with_asid_head list |
* - as->asid for each as of the as_t type |
* - asids_allocated counter |
*/ |
SPINLOCK_INITIALIZE(inactive_as_with_asid_lock); |
SPINLOCK_INITIALIZE(asidlock); |
|
/** |
* This list contains address spaces that are not active on any |
205,14 → 208,15 |
* Since there is no reference to this area, |
* it is safe not to lock its mutex. |
*/ |
|
ipl = interrupts_disable(); |
spinlock_lock(&inactive_as_with_asid_lock); |
spinlock_lock(&asidlock); |
if (as->asid != ASID_INVALID && as != AS_KERNEL) { |
if (as != AS && as->cpu_refcount == 0) |
list_remove(&as->inactive_as_with_asid_link); |
asid_put(as->asid); |
} |
spinlock_unlock(&inactive_as_with_asid_lock); |
spinlock_unlock(&asidlock); |
|
/* |
* Destroy address space areas of the address space. |
411,7 → 415,7 |
int i = 0; |
|
if (overlaps(b, c * PAGE_SIZE, area->base, |
pages*PAGE_SIZE)) { |
pages * PAGE_SIZE)) { |
|
if (b + c * PAGE_SIZE <= start_free) { |
/* |
553,7 → 557,7 |
if (area->backend && |
area->backend->frame_free) { |
area->backend->frame_free(area, b + |
j * PAGE_SIZE, PTE_GET_FRAME(pte)); |
j * PAGE_SIZE, PTE_GET_FRAME(pte)); |
} |
page_mapping_remove(as, b + j * PAGE_SIZE); |
page_table_unlock(as, false); |
613,8 → 617,7 |
* 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 or if the kernel detects an attempt to create an illegal address |
* alias. |
* 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) |
667,20 → 670,6 |
return EPERM; |
} |
|
#ifdef CONFIG_VIRT_IDX_DCACHE |
if (!(dst_flags_mask & AS_AREA_EXEC)) { |
if (PAGE_COLOR(src_area->base) != PAGE_COLOR(dst_base)) { |
/* |
* Refuse to create an illegal address alias. |
*/ |
mutex_unlock(&src_area->lock); |
mutex_unlock(&src_as->lock); |
interrupts_restore(ipl); |
return ENOTSUP; |
} |
} |
#endif /* CONFIG_VIRT_IDX_DCACHE */ |
|
/* |
* Now we are committed to sharing the area. |
* First, prepare the area for sharing. |
875,7 → 864,8 |
/** Switch address spaces. |
* |
* Note that this function cannot sleep as it is essentially a part of |
* scheduling. Sleeping here would lead to deadlock on wakeup. |
* scheduling. Sleeping here would lead to deadlock on wakeup. Another |
* thing which is forbidden in this context is locking the address space. |
* |
* @param old Old address space or NULL. |
* @param new New address space. |
882,17 → 872,12 |
*/ |
void as_switch(as_t *old_as, as_t *new_as) |
{ |
ipl_t ipl; |
bool needs_asid = false; |
|
ipl = interrupts_disable(); |
spinlock_lock(&inactive_as_with_asid_lock); |
spinlock_lock(&asidlock); |
|
/* |
* First, take care of the old address space. |
*/ |
if (old_as) { |
mutex_lock_active(&old_as->lock); |
ASSERT(old_as->cpu_refcount); |
if((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) { |
/* |
901,11 → 886,10 |
* list of inactive address spaces with assigned |
* ASID. |
*/ |
ASSERT(old_as->asid != ASID_INVALID); |
list_append(&old_as->inactive_as_with_asid_link, |
&inactive_as_with_asid_head); |
ASSERT(old_as->asid != ASID_INVALID); |
list_append(&old_as->inactive_as_with_asid_link, |
&inactive_as_with_asid_head); |
} |
mutex_unlock(&old_as->lock); |
|
/* |
* Perform architecture-specific tasks when the address space |
917,36 → 901,15 |
/* |
* Second, prepare the new address space. |
*/ |
mutex_lock_active(&new_as->lock); |
if ((new_as->cpu_refcount++ == 0) && (new_as != AS_KERNEL)) { |
if (new_as->asid != ASID_INVALID) { |
if (new_as->asid != ASID_INVALID) |
list_remove(&new_as->inactive_as_with_asid_link); |
} else { |
/* |
* Defer call to asid_get() until new_as->lock is released. |
*/ |
needs_asid = true; |
} |
else |
new_as->asid = asid_get(); |
} |
#ifdef AS_PAGE_TABLE |
SET_PTL0_ADDRESS(new_as->genarch.page_table); |
#endif |
mutex_unlock(&new_as->lock); |
|
if (needs_asid) { |
/* |
* Allocation of new ASID was deferred |
* until now in order to avoid deadlock. |
*/ |
asid_t asid; |
|
asid = asid_get(); |
mutex_lock_active(&new_as->lock); |
new_as->asid = asid; |
mutex_unlock(&new_as->lock); |
} |
spinlock_unlock(&inactive_as_with_asid_lock); |
interrupts_restore(ipl); |
|
/* |
* Perform architecture-specific steps. |
953,6 → 916,8 |
* (e.g. write ASID to hardware register etc.) |
*/ |
as_install_arch(new_as); |
|
spinlock_unlock(&asidlock); |
|
AS = new_as; |
} |