1 /* $NetBSD: uvm_fault_i.h,v 1.10 2000/01/11 06:57:50 chs Exp $ */ 2 3 /* 4 * 5 * Copyright (c) 1997 Charles D. Cranor and Washington University. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles D. Cranor and 19 * Washington University. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * from: Id: uvm_fault_i.h,v 1.1.6.1 1997/12/08 16:07:12 chuck Exp 35 */ 36 37 #ifndef _UVM_UVM_FAULT_I_H_ 38 #define _UVM_UVM_FAULT_I_H_ 39 40 /* 41 * uvm_fault_i.h: fault inline functions 42 */ 43 44 /* 45 * uvmfault_unlockmaps: unlock the maps 46 */ 47 48 static __inline void 49 uvmfault_unlockmaps(ufi, write_locked) 50 struct uvm_faultinfo *ufi; 51 boolean_t write_locked; 52 { 53 /* 54 * ufi can be NULL when this isn't really a fault, 55 * but merely paging in anon data. 56 */ 57 58 if (ufi == NULL) { 59 return; 60 } 61 62 if (write_locked) { 63 vm_map_unlock(ufi->map); 64 } else { 65 vm_map_unlock_read(ufi->map); 66 } 67 } 68 69 /* 70 * uvmfault_unlockall: unlock everything passed in. 71 * 72 * => maps must be read-locked (not write-locked). 73 */ 74 75 static __inline void 76 uvmfault_unlockall(ufi, amap, uobj, anon) 77 struct uvm_faultinfo *ufi; 78 struct vm_amap *amap; 79 struct uvm_object *uobj; 80 struct vm_anon *anon; 81 { 82 83 if (anon) 84 simple_unlock(&anon->an_lock); 85 if (uobj) 86 simple_unlock(&uobj->vmobjlock); 87 if (amap) 88 amap_unlock(amap); 89 uvmfault_unlockmaps(ufi, FALSE); 90 } 91 92 /* 93 * uvmfault_check_intrsafe: check for a virtual address managed by 94 * an interrupt-safe map. 95 * 96 * => caller must provide a uvm_faultinfo structure with the IN 97 * params properly filled in 98 * => if we find an intersafe VA, we fill in ufi->map, and return TRUE 99 */ 100 101 static __inline boolean_t 102 uvmfault_check_intrsafe(ufi) 103 struct uvm_faultinfo *ufi; 104 { 105 struct vm_map_intrsafe *vmi; 106 int s; 107 108 s = vmi_list_lock(); 109 for (vmi = LIST_FIRST(&vmi_list); vmi != NULL; 110 vmi = LIST_NEXT(vmi, vmi_list)) { 111 if (ufi->orig_rvaddr >= vm_map_min(&vmi->vmi_map) && 112 ufi->orig_rvaddr < vm_map_max(&vmi->vmi_map)) 113 break; 114 } 115 vmi_list_unlock(s); 116 117 if (vmi != NULL) { 118 ufi->map = &vmi->vmi_map; 119 return (TRUE); 120 } 121 122 return (FALSE); 123 } 124 125 /* 126 * uvmfault_lookup: lookup a virtual address in a map 127 * 128 * => caller must provide a uvm_faultinfo structure with the IN 129 * params properly filled in 130 * => we will lookup the map entry (handling submaps) as we go 131 * => if the lookup is a success we will return with the maps locked 132 * => if "write_lock" is TRUE, we write_lock the map, otherwise we only 133 * get a read lock. 134 * => note that submaps can only appear in the kernel and they are 135 * required to use the same virtual addresses as the map they 136 * are referenced by (thus address translation between the main 137 * map and the submap is unnecessary). 138 */ 139 140 static __inline boolean_t 141 uvmfault_lookup(ufi, write_lock) 142 struct uvm_faultinfo *ufi; 143 boolean_t write_lock; 144 { 145 vm_map_t tmpmap; 146 147 /* 148 * init ufi values for lookup. 149 */ 150 151 ufi->map = ufi->orig_map; 152 ufi->size = ufi->orig_size; 153 154 /* 155 * keep going down levels until we are done. note that there can 156 * only be two levels so we won't loop very long. 157 */ 158 159 while (1) { 160 161 /* 162 * lock map 163 */ 164 if (write_lock) { 165 vm_map_lock(ufi->map); 166 } else { 167 vm_map_lock_read(ufi->map); 168 } 169 170 /* 171 * lookup 172 */ 173 if (!uvm_map_lookup_entry(ufi->map, ufi->orig_rvaddr, 174 &ufi->entry)) { 175 uvmfault_unlockmaps(ufi, write_lock); 176 return(FALSE); 177 } 178 179 /* 180 * reduce size if necessary 181 */ 182 if (ufi->entry->end - ufi->orig_rvaddr < ufi->size) 183 ufi->size = ufi->entry->end - ufi->orig_rvaddr; 184 185 /* 186 * submap? replace map with the submap and lookup again. 187 * note: VAs in submaps must match VAs in main map. 188 */ 189 if (UVM_ET_ISSUBMAP(ufi->entry)) { 190 tmpmap = ufi->entry->object.sub_map; 191 if (write_lock) { 192 vm_map_unlock(ufi->map); 193 } else { 194 vm_map_unlock_read(ufi->map); 195 } 196 ufi->map = tmpmap; 197 continue; 198 } 199 200 /* 201 * got it! 202 */ 203 204 ufi->mapv = ufi->map->timestamp; 205 return(TRUE); 206 207 } /* while loop */ 208 209 /*NOTREACHED*/ 210 } 211 212 /* 213 * uvmfault_relock: attempt to relock the same version of the map 214 * 215 * => fault data structures should be unlocked before calling. 216 * => if a success (TRUE) maps will be locked after call. 217 */ 218 219 static __inline boolean_t 220 uvmfault_relock(ufi) 221 struct uvm_faultinfo *ufi; 222 { 223 /* 224 * ufi can be NULL when this isn't really a fault, 225 * but merely paging in anon data. 226 */ 227 228 if (ufi == NULL) { 229 return TRUE; 230 } 231 232 uvmexp.fltrelck++; 233 234 /* 235 * relock map. fail if version mismatch (in which case nothing 236 * gets locked). 237 */ 238 239 vm_map_lock_read(ufi->map); 240 if (ufi->mapv != ufi->map->timestamp) { 241 vm_map_unlock_read(ufi->map); 242 return(FALSE); 243 } 244 245 uvmexp.fltrelckok++; 246 return(TRUE); /* got it! */ 247 } 248 249 #endif /* _UVM_UVM_FAULT_I_H_ */ 250