Home | History | Annotate | Line # | Download | only in uvm
uvm_fault_i.h revision 1.1
      1 /*	$Id: uvm_fault_i.h,v 1.1 1998/02/05 06:25:10 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 
     39 /*
     40  * uvm_fault_i.h: fault inline functions
     41  */
     42 
     43 /*
     44  * uvmfault_unlockmaps: unlock the maps
     45  */
     46 
     47 static __inline void uvmfault_unlockmaps(ufi, write_locked)
     48 
     49 struct uvm_faultinfo *ufi;
     50 boolean_t write_locked;
     51 
     52 {
     53   if (write_locked) {
     54     vm_map_unlock(ufi->map);
     55     if (ufi->parent_map) vm_map_unlock(ufi->parent_map);
     56   } else {
     57     vm_map_unlock_read(ufi->map);
     58     if (ufi->parent_map) vm_map_unlock_read(ufi->parent_map);
     59   }
     60 }
     61 
     62 /*
     63  * uvmfault_unlockall: unlock everything passed in.
     64  *
     65  * => maps must be read-locked (not write-locked).
     66  */
     67 
     68 static __inline void uvmfault_unlockall(ufi, amap, uobj, anon)
     69 
     70 struct uvm_faultinfo *ufi;
     71 struct vm_amap *amap;
     72 struct uvm_object *uobj;
     73 struct vm_anon *anon;
     74 
     75 {
     76   if (anon)
     77     simple_unlock(&anon->an_lock);
     78   if (uobj)
     79     simple_unlock(&uobj->vmobjlock);
     80   if (amap)
     81     simple_unlock(&amap->am_l);
     82   uvmfault_unlockmaps(ufi, FALSE);
     83 }
     84 
     85 /*
     86  * uvmfault_lookup: lookup a virtual address in a map
     87  *
     88  * => caller must provide a uvm_faultinfo structure with the (IN)
     89  *	params properly filled in
     90  * => we will lookup the map entry and fill in parent_map, etc, as we go
     91  * => if the lookup is a success we will return with the maps locked
     92  * => if "write_lock" is TRUE, we write_lock the map, otherwise we only
     93  *	get a read lock.
     94  * => currently we require sharemaps to have the same virtual addresses
     95  *	as the main maps they are attached to.   in other words, the share
     96  *	map starts at zero and goes to the map user address.   the main
     97  *	map references it by setting its offset to be the same as the
     98  *	starting virtual address.    if we ever wanted to have sharemaps
     99  *	have different virtual addresses than main maps we would calculate
    100  *	it like:
    101  *		share_va = (rvaddr - entry->start) + entry->offset
    102  *	[i.e. offset from start of map entry plus offset of mapping]
    103  *	since (entry->start == entry->offset), share_va must equal rvaddr.
    104  *	if we need to change this we should store share_va in rvaddr
    105  *	and move rvaddr to orig_rvaddr.
    106  */
    107 
    108 static __inline boolean_t uvmfault_lookup(ufi, write_lock)
    109 
    110 struct uvm_faultinfo *ufi;
    111 boolean_t write_lock;
    112 
    113 {
    114   vm_map_t tmpmap;
    115 
    116   /*
    117    * init ufi values for lookup.
    118    */
    119 
    120   ufi->map = ufi->orig_map;
    121   ufi->rvaddr = ufi->orig_rvaddr;
    122   ufi->parent_map = NULL;
    123   ufi->size = ufi->orig_size;
    124 
    125   /*
    126    * keep going down levels until we are done.   note that there can
    127    * only be two levels so we won't loop very long.
    128    */
    129 
    130   while (1) {
    131 
    132     /*
    133      * lock map
    134      */
    135     if (write_lock) {
    136       vm_map_lock(ufi->map);
    137     } else {
    138       vm_map_lock_read(ufi->map);
    139     }
    140 
    141     /*
    142      * lookup
    143      */
    144     if (!uvm_map_lookup_entry(ufi->map, ufi->rvaddr, &ufi->entry)) {
    145       uvmfault_unlockmaps(ufi, write_lock);
    146       return(FALSE);
    147     }
    148 
    149     /*
    150      * reduce size if necessary
    151      */
    152     if (ufi->entry->end - ufi->rvaddr < ufi->size)
    153       ufi->size = ufi->entry->end - ufi->rvaddr;
    154 
    155     /*
    156      * submap?    replace map with the submap and lookup again.
    157      * note: VAs in submaps must match VAs in main map.
    158      */
    159     if (UVM_ET_ISSUBMAP(ufi->entry)) {
    160       if (ufi->parent_map)
    161 	panic("uvmfault_lookup: submap inside a sharemap (illegal)");
    162       tmpmap = ufi->entry->object.sub_map;
    163       if (write_lock) {
    164 	vm_map_unlock(ufi->map);
    165       } else {
    166 	vm_map_unlock_read(ufi->map);
    167       }
    168       ufi->map = tmpmap;
    169       continue;
    170     }
    171 
    172     /*
    173      * share map?  drop down a level.   already taken care of submap case.
    174      */
    175     if (UVM_ET_ISMAP(ufi->entry)) {
    176       if (ufi->parent_map)
    177 	panic("uvmfault_lookup: sharemap inside a sharemap (illegal)");
    178       ufi->parent_map = ufi->map;
    179       ufi->parentv = ufi->parent_map->timestamp;
    180       ufi->map = ufi->entry->object.share_map;
    181 #ifdef DIAGNOSTIC
    182       /* see note above */
    183       if (ufi->entry->offset != ufi->entry->start)
    184 	panic("uvmfault_lookup: sharemap VA != mainmap VA (not supported)");
    185 #endif
    186       continue;
    187     }
    188 
    189     /*
    190      * got it!
    191      */
    192 
    193     ufi->mapv = ufi->map->timestamp;
    194     return(TRUE);
    195 
    196   }	/* while loop */
    197 
    198   /*NOTREACHED*/
    199 }
    200 
    201 /*
    202  * uvmfault_relock: attempt to relock the same version of the map
    203  *
    204  * => fault data structures should be unlocked before calling.
    205  * => if a success (TRUE) maps will be locked after call.
    206  */
    207 
    208 static __inline boolean_t uvmfault_relock(ufi)
    209 
    210 struct uvm_faultinfo *ufi;
    211 
    212 {
    213   uvmexp.fltrelck++;
    214   /*
    215    * simply relock parent (if any) then map in order.   fail if version
    216    * mismatch (in which case nothing gets locked).
    217    */
    218 
    219   if (ufi->parent_map) {
    220     vm_map_lock_read(ufi->parent_map);
    221     if (ufi->parentv != ufi->parent_map->timestamp) {
    222       vm_map_unlock_read(ufi->parent_map);
    223       return(FALSE);
    224     }
    225   }
    226 
    227   vm_map_lock_read(ufi->map);
    228   if (ufi->mapv != ufi->map->timestamp) {
    229     if (ufi->parent_map)
    230       vm_map_unlock_read(ufi->parent_map);
    231     vm_map_unlock_read(ufi->map);
    232     return(FALSE);
    233   }
    234 
    235   uvmexp.fltrelckok++;
    236   return(TRUE);		/* got it! */
    237 }
    238