1 /*	$OpenBSD: uvm_page_i.h,v 1.15 2002/09/10 18:29:44 art Exp $	*/
2 /*	$NetBSD: uvm_page_i.h,v 1.14 2000/11/27 07:47:42 chs Exp $	*/
3 
4 /*
5  * Copyright (c) 1997 Charles D. Cranor and Washington University.
6  * Copyright (c) 1991, 1993, The Regents of the University of California.
7  *
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * The Mach Operating System project at Carnegie-Mellon University.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by Charles D. Cranor,
24  *      Washington University, the University of California, Berkeley and
25  *      its contributors.
26  * 4. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	@(#)vm_page.c   8.3 (Berkeley) 3/21/94
43  * from: Id: uvm_page_i.h,v 1.1.2.7 1998/01/05 00:26:02 chuck Exp
44  *
45  *
46  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
47  * All rights reserved.
48  *
49  * Permission to use, copy, modify and distribute this software and
50  * its documentation is hereby granted, provided that both the copyright
51  * notice and this permission notice appear in all copies of the
52  * software, derivative works or modified versions, and any portions
53  * thereof, and that both notices appear in supporting documentation.
54  *
55  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
57  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58  *
59  * Carnegie Mellon requests users of this software to return to
60  *
61  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
62  *  School of Computer Science
63  *  Carnegie Mellon University
64  *  Pittsburgh PA 15213-3890
65  *
66  * any improvements or extensions that they make and grant Carnegie the
67  * rights to redistribute these changes.
68  */
69 
70 #ifndef _UVM_UVM_PAGE_I_H_
71 #define _UVM_UVM_PAGE_I_H_
72 
73 /*
74  * uvm_page_i.h
75  */
76 
77 /*
78  * inline functions [maybe]
79  */
80 
81 #if defined(UVM_PAGE_INLINE) || defined(UVM_PAGE)
82 
83 /*
84  * uvm_lock_fpageq: lock the free page queue
85  *
86  * => free page queue can be accessed in interrupt context, so this
87  *	blocks all interrupts that can cause memory allocation, and
88  *	returns the previous interrupt level.
89  */
90 
91 PAGE_INLINE int
uvm_lock_fpageq()92 uvm_lock_fpageq()
93 {
94 	int s;
95 
96 	s = splvm();
97 	simple_lock(&uvm.fpageqlock);
98 	return (s);
99 }
100 
101 /*
102  * uvm_unlock_fpageq: unlock the free page queue
103  *
104  * => caller must supply interrupt level returned by uvm_lock_fpageq()
105  *	so that it may be restored.
106  */
107 
108 PAGE_INLINE void
uvm_unlock_fpageq(s)109 uvm_unlock_fpageq(s)
110 	int s;
111 {
112 
113 	simple_unlock(&uvm.fpageqlock);
114 	splx(s);
115 }
116 
117 /*
118  * uvm_pagelookup: look up a page
119  *
120  * => caller should lock object to keep someone from pulling the page
121  *	out from under it
122  */
123 
124 struct vm_page *
uvm_pagelookup(obj,off)125 uvm_pagelookup(obj, off)
126 	struct uvm_object *obj;
127 	voff_t off;
128 {
129 	struct vm_page *pg;
130 	struct pglist *buck;
131 	int s;
132 
133 	buck = &uvm.page_hash[uvm_pagehash(obj,off)];
134 
135 	s = splvm();
136 	simple_lock(&uvm.hashlock);
137 	TAILQ_FOREACH(pg, buck, hashq) {
138 		if (pg->uobject == obj && pg->offset == off) {
139 			break;
140 		}
141 	}
142 	simple_unlock(&uvm.hashlock);
143 	splx(s);
144 	return(pg);
145 }
146 
147 /*
148  * uvm_pagewire: wire the page, thus removing it from the daemon's grasp
149  *
150  * => caller must lock page queues
151  */
152 
153 PAGE_INLINE void
uvm_pagewire(pg)154 uvm_pagewire(pg)
155 	struct vm_page *pg;
156 {
157 	if (pg->wire_count == 0) {
158 		if (pg->pqflags & PQ_ACTIVE) {
159 			TAILQ_REMOVE(&uvm.page_active, pg, pageq);
160 			pg->pqflags &= ~PQ_ACTIVE;
161 			uvmexp.active--;
162 		}
163 		if (pg->pqflags & PQ_INACTIVE) {
164 			if (pg->pqflags & PQ_SWAPBACKED)
165 				TAILQ_REMOVE(&uvm.page_inactive_swp, pg, pageq);
166 			else
167 				TAILQ_REMOVE(&uvm.page_inactive_obj, pg, pageq);
168 			pg->pqflags &= ~PQ_INACTIVE;
169 			uvmexp.inactive--;
170 		}
171 		uvmexp.wired++;
172 	}
173 	pg->wire_count++;
174 }
175 
176 /*
177  * uvm_pageunwire: unwire the page.
178  *
179  * => activate if wire count goes to zero.
180  * => caller must lock page queues
181  */
182 
183 PAGE_INLINE void
uvm_pageunwire(pg)184 uvm_pageunwire(pg)
185 	struct vm_page *pg;
186 {
187 	pg->wire_count--;
188 	if (pg->wire_count == 0) {
189 		TAILQ_INSERT_TAIL(&uvm.page_active, pg, pageq);
190 		uvmexp.active++;
191 		pg->pqflags |= PQ_ACTIVE;
192 		uvmexp.wired--;
193 	}
194 }
195 
196 /*
197  * uvm_pagedeactivate: deactivate page -- no pmaps have access to page
198  *
199  * => caller must lock page queues
200  * => caller must check to make sure page is not wired
201  * => object that page belongs to must be locked (so we can adjust pg->flags)
202  */
203 
204 PAGE_INLINE void
uvm_pagedeactivate(pg)205 uvm_pagedeactivate(pg)
206 	struct vm_page *pg;
207 {
208 	if (pg->pqflags & PQ_ACTIVE) {
209 		TAILQ_REMOVE(&uvm.page_active, pg, pageq);
210 		pg->pqflags &= ~PQ_ACTIVE;
211 		uvmexp.active--;
212 	}
213 	if ((pg->pqflags & PQ_INACTIVE) == 0) {
214 		KASSERT(pg->wire_count == 0);
215 		if (pg->pqflags & PQ_SWAPBACKED)
216 			TAILQ_INSERT_TAIL(&uvm.page_inactive_swp, pg, pageq);
217 		else
218 			TAILQ_INSERT_TAIL(&uvm.page_inactive_obj, pg, pageq);
219 		pg->pqflags |= PQ_INACTIVE;
220 		uvmexp.inactive++;
221 #ifndef UBC
222 		pmap_clear_reference(pg);
223 #endif
224 		/*
225 		 * update the "clean" bit.  this isn't 100%
226 		 * accurate, and doesn't have to be.  we'll
227 		 * re-sync it after we zap all mappings when
228 		 * scanning the inactive list.
229 		 */
230 		if ((pg->flags & PG_CLEAN) != 0 &&
231 		    pmap_is_modified(pg))
232 			pg->flags &= ~PG_CLEAN;
233 	}
234 }
235 
236 /*
237  * uvm_pageactivate: activate page
238  *
239  * => caller must lock page queues
240  */
241 
242 PAGE_INLINE void
uvm_pageactivate(pg)243 uvm_pageactivate(pg)
244 	struct vm_page *pg;
245 {
246 	if (pg->pqflags & PQ_INACTIVE) {
247 		if (pg->pqflags & PQ_SWAPBACKED)
248 			TAILQ_REMOVE(&uvm.page_inactive_swp, pg, pageq);
249 		else
250 			TAILQ_REMOVE(&uvm.page_inactive_obj, pg, pageq);
251 		pg->pqflags &= ~PQ_INACTIVE;
252 		uvmexp.inactive--;
253 	}
254 	if (pg->wire_count == 0) {
255 
256 		/*
257 		 * if page is already active, remove it from list so we
258 		 * can put it at tail.  if it wasn't active, then mark
259 		 * it active and bump active count
260 		 */
261 		if (pg->pqflags & PQ_ACTIVE)
262 			TAILQ_REMOVE(&uvm.page_active, pg, pageq);
263 		else {
264 			pg->pqflags |= PQ_ACTIVE;
265 			uvmexp.active++;
266 		}
267 
268 		TAILQ_INSERT_TAIL(&uvm.page_active, pg, pageq);
269 	}
270 }
271 
272 /*
273  * uvm_pagezero: zero fill a page
274  *
275  * => if page is part of an object then the object should be locked
276  *	to protect pg->flags.
277  */
278 
279 PAGE_INLINE void
uvm_pagezero(pg)280 uvm_pagezero(pg)
281 	struct vm_page *pg;
282 {
283 
284 	pg->flags &= ~PG_CLEAN;
285 	pmap_zero_page(pg);
286 }
287 
288 /*
289  * uvm_pagecopy: copy a page
290  *
291  * => if page is part of an object then the object should be locked
292  *	to protect pg->flags.
293  */
294 
295 PAGE_INLINE void
uvm_pagecopy(src,dst)296 uvm_pagecopy(src, dst)
297 	struct vm_page *src, *dst;
298 {
299 
300 	dst->flags &= ~PG_CLEAN;
301 	pmap_copy_page(src, dst);
302 }
303 
304 /*
305  * uvm_page_lookup_freelist: look up the free list for the specified page
306  */
307 
308 PAGE_INLINE int
uvm_page_lookup_freelist(pg)309 uvm_page_lookup_freelist(pg)
310 	struct vm_page *pg;
311 {
312 	int lcv;
313 
314 	lcv = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
315 	KASSERT(lcv != -1);
316 	return (vm_physmem[lcv].free_list);
317 }
318 
319 #endif /* defined(UVM_PAGE_INLINE) || defined(UVM_PAGE) */
320 
321 #endif /* _UVM_UVM_PAGE_I_H_ */
322