Rev 2292 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2292 | Rev 2307 | ||
|---|---|---|---|
| Line 55... | Line 55... | ||
| 55 | #include <arch/mm/page.h> |
55 | #include <arch/mm/page.h> |
| 56 | #include <genarch/mm/page_pt.h> |
56 | #include <genarch/mm/page_pt.h> |
| 57 | #include <genarch/mm/page_ht.h> |
57 | #include <genarch/mm/page_ht.h> |
| 58 | #include <mm/asid.h> |
58 | #include <mm/asid.h> |
| 59 | #include <arch/mm/asid.h> |
59 | #include <arch/mm/asid.h> |
| - | 60 | #include <preemption.h> |
|
| 60 | #include <synch/spinlock.h> |
61 | #include <synch/spinlock.h> |
| 61 | #include <synch/mutex.h> |
62 | #include <synch/mutex.h> |
| 62 | #include <adt/list.h> |
63 | #include <adt/list.h> |
| 63 | #include <adt/btree.h> |
64 | #include <adt/btree.h> |
| 64 | #include <proc/task.h> |
65 | #include <proc/task.h> |
| Line 179... | Line 180... | ||
| 179 | if (flags & FLAG_AS_KERNEL) |
180 | if (flags & FLAG_AS_KERNEL) |
| 180 | as->asid = ASID_KERNEL; |
181 | as->asid = ASID_KERNEL; |
| 181 | else |
182 | else |
| 182 | as->asid = ASID_INVALID; |
183 | as->asid = ASID_INVALID; |
| 183 | 184 | ||
| 184 | as->refcount = 0; |
185 | atomic_set(&as->refcount, 0); |
| 185 | as->cpu_refcount = 0; |
186 | as->cpu_refcount = 0; |
| 186 | #ifdef AS_PAGE_TABLE |
187 | #ifdef AS_PAGE_TABLE |
| 187 | as->genarch.page_table = page_table_create(flags); |
188 | as->genarch.page_table = page_table_create(flags); |
| 188 | #else |
189 | #else |
| 189 | page_table_create(flags); |
190 | page_table_create(flags); |
| Line 194... | Line 195... | ||
| 194 | 195 | ||
| 195 | /** Destroy adress space. |
196 | /** Destroy adress space. |
| 196 | * |
197 | * |
| 197 | * When there are no tasks referencing this address space (i.e. its refcount is |
198 | * When there are no tasks referencing this address space (i.e. its refcount is |
| 198 | * zero), the address space can be destroyed. |
199 | * zero), the address space can be destroyed. |
| - | 200 | * |
|
| - | 201 | * We know that we don't hold any spinlock. |
|
| 199 | */ |
202 | */ |
| 200 | void as_destroy(as_t *as) |
203 | void as_destroy(as_t *as) |
| 201 | { |
204 | { |
| 202 | ipl_t ipl; |
205 | ipl_t ipl; |
| 203 | bool cond; |
206 | bool cond; |
| - | 207 | DEADLOCK_PROBE_INIT(p_asidlock); |
|
| 204 | 208 | ||
| 205 | ASSERT(as->refcount == 0); |
209 | ASSERT(atomic_get(&as->refcount) == 0); |
| 206 | 210 | ||
| 207 | /* |
211 | /* |
| 208 | * Since there is no reference to this area, |
212 | * Since there is no reference to this area, |
| 209 | * it is safe not to lock its mutex. |
213 | * it is safe not to lock its mutex. |
| 210 | */ |
214 | */ |
| 211 | 215 | ||
| - | 216 | /* |
|
| - | 217 | * We need to avoid deadlock between TLB shootdown and asidlock. |
|
| - | 218 | * We therefore try to take asid conditionally and if we don't succeed, |
|
| - | 219 | * we enable interrupts and try again. This is done while preemption is |
|
| - | 220 | * disabled to prevent nested context switches. We also depend on the |
|
| - | 221 | * fact that so far no spinlocks are held. |
|
| - | 222 | */ |
|
| - | 223 | preemption_disable(); |
|
| 212 | ipl = interrupts_disable(); |
224 | ipl = interrupts_read(); |
| - | 225 | retry: |
|
| - | 226 | interrupts_disable(); |
|
| 213 | spinlock_lock(&asidlock); |
227 | if (!spinlock_trylock(&asidlock)) { |
| - | 228 | interrupts_enable(); |
|
| - | 229 | DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD); |
|
| - | 230 | goto retry; |
|
| - | 231 | } |
|
| - | 232 | preemption_enable(); /* Interrupts disabled, enable preemption */ |
|
| 214 | if (as->asid != ASID_INVALID && as != AS_KERNEL) { |
233 | if (as->asid != ASID_INVALID && as != AS_KERNEL) { |
| 215 | if (as != AS && as->cpu_refcount == 0) |
234 | if (as != AS && as->cpu_refcount == 0) |
| 216 | list_remove(&as->inactive_as_with_asid_link); |
235 | list_remove(&as->inactive_as_with_asid_link); |
| 217 | asid_put(as->asid); |
236 | asid_put(as->asid); |
| 218 | } |
237 | } |
| Line 470... | Line 489... | ||
| 470 | } |
489 | } |
| 471 | 490 | ||
| 472 | /* |
491 | /* |
| 473 | * Finish TLB shootdown sequence. |
492 | * Finish TLB shootdown sequence. |
| 474 | */ |
493 | */ |
| - | 494 | ||
| 475 | tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE, |
495 | tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE, |
| 476 | area->pages - pages); |
496 | area->pages - pages); |
| 477 | tlb_shootdown_finalize(); |
- | |
| 478 | - | ||
| 479 | /* |
497 | /* |
| 480 | * Invalidate software translation caches (e.g. TSB on sparc64). |
498 | * Invalidate software translation caches (e.g. TSB on sparc64). |
| 481 | */ |
499 | */ |
| 482 | as_invalidate_translation_cache(as, area->base + |
500 | as_invalidate_translation_cache(as, area->base + |
| 483 | pages * PAGE_SIZE, area->pages - pages); |
501 | pages * PAGE_SIZE, area->pages - pages); |
| - | 502 | tlb_shootdown_finalize(); |
|
| - | 503 | ||
| 484 | } else { |
504 | } else { |
| 485 | /* |
505 | /* |
| 486 | * Growing the area. |
506 | * Growing the area. |
| 487 | * Check for overlaps with other address space areas. |
507 | * Check for overlaps with other address space areas. |
| 488 | */ |
508 | */ |
| Line 566... | Line 586... | ||
| 566 | } |
586 | } |
| 567 | 587 | ||
| 568 | /* |
588 | /* |
| 569 | * Finish TLB shootdown sequence. |
589 | * Finish TLB shootdown sequence. |
| 570 | */ |
590 | */ |
| - | 591 | ||
| 571 | tlb_invalidate_pages(as->asid, area->base, area->pages); |
592 | tlb_invalidate_pages(as->asid, area->base, area->pages); |
| 572 | tlb_shootdown_finalize(); |
- | |
| 573 | - | ||
| 574 | /* |
593 | /* |
| 575 | * Invalidate potential software translation caches (e.g. TSB on |
594 | * Invalidate potential software translation caches (e.g. TSB on |
| 576 | * sparc64). |
595 | * sparc64). |
| 577 | */ |
596 | */ |
| 578 | as_invalidate_translation_cache(as, area->base, area->pages); |
597 | as_invalidate_translation_cache(as, area->base, area->pages); |
| - | 598 | tlb_shootdown_finalize(); |
|
| 579 | 599 | ||
| 580 | btree_destroy(&area->used_space); |
600 | btree_destroy(&area->used_space); |
| 581 | 601 | ||
| 582 | area->attributes |= AS_AREA_ATTR_PARTIAL; |
602 | area->attributes |= AS_AREA_ATTR_PARTIAL; |
| 583 | 603 | ||
| Line 865... | Line 885... | ||
| 865 | * |
885 | * |
| 866 | * Note that this function cannot sleep as it is essentially a part of |
886 | * Note that this function cannot sleep as it is essentially a part of |
| 867 | * scheduling. Sleeping here would lead to deadlock on wakeup. Another |
887 | * scheduling. Sleeping here would lead to deadlock on wakeup. Another |
| 868 | * thing which is forbidden in this context is locking the address space. |
888 | * thing which is forbidden in this context is locking the address space. |
| 869 | * |
889 | * |
| - | 890 | * When this function is enetered, no spinlocks may be held. |
|
| - | 891 | * |
|
| 870 | * @param old Old address space or NULL. |
892 | * @param old Old address space or NULL. |
| 871 | * @param new New address space. |
893 | * @param new New address space. |
| 872 | */ |
894 | */ |
| 873 | void as_switch(as_t *old_as, as_t *new_as) |
895 | void as_switch(as_t *old_as, as_t *new_as) |
| 874 | { |
896 | { |
| - | 897 | DEADLOCK_PROBE_INIT(p_asidlock); |
|
| - | 898 | preemption_disable(); |
|
| - | 899 | retry: |
|
| - | 900 | (void) interrupts_disable(); |
|
| 875 | spinlock_lock(&asidlock); |
901 | if (!spinlock_trylock(&asidlock)) { |
| - | 902 | /* |
|
| - | 903 | * Avoid deadlock with TLB shootdown. |
|
| - | 904 | * We can enable interrupts here because |
|
| - | 905 | * preemption is disabled. We should not be |
|
| - | 906 | * holding any other lock. |
|
| - | 907 | */ |
|
| - | 908 | (void) interrupts_enable(); |
|
| - | 909 | DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD); |
|
| - | 910 | goto retry; |
|
| - | 911 | } |
|
| - | 912 | preemption_enable(); |
|
| 876 | 913 | ||
| 877 | /* |
914 | /* |
| 878 | * First, take care of the old address space. |
915 | * First, take care of the old address space. |
| 879 | */ |
916 | */ |
| 880 | if (old_as) { |
917 | if (old_as) { |