Bug Summary

File:uvm/uvm_page.c
Warning:line 157, column 2
Access to field 'pgops' results in a dereference of a null pointer (loaded from field 'uobject')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name uvm_page.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/uvm/uvm_page.c

/usr/src/sys/uvm/uvm_page.c

1/* $OpenBSD: uvm_page.c,v 1.173 2023/08/12 07:22:56 mpi Exp $ */
2/* $NetBSD: uvm_page.c,v 1.44 2000/11/27 08:40:04 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.c 8.3 (Berkeley) 3/21/94
38 * from: Id: uvm_page.c,v 1.1.2.18 1998/02/06 05:24:42 chs 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/*
66 * uvm_page.c: page ops.
67 */
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/sched.h>
72#include <sys/vnode.h>
73#include <sys/mount.h>
74#include <sys/proc.h>
75#include <sys/smr.h>
76
77#include <uvm/uvm.h>
78
79/*
80 * for object trees
81 */
82RBT_GENERATE(uvm_objtree, vm_page, objt, uvm_pagecmp)static int uvm_objtree_RBT_COMPARE(const void *lptr, const void
*rptr) { const struct vm_page *l = lptr, *r = rptr; return uvm_pagecmp
(l, r); } static const struct rb_type uvm_objtree_RBT_INFO = {
uvm_objtree_RBT_COMPARE, ((void *)0), __builtin_offsetof(struct
vm_page, objt), }; const struct rb_type *const uvm_objtree_RBT_TYPE
= &uvm_objtree_RBT_INFO
;
83
84int
85uvm_pagecmp(const struct vm_page *a, const struct vm_page *b)
86{
87 return a->offset < b->offset ? -1 : a->offset > b->offset;
88}
89
90/*
91 * global vars... XXXCDC: move to uvm. structure.
92 */
93/*
94 * physical memory config is stored in vm_physmem.
95 */
96struct vm_physseg vm_physmem[VM_PHYSSEG_MAX16]; /* XXXCDC: uvm.physmem */
97int vm_nphysseg = 0; /* XXXCDC: uvm.nphysseg */
98
99/*
100 * Some supported CPUs in a given architecture don't support all
101 * of the things necessary to do idle page zero'ing efficiently.
102 * We therefore provide a way to disable it from machdep code here.
103 */
104
105/*
106 * local variables
107 */
108/*
109 * these variables record the values returned by vm_page_bootstrap,
110 * for debugging purposes. The implementation of uvm_pageboot_alloc
111 * and pmap_startup here also uses them internally.
112 */
113static vaddr_t virtual_space_start;
114static vaddr_t virtual_space_end;
115
116/*
117 * local prototypes
118 */
119static void uvm_pageinsert(struct vm_page *);
120static void uvm_pageremove(struct vm_page *);
121int uvm_page_owner_locked_p(struct vm_page *);
122
123/*
124 * inline functions
125 */
126/*
127 * uvm_pageinsert: insert a page in the object
128 *
129 * => caller must lock object
130 * => call should have already set pg's object and offset pointers
131 * and bumped the version counter
132 */
133static inline void
134uvm_pageinsert(struct vm_page *pg)
135{
136 struct vm_page *dupe;
137
138 KASSERT(UVM_OBJ_IS_DUMMY(pg->uobject) ||(((((pg->uobject)->pgops == &pmap_pager) || ((pg->
uobject)->pgops == &bufcache_pager)) || rw_write_held(
pg->uobject->vmobjlock)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 139, "UVM_OBJ_IS_DUMMY(pg->uobject) || rw_write_held(pg->uobject->vmobjlock)"
))
139 rw_write_held(pg->uobject->vmobjlock))(((((pg->uobject)->pgops == &pmap_pager) || ((pg->
uobject)->pgops == &bufcache_pager)) || rw_write_held(
pg->uobject->vmobjlock)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 139, "UVM_OBJ_IS_DUMMY(pg->uobject) || rw_write_held(pg->uobject->vmobjlock)"
))
;
140 KASSERT((pg->pg_flags & PG_TABLED) == 0)(((pg->pg_flags & 0x00000004) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 140, "(pg->pg_flags & PG_TABLED) == 0"
))
;
141
142 dupe = RBT_INSERT(uvm_objtree, &pg->uobject->memt, pg)uvm_objtree_RBT_INSERT(&pg->uobject->memt, pg);
143 /* not allowed to insert over another page */
144 KASSERT(dupe == NULL)((dupe == ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 144, "dupe == NULL"))
;
145 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PG_TABLED0x00000004);
146 pg->uobject->uo_npages++;
147}
148
149/*
150 * uvm_page_remove: remove page from object
151 *
152 * => caller must lock object
153 */
154static inline void
155uvm_pageremove(struct vm_page *pg)
156{
157 KASSERT(UVM_OBJ_IS_DUMMY(pg->uobject) ||(((((pg->uobject)->pgops == &pmap_pager) || ((pg->
uobject)->pgops == &bufcache_pager)) || rw_write_held(
pg->uobject->vmobjlock)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 158, "UVM_OBJ_IS_DUMMY(pg->uobject) || rw_write_held(pg->uobject->vmobjlock)"
))
32
Access to field 'pgops' results in a dereference of a null pointer (loaded from field 'uobject')
158 rw_write_held(pg->uobject->vmobjlock))(((((pg->uobject)->pgops == &pmap_pager) || ((pg->
uobject)->pgops == &bufcache_pager)) || rw_write_held(
pg->uobject->vmobjlock)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 158, "UVM_OBJ_IS_DUMMY(pg->uobject) || rw_write_held(pg->uobject->vmobjlock)"
))
;
159 KASSERT(pg->pg_flags & PG_TABLED)((pg->pg_flags & 0x00000004) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 159, "pg->pg_flags & PG_TABLED"
))
;
160
161 RBT_REMOVE(uvm_objtree, &pg->uobject->memt, pg)uvm_objtree_RBT_REMOVE(&pg->uobject->memt, pg);
162
163 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PG_TABLED0x00000004);
164 pg->uobject->uo_npages--;
165 pg->uobject = NULL((void *)0);
166 pg->pg_version++;
167}
168
169/*
170 * uvm_page_init: init the page system. called from uvm_init().
171 *
172 * => we return the range of kernel virtual memory in kvm_startp/kvm_endp
173 */
174void
175uvm_page_init(vaddr_t *kvm_startp, vaddr_t *kvm_endp)
176{
177 vsize_t freepages, pagecount, n;
178 vm_page_t pagearray, curpg;
179 int lcv, i;
180 paddr_t paddr, pgno;
181 struct vm_physseg *seg;
182
183 /*
184 * init the page queues and page queue locks
185 */
186
187 TAILQ_INIT(&uvm.page_active)do { (&uvm.page_active)->tqh_first = ((void *)0); (&
uvm.page_active)->tqh_last = &(&uvm.page_active)->
tqh_first; } while (0)
;
188 TAILQ_INIT(&uvm.page_inactive)do { (&uvm.page_inactive)->tqh_first = ((void *)0); (&
uvm.page_inactive)->tqh_last = &(&uvm.page_inactive
)->tqh_first; } while (0)
;
189 mtx_init(&uvm.pageqlock, IPL_VM)do { (void)(((void *)0)); (void)(0); __mtx_init((&uvm.pageqlock
), ((((0xa)) > 0x0 && ((0xa)) < 0x9) ? 0x9 : ((
0xa)))); } while (0)
;
190 mtx_init(&uvm.fpageqlock, IPL_VM)do { (void)(((void *)0)); (void)(0); __mtx_init((&uvm.fpageqlock
), ((((0xa)) > 0x0 && ((0xa)) < 0x9) ? 0x9 : ((
0xa)))); } while (0)
;
191 uvm_pmr_init();
192
193 /*
194 * allocate vm_page structures.
195 */
196
197 /*
198 * sanity check:
199 * before calling this function the MD code is expected to register
200 * some free RAM with the uvm_page_physload() function. our job
201 * now is to allocate vm_page structures for this memory.
202 */
203
204 if (vm_nphysseg == 0)
205 panic("uvm_page_bootstrap: no memory pre-allocated");
206
207 /*
208 * first calculate the number of free pages...
209 *
210 * note that we use start/end rather than avail_start/avail_end.
211 * this allows us to allocate extra vm_page structures in case we
212 * want to return some memory to the pool after booting.
213 */
214
215 freepages = 0;
216 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg ; lcv++, seg++)
217 freepages += (seg->end - seg->start);
218
219 /*
220 * we now know we have (PAGE_SIZE * freepages) bytes of memory we can
221 * use. for each page of memory we use we need a vm_page structure.
222 * thus, the total number of pages we can use is the total size of
223 * the memory divided by the PAGE_SIZE plus the size of the vm_page
224 * structure. we add one to freepages as a fudge factor to avoid
225 * truncation errors (since we can only allocate in terms of whole
226 * pages).
227 */
228
229 pagecount = (((paddr_t)freepages + 1) << PAGE_SHIFT12) /
230 (PAGE_SIZE(1 << 12) + sizeof(struct vm_page));
231 pagearray = (vm_page_t)uvm_pageboot_alloc(pagecount *
232 sizeof(struct vm_page));
233 memset(pagearray, 0, pagecount * sizeof(struct vm_page))__builtin_memset((pagearray), (0), (pagecount * sizeof(struct
vm_page)))
;
234
235 /* init the vm_page structures and put them in the correct place. */
236 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg ; lcv++, seg++) {
237 n = seg->end - seg->start;
238 if (n > pagecount) {
239 panic("uvm_page_init: lost %ld page(s) in init",
240 (long)(n - pagecount));
241 /* XXXCDC: shouldn't happen? */
242 /* n = pagecount; */
243 }
244
245 /* set up page array pointers */
246 seg->pgs = pagearray;
247 pagearray += n;
248 pagecount -= n;
249 seg->lastpg = seg->pgs + (n - 1);
250
251 /* init and free vm_pages (we've already zeroed them) */
252 pgno = seg->start;
253 paddr = ptoa(pgno)((paddr_t)(pgno) << 12);
254 for (i = 0, curpg = seg->pgs; i < n;
255 i++, curpg++, pgno++, paddr += PAGE_SIZE(1 << 12)) {
256 curpg->phys_addr = paddr;
257 VM_MDPAGE_INIT(curpg)do { do { (void)(((void *)0)); (void)(0); __mtx_init((&(curpg
)->mdpage.pv_mtx), ((((0xa)) > 0x0 && ((0xa)) <
0x9) ? 0x9 : ((0xa)))); } while (0); (curpg)->mdpage.pv_list
= ((void *)0); } while (0)
;
258 if (pgno >= seg->avail_start &&
259 pgno < seg->avail_end) {
260 uvmexp.npages++;
261 }
262 }
263
264 /* Add pages to free pool. */
265 uvm_pmr_freepages(&seg->pgs[seg->avail_start - seg->start],
266 seg->avail_end - seg->avail_start);
267 }
268
269 /*
270 * pass up the values of virtual_space_start and
271 * virtual_space_end (obtained by uvm_pageboot_alloc) to the upper
272 * layers of the VM.
273 */
274
275 *kvm_startp = round_page(virtual_space_start)(((virtual_space_start) + ((1 << 12) - 1)) & ~((1 <<
12) - 1))
;
276 *kvm_endp = trunc_page(virtual_space_end)((virtual_space_end) & ~((1 << 12) - 1));
277
278 /* init locks for kernel threads */
279 mtx_init(&uvm.aiodoned_lock, IPL_BIO)do { (void)(((void *)0)); (void)(0); __mtx_init((&uvm.aiodoned_lock
), ((((0x3)) > 0x0 && ((0x3)) < 0x9) ? 0x9 : ((
0x3)))); } while (0)
;
280
281 /*
282 * init reserve thresholds
283 * XXXCDC - values may need adjusting
284 */
285 uvmexp.reserve_pagedaemon = 4;
286 uvmexp.reserve_kernel = 8;
287 uvmexp.anonminpct = 10;
288 uvmexp.vnodeminpct = 10;
289 uvmexp.vtextminpct = 5;
290 uvmexp.anonmin = uvmexp.anonminpct * 256 / 100;
291 uvmexp.vnodemin = uvmexp.vnodeminpct * 256 / 100;
292 uvmexp.vtextmin = uvmexp.vtextminpct * 256 / 100;
293
294 uvm.page_init_done = TRUE1;
295}
296
297/*
298 * uvm_setpagesize: set the page size
299 *
300 * => sets page_shift and page_mask from uvmexp.pagesize.
301 */
302void
303uvm_setpagesize(void)
304{
305 if (uvmexp.pagesize == 0)
306 uvmexp.pagesize = DEFAULT_PAGE_SIZE4096;
307 uvmexp.pagemask = uvmexp.pagesize - 1;
308 if ((uvmexp.pagemask & uvmexp.pagesize) != 0)
309 panic("uvm_setpagesize: page size not a power of two");
310 for (uvmexp.pageshift = 0; ; uvmexp.pageshift++)
311 if ((1 << uvmexp.pageshift) == uvmexp.pagesize)
312 break;
313}
314
315/*
316 * uvm_pageboot_alloc: steal memory from physmem for bootstrapping
317 */
318vaddr_t
319uvm_pageboot_alloc(vsize_t size)
320{
321#if defined(PMAP_STEAL_MEMORY)
322 vaddr_t addr;
323
324 /*
325 * defer bootstrap allocation to MD code (it may want to allocate
326 * from a direct-mapped segment). pmap_steal_memory should round
327 * off virtual_space_start/virtual_space_end.
328 */
329
330 addr = pmap_steal_memory(size, &virtual_space_start,
331 &virtual_space_end);
332
333 return addr;
334
335#else /* !PMAP_STEAL_MEMORY */
336
337 static boolean_t initialized = FALSE0;
338 vaddr_t addr, vaddr;
339 paddr_t paddr;
340
341 /* round to page size */
342 size = round_page(size)(((size) + ((1 << 12) - 1)) & ~((1 << 12) - 1
))
;
343
344 /* on first call to this function, initialize ourselves. */
345 if (initialized == FALSE0) {
346 pmap_virtual_space(&virtual_space_start, &virtual_space_end);
347
348 /* round it the way we like it */
349 virtual_space_start = round_page(virtual_space_start)(((virtual_space_start) + ((1 << 12) - 1)) & ~((1 <<
12) - 1))
;
350 virtual_space_end = trunc_page(virtual_space_end)((virtual_space_end) & ~((1 << 12) - 1));
351
352 initialized = TRUE1;
353 }
354
355 /* allocate virtual memory for this request */
356 if (virtual_space_start == virtual_space_end ||
357 (virtual_space_end - virtual_space_start) < size)
358 panic("uvm_pageboot_alloc: out of virtual space");
359
360 addr = virtual_space_start;
361
362#ifdef PMAP_GROWKERNEL
363 /*
364 * If the kernel pmap can't map the requested space,
365 * then allocate more resources for it.
366 */
367 if (uvm_maxkaddr < (addr + size)) {
368 uvm_maxkaddr = pmap_growkernel(addr + size);
369 if (uvm_maxkaddr < (addr + size))
370 panic("uvm_pageboot_alloc: pmap_growkernel() failed");
371 }
372#endif
373
374 virtual_space_start += size;
375
376 /* allocate and mapin physical pages to back new virtual pages */
377 for (vaddr = round_page(addr)(((addr) + ((1 << 12) - 1)) & ~((1 << 12) - 1
))
; vaddr < addr + size ;
378 vaddr += PAGE_SIZE(1 << 12)) {
379 if (!uvm_page_physget(&paddr))
380 panic("uvm_pageboot_alloc: out of memory");
381
382 /*
383 * Note this memory is no longer managed, so using
384 * pmap_kenter is safe.
385 */
386 pmap_kenter_pa(vaddr, paddr, PROT_READ0x01 | PROT_WRITE0x02);
387 }
388 pmap_update(pmap_kernel());
389 return addr;
390#endif /* PMAP_STEAL_MEMORY */
391}
392
393#if !defined(PMAP_STEAL_MEMORY)
394/*
395 * uvm_page_physget: "steal" one page from the vm_physmem structure.
396 *
397 * => attempt to allocate it off the end of a segment in which the "avail"
398 * values match the start/end values. if we can't do that, then we
399 * will advance both values (making them equal, and removing some
400 * vm_page structures from the non-avail area).
401 * => return false if out of memory.
402 */
403
404boolean_t
405uvm_page_physget(paddr_t *paddrp)
406{
407 int lcv;
408 struct vm_physseg *seg;
409
410 /* pass 1: try allocating from a matching end */
411#if (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BIGFIRST3) || \
412 (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BSEARCH2)
413 for (lcv = vm_nphysseg - 1, seg = vm_physmem + lcv; lcv >= 0;
414 lcv--, seg--)
415#else
416 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg ; lcv++, seg++)
417#endif
418 {
419 if (uvm.page_init_done == TRUE1)
420 panic("uvm_page_physget: called _after_ bootstrap");
421
422 /* try from front */
423 if (seg->avail_start == seg->start &&
424 seg->avail_start < seg->avail_end) {
425 *paddrp = ptoa(seg->avail_start)((paddr_t)(seg->avail_start) << 12);
426 seg->avail_start++;
427 seg->start++;
428 /* nothing left? nuke it */
429 if (seg->avail_start == seg->end) {
430 if (vm_nphysseg == 1)
431 panic("uvm_page_physget: out of memory!");
432 vm_nphysseg--;
433 for (; lcv < vm_nphysseg; lcv++, seg++)
434 /* structure copy */
435 seg[0] = seg[1];
436 }
437 return TRUE1;
438 }
439
440 /* try from rear */
441 if (seg->avail_end == seg->end &&
442 seg->avail_start < seg->avail_end) {
443 *paddrp = ptoa(seg->avail_end - 1)((paddr_t)(seg->avail_end - 1) << 12);
444 seg->avail_end--;
445 seg->end--;
446 /* nothing left? nuke it */
447 if (seg->avail_end == seg->start) {
448 if (vm_nphysseg == 1)
449 panic("uvm_page_physget: out of memory!");
450 vm_nphysseg--;
451 for (; lcv < vm_nphysseg ; lcv++, seg++)
452 /* structure copy */
453 seg[0] = seg[1];
454 }
455 return TRUE1;
456 }
457 }
458
459 /* pass2: forget about matching ends, just allocate something */
460#if (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BIGFIRST3) || \
461 (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BSEARCH2)
462 for (lcv = vm_nphysseg - 1, seg = vm_physmem + lcv; lcv >= 0;
463 lcv--, seg--)
464#else
465 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg ; lcv++, seg++)
466#endif
467 {
468
469 /* any room in this bank? */
470 if (seg->avail_start >= seg->avail_end)
471 continue; /* nope */
472
473 *paddrp = ptoa(seg->avail_start)((paddr_t)(seg->avail_start) << 12);
474 seg->avail_start++;
475 /* truncate! */
476 seg->start = seg->avail_start;
477
478 /* nothing left? nuke it */
479 if (seg->avail_start == seg->end) {
480 if (vm_nphysseg == 1)
481 panic("uvm_page_physget: out of memory!");
482 vm_nphysseg--;
483 for (; lcv < vm_nphysseg ; lcv++, seg++)
484 /* structure copy */
485 seg[0] = seg[1];
486 }
487 return TRUE1;
488 }
489
490 return FALSE0; /* whoops! */
491}
492
493#endif /* PMAP_STEAL_MEMORY */
494
495/*
496 * uvm_page_physload: load physical memory into VM system
497 *
498 * => all args are PFs
499 * => all pages in start/end get vm_page structures
500 * => areas marked by avail_start/avail_end get added to the free page pool
501 * => we are limited to VM_PHYSSEG_MAX physical memory segments
502 */
503
504void
505uvm_page_physload(paddr_t start, paddr_t end, paddr_t avail_start,
506 paddr_t avail_end, int flags)
507{
508 int preload, lcv;
509 psize_t npages;
510 struct vm_page *pgs;
511 struct vm_physseg *ps, *seg;
512
513#ifdef DIAGNOSTIC1
514 if (uvmexp.pagesize == 0)
515 panic("uvm_page_physload: page size not set!");
516
517 if (start >= end)
518 panic("uvm_page_physload: start >= end");
519#endif
520
521 /* do we have room? */
522 if (vm_nphysseg == VM_PHYSSEG_MAX16) {
523 printf("uvm_page_physload: unable to load physical memory "
524 "segment\n");
525 printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n",
526 VM_PHYSSEG_MAX16, (long long)start, (long long)end);
527 printf("\tincrease VM_PHYSSEG_MAX\n");
528 return;
529 }
530
531 /*
532 * check to see if this is a "preload" (i.e. uvm_mem_init hasn't been
533 * called yet, so malloc is not available).
534 */
535 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg; lcv++, seg++) {
536 if (seg->pgs)
537 break;
538 }
539 preload = (lcv == vm_nphysseg);
540
541 /* if VM is already running, attempt to malloc() vm_page structures */
542 if (!preload) {
543 /*
544 * XXXCDC: need some sort of lockout for this case
545 * right now it is only used by devices so it should be alright.
546 */
547 paddr_t paddr;
548
549 npages = end - start; /* # of pages */
550
551 pgs = km_alloc(round_page(npages * sizeof(*pgs))(((npages * sizeof(*pgs)) + ((1 << 12) - 1)) & ~((1
<< 12) - 1))
,
552 &kv_any, &kp_zero, &kd_waitok);
553 if (pgs == NULL((void *)0)) {
554 printf("uvm_page_physload: can not malloc vm_page "
555 "structs for segment\n");
556 printf("\tignoring 0x%lx -> 0x%lx\n", start, end);
557 return;
558 }
559 /* init phys_addr and free pages, XXX uvmexp.npages */
560 for (lcv = 0, paddr = ptoa(start)((paddr_t)(start) << 12); lcv < npages;
561 lcv++, paddr += PAGE_SIZE(1 << 12)) {
562 pgs[lcv].phys_addr = paddr;
563 VM_MDPAGE_INIT(&pgs[lcv])do { do { (void)(((void *)0)); (void)(0); __mtx_init((&(&
pgs[lcv])->mdpage.pv_mtx), ((((0xa)) > 0x0 && (
(0xa)) < 0x9) ? 0x9 : ((0xa)))); } while (0); (&pgs[lcv
])->mdpage.pv_list = ((void *)0); } while (0)
;
564 if (atop(paddr)((paddr) >> 12) >= avail_start &&
565 atop(paddr)((paddr) >> 12) < avail_end) {
566 if (flags & PHYSLOAD_DEVICE0x01) {
567 atomic_setbits_intx86_atomic_setbits_u32(&pgs[lcv].pg_flags,
568 PG_DEV0x00000200);
569 pgs[lcv].wire_count = 1;
570 } else {
571#if defined(VM_PHYSSEG_NOADD)
572 panic("uvm_page_physload: tried to add RAM after vm_mem_init");
573#endif
574 }
575 }
576 }
577
578 /* Add pages to free pool. */
579 if ((flags & PHYSLOAD_DEVICE0x01) == 0) {
580 uvm_pmr_freepages(&pgs[avail_start - start],
581 avail_end - avail_start);
582 }
583
584 /* XXXCDC: need hook to tell pmap to rebuild pv_list, etc... */
585 } else {
586 /* gcc complains if these don't get init'd */
587 pgs = NULL((void *)0);
588 npages = 0;
589
590 }
591
592 /* now insert us in the proper place in vm_physmem[] */
593#if (VM_PHYSSEG_STRAT3 == VM_PSTRAT_RANDOM1)
594 /* random: put it at the end (easy!) */
595 ps = &vm_physmem[vm_nphysseg];
596#elif (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BSEARCH2)
597 {
598 int x;
599 /* sort by address for binary search */
600 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg; lcv++, seg++)
601 if (start < seg->start)
602 break;
603 ps = seg;
604 /* move back other entries, if necessary ... */
605 for (x = vm_nphysseg, seg = vm_physmem + x - 1; x > lcv;
606 x--, seg--)
607 /* structure copy */
608 seg[1] = seg[0];
609 }
610#elif (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BIGFIRST3)
611 {
612 int x;
613 /* sort by largest segment first */
614 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg; lcv++, seg++)
615 if ((end - start) >
616 (seg->end - seg->start))
617 break;
618 ps = &vm_physmem[lcv];
619 /* move back other entries, if necessary ... */
620 for (x = vm_nphysseg, seg = vm_physmem + x - 1; x > lcv;
621 x--, seg--)
622 /* structure copy */
623 seg[1] = seg[0];
624 }
625#else
626 panic("uvm_page_physload: unknown physseg strategy selected!");
627#endif
628
629 ps->start = start;
630 ps->end = end;
631 ps->avail_start = avail_start;
632 ps->avail_end = avail_end;
633 if (preload) {
634 ps->pgs = NULL((void *)0);
635 } else {
636 ps->pgs = pgs;
637 ps->lastpg = pgs + npages - 1;
638 }
639 vm_nphysseg++;
640
641 return;
642}
643
644#ifdef DDB1 /* XXXCDC: TMP TMP TMP DEBUG DEBUG DEBUG */
645
646void uvm_page_physdump(void); /* SHUT UP GCC */
647
648/* call from DDB */
649void
650uvm_page_physdump(void)
651{
652 int lcv;
653 struct vm_physseg *seg;
654
655 printf("uvm_page_physdump: physical memory config [segs=%d of %d]:\n",
656 vm_nphysseg, VM_PHYSSEG_MAX16);
657 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg ; lcv++, seg++)
658 printf("0x%llx->0x%llx [0x%llx->0x%llx]\n",
659 (long long)seg->start,
660 (long long)seg->end,
661 (long long)seg->avail_start,
662 (long long)seg->avail_end);
663 printf("STRATEGY = ");
664 switch (VM_PHYSSEG_STRAT3) {
665 case VM_PSTRAT_RANDOM1: printf("RANDOM\n"); break;
666 case VM_PSTRAT_BSEARCH2: printf("BSEARCH\n"); break;
667 case VM_PSTRAT_BIGFIRST3: printf("BIGFIRST\n"); break;
668 default: printf("<<UNKNOWN>>!!!!\n");
669 }
670}
671#endif
672
673void
674uvm_shutdown(void)
675{
676#ifdef UVM_SWAP_ENCRYPT1
677 uvm_swap_finicrypt_all();
678#endif
679 smr_flush()smr_barrier_impl(1);
680}
681
682/*
683 * Perform insert of a given page in the specified anon of obj.
684 * This is basically, uvm_pagealloc, but with the page already given.
685 */
686void
687uvm_pagealloc_pg(struct vm_page *pg, struct uvm_object *obj, voff_t off,
688 struct vm_anon *anon)
689{
690 int flags;
691
692 KASSERT(obj == NULL || anon == NULL)((obj == ((void *)0) || anon == ((void *)0)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 692, "obj == NULL || anon == NULL"
))
;
693 KASSERT(anon == NULL || off == 0)((anon == ((void *)0) || off == 0) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 693, "anon == NULL || off == 0"
))
;
694 KASSERT(off == trunc_page(off))((off == ((off) & ~((1 << 12) - 1))) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 694, "off == trunc_page(off)"
))
;
695 KASSERT(obj == NULL || UVM_OBJ_IS_DUMMY(obj) ||((obj == ((void *)0) || (((obj)->pgops == &pmap_pager)
|| ((obj)->pgops == &bufcache_pager)) || rw_write_held
(obj->vmobjlock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 696, "obj == NULL || UVM_OBJ_IS_DUMMY(obj) || rw_write_held(obj->vmobjlock)"
))
696 rw_write_held(obj->vmobjlock))((obj == ((void *)0) || (((obj)->pgops == &pmap_pager)
|| ((obj)->pgops == &bufcache_pager)) || rw_write_held
(obj->vmobjlock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 696, "obj == NULL || UVM_OBJ_IS_DUMMY(obj) || rw_write_held(obj->vmobjlock)"
))
;
697 KASSERT(anon == NULL || anon->an_lock == NULL ||((anon == ((void *)0) || anon->an_lock == ((void *)0) || rw_write_held
(anon->an_lock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 698, "anon == NULL || anon->an_lock == NULL || rw_write_held(anon->an_lock)"
))
698 rw_write_held(anon->an_lock))((anon == ((void *)0) || anon->an_lock == ((void *)0) || rw_write_held
(anon->an_lock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 698, "anon == NULL || anon->an_lock == NULL || rw_write_held(anon->an_lock)"
))
;
699
700 flags = PG_BUSY0x00000001 | PG_FAKE0x00000040;
701 pg->offset = off;
702 pg->uobject = obj;
703 pg->uanon = anon;
704 KASSERT(uvm_page_owner_locked_p(pg))((uvm_page_owner_locked_p(pg)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 704, "uvm_page_owner_locked_p(pg)"
))
;
705 if (anon) {
706 anon->an_page = pg;
707 flags |= PQ_ANON0x00100000;
708 } else if (obj)
709 uvm_pageinsert(pg);
710 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, flags);
711#if defined(UVM_PAGE_TRKOWN)
712 pg->owner_tag = NULL((void *)0);
713#endif
714 UVM_PAGE_OWN(pg, "new alloc");
715}
716
717/*
718 * uvm_pglistalloc: allocate a list of pages
719 *
720 * => allocated pages are placed at the tail of rlist. rlist is
721 * assumed to be properly initialized by caller.
722 * => returns 0 on success or errno on failure
723 * => doesn't take into account clean non-busy pages on inactive list
724 * that could be used(?)
725 * => params:
726 * size the size of the allocation, rounded to page size.
727 * low the low address of the allowed allocation range.
728 * high the high address of the allowed allocation range.
729 * alignment memory must be aligned to this power-of-two boundary.
730 * boundary no segment in the allocation may cross this
731 * power-of-two boundary (relative to zero).
732 * => flags:
733 * UVM_PLA_NOWAIT fail if allocation fails
734 * UVM_PLA_WAITOK wait for memory to become avail
735 * UVM_PLA_ZERO return zeroed memory
736 */
737int
738uvm_pglistalloc(psize_t size, paddr_t low, paddr_t high, paddr_t alignment,
739 paddr_t boundary, struct pglist *rlist, int nsegs, int flags)
740{
741 KASSERT((alignment & (alignment - 1)) == 0)(((alignment & (alignment - 1)) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 741, "(alignment & (alignment - 1)) == 0"
))
;
742 KASSERT((boundary & (boundary - 1)) == 0)(((boundary & (boundary - 1)) == 0) ? (void)0 : __assert(
"diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 742, "(boundary & (boundary - 1)) == 0"
))
;
743 KASSERT(!(flags & UVM_PLA_WAITOK) ^ !(flags & UVM_PLA_NOWAIT))((!(flags & 0x0001) ^ !(flags & 0x0002)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 743, "!(flags & UVM_PLA_WAITOK) ^ !(flags & UVM_PLA_NOWAIT)"
))
;
744
745 if (size == 0)
746 return EINVAL22;
747 size = atop(round_page(size))(((((size) + ((1 << 12) - 1)) & ~((1 << 12) -
1))) >> 12)
;
748
749 /*
750 * XXX uvm_pglistalloc is currently only used for kernel
751 * objects. Unlike the checks in uvm_pagealloc, below, here
752 * we are always allowed to use the kernel reserve.
753 */
754 flags |= UVM_PLA_USERESERVE0x0040;
755
756 if ((high & PAGE_MASK((1 << 12) - 1)) != PAGE_MASK((1 << 12) - 1)) {
757 printf("uvm_pglistalloc: Upper boundary 0x%lx "
758 "not on pagemask.\n", (unsigned long)high);
759 }
760
761 /*
762 * Our allocations are always page granularity, so our alignment
763 * must be, too.
764 */
765 if (alignment < PAGE_SIZE(1 << 12))
766 alignment = PAGE_SIZE(1 << 12);
767
768 low = atop(roundup(low, alignment))((((((low)+((alignment)-1))/(alignment))*(alignment))) >>
12)
;
769 /*
770 * high + 1 may result in overflow, in which case high becomes 0x0,
771 * which is the 'don't care' value.
772 * The only requirement in that case is that low is also 0x0, or the
773 * low<high assert will fail.
774 */
775 high = atop(high + 1)((high + 1) >> 12);
776 alignment = atop(alignment)((alignment) >> 12);
777 if (boundary < PAGE_SIZE(1 << 12) && boundary != 0)
778 boundary = PAGE_SIZE(1 << 12);
779 boundary = atop(boundary)((boundary) >> 12);
780
781 return uvm_pmr_getpages(size, low, high, alignment, boundary, nsegs,
782 flags, rlist);
783}
784
785/*
786 * uvm_pglistfree: free a list of pages
787 *
788 * => pages should already be unmapped
789 */
790void
791uvm_pglistfree(struct pglist *list)
792{
793 uvm_pmr_freepageq(list);
794}
795
796/*
797 * interface used by the buffer cache to allocate a buffer at a time.
798 * The pages are allocated wired in DMA accessible memory
799 */
800int
801uvm_pagealloc_multi(struct uvm_object *obj, voff_t off, vsize_t size,
802 int flags)
803{
804 struct pglist plist;
805 struct vm_page *pg;
806 int i, r;
807
808 KASSERT(UVM_OBJ_IS_BUFCACHE(obj))((((obj)->pgops == &bufcache_pager)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 808, "UVM_OBJ_IS_BUFCACHE(obj)"
))
;
809 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 809, "_kernel_lock_held()"))
;
810
811 TAILQ_INIT(&plist)do { (&plist)->tqh_first = ((void *)0); (&plist)->
tqh_last = &(&plist)->tqh_first; } while (0)
;
812 r = uvm_pglistalloc(size, dma_constraint.ucr_low,
813 dma_constraint.ucr_high, 0, 0, &plist, atop(round_page(size))(((((size) + ((1 << 12) - 1)) & ~((1 << 12) -
1))) >> 12)
,
814 flags);
815 if (r == 0) {
816 i = 0;
817 while ((pg = TAILQ_FIRST(&plist)((&plist)->tqh_first)) != NULL((void *)0)) {
818 pg->wire_count = 1;
819 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PG_CLEAN0x00000008 | PG_FAKE0x00000040);
820 KASSERT((pg->pg_flags & PG_DEV) == 0)(((pg->pg_flags & 0x00000200) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 820, "(pg->pg_flags & PG_DEV) == 0"
))
;
821 TAILQ_REMOVE(&plist, pg, pageq)do { if (((pg)->pageq.tqe_next) != ((void *)0)) (pg)->pageq
.tqe_next->pageq.tqe_prev = (pg)->pageq.tqe_prev; else (
&plist)->tqh_last = (pg)->pageq.tqe_prev; *(pg)->
pageq.tqe_prev = (pg)->pageq.tqe_next; ((pg)->pageq.tqe_prev
) = ((void *)-1); ((pg)->pageq.tqe_next) = ((void *)-1); }
while (0)
;
822 uvm_pagealloc_pg(pg, obj, off + ptoa(i++)((paddr_t)(i++) << 12), NULL((void *)0));
823 }
824 }
825 return r;
826}
827
828/*
829 * interface used by the buffer cache to reallocate a buffer at a time.
830 * The pages are reallocated wired outside the DMA accessible region.
831 *
832 */
833int
834uvm_pagerealloc_multi(struct uvm_object *obj, voff_t off, vsize_t size,
835 int flags, struct uvm_constraint_range *where)
836{
837 struct pglist plist;
838 struct vm_page *pg, *tpg;
839 int i, r;
840 voff_t offset;
841
842 KASSERT(UVM_OBJ_IS_BUFCACHE(obj))((((obj)->pgops == &bufcache_pager)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 842, "UVM_OBJ_IS_BUFCACHE(obj)"
))
;
843 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 843, "_kernel_lock_held()"))
;
844
845 TAILQ_INIT(&plist)do { (&plist)->tqh_first = ((void *)0); (&plist)->
tqh_last = &(&plist)->tqh_first; } while (0)
;
846 if (size == 0)
847 panic("size 0 uvm_pagerealloc");
848 r = uvm_pglistalloc(size, where->ucr_low, where->ucr_high, 0,
849 0, &plist, atop(round_page(size))(((((size) + ((1 << 12) - 1)) & ~((1 << 12) -
1))) >> 12)
, flags);
850 if (r == 0) {
851 i = 0;
852 while((pg = TAILQ_FIRST(&plist)((&plist)->tqh_first)) != NULL((void *)0)) {
853 offset = off + ptoa(i++)((paddr_t)(i++) << 12);
854 tpg = uvm_pagelookup(obj, offset);
855 KASSERT(tpg != NULL)((tpg != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 855, "tpg != NULL"))
;
856 pg->wire_count = 1;
857 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PG_CLEAN0x00000008 | PG_FAKE0x00000040);
858 KASSERT((pg->pg_flags & PG_DEV) == 0)(((pg->pg_flags & 0x00000200) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 858, "(pg->pg_flags & PG_DEV) == 0"
))
;
859 TAILQ_REMOVE(&plist, pg, pageq)do { if (((pg)->pageq.tqe_next) != ((void *)0)) (pg)->pageq
.tqe_next->pageq.tqe_prev = (pg)->pageq.tqe_prev; else (
&plist)->tqh_last = (pg)->pageq.tqe_prev; *(pg)->
pageq.tqe_prev = (pg)->pageq.tqe_next; ((pg)->pageq.tqe_prev
) = ((void *)-1); ((pg)->pageq.tqe_next) = ((void *)-1); }
while (0)
;
860 uvm_pagecopy(tpg, pg);
861 KASSERT(tpg->wire_count == 1)((tpg->wire_count == 1) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 861, "tpg->wire_count == 1"
))
;
862 tpg->wire_count = 0;
863 uvm_lock_pageq()mtx_enter(&uvm.pageqlock);
864 uvm_pagefree(tpg);
865 uvm_unlock_pageq()mtx_leave(&uvm.pageqlock);
866 uvm_pagealloc_pg(pg, obj, offset, NULL((void *)0));
867 }
868 }
869 return r;
870}
871
872/*
873 * uvm_pagealloc: allocate vm_page from a particular free list.
874 *
875 * => return null if no pages free
876 * => wake up pagedaemon if number of free pages drops below low water mark
877 * => only one of obj or anon can be non-null
878 * => caller must activate/deactivate page if it is not wired.
879 */
880
881struct vm_page *
882uvm_pagealloc(struct uvm_object *obj, voff_t off, struct vm_anon *anon,
883 int flags)
884{
885 struct vm_page *pg;
886 struct pglist pgl;
887 int pmr_flags;
888
889 KASSERT(obj == NULL || anon == NULL)((obj == ((void *)0) || anon == ((void *)0)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 889, "obj == NULL || anon == NULL"
))
;
890 KASSERT(anon == NULL || off == 0)((anon == ((void *)0) || off == 0) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 890, "anon == NULL || off == 0"
))
;
891 KASSERT(off == trunc_page(off))((off == ((off) & ~((1 << 12) - 1))) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 891, "off == trunc_page(off)"
))
;
892 KASSERT(obj == NULL || UVM_OBJ_IS_DUMMY(obj) ||((obj == ((void *)0) || (((obj)->pgops == &pmap_pager)
|| ((obj)->pgops == &bufcache_pager)) || rw_write_held
(obj->vmobjlock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 893, "obj == NULL || UVM_OBJ_IS_DUMMY(obj) || rw_write_held(obj->vmobjlock)"
))
893 rw_write_held(obj->vmobjlock))((obj == ((void *)0) || (((obj)->pgops == &pmap_pager)
|| ((obj)->pgops == &bufcache_pager)) || rw_write_held
(obj->vmobjlock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 893, "obj == NULL || UVM_OBJ_IS_DUMMY(obj) || rw_write_held(obj->vmobjlock)"
))
;
894 KASSERT(anon == NULL || anon->an_lock == NULL ||((anon == ((void *)0) || anon->an_lock == ((void *)0) || rw_write_held
(anon->an_lock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 895, "anon == NULL || anon->an_lock == NULL || rw_write_held(anon->an_lock)"
))
895 rw_write_held(anon->an_lock))((anon == ((void *)0) || anon->an_lock == ((void *)0) || rw_write_held
(anon->an_lock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 895, "anon == NULL || anon->an_lock == NULL || rw_write_held(anon->an_lock)"
))
;
896
897 pmr_flags = UVM_PLA_NOWAIT0x0002;
898
899 /*
900 * We're allowed to use the kernel reserve if the page is
901 * being allocated to a kernel object.
902 */
903 if ((flags & UVM_PGA_USERESERVE0x0001) ||
904 (obj != NULL((void *)0) && UVM_OBJ_IS_KERN_OBJECT(obj)((obj)->uo_refs == (-2))))
905 pmr_flags |= UVM_PLA_USERESERVE0x0040;
906
907 if (flags & UVM_PGA_ZERO0x0002)
908 pmr_flags |= UVM_PLA_ZERO0x0004;
909 TAILQ_INIT(&pgl)do { (&pgl)->tqh_first = ((void *)0); (&pgl)->tqh_last
= &(&pgl)->tqh_first; } while (0)
;
910 if (uvm_pmr_getpages(1, 0, 0, 1, 0, 1, pmr_flags, &pgl) != 0)
911 goto fail;
912
913 pg = TAILQ_FIRST(&pgl)((&pgl)->tqh_first);
914 KASSERT(pg != NULL && TAILQ_NEXT(pg, pageq) == NULL)((pg != ((void *)0) && ((pg)->pageq.tqe_next) == (
(void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 914, "pg != NULL && TAILQ_NEXT(pg, pageq) == NULL")
)
;
915
916 uvm_pagealloc_pg(pg, obj, off, anon);
917 KASSERT((pg->pg_flags & PG_DEV) == 0)(((pg->pg_flags & 0x00000200) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 917, "(pg->pg_flags & PG_DEV) == 0"
))
;
918 if (flags & UVM_PGA_ZERO0x0002)
919 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PG_CLEAN0x00000008);
920 else
921 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PG_CLEAN0x00000008);
922
923 return pg;
924
925fail:
926 return NULL((void *)0);
927}
928
929/*
930 * uvm_pagerealloc: reallocate a page from one object to another
931 */
932
933void
934uvm_pagerealloc(struct vm_page *pg, struct uvm_object *newobj, voff_t newoff)
935{
936
937 /* remove it from the old object */
938 if (pg->uobject) {
939 uvm_pageremove(pg);
940 }
941
942 /* put it in the new object */
943 if (newobj) {
944 pg->uobject = newobj;
945 pg->offset = newoff;
946 pg->pg_version++;
947 uvm_pageinsert(pg);
948 }
949}
950
951/*
952 * uvm_pageclean: clean page
953 *
954 * => erase page's identity (i.e. remove from object)
955 * => caller must lock page queues if `pg' is managed
956 * => assumes all valid mappings of pg are gone
957 */
958void
959uvm_pageclean(struct vm_page *pg)
960{
961 u_int flags_to_clear = 0;
962
963 if ((pg->pg_flags & (PG_TABLED0x00000004|PQ_ACTIVE0x00040000|PQ_INACTIVE0x00020000)) &&
964 (pg->uobject
23.1
Field 'uobject' is equal to NULL
23.1
Field 'uobject' is equal to NULL
== NULL((void *)0) || !UVM_OBJ_IS_PMAP(pg->uobject)((pg->uobject)->pgops == &pmap_pager)))
965 MUTEX_ASSERT_LOCKED(&uvm.pageqlock)do { if (((&uvm.pageqlock)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&uvm.pageqlock
), __func__); } while (0)
;
24
Assuming the condition is false
966
967#ifdef DEBUG
968 if (pg->uobject == (void *)0xdeadbeef &&
969 pg->uanon == (void *)0xdeadbeef) {
970 panic("uvm_pagefree: freeing free page %p", pg);
971 }
972#endif
973
974 KASSERT((pg->pg_flags & PG_DEV) == 0)(((pg->pg_flags & 0x00000200) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 974, "(pg->pg_flags & PG_DEV) == 0"
))
;
25
Loop condition is false. Exiting loop
26
Assuming the condition is true
27
'?' condition is true
975 KASSERT(pg->uobject == NULL || UVM_OBJ_IS_DUMMY(pg->uobject) ||((pg->uobject == ((void *)0) || (((pg->uobject)->pgops
== &pmap_pager) || ((pg->uobject)->pgops == &bufcache_pager
)) || rw_write_held(pg->uobject->vmobjlock)) ? (void)0 :
__assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 976, "pg->uobject == NULL || UVM_OBJ_IS_DUMMY(pg->uobject) || rw_write_held(pg->uobject->vmobjlock)"
))
976 rw_write_held(pg->uobject->vmobjlock))((pg->uobject == ((void *)0) || (((pg->uobject)->pgops
== &pmap_pager) || ((pg->uobject)->pgops == &bufcache_pager
)) || rw_write_held(pg->uobject->vmobjlock)) ? (void)0 :
__assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 976, "pg->uobject == NULL || UVM_OBJ_IS_DUMMY(pg->uobject) || rw_write_held(pg->uobject->vmobjlock)"
))
;
977 KASSERT(pg->uobject != NULL || pg->uanon == NULL ||((pg->uobject != ((void *)0) || pg->uanon == ((void *)0
) || rw_write_held(pg->uanon->an_lock)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 978, "pg->uobject != NULL || pg->uanon == NULL || rw_write_held(pg->uanon->an_lock)"
))
28
Assuming field 'uanon' is equal to null
978 rw_write_held(pg->uanon->an_lock))((pg->uobject != ((void *)0) || pg->uanon == ((void *)0
) || rw_write_held(pg->uanon->an_lock)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 978, "pg->uobject != NULL || pg->uanon == NULL || rw_write_held(pg->uanon->an_lock)"
))
;
979
980 /*
981 * if the page was an object page (and thus "TABLED"), remove it
982 * from the object.
983 */
984 if (pg->pg_flags & PG_TABLED0x00000004)
29
Assuming the condition is true
30
Taking true branch
985 uvm_pageremove(pg);
31
Calling 'uvm_pageremove'
986
987 /*
988 * now remove the page from the queues
989 */
990 uvm_pagedequeue(pg);
991
992 /*
993 * if the page was wired, unwire it now.
994 */
995 if (pg->wire_count) {
996 pg->wire_count = 0;
997 uvmexp.wired--;
998 }
999 if (pg->uanon) {
1000 pg->uanon->an_page = NULL((void *)0);
1001 pg->uanon = NULL((void *)0);
1002 }
1003
1004 /* Clean page state bits. */
1005 flags_to_clear |= PQ_ANON0x00100000|PQ_AOBJ0x00200000|PQ_ENCRYPT0x00400000|PG_ZERO0x00000100|PG_FAKE0x00000040|PG_BUSY0x00000001|
1006 PG_RELEASED0x00000020|PG_CLEAN0x00000008|PG_CLEANCHK0x00000010;
1007 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, flags_to_clear);
1008
1009#ifdef DEBUG
1010 pg->uobject = (void *)0xdeadbeef;
1011 pg->offset = 0xdeadbeef;
1012 pg->uanon = (void *)0xdeadbeef;
1013#endif
1014}
1015
1016/*
1017 * uvm_pagefree: free page
1018 *
1019 * => erase page's identity (i.e. remove from object)
1020 * => put page on free list
1021 * => caller must lock page queues if `pg' is managed
1022 * => assumes all valid mappings of pg are gone
1023 */
1024void
1025uvm_pagefree(struct vm_page *pg)
1026{
1027 if ((pg->pg_flags & (PG_TABLED0x00000004|PQ_ACTIVE0x00040000|PQ_INACTIVE0x00020000)) &&
19
Assuming the condition is true
1028 (pg->uobject == NULL((void *)0) || !UVM_OBJ_IS_PMAP(pg->uobject)((pg->uobject)->pgops == &pmap_pager)))
20
Assuming field 'uobject' is equal to NULL
1029 MUTEX_ASSERT_LOCKED(&uvm.pageqlock)do { if (((&uvm.pageqlock)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&uvm.pageqlock
), __func__); } while (0)
;
21
Assuming the condition is false
22
Loop condition is false. Exiting loop
1030
1031 uvm_pageclean(pg);
23
Calling 'uvm_pageclean'
1032 uvm_pmr_freepages(pg, 1);
1033}
1034
1035/*
1036 * uvm_page_unbusy: unbusy an array of pages.
1037 *
1038 * => pages must either all belong to the same object, or all belong to anons.
1039 * => if pages are object-owned, object must be locked.
1040 * => if pages are anon-owned, anons must have 0 refcount.
1041 * => caller must make sure that anon-owned pages are not PG_RELEASED.
1042 */
1043void
1044uvm_page_unbusy(struct vm_page **pgs, int npgs)
1045{
1046 struct vm_page *pg;
1047 int i;
1048
1049 for (i = 0; i < npgs; i++) {
1
Assuming 'i' is < 'npgs'
2
Loop condition is true. Entering loop body
1050 pg = pgs[i];
1051
1052 if (pg == NULL((void *)0) || pg == PGO_DONTCARE((struct vm_page *) -1L)) {
3
Assuming 'pg' is not equal to NULL
4
Assuming the condition is false
1053 continue;
1054 }
1055
1056 KASSERT(uvm_page_owner_locked_p(pg))((uvm_page_owner_locked_p(pg)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 1056, "uvm_page_owner_locked_p(pg)"
))
;
5
Taking false branch
6
'?' condition is true
1057 KASSERT(pg->pg_flags & PG_BUSY)((pg->pg_flags & 0x00000001) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 1057, "pg->pg_flags & PG_BUSY"
))
;
7
Assuming the condition is true
8
'?' condition is true
1058
1059 if (pg->pg_flags & PG_WANTED0x00000002) {
9
Assuming the condition is false
10
Taking false branch
1060 wakeup(pg);
1061 }
1062 if (pg->pg_flags & PG_RELEASED0x00000020) {
11
Assuming the condition is true
1063 KASSERT(pg->uobject != NULL ||((pg->uobject != ((void *)0) || (pg->uanon != ((void *)
0) && pg->uanon->an_ref > 0)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1064, "pg->uobject != NULL || (pg->uanon != NULL && pg->uanon->an_ref > 0)"
))
12
Taking true branch
1064 (pg->uanon != NULL && pg->uanon->an_ref > 0))((pg->uobject != ((void *)0) || (pg->uanon != ((void *)
0) && pg->uanon->an_ref > 0)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1064, "pg->uobject != NULL || (pg->uanon != NULL && pg->uanon->an_ref > 0)"
))
;
1065 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PG_RELEASED0x00000020);
1066 pmap_page_protect(pg, PROT_NONE0x00);
13
Calling 'pmap_page_protect'
17
Returning from 'pmap_page_protect'
1067 uvm_pagefree(pg);
18
Calling 'uvm_pagefree'
1068 } else {
1069 KASSERT((pg->pg_flags & PG_FAKE) == 0)(((pg->pg_flags & 0x00000040) == 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1069, "(pg->pg_flags & PG_FAKE) == 0"
))
;
1070 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PG_WANTED0x00000002|PG_BUSY0x00000001);
1071 UVM_PAGE_OWN(pg, NULL);
1072 }
1073 }
1074}
1075
1076/*
1077 * uvm_pagewait: wait for a busy page
1078 *
1079 * => page must be known PG_BUSY
1080 * => object must be locked
1081 * => object will be unlocked on return
1082 */
1083void
1084uvm_pagewait(struct vm_page *pg, struct rwlock *lock, const char *wmesg)
1085{
1086 KASSERT(rw_lock_held(lock))((rw_lock_held(lock)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/uvm/uvm_page.c"
, 1086, "rw_lock_held(lock)"))
;
1087 KASSERT((pg->pg_flags & PG_BUSY) != 0)(((pg->pg_flags & 0x00000001) != 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1087, "(pg->pg_flags & PG_BUSY) != 0"
))
;
1088
1089 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PG_WANTED0x00000002);
1090 rwsleep_nsec(pg, lock, PVM4 | PNORELOCK0x200, wmesg, INFSLP0xffffffffffffffffULL);
1091}
1092
1093#if defined(UVM_PAGE_TRKOWN)
1094/*
1095 * uvm_page_own: set or release page ownership
1096 *
1097 * => this is a debugging function that keeps track of who sets PG_BUSY
1098 * and where they do it. it can be used to track down problems
1099 * such a thread setting "PG_BUSY" and never releasing it.
1100 * => if "tag" is NULL then we are releasing page ownership
1101 */
1102void
1103uvm_page_own(struct vm_page *pg, char *tag)
1104{
1105 /* gain ownership? */
1106 if (tag) {
1107 if (pg->owner_tag) {
1108 printf("uvm_page_own: page %p already owned "
1109 "by thread %d [%s]\n", pg,
1110 pg->owner, pg->owner_tag);
1111 panic("uvm_page_own");
1112 }
1113 pg->owner = (curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
) ? curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
->p_tid : (pid_t) -1;
1114 pg->owner_tag = tag;
1115 return;
1116 }
1117
1118 /* drop ownership */
1119 if (pg->owner_tag == NULL((void *)0)) {
1120 printf("uvm_page_own: dropping ownership of an non-owned "
1121 "page (%p)\n", pg);
1122 panic("uvm_page_own");
1123 }
1124 pg->owner_tag = NULL((void *)0);
1125 return;
1126}
1127#endif
1128
1129/*
1130 * when VM_PHYSSEG_MAX is 1, we can simplify these functions
1131 */
1132
1133#if VM_PHYSSEG_MAX16 > 1
1134/*
1135 * vm_physseg_find: find vm_physseg structure that belongs to a PA
1136 */
1137int
1138vm_physseg_find(paddr_t pframe, int *offp)
1139{
1140 struct vm_physseg *seg;
1141
1142#if (VM_PHYSSEG_STRAT3 == VM_PSTRAT_BSEARCH2)
1143 /* binary search for it */
1144 int start, len, try;
1145
1146 /*
1147 * if try is too large (thus target is less than try) we reduce
1148 * the length to trunc(len/2) [i.e. everything smaller than "try"]
1149 *
1150 * if the try is too small (thus target is greater than try) then
1151 * we set the new start to be (try + 1). this means we need to
1152 * reduce the length to (round(len/2) - 1).
1153 *
1154 * note "adjust" below which takes advantage of the fact that
1155 * (round(len/2) - 1) == trunc((len - 1) / 2)
1156 * for any value of len we may have
1157 */
1158
1159 for (start = 0, len = vm_nphysseg ; len != 0 ; len = len / 2) {
1160 try = start + (len / 2); /* try in the middle */
1161 seg = vm_physmem + try;
1162
1163 /* start past our try? */
1164 if (pframe >= seg->start) {
1165 /* was try correct? */
1166 if (pframe < seg->end) {
1167 if (offp)
1168 *offp = pframe - seg->start;
1169 return try; /* got it */
1170 }
1171 start = try + 1; /* next time, start here */
1172 len--; /* "adjust" */
1173 } else {
1174 /*
1175 * pframe before try, just reduce length of
1176 * region, done in "for" loop
1177 */
1178 }
1179 }
1180 return -1;
1181
1182#else
1183 /* linear search for it */
1184 int lcv;
1185
1186 for (lcv = 0, seg = vm_physmem; lcv < vm_nphysseg ; lcv++, seg++) {
1187 if (pframe >= seg->start && pframe < seg->end) {
1188 if (offp)
1189 *offp = pframe - seg->start;
1190 return lcv; /* got it */
1191 }
1192 }
1193 return -1;
1194
1195#endif
1196}
1197
1198/*
1199 * PHYS_TO_VM_PAGE: find vm_page for a PA. used by MI code to get vm_pages
1200 * back from an I/O mapping (ugh!). used in some MD code as well.
1201 */
1202struct vm_page *
1203PHYS_TO_VM_PAGE(paddr_t pa)
1204{
1205 paddr_t pf = atop(pa)((pa) >> 12);
1206 int off;
1207 int psi;
1208
1209 psi = vm_physseg_find(pf, &off);
1210
1211 return (psi == -1) ? NULL((void *)0) : &vm_physmem[psi].pgs[off];
1212}
1213#endif /* VM_PHYSSEG_MAX > 1 */
1214
1215/*
1216 * uvm_pagelookup: look up a page
1217 */
1218struct vm_page *
1219uvm_pagelookup(struct uvm_object *obj, voff_t off)
1220{
1221 /* XXX if stack is too much, handroll */
1222 struct vm_page p, *pg;
1223
1224 p.offset = off;
1225 pg = RBT_FIND(uvm_objtree, &obj->memt, &p)uvm_objtree_RBT_FIND(&obj->memt, &p);
1226
1227 KASSERT(pg == NULL || obj->uo_npages != 0)((pg == ((void *)0) || obj->uo_npages != 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1227, "pg == NULL || obj->uo_npages != 0"
))
;
1228 KASSERT(pg == NULL || (pg->pg_flags & PG_RELEASED) == 0 ||((pg == ((void *)0) || (pg->pg_flags & 0x00000020) == 0
|| (pg->pg_flags & 0x00000001) != 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1229, "pg == NULL || (pg->pg_flags & PG_RELEASED) == 0 || (pg->pg_flags & PG_BUSY) != 0"
))
1229 (pg->pg_flags & PG_BUSY) != 0)((pg == ((void *)0) || (pg->pg_flags & 0x00000020) == 0
|| (pg->pg_flags & 0x00000001) != 0) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/uvm/uvm_page.c", 1229, "pg == NULL || (pg->pg_flags & PG_RELEASED) == 0 || (pg->pg_flags & PG_BUSY) != 0"
))
;
1230 return (pg);
1231}
1232
1233/*
1234 * uvm_pagewire: wire the page, thus removing it from the daemon's grasp
1235 *
1236 * => caller must lock page queues
1237 */
1238void
1239uvm_pagewire(struct vm_page *pg)
1240{
1241 KASSERT(uvm_page_owner_locked_p(pg))((uvm_page_owner_locked_p(pg)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 1241, "uvm_page_owner_locked_p(pg)"
))
;
1242 MUTEX_ASSERT_LOCKED(&uvm.pageqlock)do { if (((&uvm.pageqlock)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&uvm.pageqlock
), __func__); } while (0)
;
1243
1244 if (pg->wire_count == 0) {
1245 uvm_pagedequeue(pg);
1246 uvmexp.wired++;
1247 }
1248 pg->wire_count++;
1249}
1250
1251/*
1252 * uvm_pageunwire: unwire the page.
1253 *
1254 * => activate if wire count goes to zero.
1255 * => caller must lock page queues
1256 */
1257void
1258uvm_pageunwire(struct vm_page *pg)
1259{
1260 KASSERT(uvm_page_owner_locked_p(pg))((uvm_page_owner_locked_p(pg)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 1260, "uvm_page_owner_locked_p(pg)"
))
;
1261 MUTEX_ASSERT_LOCKED(&uvm.pageqlock)do { if (((&uvm.pageqlock)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&uvm.pageqlock
), __func__); } while (0)
;
1262
1263 pg->wire_count--;
1264 if (pg->wire_count == 0) {
1265 uvm_pageactivate(pg);
1266 uvmexp.wired--;
1267 }
1268}
1269
1270/*
1271 * uvm_pagedeactivate: deactivate page -- no pmaps have access to page
1272 *
1273 * => caller must lock page queues
1274 * => caller must check to make sure page is not wired
1275 * => object that page belongs to must be locked (so we can adjust pg->flags)
1276 */
1277void
1278uvm_pagedeactivate(struct vm_page *pg)
1279{
1280 KASSERT(uvm_page_owner_locked_p(pg))((uvm_page_owner_locked_p(pg)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 1280, "uvm_page_owner_locked_p(pg)"
))
;
1281 MUTEX_ASSERT_LOCKED(&uvm.pageqlock)do { if (((&uvm.pageqlock)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&uvm.pageqlock
), __func__); } while (0)
;
1282
1283 if (pg->pg_flags & PQ_ACTIVE0x00040000) {
1284 TAILQ_REMOVE(&uvm.page_active, pg, pageq)do { if (((pg)->pageq.tqe_next) != ((void *)0)) (pg)->pageq
.tqe_next->pageq.tqe_prev = (pg)->pageq.tqe_prev; else (
&uvm.page_active)->tqh_last = (pg)->pageq.tqe_prev;
*(pg)->pageq.tqe_prev = (pg)->pageq.tqe_next; ((pg)->
pageq.tqe_prev) = ((void *)-1); ((pg)->pageq.tqe_next) = (
(void *)-1); } while (0)
;
1285 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PQ_ACTIVE0x00040000);
1286 uvmexp.active--;
1287 }
1288 if ((pg->pg_flags & PQ_INACTIVE0x00020000) == 0) {
1289 KASSERT(pg->wire_count == 0)((pg->wire_count == 0) ? (void)0 : __assert("diagnostic ",
"/usr/src/sys/uvm/uvm_page.c", 1289, "pg->wire_count == 0"
))
;
1290 TAILQ_INSERT_TAIL(&uvm.page_inactive, pg, pageq)do { (pg)->pageq.tqe_next = ((void *)0); (pg)->pageq.tqe_prev
= (&uvm.page_inactive)->tqh_last; *(&uvm.page_inactive
)->tqh_last = (pg); (&uvm.page_inactive)->tqh_last =
&(pg)->pageq.tqe_next; } while (0)
;
1291 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PQ_INACTIVE0x00020000);
1292 uvmexp.inactive++;
1293 pmap_clear_reference(pg)pmap_clear_attrs(pg, 0x0000000000000020UL);
1294 /*
1295 * update the "clean" bit. this isn't 100%
1296 * accurate, and doesn't have to be. we'll
1297 * re-sync it after we zap all mappings when
1298 * scanning the inactive list.
1299 */
1300 if ((pg->pg_flags & PG_CLEAN0x00000008) != 0 &&
1301 pmap_is_modified(pg)pmap_test_attrs(pg, 0x0000000000000040UL))
1302 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PG_CLEAN0x00000008);
1303 }
1304}
1305
1306/*
1307 * uvm_pageactivate: activate page
1308 *
1309 * => caller must lock page queues
1310 */
1311void
1312uvm_pageactivate(struct vm_page *pg)
1313{
1314 KASSERT(uvm_page_owner_locked_p(pg))((uvm_page_owner_locked_p(pg)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/uvm/uvm_page.c", 1314, "uvm_page_owner_locked_p(pg)"
))
;
1315 MUTEX_ASSERT_LOCKED(&uvm.pageqlock)do { if (((&uvm.pageqlock)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&uvm.pageqlock
), __func__); } while (0)
;
1316
1317 uvm_pagedequeue(pg);
1318 if (pg->wire_count == 0) {
1319 TAILQ_INSERT_TAIL(&uvm.page_active, pg, pageq)do { (pg)->pageq.tqe_next = ((void *)0); (pg)->pageq.tqe_prev
= (&uvm.page_active)->tqh_last; *(&uvm.page_active
)->tqh_last = (pg); (&uvm.page_active)->tqh_last = &
(pg)->pageq.tqe_next; } while (0)
;
1320 atomic_setbits_intx86_atomic_setbits_u32(&pg->pg_flags, PQ_ACTIVE0x00040000);
1321 uvmexp.active++;
1322
1323 }
1324}
1325
1326/*
1327 * uvm_pagedequeue: remove a page from any paging queue
1328 */
1329void
1330uvm_pagedequeue(struct vm_page *pg)
1331{
1332 if (pg->pg_flags & PQ_ACTIVE0x00040000) {
1333 TAILQ_REMOVE(&uvm.page_active, pg, pageq)do { if (((pg)->pageq.tqe_next) != ((void *)0)) (pg)->pageq
.tqe_next->pageq.tqe_prev = (pg)->pageq.tqe_prev; else (
&uvm.page_active)->tqh_last = (pg)->pageq.tqe_prev;
*(pg)->pageq.tqe_prev = (pg)->pageq.tqe_next; ((pg)->
pageq.tqe_prev) = ((void *)-1); ((pg)->pageq.tqe_next) = (
(void *)-1); } while (0)
;
1334 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PQ_ACTIVE0x00040000);
1335 uvmexp.active--;
1336 }
1337 if (pg->pg_flags & PQ_INACTIVE0x00020000) {
1338 TAILQ_REMOVE(&uvm.page_inactive, pg, pageq)do { if (((pg)->pageq.tqe_next) != ((void *)0)) (pg)->pageq
.tqe_next->pageq.tqe_prev = (pg)->pageq.tqe_prev; else (
&uvm.page_inactive)->tqh_last = (pg)->pageq.tqe_prev
; *(pg)->pageq.tqe_prev = (pg)->pageq.tqe_next; ((pg)->
pageq.tqe_prev) = ((void *)-1); ((pg)->pageq.tqe_next) = (
(void *)-1); } while (0)
;
1339 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PQ_INACTIVE0x00020000);
1340 uvmexp.inactive--;
1341 }
1342}
1343/*
1344 * uvm_pagezero: zero fill a page
1345 */
1346void
1347uvm_pagezero(struct vm_page *pg)
1348{
1349 atomic_clearbits_intx86_atomic_clearbits_u32(&pg->pg_flags, PG_CLEAN0x00000008);
1350 pmap_zero_page(pg);
1351}
1352
1353/*
1354 * uvm_pagecopy: copy a page
1355 */
1356void
1357uvm_pagecopy(struct vm_page *src, struct vm_page *dst)
1358{
1359 atomic_clearbits_intx86_atomic_clearbits_u32(&dst->pg_flags, PG_CLEAN0x00000008);
1360 pmap_copy_page(src, dst);
1361}
1362
1363/*
1364 * uvm_page_owner_locked_p: return true if object associated with page is
1365 * locked. this is a weak check for runtime assertions only.
1366 */
1367int
1368uvm_page_owner_locked_p(struct vm_page *pg)
1369{
1370 if (pg->uobject != NULL((void *)0)) {
1371 if (UVM_OBJ_IS_DUMMY(pg->uobject)(((pg->uobject)->pgops == &pmap_pager) || ((pg->
uobject)->pgops == &bufcache_pager))
)
1372 return 1;
1373 return rw_write_held(pg->uobject->vmobjlock);
1374 }
1375 if (pg->uanon != NULL((void *)0)) {
1376 return rw_write_held(pg->uanon->an_lock);
1377 }
1378 return 1;
1379}
1380
1381/*
1382 * uvm_pagecount: count the number of physical pages in the address range.
1383 */
1384psize_t
1385uvm_pagecount(struct uvm_constraint_range* constraint)
1386{
1387 int lcv;
1388 psize_t sz;
1389 paddr_t low, high;
1390 paddr_t ps_low, ps_high;
1391
1392 /* Algorithm uses page numbers. */
1393 low = atop(constraint->ucr_low)((constraint->ucr_low) >> 12);
1394 high = atop(constraint->ucr_high)((constraint->ucr_high) >> 12);
1395
1396 sz = 0;
1397 for (lcv = 0; lcv < vm_nphysseg; lcv++) {
1398 ps_low = MAX(low, vm_physmem[lcv].avail_start)(((low)>(vm_physmem[lcv].avail_start))?(low):(vm_physmem[lcv
].avail_start))
;
1399 ps_high = MIN(high, vm_physmem[lcv].avail_end)(((high)<(vm_physmem[lcv].avail_end))?(high):(vm_physmem[lcv
].avail_end))
;
1400 if (ps_low < ps_high)
1401 sz += ps_high - ps_low;
1402 }
1403 return sz;
1404}

/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj/machine/pmap.h

1/* $OpenBSD: pmap.h,v 1.88 2023/12/29 13:23:28 jca Exp $ */
2/* $NetBSD: pmap.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */
3
4/*
5 * Copyright (c) 1997 Charles D. Cranor and Washington University.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Copyright (c) 2001 Wasabi Systems, Inc.
31 * All rights reserved.
32 *
33 * Written by Frank van der Linden for Wasabi Systems, Inc.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed for the NetBSD Project by
46 * Wasabi Systems, Inc.
47 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
48 * or promote products derived from this software without specific prior
49 * written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 * POSSIBILITY OF SUCH DAMAGE.
62 */
63
64/*
65 * pmap.h: see pmap.c for the history of this pmap module.
66 */
67
68#ifndef _MACHINE_PMAP_H_
69#define _MACHINE_PMAP_H_
70
71#ifndef _LOCORE
72#ifdef _KERNEL1
73#include <lib/libkern/libkern.h> /* for KASSERT() */
74#include <machine/cpufunc.h>
75#endif /* _KERNEL */
76#include <sys/mutex.h>
77#include <uvm/uvm_object.h>
78#include <machine/pte.h>
79#endif
80
81/*
82 * The x86_64 pmap module closely resembles the i386 one. It uses
83 * the same recursive entry scheme. See the i386 pmap.h for a
84 * description. The alternate area trick for accessing non-current
85 * pmaps has been removed, though, because it performs badly on SMP
86 * systems.
87 * The most obvious difference to i386 is that 2 extra levels of page
88 * table need to be dealt with. The level 1 page table pages are at:
89 *
90 * l1: 0x00007f8000000000 - 0x00007fffffffffff (39 bits, needs PML4 entry)
91 *
92 * The other levels are kept as physical pages in 3 UVM objects and are
93 * temporarily mapped for virtual access when needed.
94 *
95 * The other obvious difference from i386 is that it has a direct map of all
96 * physical memory in the VA range:
97 *
98 * 0xfffffd8000000000 - 0xffffff7fffffffff
99 *
100 * The direct map is used in some cases to access PTEs of non-current pmaps.
101 *
102 * Note that address space is signed, so the layout for 48 bits is:
103 *
104 * +---------------------------------+ 0xffffffffffffffff
105 * | Kernel Image |
106 * +---------------------------------+ 0xffffff8000000000
107 * | Direct Map |
108 * +---------------------------------+ 0xfffffd8000000000
109 * ~ ~
110 * | |
111 * | Kernel Space |
112 * | |
113 * | |
114 * +---------------------------------+ 0xffff800000000000 = 0x0000800000000000
115 * | L1 table (PTE pages) |
116 * +---------------------------------+ 0x00007f8000000000
117 * ~ ~
118 * | |
119 * | User Space |
120 * | |
121 * | |
122 * +---------------------------------+ 0x0000000000000000
123 *
124 * In other words, there is a 'VA hole' at 0x0000800000000000 -
125 * 0xffff800000000000 which will trap, just as on, for example,
126 * sparcv9.
127 *
128 * The unused space can be used if needed, but it adds a little more
129 * complexity to the calculations.
130 */
131
132/*
133 * Mask to get rid of the sign-extended part of addresses.
134 */
135#define VA_SIGN_MASK0xffff000000000000 0xffff000000000000
136#define VA_SIGN_NEG(va)((va) | 0xffff000000000000) ((va) | VA_SIGN_MASK0xffff000000000000)
137/*
138 * XXXfvdl this one's not right.
139 */
140#define VA_SIGN_POS(va)((va) & ~0xffff000000000000) ((va) & ~VA_SIGN_MASK0xffff000000000000)
141
142#define L4_SLOT_PTE255 255
143#define L4_SLOT_KERN256 256
144#define L4_SLOT_KERNBASE511 511
145#define NUM_L4_SLOT_DIRECT4 4
146#define L4_SLOT_DIRECT(511 - 4) (L4_SLOT_KERNBASE511 - NUM_L4_SLOT_DIRECT4)
147#define L4_SLOT_EARLY((511 - 4) - 1) (L4_SLOT_DIRECT(511 - 4) - 1)
148
149#define PDIR_SLOT_KERN256 L4_SLOT_KERN256
150#define PDIR_SLOT_PTE255 L4_SLOT_PTE255
151#define PDIR_SLOT_DIRECT(511 - 4) L4_SLOT_DIRECT(511 - 4)
152#define PDIR_SLOT_EARLY((511 - 4) - 1) L4_SLOT_EARLY((511 - 4) - 1)
153
154/*
155 * the following defines give the virtual addresses of various MMU
156 * data structures:
157 * PTE_BASE: the base VA of the linear PTE mappings
158 * PDP_PDE: the VA of the PDE that points back to the PDP
159 *
160 */
161
162#define PTE_BASE((pt_entry_t *) (255 * (1ULL << 39))) ((pt_entry_t *) (L4_SLOT_PTE255 * NBPD_L4(1ULL << 39)))
163#define PMAP_DIRECT_BASE(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000)) (VA_SIGN_NEG((L4_SLOT_DIRECT * NBPD_L4))((((511 - 4) * (1ULL << 39))) | 0xffff000000000000))
164#define PMAP_DIRECT_END((((((511 - 4) + 4) * (1ULL << 39))) | 0xffff000000000000
))
(VA_SIGN_NEG(((L4_SLOT_DIRECT + \(((((511 - 4) + 4) * (1ULL << 39))) | 0xffff000000000000
)
165 NUM_L4_SLOT_DIRECT) * NBPD_L4))(((((511 - 4) + 4) * (1ULL << 39))) | 0xffff000000000000
)
)
166
167#define L1_BASE((pt_entry_t *) (255 * (1ULL << 39))) PTE_BASE((pt_entry_t *) (255 * (1ULL << 39)))
168
169#define L2_BASE((pd_entry_t *)((char *)((pt_entry_t *) (255 * (1ULL <<
39))) + 255 * (1ULL << 30)))
((pd_entry_t *)((char *)L1_BASE((pt_entry_t *) (255 * (1ULL << 39))) + L4_SLOT_PTE255 * NBPD_L3(1ULL << 30)))
170#define L3_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pt_entry_t *
) (255 * (1ULL << 39))) + 255 * (1ULL << 30))) + 255
* (1ULL << 21)))
((pd_entry_t *)((char *)L2_BASE((pd_entry_t *)((char *)((pt_entry_t *) (255 * (1ULL <<
39))) + 255 * (1ULL << 30)))
+ L4_SLOT_PTE255 * NBPD_L2(1ULL << 21)))
171#define L4_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t *
)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255 *
(1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (1ULL
<< 12)))
((pd_entry_t *)((char *)L3_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pt_entry_t *
) (255 * (1ULL << 39))) + 255 * (1ULL << 30))) + 255
* (1ULL << 21)))
+ L4_SLOT_PTE255 * NBPD_L1(1ULL << 12)))
172
173#define PDP_PDE(((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t
*)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255
* (1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (
1ULL << 12))) + 255)
(L4_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t *
)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255 *
(1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (1ULL
<< 12)))
+ PDIR_SLOT_PTE255)
174
175#define PDP_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t *
)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255 *
(1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (1ULL
<< 12)))
L4_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t *
)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255 *
(1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (1ULL
<< 12)))
176
177#define NKL4_MAX_ENTRIES(unsigned long)1 (unsigned long)1
178#define NKL3_MAX_ENTRIES(unsigned long)((unsigned long)1 * 512) (unsigned long)(NKL4_MAX_ENTRIES(unsigned long)1 * 512)
179#define NKL2_MAX_ENTRIES(unsigned long)((unsigned long)((unsigned long)1 * 512) * 512
)
(unsigned long)(NKL3_MAX_ENTRIES(unsigned long)((unsigned long)1 * 512) * 512)
180#define NKL1_MAX_ENTRIES(unsigned long)((unsigned long)((unsigned long)((unsigned long
)1 * 512) * 512) * 512)
(unsigned long)(NKL2_MAX_ENTRIES(unsigned long)((unsigned long)((unsigned long)1 * 512) * 512
)
* 512)
181
182#define NKL4_KIMG_ENTRIES1 1
183#define NKL3_KIMG_ENTRIES1 1
184#define NKL2_KIMG_ENTRIES64 64
185
186/* number of pages of direct map entries set up by locore0.S */
187#define NDML4_ENTRIES1 1
188#define NDML3_ENTRIES1 1
189#define NDML2_ENTRIES4 4 /* 4GB */
190
191/*
192 * Since kva space is below the kernel in its entirety, we start off
193 * with zero entries on each level.
194 */
195#define NKL4_START_ENTRIES0 0
196#define NKL3_START_ENTRIES0 0
197#define NKL2_START_ENTRIES0 0
198#define NKL1_START_ENTRIES0 0 /* XXX */
199
200#define NTOPLEVEL_PDES((1 << 12) / (sizeof (pd_entry_t))) (PAGE_SIZE(1 << 12) / (sizeof (pd_entry_t)))
201
202#define NPDPG((1 << 12) / sizeof (pd_entry_t)) (PAGE_SIZE(1 << 12) / sizeof (pd_entry_t))
203
204/*
205 * pl*_pi: index in the ptp page for a pde mapping a VA.
206 * (pl*_i below is the index in the virtual array of all pdes per level)
207 */
208#define pl1_pi(VA)(((((VA) & ~0xffff000000000000)) & 0x00000000001ff000UL
) >> 12)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L1_MASK0x00000000001ff000UL) >> L1_SHIFT12)
209#define pl2_pi(VA)(((((VA) & ~0xffff000000000000)) & 0x000000003fe00000UL
) >> 21)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L2_MASK0x000000003fe00000UL) >> L2_SHIFT21)
210#define pl3_pi(VA)(((((VA) & ~0xffff000000000000)) & 0x0000007fc0000000UL
) >> 30)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L3_MASK0x0000007fc0000000UL) >> L3_SHIFT30)
211#define pl4_pi(VA)(((((VA) & ~0xffff000000000000)) & 0x0000ff8000000000UL
) >> 39)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L4_MASK0x0000ff8000000000UL) >> L4_SHIFT39)
212
213/*
214 * pl*_i: generate index into pde/pte arrays in virtual space
215 */
216#define pl1_i(VA)(((((VA) & ~0xffff000000000000)) & (((0x0000ff8000000000UL
|0x0000007fc0000000UL)|0x000000003fe00000UL)|0x00000000001ff000UL
)) >> 12)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L1_FRAME(((0x0000ff8000000000UL|0x0000007fc0000000UL)|0x000000003fe00000UL
)|0x00000000001ff000UL)
) >> L1_SHIFT12)
217#define pl2_i(VA)(((((VA) & ~0xffff000000000000)) & ((0x0000ff8000000000UL
|0x0000007fc0000000UL)|0x000000003fe00000UL)) >> 21)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L2_FRAME((0x0000ff8000000000UL|0x0000007fc0000000UL)|0x000000003fe00000UL
)
) >> L2_SHIFT21)
218#define pl3_i(VA)(((((VA) & ~0xffff000000000000)) & (0x0000ff8000000000UL
|0x0000007fc0000000UL)) >> 30)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L3_FRAME(0x0000ff8000000000UL|0x0000007fc0000000UL)) >> L3_SHIFT30)
219#define pl4_i(VA)(((((VA) & ~0xffff000000000000)) & 0x0000ff8000000000UL
) >> 39)
(((VA_SIGN_POS(VA)((VA) & ~0xffff000000000000)) & L4_FRAME0x0000ff8000000000UL) >> L4_SHIFT39)
220#define pl_i(va, lvl)(((((va) & ~0xffff000000000000)) & ptp_masks[(lvl)-1]
) >> ptp_shifts[(lvl)-1])
\
221 (((VA_SIGN_POS(va)((va) & ~0xffff000000000000)) & ptp_masks[(lvl)-1]) >> ptp_shifts[(lvl)-1])
222
223#define PTP_MASK_INITIALIZER{ (((0x0000ff8000000000UL|0x0000007fc0000000UL)|0x000000003fe00000UL
)|0x00000000001ff000UL), ((0x0000ff8000000000UL|0x0000007fc0000000UL
)|0x000000003fe00000UL), (0x0000ff8000000000UL|0x0000007fc0000000UL
), 0x0000ff8000000000UL }
{ L1_FRAME(((0x0000ff8000000000UL|0x0000007fc0000000UL)|0x000000003fe00000UL
)|0x00000000001ff000UL)
, L2_FRAME((0x0000ff8000000000UL|0x0000007fc0000000UL)|0x000000003fe00000UL
)
, L3_FRAME(0x0000ff8000000000UL|0x0000007fc0000000UL), L4_FRAME0x0000ff8000000000UL }
224#define PTP_SHIFT_INITIALIZER{ 12, 21, 30, 39 } { L1_SHIFT12, L2_SHIFT21, L3_SHIFT30, L4_SHIFT39 }
225#define NKPTP_INITIALIZER{ 0, 0, 0, 0 } { NKL1_START_ENTRIES0, NKL2_START_ENTRIES0, \
226 NKL3_START_ENTRIES0, NKL4_START_ENTRIES0 }
227#define NKPTPMAX_INITIALIZER{ (unsigned long)((unsigned long)((unsigned long)((unsigned long
)1 * 512) * 512) * 512), (unsigned long)((unsigned long)((unsigned
long)1 * 512) * 512), (unsigned long)((unsigned long)1 * 512
), (unsigned long)1 }
{ NKL1_MAX_ENTRIES(unsigned long)((unsigned long)((unsigned long)((unsigned long
)1 * 512) * 512) * 512)
, NKL2_MAX_ENTRIES(unsigned long)((unsigned long)((unsigned long)1 * 512) * 512
)
, \
228 NKL3_MAX_ENTRIES(unsigned long)((unsigned long)1 * 512), NKL4_MAX_ENTRIES(unsigned long)1 }
229#define NBPD_INITIALIZER{ (1ULL << 12), (1ULL << 21), (1ULL << 30),
(1ULL << 39) }
{ NBPD_L1(1ULL << 12), NBPD_L2(1ULL << 21), NBPD_L3(1ULL << 30), NBPD_L4(1ULL << 39) }
230#define PDES_INITIALIZER{ ((pd_entry_t *)((char *)((pt_entry_t *) (255 * (1ULL <<
39))) + 255 * (1ULL << 30))), ((pd_entry_t *)((char *)
((pd_entry_t *)((char *)((pt_entry_t *) (255 * (1ULL <<
39))) + 255 * (1ULL << 30))) + 255 * (1ULL << 21
))), ((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t
*)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255
* (1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (
1ULL << 12))) }
{ L2_BASE((pd_entry_t *)((char *)((pt_entry_t *) (255 * (1ULL <<
39))) + 255 * (1ULL << 30)))
, L3_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pt_entry_t *
) (255 * (1ULL << 39))) + 255 * (1ULL << 30))) + 255
* (1ULL << 21)))
, L4_BASE((pd_entry_t *)((char *)((pd_entry_t *)((char *)((pd_entry_t *
)((char *)((pt_entry_t *) (255 * (1ULL << 39))) + 255 *
(1ULL << 30))) + 255 * (1ULL << 21))) + 255 * (1ULL
<< 12)))
}
231
232/*
233 * PTP macros:
234 * a PTP's index is the PD index of the PDE that points to it
235 * a PTP's offset is the byte-offset in the PTE space that this PTP is at
236 * a PTP's VA is the first VA mapped by that PTP
237 */
238
239#define ptp_va2o(va, lvl)((((((va) & ~0xffff000000000000)) & ptp_masks[((lvl)+
1)-1]) >> ptp_shifts[((lvl)+1)-1]) * (1 << 12))
(pl_i(va, (lvl)+1)(((((va) & ~0xffff000000000000)) & ptp_masks[((lvl)+1
)-1]) >> ptp_shifts[((lvl)+1)-1])
* PAGE_SIZE(1 << 12))
240
241#define PTP_LEVELS4 4
242
243/*
244 * PG_AVAIL usage: we make use of the ignored bits of the PTE
245 */
246
247#define PG_W0x0000000000000200UL PG_AVAIL10x0000000000000200UL /* "wired" mapping */
248#define PG_PVLIST0x0000000000000400UL PG_AVAIL20x0000000000000400UL /* mapping has entry on pvlist */
249/* PG_AVAIL3 not used */
250
251/*
252 * PCID assignments.
253 * The shootdown code assumes KERN, PROC, and PROC_INTEL are both
254 * consecutive and in that order.
255 */
256#define PCID_KERN0 0 /* for pmap_kernel() */
257#define PCID_PROC1 1 /* non-pmap_kernel(), U+K */
258#define PCID_PROC_INTEL2 2 /* non-pmap_kernel(), U-K (meltdown) */
259#define PCID_TEMP3 3 /* temp mapping of another non-pmap_kernel() */
260#define PCID_EFI4 4 /* EFI runtime services */
261
262extern int pmap_use_pcid; /* non-zero if PCID support is enabled */
263
264/*
265 * Number of PTEs per cache line. 8 byte pte, 64-byte cache line
266 * Used to avoid false sharing of cache lines.
267 */
268#define NPTECL8 8
269
270
271#if defined(_KERNEL1) && !defined(_LOCORE)
272/*
273 * pmap data structures: see pmap.c for details of locking.
274 */
275
276struct pmap;
277typedef struct pmap *pmap_t;
278
279/*
280 * we maintain a list of all non-kernel pmaps
281 */
282
283LIST_HEAD(pmap_head, pmap)struct pmap_head { struct pmap *lh_first; }; /* struct pmap_head: head of a pmap list */
284
285/*
286 * the pmap structure
287 *
288 * note that the pm_obj contains the reference count,
289 * page list, and number of PTPs within the pmap.
290 */
291
292#define PMAP_TYPE_NORMAL1 1
293#define PMAP_TYPE_EPT2 2
294#define PMAP_TYPE_RVI3 3
295#define pmap_nested(pm)((pm)->pm_type != 1) ((pm)->pm_type != PMAP_TYPE_NORMAL1)
296
297struct pmap {
298 struct mutex pm_mtx;
299 struct uvm_object pm_obj[PTP_LEVELS4-1]; /* objects for lvl >= 1) */
300 LIST_ENTRY(pmap)struct { struct pmap *le_next; struct pmap **le_prev; } pm_list; /* list (lck by pm_list lock) */
301 /*
302 * pm_pdir : VA of page table to be used when executing in
303 * privileged mode
304 * pm_pdirpa : PA of page table to be used when executing in
305 * privileged mode
306 * pm_pdir_intel : VA of special page table to be used when executing
307 * on an Intel CPU in usermode (no kernel mappings)
308 * pm_pdirpa_intel : PA of special page table to be used when executing
309 * on an Intel CPU in usermode (no kernel mappings)
310 */
311 pd_entry_t *pm_pdir, *pm_pdir_intel;
312 paddr_t pm_pdirpa, pm_pdirpa_intel;
313
314 struct vm_page *pm_ptphint[PTP_LEVELS4-1];
315 /* pointer to a PTP in our pmap */
316 struct pmap_statistics pm_stats; /* pmap stats (lck by object lock) */
317
318 int pm_type; /* Type of pmap this is (PMAP_TYPE_x) */
319 uint64_t eptp; /* cached EPTP (used by vmm) */
320};
321
322#define PMAP_EFI0x00000040 PMAP_MD00x00000040
323
324/*
325 * MD flags that we use for pmap_enter (in the pa):
326 */
327#define PMAP_PA_MASK~((paddr_t)((1 << 12) - 1)) ~((paddr_t)PAGE_MASK((1 << 12) - 1)) /* to remove the flags */
328#define PMAP_NOCACHE0x1 0x1 /* set the non-cacheable bit. */
329#define PMAP_WC0x2 0x2 /* set page write combining. */
330
331/*
332 * We keep mod/ref flags in struct vm_page->pg_flags.
333 */
334#define PG_PMAP_MOD0x01000000 PG_PMAP00x01000000
335#define PG_PMAP_REF0x02000000 PG_PMAP10x02000000
336#define PG_PMAP_WC0x04000000 PG_PMAP20x04000000
337
338/*
339 * for each managed physical page we maintain a list of <PMAP,VA>'s
340 * which it is mapped at.
341 */
342struct pv_entry { /* locked by its list's pvh_lock */
343 struct pv_entry *pv_next; /* next entry */
344 struct pmap *pv_pmap; /* the pmap */
345 vaddr_t pv_va; /* the virtual address */
346 struct vm_page *pv_ptp; /* the vm_page of the PTP */
347};
348
349/*
350 * global kernel variables
351 */
352
353extern struct pmap kernel_pmap_store; /* kernel pmap */
354
355extern long nkptp[];
356
357extern const paddr_t ptp_masks[];
358extern const int ptp_shifts[];
359extern const long nbpd[], nkptpmax[];
360
361/*
362 * macros
363 */
364
365#define pmap_kernel()(&kernel_pmap_store) (&kernel_pmap_store)
366#define pmap_resident_count(pmap)((pmap)->pm_stats.resident_count) ((pmap)->pm_stats.resident_count)
367#define pmap_wired_count(pmap)((pmap)->pm_stats.wired_count) ((pmap)->pm_stats.wired_count)
368#define pmap_update(pmap) /* nothing (yet) */
369
370#define pmap_clear_modify(pg)pmap_clear_attrs(pg, 0x0000000000000040UL) pmap_clear_attrs(pg, PG_M0x0000000000000040UL)
371#define pmap_clear_reference(pg)pmap_clear_attrs(pg, 0x0000000000000020UL) pmap_clear_attrs(pg, PG_U0x0000000000000020UL)
372#define pmap_is_modified(pg)pmap_test_attrs(pg, 0x0000000000000040UL) pmap_test_attrs(pg, PG_M0x0000000000000040UL)
373#define pmap_is_referenced(pg)pmap_test_attrs(pg, 0x0000000000000020UL) pmap_test_attrs(pg, PG_U0x0000000000000020UL)
374#define pmap_move(DP,SP,D,L,S)
375#define pmap_valid_entry(E)((E) & 0x0000000000000001UL) ((E) & PG_V0x0000000000000001UL) /* is PDE or PTE valid? */
376
377#define pmap_proc_iflush(p,va,len) /* nothing */
378#define pmap_unuse_final(p) /* nothing */
379#define pmap_remove_holes(vm)do { } while (0) do { /* nothing */ } while (0)
380
381
382/*
383 * prototypes
384 */
385
386void map_tramps(void); /* machdep.c */
387paddr_t pmap_bootstrap(paddr_t, paddr_t);
388void pmap_init_percpu(void);
389void pmap_randomize(void);
390void pmap_randomize_level(pd_entry_t *, int);
391int pmap_clear_attrs(struct vm_page *, unsigned long);
392static void pmap_page_protect(struct vm_page *, vm_prot_t);
393void pmap_page_remove (struct vm_page *);
394static void pmap_protect(struct pmap *, vaddr_t,
395 vaddr_t, vm_prot_t);
396void pmap_remove(struct pmap *, vaddr_t, vaddr_t);
397int pmap_test_attrs(struct vm_page *, unsigned);
398static void pmap_update_pg(vaddr_t);
399void pmap_write_protect(struct pmap *, vaddr_t,
400 vaddr_t, vm_prot_t);
401void pmap_fix_ept(struct pmap *, vaddr_t);
402
403paddr_t pmap_prealloc_lowmem_ptps(paddr_t);
404
405void pagezero(vaddr_t);
406
407void pmap_convert(struct pmap *, int);
408void pmap_enter_special(vaddr_t, paddr_t, vm_prot_t);
409vaddr_t pmap_set_pml4_early(paddr_t pa);
410void pmap_clear_pml4_early(void);
411
412/*
413 * functions for flushing the cache for vaddrs and pages.
414 * these functions are not part of the MI pmap interface and thus
415 * should not be used as such.
416 */
417void pmap_flush_cache(vaddr_t, vsize_t);
418#define pmap_flush_page(paddr)do { ((void)0); pmap_flush_cache(((vaddr_t)(((((511 - 4) * (1ULL
<< 39))) | 0xffff000000000000)) + (paddr)), (1 <<
12)); } while ( 0)
do { \
419 KDASSERT(PHYS_TO_VM_PAGE(paddr) != NULL)((void)0); \
420 pmap_flush_cache(PMAP_DIRECT_MAP(paddr)((vaddr_t)(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000
)) + (paddr))
, PAGE_SIZE(1 << 12)); \
421} while (/* CONSTCOND */ 0)
422
423#define PMAP_CHECK_COPYIN(pg_xo == 0) (pg_xo == 0)
424
425#define PMAP_STEAL_MEMORY /* enable pmap_steal_memory() */
426#define PMAP_GROWKERNEL /* turn on pmap_growkernel interface */
427
428/*
429 * inline functions
430 */
431
432static inline void
433pmap_remove_all(struct pmap *pmap)
434{
435 /* Nothing. */
436}
437
438/*
439 * pmap_update_pg: flush one page from the TLB (or flush the whole thing
440 * if hardware doesn't support one-page flushing)
441 */
442
443static inline void
444pmap_update_pg(vaddr_t va)
445{
446 invlpg(va);
447}
448
449/*
450 * pmap_page_protect: change the protection of all recorded mappings
451 * of a managed page
452 *
453 * => this function is a frontend for pmap_page_remove/pmap_clear_attrs
454 * => we only have to worry about making the page more protected.
455 * unprotecting a page is done on-demand at fault time.
456 */
457
458static inline void
459pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
460{
461 if (prot
13.1
'prot' is not equal to PROT_READ
13.1
'prot' is not equal to PROT_READ
== PROT_READ0x01) {
462 (void) pmap_clear_attrs(pg, PG_RW0x0000000000000002UL);
463 } else {
464 KASSERT(prot == PROT_NONE)((prot == 0x00) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj/machine/pmap.h"
, 464, "prot == PROT_NONE"))
;
14
Taking false branch
15
'?' condition is true
465 pmap_page_remove(pg);
16
Value assigned to field 'uobject'
466 }
467}
468
469/*
470 * pmap_protect: change the protection of pages in a pmap
471 *
472 * => this function is a frontend for pmap_remove/pmap_write_protect
473 * => we only have to worry about making the page more protected.
474 * unprotecting a page is done on-demand at fault time.
475 */
476
477static inline void
478pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
479{
480 if (prot != PROT_NONE0x00) {
481 pmap_write_protect(pmap, sva, eva, prot);
482 } else {
483 pmap_remove(pmap, sva, eva);
484 }
485}
486
487/*
488 * various address inlines
489 *
490 * vtopte: return a pointer to the PTE mapping a VA, works only for
491 * user and PT addresses
492 *
493 * kvtopte: return a pointer to the PTE mapping a kernel VA
494 */
495
496static inline pt_entry_t *
497vtopte(vaddr_t va)
498{
499 return (PTE_BASE((pt_entry_t *) (255 * (1ULL << 39))) + pl1_i(va)(((((va) & ~0xffff000000000000)) & (((0x0000ff8000000000UL
|0x0000007fc0000000UL)|0x000000003fe00000UL)|0x00000000001ff000UL
)) >> 12)
);
500}
501
502static inline pt_entry_t *
503kvtopte(vaddr_t va)
504{
505#ifdef LARGEPAGES
506 {
507 pd_entry_t *pde;
508
509 pde = L1_BASE((pt_entry_t *) (255 * (1ULL << 39))) + pl2_i(va)(((((va) & ~0xffff000000000000)) & ((0x0000ff8000000000UL
|0x0000007fc0000000UL)|0x000000003fe00000UL)) >> 21)
;
510 if (*pde & PG_PS0x0000000000000080UL)
511 return ((pt_entry_t *)pde);
512 }
513#endif
514
515 return (PTE_BASE((pt_entry_t *) (255 * (1ULL << 39))) + pl1_i(va)(((((va) & ~0xffff000000000000)) & (((0x0000ff8000000000UL
|0x0000007fc0000000UL)|0x000000003fe00000UL)|0x00000000001ff000UL
)) >> 12)
);
516}
517
518#define PMAP_DIRECT_MAP(pa)((vaddr_t)(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000
)) + (pa))
((vaddr_t)PMAP_DIRECT_BASE(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000)) + (pa))
519#define PMAP_DIRECT_UNMAP(va)((paddr_t)(va) - (((((511 - 4) * (1ULL << 39))) | 0xffff000000000000
)))
((paddr_t)(va) - PMAP_DIRECT_BASE(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000)))
520#define pmap_map_direct(pg)((vaddr_t)(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000
)) + (((pg)->phys_addr)))
PMAP_DIRECT_MAP(VM_PAGE_TO_PHYS(pg))((vaddr_t)(((((511 - 4) * (1ULL << 39))) | 0xffff000000000000
)) + (((pg)->phys_addr)))
521#define pmap_unmap_direct(va)PHYS_TO_VM_PAGE(((paddr_t)(va) - (((((511 - 4) * (1ULL <<
39))) | 0xffff000000000000))))
PHYS_TO_VM_PAGE(PMAP_DIRECT_UNMAP(va)((paddr_t)(va) - (((((511 - 4) * (1ULL << 39))) | 0xffff000000000000
)))
)
522
523#define __HAVE_PMAP_DIRECT
524#define __HAVE_PMAP_MPSAFE_ENTER_COW
525
526#endif /* _KERNEL && !_LOCORE */
527
528#ifndef _LOCORE
529struct pv_entry;
530struct vm_page_md {
531 struct mutex pv_mtx;
532 struct pv_entry *pv_list;
533};
534
535#define VM_MDPAGE_INIT(pg)do { do { (void)(((void *)0)); (void)(0); __mtx_init((&(pg
)->mdpage.pv_mtx), ((((0xa)) > 0x0 && ((0xa)) <
0x9) ? 0x9 : ((0xa)))); } while (0); (pg)->mdpage.pv_list
= ((void *)0); } while (0)
do { \
536 mtx_init(&(pg)->mdpage.pv_mtx, IPL_VM)do { (void)(((void *)0)); (void)(0); __mtx_init((&(pg)->
mdpage.pv_mtx), ((((0xa)) > 0x0 && ((0xa)) < 0x9
) ? 0x9 : ((0xa)))); } while (0)
; \
537 (pg)->mdpage.pv_list = NULL((void *)0); \
538} while (0)
539#endif /* !_LOCORE */
540
541#endif /* _MACHINE_PMAP_H_ */