xref: /netbsd-src/sys/uvm/uvm_fault_i.h (revision d2a0ebb67a049a5c019aba780e67b6c65954d3db)
1*d2a0ebb6Sad /*	$NetBSD: uvm_fault_i.h,v 1.33 2020/02/23 15:46:43 ad Exp $	*/
2f2caacc7Smrg 
3f2caacc7Smrg /*
4f2caacc7Smrg  * Copyright (c) 1997 Charles D. Cranor and Washington University.
5f2caacc7Smrg  * All rights reserved.
6f2caacc7Smrg  *
7f2caacc7Smrg  * Redistribution and use in source and binary forms, with or without
8f2caacc7Smrg  * modification, are permitted provided that the following conditions
9f2caacc7Smrg  * are met:
10f2caacc7Smrg  * 1. Redistributions of source code must retain the above copyright
11f2caacc7Smrg  *    notice, this list of conditions and the following disclaimer.
12f2caacc7Smrg  * 2. Redistributions in binary form must reproduce the above copyright
13f2caacc7Smrg  *    notice, this list of conditions and the following disclaimer in the
14f2caacc7Smrg  *    documentation and/or other materials provided with the distribution.
15f2caacc7Smrg  *
16f2caacc7Smrg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f2caacc7Smrg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18f2caacc7Smrg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19f2caacc7Smrg  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20f2caacc7Smrg  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21f2caacc7Smrg  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22f2caacc7Smrg  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23f2caacc7Smrg  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24f2caacc7Smrg  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25f2caacc7Smrg  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
261f6b921cSmrg  *
271f6b921cSmrg  * from: Id: uvm_fault_i.h,v 1.1.6.1 1997/12/08 16:07:12 chuck Exp
28f2caacc7Smrg  */
29f2caacc7Smrg 
30021fdb64Sperry #ifndef _UVM_UVM_FAULT_I_H_
31021fdb64Sperry #define _UVM_UVM_FAULT_I_H_
32021fdb64Sperry 
33f2caacc7Smrg /*
34f2caacc7Smrg  * uvm_fault_i.h: fault inline functions
35f2caacc7Smrg  */
3661768d92Schristos void uvmfault_update_stats(struct uvm_faultinfo *);
3761768d92Schristos 
38f2caacc7Smrg 
39f2caacc7Smrg /*
40f2caacc7Smrg  * uvmfault_unlockmaps: unlock the maps
41f2caacc7Smrg  */
42f2caacc7Smrg 
4387fd18f8Schristos static __inline void
uvmfault_unlockmaps(struct uvm_faultinfo * ufi,bool write_locked)44712239e3Sthorpej uvmfault_unlockmaps(struct uvm_faultinfo *ufi, bool write_locked)
45f2caacc7Smrg {
4616f0ca36Schs 	/*
4716f0ca36Schs 	 * ufi can be NULL when this isn't really a fault,
4816f0ca36Schs 	 * but merely paging in anon data.
4916f0ca36Schs 	 */
5016f0ca36Schs 
5116f0ca36Schs 	if (ufi == NULL) {
5216f0ca36Schs 		return;
5316f0ca36Schs 	}
548106d135Smrg 
5587287ec1Schristos #ifndef __HAVE_NO_PMAP_STATS
5661768d92Schristos 	uvmfault_update_stats(ufi);
5787287ec1Schristos #endif
58f2caacc7Smrg 	if (write_locked) {
59f2caacc7Smrg 		vm_map_unlock(ufi->map);
60f2caacc7Smrg 	} else {
61f2caacc7Smrg 		vm_map_unlock_read(ufi->map);
62f2caacc7Smrg 	}
63f2caacc7Smrg }
64f2caacc7Smrg 
65f2caacc7Smrg /*
66f2caacc7Smrg  * uvmfault_unlockall: unlock everything passed in.
67f2caacc7Smrg  *
68f2caacc7Smrg  * => maps must be read-locked (not write-locked).
69f2caacc7Smrg  */
70f2caacc7Smrg 
7187fd18f8Schristos static __inline void
uvmfault_unlockall(struct uvm_faultinfo * ufi,struct vm_amap * amap,struct uvm_object * uobj)72e569faccSthorpej uvmfault_unlockall(struct uvm_faultinfo *ufi, struct vm_amap *amap,
73e225b7bdSrmind     struct uvm_object *uobj)
74f2caacc7Smrg {
758106d135Smrg 
76f2caacc7Smrg 	if (uobj)
77*d2a0ebb6Sad 		rw_exit(uobj->vmobjlock);
78f2caacc7Smrg 	if (amap)
7944f5fc28Schuck 		amap_unlock(amap);
80b3667adaSthorpej 	uvmfault_unlockmaps(ufi, false);
81f2caacc7Smrg }
82f2caacc7Smrg 
83f2caacc7Smrg /*
84f2caacc7Smrg  * uvmfault_lookup: lookup a virtual address in a map
85f2caacc7Smrg  *
861b59a238Schuck  * => caller must provide a uvm_faultinfo structure with the IN
87f2caacc7Smrg  *	params properly filled in
881b59a238Schuck  * => we will lookup the map entry (handling submaps) as we go
89f2caacc7Smrg  * => if the lookup is a success we will return with the maps locked
90b3667adaSthorpej  * => if "write_lock" is true, we write_lock the map, otherwise we only
91f2caacc7Smrg  *	get a read lock.
921b59a238Schuck  * => note that submaps can only appear in the kernel and they are
931b59a238Schuck  *	required to use the same virtual addresses as the map they
941b59a238Schuck  *	are referenced by (thus address translation between the main
951b59a238Schuck  *	map and the submap is unnecessary).
96f2caacc7Smrg  */
97f2caacc7Smrg 
9887fd18f8Schristos static __inline bool
uvmfault_lookup(struct uvm_faultinfo * ufi,bool write_lock)99712239e3Sthorpej uvmfault_lookup(struct uvm_faultinfo *ufi, bool write_lock)
100f2caacc7Smrg {
101821ec03eSchs 	struct vm_map *tmpmap;
102f2caacc7Smrg 
103f2caacc7Smrg 	/*
104f2caacc7Smrg 	 * init ufi values for lookup.
105f2caacc7Smrg 	 */
106f2caacc7Smrg 
107f2caacc7Smrg 	ufi->map = ufi->orig_map;
108f2caacc7Smrg 	ufi->size = ufi->orig_size;
109f2caacc7Smrg 
110f2caacc7Smrg 	/*
111f2caacc7Smrg 	 * keep going down levels until we are done.   note that there can
112f2caacc7Smrg 	 * only be two levels so we won't loop very long.
113f2caacc7Smrg 	 */
114f2caacc7Smrg 
115a4c86c1bSrmind 	for (;;) {
116f2caacc7Smrg 		/*
117f2caacc7Smrg 		 * lock map
118f2caacc7Smrg 		 */
119f2caacc7Smrg 		if (write_lock) {
120f2caacc7Smrg 			vm_map_lock(ufi->map);
121f2caacc7Smrg 		} else {
122f2caacc7Smrg 			vm_map_lock_read(ufi->map);
123f2caacc7Smrg 		}
124f2caacc7Smrg 
125f2caacc7Smrg 		/*
126f2caacc7Smrg 		 * lookup
127f2caacc7Smrg 		 */
1281b59a238Schuck 		if (!uvm_map_lookup_entry(ufi->map, ufi->orig_rvaddr,
1291b59a238Schuck 		    &ufi->entry)) {
130f2caacc7Smrg 			uvmfault_unlockmaps(ufi, write_lock);
131b3667adaSthorpej 			return(false);
132f2caacc7Smrg 		}
133f2caacc7Smrg 
134f2caacc7Smrg 		/*
135f2caacc7Smrg 		 * reduce size if necessary
136f2caacc7Smrg 		 */
1371b59a238Schuck 		if (ufi->entry->end - ufi->orig_rvaddr < ufi->size)
1381b59a238Schuck 			ufi->size = ufi->entry->end - ufi->orig_rvaddr;
139f2caacc7Smrg 
140f2caacc7Smrg 		/*
141f2caacc7Smrg 		 * submap?    replace map with the submap and lookup again.
142f2caacc7Smrg 		 * note: VAs in submaps must match VAs in main map.
143f2caacc7Smrg 		 */
144f2caacc7Smrg 		if (UVM_ET_ISSUBMAP(ufi->entry)) {
145f2caacc7Smrg 			tmpmap = ufi->entry->object.sub_map;
146f2caacc7Smrg 			if (write_lock) {
147f2caacc7Smrg 				vm_map_unlock(ufi->map);
148f2caacc7Smrg 			} else {
149f2caacc7Smrg 				vm_map_unlock_read(ufi->map);
150f2caacc7Smrg 			}
151f2caacc7Smrg 			ufi->map = tmpmap;
152f2caacc7Smrg 			continue;
153f2caacc7Smrg 		}
154f2caacc7Smrg 
155f2caacc7Smrg 		/*
156f2caacc7Smrg 		 * got it!
157f2caacc7Smrg 		 */
158f2caacc7Smrg 
159f2caacc7Smrg 		ufi->mapv = ufi->map->timestamp;
160b3667adaSthorpej 		return(true);
161f2caacc7Smrg 
162f2caacc7Smrg 	}	/* while loop */
163f2caacc7Smrg 
164f2caacc7Smrg 	/*NOTREACHED*/
165f2caacc7Smrg }
166f2caacc7Smrg 
167f2caacc7Smrg /*
168f2caacc7Smrg  * uvmfault_relock: attempt to relock the same version of the map
169f2caacc7Smrg  *
170f2caacc7Smrg  * => fault data structures should be unlocked before calling.
171b3667adaSthorpej  * => if a success (true) maps will be locked after call.
172f2caacc7Smrg  */
173f2caacc7Smrg 
17487fd18f8Schristos static __inline bool
uvmfault_relock(struct uvm_faultinfo * ufi)175e569faccSthorpej uvmfault_relock(struct uvm_faultinfo *ufi)
176f2caacc7Smrg {
17716f0ca36Schs 	/*
17816f0ca36Schs 	 * ufi can be NULL when this isn't really a fault,
17916f0ca36Schs 	 * but merely paging in anon data.
18016f0ca36Schs 	 */
18116f0ca36Schs 
18216f0ca36Schs 	if (ufi == NULL) {
183b3667adaSthorpej 		return true;
18416f0ca36Schs 	}
1858106d135Smrg 
186a98966d3Sad 	cpu_count(CPU_COUNT_FLTRELCK, 1);
18716f0ca36Schs 
188f2caacc7Smrg 	/*
1891b59a238Schuck 	 * relock map.   fail if version mismatch (in which case nothing
1901b59a238Schuck 	 * gets locked).
191f2caacc7Smrg 	 */
192f2caacc7Smrg 
193f2caacc7Smrg 	vm_map_lock_read(ufi->map);
194f2caacc7Smrg 	if (ufi->mapv != ufi->map->timestamp) {
195f2caacc7Smrg 		vm_map_unlock_read(ufi->map);
196b3667adaSthorpej 		return(false);
197f2caacc7Smrg 	}
198f2caacc7Smrg 
199a98966d3Sad 	cpu_count(CPU_COUNT_FLTRELCKOK, 1);
200b3667adaSthorpej 	return(true);
201f2caacc7Smrg }
202021fdb64Sperry 
203021fdb64Sperry #endif /* _UVM_UVM_FAULT_I_H_ */
204