| 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 | |
| 96 | TAILQ_HEAD(pglist, vm_page); |
| 97 | |
| 98 | struct 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 | */ |
| 192 | struct 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 | |
| 207 | extern struct vm_physseg vm_physmem[VM_PHYSSEG_MAX]; |
| 208 | extern int vm_nphysseg; |
| 209 | |
| 210 | /* |
| 211 | * prototypes: the following prototypes define the interface to pages |
| 212 | */ |
| 213 | |
| 214 | void		uvm_page_init(vaddr_t *, vaddr_t *); |
| 215 | #if defined(UVM_PAGE_TRKOWN) |
| 216 | void		uvm_page_own(struct vm_page *, char *); |
| 217 | #endif |
| 218 | #if !defined(PMAP_STEAL_MEMORY) |
| 219 | boolean_t	uvm_page_physget(paddr_t *); |
| 220 | #endif |
| 221 | |
| 222 | void		uvm_pageactivate(struct vm_page *); |
| 223 | void		uvm_pagedequeue(struct vm_page *); |
| 224 | vaddr_t		uvm_pageboot_alloc(vsize_t); |
| 225 | void		uvm_pagecopy(struct vm_page *, struct vm_page *); |
| 226 | void		uvm_pagedeactivate(struct vm_page *); |
| 227 | void		uvm_pageclean(struct vm_page *); |
| 228 | void		uvm_pagefree(struct vm_page *); |
| 229 | void		uvm_page_unbusy(struct vm_page **, int); |
| 230 | struct vm_page	*uvm_pagelookup(struct uvm_object *, voff_t); |
| 231 | void		uvm_pageunwire(struct vm_page *); |
| 232 | void		uvm_pagewait(struct vm_page *, struct rwlock *, const char *); |
| 233 | void		uvm_pagewire(struct vm_page *); |
| 234 | void		uvm_pagezero(struct vm_page *); |
| 235 | void		uvm_pagealloc_pg(struct vm_page *, struct uvm_object *, |
| 236 | 		 voff_t, struct vm_anon *); |
| 237 | |
| 238 | struct uvm_constraint_range; /* XXX move to uvm_extern.h? */ |
| 239 | psize_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 | */ |
| 248 | static inline int |
| 249 | vm_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 | */ |
| 264 | static inline struct vm_page * |
| 265 | PHYS_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. */ |
| 277 | struct vm_page	*PHYS_TO_VM_PAGE(paddr_t); |
| 278 | int		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_ */ |