1 /*	$OpenBSD: uvm_amap_i.h,v 1.12 2001/12/19 08:58:07 art Exp $	*/
2 /*	$NetBSD: uvm_amap_i.h,v 1.15 2000/11/25 06:27:59 chs Exp $	*/
3 
4 /*
5  *
6  * Copyright (c) 1997 Charles D. Cranor and Washington University.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Charles D. Cranor and
20  *      Washington University.
21  * 4. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  * from: Id: uvm_amap_i.h,v 1.1.2.4 1998/01/05 18:12:57 chuck Exp
36  */
37 
38 #ifndef _UVM_UVM_AMAP_I_H_
39 #define _UVM_UVM_AMAP_I_H_
40 
41 /*
42  * uvm_amap_i.h
43  */
44 
45 /*
46  * if inlines are enabled always pull in these functions, otherwise
47  * pull them in only once (when we are compiling uvm_amap.c).
48  */
49 
50 #if defined(UVM_AMAP_INLINE) || defined(UVM_AMAP_C)
51 
52 /*
53  * amap_lookup: look up a page in an amap
54  *
55  * => amap should be locked by caller.
56  */
57 AMAP_INLINE struct vm_anon *
amap_lookup(aref,offset)58 amap_lookup(aref, offset)
59 	struct vm_aref *aref;
60 	vaddr_t offset;
61 {
62 	int slot;
63 	struct vm_amap *amap = aref->ar_amap;
64 	UVMHIST_FUNC("amap_lookup"); UVMHIST_CALLED(maphist);
65 
66 	AMAP_B2SLOT(slot, offset);
67 	slot += aref->ar_pageoff;
68 
69 	if (slot >= amap->am_nslot)
70 		panic("amap_lookup: offset out of range");
71 
72 	UVMHIST_LOG(maphist, "<- done (amap=0x%x, offset=0x%x, result=0x%x)",
73 	    amap, offset, amap->am_anon[slot], 0);
74 	return(amap->am_anon[slot]);
75 }
76 
77 /*
78  * amap_lookups: look up a range of pages in an amap
79  *
80  * => amap should be locked by caller.
81  * => XXXCDC: this interface is biased toward array-based amaps.  fix.
82  */
83 AMAP_INLINE void
amap_lookups(aref,offset,anons,npages)84 amap_lookups(aref, offset, anons, npages)
85 	struct vm_aref *aref;
86 	vaddr_t offset;
87 	struct vm_anon **anons;
88 	int npages;
89 {
90 	int slot;
91 	struct vm_amap *amap = aref->ar_amap;
92 	UVMHIST_FUNC("amap_lookups"); UVMHIST_CALLED(maphist);
93 
94 	AMAP_B2SLOT(slot, offset);
95 	slot += aref->ar_pageoff;
96 
97 	UVMHIST_LOG(maphist, "  slot=%d, npages=%d, nslot=%d", slot, npages,
98 		amap->am_nslot, 0);
99 
100 	if ((slot + (npages - 1)) >= amap->am_nslot)
101 		panic("amap_lookups: offset out of range");
102 
103 	memcpy(anons, &amap->am_anon[slot], npages * sizeof(struct vm_anon *));
104 
105 	UVMHIST_LOG(maphist, "<- done", 0, 0, 0, 0);
106 	return;
107 }
108 
109 /*
110  * amap_add: add (or replace) a page to an amap
111  *
112  * => caller must lock amap.
113  * => if (replace) caller must lock anon because we might have to call
114  *	pmap_page_protect on the anon's page.
115  * => returns an "offset" which is meaningful to amap_unadd().
116  */
117 AMAP_INLINE void
amap_add(aref,offset,anon,replace)118 amap_add(aref, offset, anon, replace)
119 	struct vm_aref *aref;
120 	vaddr_t offset;
121 	struct vm_anon *anon;
122 	boolean_t replace;
123 {
124 	int slot;
125 	struct vm_amap *amap = aref->ar_amap;
126 	UVMHIST_FUNC("amap_add"); UVMHIST_CALLED(maphist);
127 
128 	AMAP_B2SLOT(slot, offset);
129 	slot += aref->ar_pageoff;
130 
131 	if (slot >= amap->am_nslot)
132 		panic("amap_add: offset out of range");
133 
134 	if (replace) {
135 
136 		if (amap->am_anon[slot] == NULL)
137 			panic("amap_add: replacing null anon");
138 		if (amap->am_anon[slot]->u.an_page != NULL &&
139 		    (amap->am_flags & AMAP_SHARED) != 0) {
140 			pmap_page_protect(amap->am_anon[slot]->u.an_page,
141 			    VM_PROT_NONE);
142 			/*
143 			 * XXX: suppose page is supposed to be wired somewhere?
144 			 */
145 		}
146 	} else {   /* !replace */
147 		if (amap->am_anon[slot] != NULL)
148 			panic("amap_add: slot in use");
149 
150 		amap->am_bckptr[slot] = amap->am_nused;
151 		amap->am_slots[amap->am_nused] = slot;
152 		amap->am_nused++;
153 	}
154 	amap->am_anon[slot] = anon;
155 	UVMHIST_LOG(maphist,
156 	    "<- done (amap=0x%x, offset=0x%x, anon=0x%x, rep=%d)",
157 	    amap, offset, anon, replace);
158 }
159 
160 /*
161  * amap_unadd: remove a page from an amap
162  *
163  * => caller must lock amap
164  */
165 AMAP_INLINE void
amap_unadd(aref,offset)166 amap_unadd(aref, offset)
167 	struct vm_aref *aref;
168 	vaddr_t offset;
169 {
170 	int ptr, slot;
171 	struct vm_amap *amap = aref->ar_amap;
172 	UVMHIST_FUNC("amap_unadd"); UVMHIST_CALLED(maphist);
173 
174 	AMAP_B2SLOT(slot, offset);
175 	slot += aref->ar_pageoff;
176 
177 	if (slot >= amap->am_nslot)
178 		panic("amap_unadd: offset out of range");
179 
180 	if (amap->am_anon[slot] == NULL)
181 		panic("amap_unadd: nothing there");
182 
183 	amap->am_anon[slot] = NULL;
184 	ptr = amap->am_bckptr[slot];
185 
186 	if (ptr != (amap->am_nused - 1)) {	/* swap to keep slots contig? */
187 		amap->am_slots[ptr] = amap->am_slots[amap->am_nused - 1];
188 		amap->am_bckptr[amap->am_slots[ptr]] = ptr;	/* back link */
189 	}
190 	amap->am_nused--;
191 	UVMHIST_LOG(maphist, "<- done (amap=0x%x, slot=0x%x)", amap, slot,0, 0);
192 }
193 
194 /*
195  * amap_ref: gain a reference to an amap
196  *
197  * => amap must not be locked (we will lock)
198  * => "offset" and "len" are in units of pages
199  * => called at fork time to gain the child's reference
200  */
201 AMAP_INLINE void
amap_ref(amap,offset,len,flags)202 amap_ref(amap, offset, len, flags)
203 	struct vm_amap *amap;
204 	vaddr_t offset;
205 	vsize_t len;
206 	int flags;
207 {
208 	UVMHIST_FUNC("amap_ref"); UVMHIST_CALLED(maphist);
209 
210 	amap_lock(amap);
211 	amap->am_ref++;
212 	if (flags & AMAP_SHARED)
213 		amap->am_flags |= AMAP_SHARED;
214 #ifdef UVM_AMAP_PPREF
215 	if (amap->am_ppref == NULL && (flags & AMAP_REFALL) == 0 &&
216 	    len != amap->am_nslot)
217 		amap_pp_establish(amap);
218 	if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
219 		if (flags & AMAP_REFALL)
220 			amap_pp_adjref(amap, 0, amap->am_nslot, 1);
221 		else
222 			amap_pp_adjref(amap, offset, len, 1);
223 	}
224 #endif
225 	amap_unlock(amap);
226 	UVMHIST_LOG(maphist,"<- done!  amap=0x%x", amap, 0, 0, 0);
227 }
228 
229 /*
230  * amap_unref: remove a reference to an amap
231  *
232  * => caller must remove all pmap-level references to this amap before
233  *	dropping the reference
234  * => called from uvm_unmap_detach [only]  ... note that entry is no
235  *	longer part of a map and thus has no need for locking
236  * => amap must be unlocked (we will lock it).
237  */
238 AMAP_INLINE void
amap_unref(amap,offset,len,all)239 amap_unref(amap, offset, len, all)
240 	struct vm_amap *amap;
241 	vaddr_t offset;
242 	vsize_t len;
243 	boolean_t all;
244 {
245 	UVMHIST_FUNC("amap_unref"); UVMHIST_CALLED(maphist);
246 
247 	/*
248 	 * lock it
249 	 */
250 	amap_lock(amap);
251 	UVMHIST_LOG(maphist,"  amap=0x%x  refs=%d, nused=%d",
252 	    amap, amap->am_ref, amap->am_nused, 0);
253 
254 	/*
255 	 * if we are the last reference, free the amap and return.
256 	 */
257 
258 	if (amap->am_ref == 1) {
259 		amap_wipeout(amap);	/* drops final ref and frees */
260 		UVMHIST_LOG(maphist,"<- done (was last ref)!", 0, 0, 0, 0);
261 		return;			/* no need to unlock */
262 	}
263 
264 	/*
265 	 * otherwise just drop the reference count(s)
266 	 */
267 
268 	amap->am_ref--;
269 	if (amap->am_ref == 1 && (amap->am_flags & AMAP_SHARED) != 0)
270 		amap->am_flags &= ~AMAP_SHARED;	/* clear shared flag */
271 #ifdef UVM_AMAP_PPREF
272 	if (amap->am_ppref == NULL && all == 0 && len != amap->am_nslot)
273 		amap_pp_establish(amap);
274 	if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
275 		if (all)
276 			amap_pp_adjref(amap, 0, amap->am_nslot, -1);
277 		else
278 			amap_pp_adjref(amap, offset, len, -1);
279 	}
280 #endif
281 	amap_unlock(amap);
282 
283 	UVMHIST_LOG(maphist,"<- done!", 0, 0, 0, 0);
284 }
285 
286 #endif /* defined(UVM_AMAP_INLINE) || defined(UVM_AMAP_C) */
287 
288 #endif /* _UVM_UVM_AMAP_I_H_ */
289