Home | History | Annotate | Line # | Download | only in uvm
uvm_fault_i.h revision 1.3
      1 /*	$NetBSD: uvm_fault_i.h,v 1.3 1998/02/07 11:08:30 mrg Exp $	*/
      2 
      3 /*
      4  * XXXCDC: "ROUGH DRAFT" QUALITY UVM PRE-RELEASE FILE!
      5  *	   >>>USE AT YOUR OWN RISK, WORK IS NOT FINISHED<<<
      6  */
      7 /*
      8  *
      9  * Copyright (c) 1997 Charles D. Cranor and Washington University.
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  *      This product includes software developed by Charles D. Cranor and
     23  *      Washington University.
     24  * 4. The name of the author may not be used to endorse or promote products
     25  *    derived from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     29  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     30  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     32  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     33  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     36  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     37  *
     38  * from: Id: uvm_fault_i.h,v 1.1.6.1 1997/12/08 16:07:12 chuck Exp
     39  */
     40 
     41 /*
     42  * uvm_fault_i.h: fault inline functions
     43  */
     44 
     45 /*
     46  * uvmfault_unlockmaps: unlock the maps
     47  */
     48 
     49 static __inline void uvmfault_unlockmaps(ufi, write_locked)
     50 
     51 struct uvm_faultinfo *ufi;
     52 boolean_t write_locked;
     53 
     54 {
     55   if (write_locked) {
     56     vm_map_unlock(ufi->map);
     57     if (ufi->parent_map) vm_map_unlock(ufi->parent_map);
     58   } else {
     59     vm_map_unlock_read(ufi->map);
     60     if (ufi->parent_map) vm_map_unlock_read(ufi->parent_map);
     61   }
     62 }
     63 
     64 /*
     65  * uvmfault_unlockall: unlock everything passed in.
     66  *
     67  * => maps must be read-locked (not write-locked).
     68  */
     69 
     70 static __inline void uvmfault_unlockall(ufi, amap, uobj, anon)
     71 
     72 struct uvm_faultinfo *ufi;
     73 struct vm_amap *amap;
     74 struct uvm_object *uobj;
     75 struct vm_anon *anon;
     76 
     77 {
     78   if (anon)
     79     simple_unlock(&anon->an_lock);
     80   if (uobj)
     81     simple_unlock(&uobj->vmobjlock);
     82   if (amap)
     83     simple_unlock(&amap->am_l);
     84   uvmfault_unlockmaps(ufi, FALSE);
     85 }
     86 
     87 /*
     88  * uvmfault_lookup: lookup a virtual address in a map
     89  *
     90  * => caller must provide a uvm_faultinfo structure with the (IN)
     91  *	params properly filled in
     92  * => we will lookup the map entry and fill in parent_map, etc, as we go
     93  * => if the lookup is a success we will return with the maps locked
     94  * => if "write_lock" is TRUE, we write_lock the map, otherwise we only
     95  *	get a read lock.
     96  * => currently we require sharemaps to have the same virtual addresses
     97  *	as the main maps they are attached to.   in other words, the share
     98  *	map starts at zero and goes to the map user address.   the main
     99  *	map references it by setting its offset to be the same as the
    100  *	starting virtual address.    if we ever wanted to have sharemaps
    101  *	have different virtual addresses than main maps we would calculate
    102  *	it like:
    103  *		share_va = (rvaddr - entry->start) + entry->offset
    104  *	[i.e. offset from start of map entry plus offset of mapping]
    105  *	since (entry->start == entry->offset), share_va must equal rvaddr.
    106  *	if we need to change this we should store share_va in rvaddr
    107  *	and move rvaddr to orig_rvaddr.
    108  */
    109 
    110 static __inline boolean_t uvmfault_lookup(ufi, write_lock)
    111 
    112 struct uvm_faultinfo *ufi;
    113 boolean_t write_lock;
    114 
    115 {
    116   vm_map_t tmpmap;
    117 
    118   /*
    119    * init ufi values for lookup.
    120    */
    121 
    122   ufi->map = ufi->orig_map;
    123   ufi->rvaddr = ufi->orig_rvaddr;
    124   ufi->parent_map = NULL;
    125   ufi->size = ufi->orig_size;
    126 
    127   /*
    128    * keep going down levels until we are done.   note that there can
    129    * only be two levels so we won't loop very long.
    130    */
    131 
    132   while (1) {
    133 
    134     /*
    135      * lock map
    136      */
    137     if (write_lock) {
    138       vm_map_lock(ufi->map);
    139     } else {
    140       vm_map_lock_read(ufi->map);
    141     }
    142 
    143     /*
    144      * lookup
    145      */
    146     if (!uvm_map_lookup_entry(ufi->map, ufi->rvaddr, &ufi->entry)) {
    147       uvmfault_unlockmaps(ufi, write_lock);
    148       return(FALSE);
    149     }
    150 
    151     /*
    152      * reduce size if necessary
    153      */
    154     if (ufi->entry->end - ufi->rvaddr < ufi->size)
    155       ufi->size = ufi->entry->end - ufi->rvaddr;
    156 
    157     /*
    158      * submap?    replace map with the submap and lookup again.
    159      * note: VAs in submaps must match VAs in main map.
    160      */
    161     if (UVM_ET_ISSUBMAP(ufi->entry)) {
    162       if (ufi->parent_map)
    163 	panic("uvmfault_lookup: submap inside a sharemap (illegal)");
    164       tmpmap = ufi->entry->object.sub_map;
    165       if (write_lock) {
    166 	vm_map_unlock(ufi->map);
    167       } else {
    168 	vm_map_unlock_read(ufi->map);
    169       }
    170       ufi->map = tmpmap;
    171       continue;
    172     }
    173 
    174     /*
    175      * share map?  drop down a level.   already taken care of submap case.
    176      */
    177     if (UVM_ET_ISMAP(ufi->entry)) {
    178       if (ufi->parent_map)
    179 	panic("uvmfault_lookup: sharemap inside a sharemap (illegal)");
    180       ufi->parent_map = ufi->map;
    181       ufi->parentv = ufi->parent_map->timestamp;
    182       ufi->map = ufi->entry->object.share_map;
    183 #ifdef DIAGNOSTIC
    184       /* see note above */
    185       if (ufi->entry->offset != ufi->entry->start)
    186 	panic("uvmfault_lookup: sharemap VA != mainmap VA (not supported)");
    187 #endif
    188       continue;
    189     }
    190 
    191     /*
    192      * got it!
    193      */
    194 
    195     ufi->mapv = ufi->map->timestamp;
    196     return(TRUE);
    197 
    198   }	/* while loop */
    199 
    200   /*NOTREACHED*/
    201 }
    202 
    203 /*
    204  * uvmfault_relock: attempt to relock the same version of the map
    205  *
    206  * => fault data structures should be unlocked before calling.
    207  * => if a success (TRUE) maps will be locked after call.
    208  */
    209 
    210 static __inline boolean_t uvmfault_relock(ufi)
    211 
    212 struct uvm_faultinfo *ufi;
    213 
    214 {
    215   uvmexp.fltrelck++;
    216   /*
    217    * simply relock parent (if any) then map in order.   fail if version
    218    * mismatch (in which case nothing gets locked).
    219    */
    220 
    221   if (ufi->parent_map) {
    222     vm_map_lock_read(ufi->parent_map);
    223     if (ufi->parentv != ufi->parent_map->timestamp) {
    224       vm_map_unlock_read(ufi->parent_map);
    225       return(FALSE);
    226     }
    227   }
    228 
    229   vm_map_lock_read(ufi->map);
    230   if (ufi->mapv != ufi->map->timestamp) {
    231     if (ufi->parent_map)
    232       vm_map_unlock_read(ufi->parent_map);
    233     vm_map_unlock_read(ufi->map);
    234     return(FALSE);
    235   }
    236 
    237   uvmexp.fltrelckok++;
    238   return(TRUE);		/* got it! */
    239 }
    240