00001 /* 00002 * Copyright (C) 2006 Jakub Jermar 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 00009 * - Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * - Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * - The name of the author may not be used to endorse or promote products 00015 * derived from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00019 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00020 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00059 #include <mm/asid.h> 00060 #include <mm/as.h> 00061 #include <mm/tlb.h> 00062 #include <arch/mm/asid.h> 00063 #include <synch/spinlock.h> 00064 #include <synch/mutex.h> 00065 #include <arch.h> 00066 #include <adt/list.h> 00067 #include <debug.h> 00068 00072 SPINLOCK_INITIALIZE(asidlock); 00073 00074 static count_t asids_allocated = 0; 00075 00083 asid_t asid_get(void) 00084 { 00085 asid_t asid; 00086 link_t *tmp; 00087 as_t *as; 00088 00089 /* 00090 * Check if there is an unallocated ASID. 00091 */ 00092 00093 spinlock_lock(&asidlock); 00094 if (asids_allocated == ASIDS_ALLOCABLE) { 00095 00096 /* 00097 * All ASIDs are already allocated. 00098 * Resort to stealing. 00099 */ 00100 00101 /* 00102 * Remove the first item on the list. 00103 * It is guaranteed to belong to an 00104 * inactive address space. 00105 */ 00106 ASSERT(!list_empty(&inactive_as_with_asid_head)); 00107 tmp = inactive_as_with_asid_head.next; 00108 list_remove(tmp); 00109 00110 as = list_get_instance(tmp, as_t, inactive_as_with_asid_link); 00111 mutex_lock_active(&as->lock); 00112 00113 /* 00114 * Steal the ASID. 00115 * Note that the stolen ASID is not active. 00116 */ 00117 asid = as->asid; 00118 ASSERT(asid != ASID_INVALID); 00119 00120 /* 00121 * Notify the address space from wich the ASID 00122 * was stolen by invalidating its asid member. 00123 */ 00124 as->asid = ASID_INVALID; 00125 mutex_unlock(&as->lock); 00126 00127 /* 00128 * Get the system rid of the stolen ASID. 00129 */ 00130 tlb_shootdown_start(TLB_INVL_ASID, asid, 0, 0); 00131 tlb_invalidate_asid(asid); 00132 tlb_shootdown_finalize(); 00133 } else { 00134 00135 /* 00136 * There is at least one unallocated ASID. 00137 * Find it and assign it. 00138 */ 00139 00140 asid = asid_find_free(); 00141 asids_allocated++; 00142 00143 /* 00144 * Purge the allocated rid from TLBs. 00145 */ 00146 tlb_shootdown_start(TLB_INVL_ASID, asid, 0, 0); 00147 tlb_invalidate_asid(asid); 00148 tlb_shootdown_finalize(); 00149 } 00150 00151 spinlock_unlock(&asidlock); 00152 00153 return asid; 00154 } 00155 00163 void asid_put(asid_t asid) 00164 { 00165 ipl_t ipl; 00166 00167 ipl = interrupts_disable(); 00168 spinlock_lock(&asidlock); 00169 00170 asids_allocated--; 00171 asid_put_arch(asid); 00172 00173 spinlock_unlock(&asidlock); 00174 interrupts_restore(ipl); 00175 } 00176