1/* $OpenBSD: uvm_page.h,v 1.73 2025/03/10 18:54:38 mpi Exp $ */
2/* $NetBSD: uvm_page.h,v 1.19 2000/12/28 08:24:55 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. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)vm_page.h 7.3 (Berkeley) 4/21/91
38 * from: Id: uvm_page.h,v 1.1.2.6 1998/02/04 02:31:42 chuck Exp
39 *
40 *
41 * Copyright (c) 1987, 1990 Carnegie-Mellon University.
42 * All rights reserved.
43 *
44 * Permission to use, copy, modify and distribute this software and
45 * its documentation is hereby granted, provided that both the copyright
46 * notice and this permission notice appear in all copies of the
47 * software, derivative works or modified versions, and any portions
48 * thereof, and that both notices appear in supporting documentation.
49 *
50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53 *
54 * Carnegie Mellon requests users of this software to return to
55 *
56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
57 * School of Computer Science
58 * Carnegie Mellon University
59 * Pittsburgh PA 15213-3890
60 *
61 * any improvements or extensions that they make and grant Carnegie the
62 * rights to redistribute these changes.
63 */
64
65#ifndef _UVM_UVM_PAGE_H_
66#define _UVM_UVM_PAGE_H_
67
68/*
69 * uvm_page.h
70 */
71
72/*
73 * Resident memory system definitions.
74 */
75
76/*
77 * Management of resident (logical) pages.
78 *
79 * A small structure is kept for each resident
80 * page, indexed by page number. Each structure
81 * contains a list used for manipulating pages, and
82 * a tree structure for in object/offset lookups
83 *
84 * In addition, the structure contains the object
85 * and offset to which this page belongs (for pageout),
86 * and sundry status bits.
87 *
88 * Locks used to protect struct members in this file:
89 * I immutable after creation
90 * a atomic operations
91 * Q uvm.pageqlock
92 * F uvm.fpageqlock
93 * o owner lock (uobject->vmobjlock or uanon->an_lock)
94 */
95
96TAILQ_HEAD(pglist, vm_page);
97
98struct vm_page {
99 TAILQ_ENTRY(vm_page) pageq; /* [Q] LRU or free page queue */
100 RBT_ENTRY(vm_page) objt; /* [o] object tree */
101
102 struct vm_anon *uanon; /* [o] anon */
103 struct uvm_object *uobject; /* [o] object */
104 voff_t offset; /* [o] offset into object */
105
106 uint32_t pg_flags; /* [a] object flags */
107
108 uint32_t pg_version; /* version count */
109 uint32_t wire_count; /* [o] wired down map refs */
110
111 paddr_t phys_addr; /* [I] physical address */
112 psize_t fpgsz; /* [F] free page range size */
113
114 struct vm_page_md mdpage; /* pmap-specific data */
115
116#if defined(UVM_PAGE_TRKOWN)
117 /* debugging fields to track page ownership */
118 pid_t owner; /* thread that set PG_BUSY */
119 char *owner_tag; /* why it was set busy */
120#endif
121};
122
123/*
124 * These are the flags defined for vm_page.
125 *
126 * Note: PG_FILLED and PG_DIRTY are added for the filesystems.
127 */
128
129/*
130 * locking rules:
131 * PQ_ ==> lock by page queue lock
132 * PQ_FREE is locked by free queue lock and is mutex with all other PQs
133 * pg_flags may only be changed using the atomic operations.
134 *
135 * PG_ZERO is used to indicate that a page has been pre-zero'd. This flag
136 * is only set when the page is on no queues, and is cleared when the page
137 * is placed on the free list.
138 */
139
140#define PG_BUSY 0x00000001 /* page is locked */
141#define PG_WANTED 0x00000002 /* someone is waiting for page */
142#define PG_TABLED 0x00000004 /* page is in VP table */
143#define PG_CLEAN 0x00000008 /* page has not been modified */
144#define PG_CLEANCHK 0x00000010 /* clean bit has been checked */
145#define PG_RELEASED 0x00000020 /* page released while paging */
146#define PG_FAKE 0x00000040 /* page is not yet initialized */
147#define PG_RDONLY 0x00000080 /* page must be mapped read-only */
148#define PG_ZERO 0x00000100 /* page is pre-zero'd */
149#define PG_DEV 0x00000200 /* page is in device space, lay off */
150#define PG_MASK 0x0000ffff
151
152#define PQ_FREE 0x00010000 /* page is on free list */
153#define PQ_INACTIVE 0x00020000 /* page is in inactive list */
154#define PQ_ACTIVE 0x00040000 /* page is in active list */
155#define PQ_ITER 0x00080000 /* page is an iterator marker */
156#define PQ_ANON 0x00100000 /* page is part of an anon, rather
157 than an uvm_object */
158#define PQ_AOBJ 0x00200000 /* page is part of an anonymous
159 uvm_object */
160#define PQ_SWAPBACKED (PQ_ANON|PQ_AOBJ)
161#define PQ_ENCRYPT 0x00400000 /* page needs {en,de}cryption */
162#define PQ_MASK 0x00ff0000
163
164#define PG_PMAP0 0x01000000 /* Used by some pmaps. */
165#define PG_PMAP1 0x02000000 /* Used by some pmaps. */
166#define PG_PMAP2 0x04000000 /* Used by some pmaps. */
167#define PG_PMAP3 0x08000000 /* Used by some pmaps. */
168#define PG_PMAP4 0x10000000 /* Used by some pmaps. */
169#define PG_PMAP5 0x20000000 /* Used by some pmaps. */
170#define PG_PMAPMASK 0x3f000000
171
172/*
173 * physical memory layout structure
174 *
175 * MD vmparam.h must #define:
176 * VM_PHYSSEG_MAX = max number of physical memory segments we support
177 * (if this is "1" then we revert to a "contig" case)
178 * VM_PHYSSEG_STRAT: memory sort/search options (for VM_PHYSSEG_MAX > 1)
179 * - VM_PSTRAT_RANDOM: linear search (random order)
180 * - VM_PSTRAT_BSEARCH: binary search (sorted by address)
181 * - VM_PSTRAT_BIGFIRST: linear search (sorted by largest segment first)
182 * - others?
183 * XXXCDC: eventually we should purge all left-over global variables...
184 */
185#define VM_PSTRAT_RANDOM 1
186#define VM_PSTRAT_BSEARCH 2
187#define VM_PSTRAT_BIGFIRST 3
188
189/*
190 * vm_physmemseg: describes one segment of physical memory
191 */
192struct vm_physseg {
193 paddr_t start; /* PF# of first page in segment */
194 paddr_t end; /* (PF# of last page in segment) + 1 */
195 paddr_t avail_start; /* PF# of first free page in segment */
196 paddr_t avail_end; /* (PF# of last free page in segment) +1 */
197 struct vm_page *pgs; /* vm_page structures (from start) */
198 struct vm_page *lastpg; /* vm_page structure for end */
199};
200
201#ifdef _KERNEL
202
203/*
204 * physical memory config is stored in vm_physmem.
205 */
206
207extern struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];
208extern int vm_nphysseg;
209
210/*
211 * prototypes: the following prototypes define the interface to pages
212 */
213
214void uvm_page_init(vaddr_t *, vaddr_t *);
215#if defined(UVM_PAGE_TRKOWN)
216void uvm_page_own(struct vm_page *, char *);
217#endif
218#if !defined(PMAP_STEAL_MEMORY)
219boolean_t uvm_page_physget(paddr_t *);
220#endif
221
222void uvm_pageactivate(struct vm_page *);
223void uvm_pagedequeue(struct vm_page *);
224vaddr_t uvm_pageboot_alloc(vsize_t);
225void uvm_pagecopy(struct vm_page *, struct vm_page *);
226void uvm_pagedeactivate(struct vm_page *);
227void uvm_pageclean(struct vm_page *);
228void uvm_pagefree(struct vm_page *);
229void uvm_page_unbusy(struct vm_page **, int);
230struct vm_page *uvm_pagelookup(struct uvm_object *, voff_t);
231void uvm_pageunwire(struct vm_page *);
232void uvm_pagewait(struct vm_page *, struct rwlock *, const char *);
233void uvm_pagewire(struct vm_page *);
234void uvm_pagezero(struct vm_page *);
235void uvm_pagealloc_pg(struct vm_page *, struct uvm_object *,
236 voff_t, struct vm_anon *);
237
238struct uvm_constraint_range; /* XXX move to uvm_extern.h? */
239psize_t uvm_pagecount(struct uvm_constraint_range*);
240
241#if VM_PHYSSEG_MAX == 1
242/*
243 * Inline functions for archs where function calls are expensive.
244 */
245/*
246 * vm_physseg_find: find vm_physseg structure that belongs to a PA
247 */
248static inline int
249vm_physseg_find(paddr_t pframe, int *offp)
250{
251 /* 'contig' case */
252 if (pframe >= vm_physmem[0].start && pframe < vm_physmem[0].end) {
253 if (offp)
254 *offp = pframe - vm_physmem[0].start;
255 return 0;
256 }
257 return -1;
258}
259
260/*
261 * PHYS_TO_VM_PAGE: find vm_page for a PA. used by MI code to get vm_pages
262 * back from an I/O mapping (ugh!). used in some MD code as well.
263 */
264static inline struct vm_page *
265PHYS_TO_VM_PAGE(paddr_t pa)
266{
267 paddr_t pf = atop(pa);
268 int off;
269 int psi;
270
271 psi = vm_physseg_find(pf, &off);
272
273 return ((psi == -1) ? NULL : &vm_physmem[psi].pgs[off]);
274}
275#else
276/* if VM_PHYSSEG_MAX > 1 they're not inline, they're in uvm_page.c. */
277struct vm_page *PHYS_TO_VM_PAGE(paddr_t);
278int vm_physseg_find(paddr_t, int *);
279#endif
280
281/*
282 * macros
283 */
284
285#define uvm_lock_pageq() mtx_enter(&uvm.pageqlock)
286#define uvm_unlock_pageq() mtx_leave(&uvm.pageqlock)
287#define uvm_lock_fpageq() mtx_enter(&uvm.fpageqlock)
288#define uvm_unlock_fpageq() mtx_leave(&uvm.fpageqlock)
289
290#define UVM_PAGEZERO_TARGET (uvmexp.free / 8)
291
292#define VM_PAGE_TO_PHYS(pg) ((pg)->phys_addr)
293
294#define VM_PAGE_IS_FREE(pg) ((pg)->pg_flags & PQ_FREE)
295
296#define PADDR_IS_DMA_REACHABLE(paddr) \
297 (dma_constraint.ucr_low <= paddr && dma_constraint.ucr_high > paddr)
298
299#endif /* _KERNEL */
300
301#endif /* _UVM_UVM_PAGE_H_ */