1 1.20 tnn /* $NetBSD: uvm_physseg.c,v 1.20 2024/01/13 09:44:42 tnn Exp $ */ 2 1.1 cherry 3 1.1 cherry /* 4 1.1 cherry * Copyright (c) 1997 Charles D. Cranor and Washington University. 5 1.1 cherry * Copyright (c) 1991, 1993, The Regents of the University of California. 6 1.1 cherry * 7 1.1 cherry * All rights reserved. 8 1.1 cherry * 9 1.1 cherry * This code is derived from software contributed to Berkeley by 10 1.1 cherry * The Mach Operating System project at Carnegie-Mellon University. 11 1.1 cherry * 12 1.1 cherry * Redistribution and use in source and binary forms, with or without 13 1.1 cherry * modification, are permitted provided that the following conditions 14 1.1 cherry * are met: 15 1.1 cherry * 1. Redistributions of source code must retain the above copyright 16 1.1 cherry * notice, this list of conditions and the following disclaimer. 17 1.1 cherry * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 cherry * notice, this list of conditions and the following disclaimer in the 19 1.1 cherry * documentation and/or other materials provided with the distribution. 20 1.1 cherry * 3. Neither the name of the University nor the names of its contributors 21 1.1 cherry * may be used to endorse or promote products derived from this software 22 1.1 cherry * without specific prior written permission. 23 1.1 cherry * 24 1.1 cherry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.1 cherry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.1 cherry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.1 cherry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.1 cherry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.1 cherry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.1 cherry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 cherry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 cherry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 cherry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 cherry * SUCH DAMAGE. 35 1.1 cherry * 36 1.1 cherry * @(#)vm_page.h 7.3 (Berkeley) 4/21/91 37 1.1 cherry * from: Id: uvm_page.h,v 1.1.2.6 1998/02/04 02:31:42 chuck Exp 38 1.1 cherry * 39 1.1 cherry * 40 1.1 cherry * Copyright (c) 1987, 1990 Carnegie-Mellon University. 41 1.1 cherry * All rights reserved. 42 1.1 cherry * 43 1.1 cherry * Permission to use, copy, modify and distribute this software and 44 1.1 cherry * its documentation is hereby granted, provided that both the copyright 45 1.1 cherry * notice and this permission notice appear in all copies of the 46 1.1 cherry * software, derivative works or modified versions, and any portions 47 1.1 cherry * thereof, and that both notices appear in supporting documentation. 48 1.1 cherry * 49 1.1 cherry * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 50 1.1 cherry * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 51 1.1 cherry * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 52 1.1 cherry * 53 1.1 cherry * Carnegie Mellon requests users of this software to return to 54 1.1 cherry * 55 1.1 cherry * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 56 1.1 cherry * School of Computer Science 57 1.1 cherry * Carnegie Mellon University 58 1.1 cherry * Pittsburgh PA 15213-3890 59 1.1 cherry * 60 1.1 cherry * any improvements or extensions that they make and grant Carnegie the 61 1.1 cherry * rights to redistribute these changes. 62 1.1 cherry */ 63 1.1 cherry 64 1.1 cherry /* 65 1.1 cherry * Consolidated API from uvm_page.c and others. 66 1.1 cherry * Consolidated and designed by Cherry G. Mathew <cherry (at) zyx.in> 67 1.1 cherry * rbtree(3) backing implementation by: 68 1.1 cherry * Santhosh N. Raju <santhosh.raju (at) gmail.com> 69 1.1 cherry */ 70 1.1 cherry 71 1.1 cherry #ifdef _KERNEL_OPT 72 1.1 cherry #include "opt_uvm.h" 73 1.1 cherry #endif 74 1.1 cherry 75 1.1 cherry #include <sys/param.h> 76 1.1 cherry #include <sys/types.h> 77 1.1 cherry #include <sys/extent.h> 78 1.1 cherry #include <sys/kmem.h> 79 1.1 cherry 80 1.1 cherry #include <uvm/uvm.h> 81 1.1 cherry #include <uvm/uvm_page.h> 82 1.1 cherry #include <uvm/uvm_param.h> 83 1.1 cherry #include <uvm/uvm_pdpolicy.h> 84 1.1 cherry #include <uvm/uvm_physseg.h> 85 1.1 cherry 86 1.1 cherry /* 87 1.1 cherry * uvm_physseg: describes one segment of physical memory 88 1.1 cherry */ 89 1.1 cherry struct uvm_physseg { 90 1.14 ad /* used during RB tree lookup for PHYS_TO_VM_PAGE(). */ 91 1.19 ad #if defined(UVM_HOTPLUG) 92 1.1 cherry struct rb_node rb_node; /* tree information */ 93 1.19 ad #endif 94 1.1 cherry paddr_t start; /* PF# of first page in segment */ 95 1.1 cherry paddr_t end; /* (PF# of last page in segment) + 1 */ 96 1.14 ad struct vm_page *pgs; /* vm_page structures (from start) */ 97 1.14 ad 98 1.14 ad /* less performance sensitive fields. */ 99 1.1 cherry paddr_t avail_start; /* PF# of first free page in segment */ 100 1.1 cherry paddr_t avail_end; /* (PF# of last free page in segment) +1 */ 101 1.1 cherry struct extent *ext; /* extent(9) structure to manage pgs[] */ 102 1.1 cherry int free_list; /* which free list they belong on */ 103 1.20 tnn u_long start_hint; /* start looking for free pages here */ 104 1.1 cherry #ifdef __HAVE_PMAP_PHYSSEG 105 1.1 cherry struct pmap_physseg pmseg; /* pmap specific (MD) data */ 106 1.1 cherry #endif 107 1.1 cherry }; 108 1.1 cherry 109 1.1 cherry /* 110 1.1 cherry * These functions are reserved for uvm(9) internal use and are not 111 1.1 cherry * exported in the header file uvm_physseg.h 112 1.1 cherry * 113 1.1 cherry * Thus they are redefined here. 114 1.1 cherry */ 115 1.1 cherry void uvm_physseg_init_seg(uvm_physseg_t, struct vm_page *); 116 1.1 cherry void uvm_physseg_seg_chomp_slab(uvm_physseg_t, struct vm_page *, size_t); 117 1.1 cherry 118 1.1 cherry /* returns a pgs array */ 119 1.1 cherry struct vm_page *uvm_physseg_seg_alloc_from_slab(uvm_physseg_t, size_t); 120 1.1 cherry 121 1.1 cherry #if defined(UVM_HOTPLUG) /* rbtree impementation */ 122 1.1 cherry 123 1.1 cherry #define HANDLE_TO_PHYSSEG_NODE(h) ((struct uvm_physseg *)(h)) 124 1.1 cherry #define PHYSSEG_NODE_TO_HANDLE(u) ((uvm_physseg_t)(u)) 125 1.1 cherry 126 1.1 cherry struct uvm_physseg_graph { 127 1.1 cherry struct rb_tree rb_tree; /* Tree for entries */ 128 1.1 cherry int nentries; /* Number of entries */ 129 1.14 ad } __aligned(COHERENCY_UNIT); 130 1.1 cherry 131 1.14 ad static struct uvm_physseg_graph uvm_physseg_graph __read_mostly; 132 1.1 cherry 133 1.1 cherry /* 134 1.1 cherry * Note on kmem(9) allocator usage: 135 1.1 cherry * We take the conservative approach that plug/unplug are allowed to 136 1.1 cherry * fail in high memory stress situations. 137 1.1 cherry * 138 1.1 cherry * We want to avoid re-entrant situations in which one plug/unplug 139 1.1 cherry * operation is waiting on a previous one to complete, since this 140 1.1 cherry * makes the design more complicated than necessary. 141 1.1 cherry * 142 1.1 cherry * We may review this and change its behaviour, once the use cases 143 1.1 cherry * become more obvious. 144 1.1 cherry */ 145 1.1 cherry 146 1.1 cherry /* 147 1.1 cherry * Special alloc()/free() functions for boot time support: 148 1.1 cherry * We assume that alloc() at boot time is only for new 'vm_physseg's 149 1.1 cherry * This allows us to use a static array for memory allocation at boot 150 1.1 cherry * time. Thus we avoid using kmem(9) which is not ready at this point 151 1.1 cherry * in boot. 152 1.1 cherry * 153 1.1 cherry * After kmem(9) is ready, we use it. We currently discard any free()s 154 1.1 cherry * to this static array, since the size is small enough to be a 155 1.1 cherry * trivial waste on all architectures we run on. 156 1.1 cherry */ 157 1.1 cherry 158 1.1 cherry static size_t nseg = 0; 159 1.1 cherry static struct uvm_physseg uvm_physseg[VM_PHYSSEG_MAX]; 160 1.1 cherry 161 1.1 cherry static void * 162 1.1 cherry uvm_physseg_alloc(size_t sz) 163 1.1 cherry { 164 1.1 cherry /* 165 1.1 cherry * During boot time, we only support allocating vm_physseg 166 1.1 cherry * entries from the static array. 167 1.1 cherry * We need to assert for this. 168 1.1 cherry */ 169 1.1 cherry 170 1.1 cherry if (__predict_false(uvm.page_init_done == false)) { 171 1.1 cherry if (sz % sizeof(struct uvm_physseg)) 172 1.1 cherry panic("%s: tried to alloc size other than multiple" 173 1.7 uwe " of struct uvm_physseg at boot\n", __func__); 174 1.1 cherry 175 1.1 cherry size_t n = sz / sizeof(struct uvm_physseg); 176 1.1 cherry nseg += n; 177 1.1 cherry 178 1.18 riastrad KASSERT(nseg > 0); 179 1.18 riastrad KASSERT(nseg <= VM_PHYSSEG_MAX); 180 1.1 cherry 181 1.1 cherry return &uvm_physseg[nseg - n]; 182 1.1 cherry } 183 1.1 cherry 184 1.1 cherry return kmem_zalloc(sz, KM_NOSLEEP); 185 1.1 cherry } 186 1.1 cherry 187 1.1 cherry static void 188 1.1 cherry uvm_physseg_free(void *p, size_t sz) 189 1.1 cherry { 190 1.1 cherry /* 191 1.1 cherry * This is a bit tricky. We do allow simulation of free() 192 1.1 cherry * during boot (for eg: when MD code is "steal"ing memory, 193 1.1 cherry * and the segment has been exhausted (and thus needs to be 194 1.1 cherry * free() - ed. 195 1.1 cherry * free() also complicates things because we leak the 196 1.1 cherry * free(). Therefore calling code can't assume that free()-ed 197 1.1 cherry * memory is available for alloc() again, at boot time. 198 1.1 cherry * 199 1.1 cherry * Thus we can't explicitly disallow free()s during 200 1.1 cherry * boot time. However, the same restriction for alloc() 201 1.1 cherry * applies to free(). We only allow uvm_physseg related free()s 202 1.1 cherry * via this function during boot time. 203 1.1 cherry */ 204 1.1 cherry 205 1.1 cherry if (__predict_false(uvm.page_init_done == false)) { 206 1.1 cherry if (sz % sizeof(struct uvm_physseg)) 207 1.1 cherry panic("%s: tried to free size other than struct uvm_physseg" 208 1.7 uwe " at boot\n", __func__); 209 1.1 cherry 210 1.1 cherry } 211 1.1 cherry 212 1.1 cherry /* 213 1.1 cherry * Could have been in a single if(){} block - split for 214 1.1 cherry * clarity 215 1.1 cherry */ 216 1.1 cherry 217 1.1 cherry if ((struct uvm_physseg *)p >= uvm_physseg && 218 1.1 cherry (struct uvm_physseg *)p < (uvm_physseg + VM_PHYSSEG_MAX)) { 219 1.1 cherry if (sz % sizeof(struct uvm_physseg)) 220 1.1 cherry panic("%s: tried to free() other than struct uvm_physseg" 221 1.7 uwe " from static array\n", __func__); 222 1.1 cherry 223 1.1 cherry if ((sz / sizeof(struct uvm_physseg)) >= VM_PHYSSEG_MAX) 224 1.1 cherry panic("%s: tried to free() the entire static array!", __func__); 225 1.1 cherry return; /* Nothing to free */ 226 1.1 cherry } 227 1.1 cherry 228 1.1 cherry kmem_free(p, sz); 229 1.1 cherry } 230 1.1 cherry 231 1.1 cherry /* XXX: Multi page size */ 232 1.1 cherry bool 233 1.1 cherry uvm_physseg_plug(paddr_t pfn, size_t pages, uvm_physseg_t *psp) 234 1.1 cherry { 235 1.1 cherry int preload; 236 1.1 cherry size_t slabpages; 237 1.1 cherry struct uvm_physseg *ps, *current_ps = NULL; 238 1.1 cherry struct vm_page *slab = NULL, *pgs = NULL; 239 1.1 cherry 240 1.1 cherry #ifdef DEBUG 241 1.1 cherry paddr_t off; 242 1.1 cherry uvm_physseg_t upm; 243 1.1 cherry upm = uvm_physseg_find(pfn, &off); 244 1.1 cherry 245 1.1 cherry ps = HANDLE_TO_PHYSSEG_NODE(upm); 246 1.1 cherry 247 1.1 cherry if (ps != NULL) /* XXX; do we allow "update" plugs ? */ 248 1.1 cherry return false; 249 1.1 cherry #endif 250 1.1 cherry 251 1.1 cherry /* 252 1.1 cherry * do we have room? 253 1.1 cherry */ 254 1.1 cherry 255 1.1 cherry ps = uvm_physseg_alloc(sizeof (struct uvm_physseg)); 256 1.1 cherry if (ps == NULL) { 257 1.1 cherry printf("uvm_page_physload: unable to load physical memory " 258 1.1 cherry "segment\n"); 259 1.1 cherry printf("\t%d segments allocated, ignoring 0x%"PRIxPADDR" -> 0x%"PRIxPADDR"\n", 260 1.1 cherry VM_PHYSSEG_MAX, pfn, pfn + pages + 1); 261 1.1 cherry printf("\tincrease VM_PHYSSEG_MAX\n"); 262 1.1 cherry return false; 263 1.1 cherry } 264 1.1 cherry 265 1.1 cherry /* span init */ 266 1.1 cherry ps->start = pfn; 267 1.1 cherry ps->end = pfn + pages; 268 1.1 cherry 269 1.1 cherry /* 270 1.1 cherry * XXX: Ugly hack because uvmexp.npages accounts for only 271 1.1 cherry * those pages in the segment included below as well - this 272 1.1 cherry * should be legacy and removed. 273 1.1 cherry */ 274 1.1 cherry 275 1.1 cherry ps->avail_start = ps->start; 276 1.1 cherry ps->avail_end = ps->end; 277 1.1 cherry 278 1.1 cherry /* 279 1.1 cherry * check to see if this is a "preload" (i.e. uvm_page_init hasn't been 280 1.1 cherry * called yet, so kmem is not available). 281 1.1 cherry */ 282 1.1 cherry 283 1.1 cherry preload = 1; /* We are going to assume it is a preload */ 284 1.1 cherry 285 1.1 cherry RB_TREE_FOREACH(current_ps, &(uvm_physseg_graph.rb_tree)) { 286 1.1 cherry /* If there are non NULL pages then we are not in a preload */ 287 1.1 cherry if (current_ps->pgs != NULL) { 288 1.1 cherry preload = 0; 289 1.1 cherry /* Try to scavenge from earlier unplug()s. */ 290 1.1 cherry pgs = uvm_physseg_seg_alloc_from_slab(current_ps, pages); 291 1.1 cherry 292 1.1 cherry if (pgs != NULL) { 293 1.1 cherry break; 294 1.1 cherry } 295 1.1 cherry } 296 1.1 cherry } 297 1.1 cherry 298 1.1 cherry 299 1.1 cherry /* 300 1.1 cherry * if VM is already running, attempt to kmem_alloc vm_page structures 301 1.1 cherry */ 302 1.1 cherry 303 1.1 cherry if (!preload) { 304 1.1 cherry if (pgs == NULL) { /* Brand new */ 305 1.1 cherry /* Iteratively try alloc down from uvmexp.npages */ 306 1.1 cherry for (slabpages = (size_t) uvmexp.npages; slabpages >= pages; slabpages--) { 307 1.1 cherry slab = kmem_zalloc(sizeof *pgs * (long unsigned int)slabpages, KM_NOSLEEP); 308 1.1 cherry if (slab != NULL) 309 1.1 cherry break; 310 1.1 cherry } 311 1.1 cherry 312 1.1 cherry if (slab == NULL) { 313 1.1 cherry uvm_physseg_free(ps, sizeof(struct uvm_physseg)); 314 1.1 cherry return false; 315 1.1 cherry } 316 1.1 cherry 317 1.1 cherry uvm_physseg_seg_chomp_slab(ps, slab, (size_t) slabpages); 318 1.1 cherry /* We allocate enough for this plug */ 319 1.1 cherry pgs = uvm_physseg_seg_alloc_from_slab(ps, pages); 320 1.1 cherry 321 1.1 cherry if (pgs == NULL) { 322 1.1 cherry printf("unable to uvm_physseg_seg_alloc_from_slab() from backend\n"); 323 1.1 cherry return false; 324 1.1 cherry } 325 1.1 cherry } else { 326 1.1 cherry /* Reuse scavenged extent */ 327 1.1 cherry ps->ext = current_ps->ext; 328 1.1 cherry } 329 1.1 cherry 330 1.1 cherry physmem += pages; 331 1.1 cherry uvmpdpol_reinit(); 332 1.1 cherry } else { /* Boot time - see uvm_page.c:uvm_page_init() */ 333 1.1 cherry pgs = NULL; 334 1.1 cherry ps->pgs = pgs; 335 1.1 cherry } 336 1.1 cherry 337 1.1 cherry /* 338 1.1 cherry * now insert us in the proper place in uvm_physseg_graph.rb_tree 339 1.1 cherry */ 340 1.1 cherry 341 1.1 cherry current_ps = rb_tree_insert_node(&(uvm_physseg_graph.rb_tree), ps); 342 1.1 cherry if (current_ps != ps) { 343 1.1 cherry panic("uvm_page_physload: Duplicate address range detected!"); 344 1.1 cherry } 345 1.1 cherry uvm_physseg_graph.nentries++; 346 1.1 cherry 347 1.1 cherry /* 348 1.1 cherry * uvm_pagefree() requires the PHYS_TO_VM_PAGE(pgs[i]) on the 349 1.1 cherry * newly allocated pgs[] to return the correct value. This is 350 1.1 cherry * a bit of a chicken and egg problem, since it needs 351 1.1 cherry * uvm_physseg_find() to succeed. For this, the node needs to 352 1.1 cherry * be inserted *before* uvm_physseg_init_seg() happens. 353 1.1 cherry * 354 1.1 cherry * During boot, this happens anyway, since 355 1.1 cherry * uvm_physseg_init_seg() is called later on and separately 356 1.1 cherry * from uvm_page.c:uvm_page_init(). 357 1.1 cherry * In the case of hotplug we need to ensure this. 358 1.1 cherry */ 359 1.1 cherry 360 1.1 cherry if (__predict_true(!preload)) 361 1.1 cherry uvm_physseg_init_seg(ps, pgs); 362 1.1 cherry 363 1.1 cherry if (psp != NULL) 364 1.1 cherry *psp = ps; 365 1.1 cherry 366 1.1 cherry return true; 367 1.1 cherry } 368 1.1 cherry 369 1.1 cherry static int 370 1.1 cherry uvm_physseg_compare_nodes(void *ctx, const void *nnode1, const void *nnode2) 371 1.1 cherry { 372 1.1 cherry const struct uvm_physseg *enode1 = nnode1; 373 1.1 cherry const struct uvm_physseg *enode2 = nnode2; 374 1.1 cherry 375 1.1 cherry KASSERT(enode1->start < enode2->start || enode1->start >= enode2->end); 376 1.1 cherry KASSERT(enode2->start < enode1->start || enode2->start >= enode1->end); 377 1.1 cherry 378 1.1 cherry if (enode1->start < enode2->start) 379 1.1 cherry return -1; 380 1.1 cherry if (enode1->start >= enode2->end) 381 1.1 cherry return 1; 382 1.1 cherry return 0; 383 1.1 cherry } 384 1.1 cherry 385 1.1 cherry static int 386 1.1 cherry uvm_physseg_compare_key(void *ctx, const void *nnode, const void *pkey) 387 1.1 cherry { 388 1.1 cherry const struct uvm_physseg *enode = nnode; 389 1.1 cherry const paddr_t pa = *(const paddr_t *) pkey; 390 1.1 cherry 391 1.1 cherry if(enode->start <= pa && pa < enode->end) 392 1.1 cherry return 0; 393 1.1 cherry if (enode->start < pa) 394 1.1 cherry return -1; 395 1.1 cherry if (enode->end > pa) 396 1.1 cherry return 1; 397 1.1 cherry 398 1.1 cherry return 0; 399 1.1 cherry } 400 1.1 cherry 401 1.1 cherry static const rb_tree_ops_t uvm_physseg_tree_ops = { 402 1.1 cherry .rbto_compare_nodes = uvm_physseg_compare_nodes, 403 1.1 cherry .rbto_compare_key = uvm_physseg_compare_key, 404 1.1 cherry .rbto_node_offset = offsetof(struct uvm_physseg, rb_node), 405 1.1 cherry .rbto_context = NULL 406 1.1 cherry }; 407 1.1 cherry 408 1.1 cherry /* 409 1.1 cherry * uvm_physseg_init: init the physmem 410 1.1 cherry * 411 1.1 cherry * => physmem unit should not be in use at this point 412 1.1 cherry */ 413 1.1 cherry 414 1.1 cherry void 415 1.1 cherry uvm_physseg_init(void) 416 1.1 cherry { 417 1.1 cherry rb_tree_init(&(uvm_physseg_graph.rb_tree), &uvm_physseg_tree_ops); 418 1.1 cherry uvm_physseg_graph.nentries = 0; 419 1.1 cherry } 420 1.1 cherry 421 1.1 cherry uvm_physseg_t 422 1.1 cherry uvm_physseg_get_next(uvm_physseg_t upm) 423 1.1 cherry { 424 1.1 cherry /* next of invalid is invalid, not fatal */ 425 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 426 1.1 cherry return UVM_PHYSSEG_TYPE_INVALID; 427 1.1 cherry 428 1.1 cherry return (uvm_physseg_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm, 429 1.1 cherry RB_DIR_RIGHT); 430 1.1 cherry } 431 1.1 cherry 432 1.1 cherry uvm_physseg_t 433 1.1 cherry uvm_physseg_get_prev(uvm_physseg_t upm) 434 1.1 cherry { 435 1.1 cherry /* prev of invalid is invalid, not fatal */ 436 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 437 1.1 cherry return UVM_PHYSSEG_TYPE_INVALID; 438 1.1 cherry 439 1.1 cherry return (uvm_physseg_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm, 440 1.1 cherry RB_DIR_LEFT); 441 1.1 cherry } 442 1.1 cherry 443 1.1 cherry uvm_physseg_t 444 1.1 cherry uvm_physseg_get_last(void) 445 1.1 cherry { 446 1.1 cherry return (uvm_physseg_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree)); 447 1.1 cherry } 448 1.1 cherry 449 1.1 cherry uvm_physseg_t 450 1.1 cherry uvm_physseg_get_first(void) 451 1.1 cherry { 452 1.1 cherry return (uvm_physseg_t) RB_TREE_MIN(&(uvm_physseg_graph.rb_tree)); 453 1.1 cherry } 454 1.1 cherry 455 1.1 cherry paddr_t 456 1.1 cherry uvm_physseg_get_highest_frame(void) 457 1.1 cherry { 458 1.1 cherry struct uvm_physseg *ps = 459 1.1 cherry (uvm_physseg_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree)); 460 1.1 cherry 461 1.1 cherry return ps->end - 1; 462 1.1 cherry } 463 1.1 cherry 464 1.1 cherry /* 465 1.1 cherry * uvm_page_physunload: unload physical memory and return it to 466 1.1 cherry * caller. 467 1.1 cherry */ 468 1.1 cherry bool 469 1.1 cherry uvm_page_physunload(uvm_physseg_t upm, int freelist, paddr_t *paddrp) 470 1.1 cherry { 471 1.1 cherry struct uvm_physseg *seg; 472 1.1 cherry 473 1.1 cherry if (__predict_true(uvm.page_init_done == true)) 474 1.1 cherry panic("%s: unload attempted after uvm_page_init()\n", __func__); 475 1.1 cherry 476 1.1 cherry seg = HANDLE_TO_PHYSSEG_NODE(upm); 477 1.1 cherry 478 1.1 cherry if (seg->free_list != freelist) { 479 1.1 cherry return false; 480 1.1 cherry } 481 1.1 cherry 482 1.1 cherry /* 483 1.1 cherry * During cold boot, what we're about to unplug hasn't been 484 1.1 cherry * put on the uvm freelist, nor has uvmexp.npages been 485 1.1 cherry * updated. (This happens in uvm_page.c:uvm_page_init()) 486 1.1 cherry * 487 1.1 cherry * For hotplug, we assume here that the pages being unloaded 488 1.1 cherry * here are completely out of sight of uvm (ie; not on any uvm 489 1.1 cherry * lists), and that uvmexp.npages has been suitably 490 1.1 cherry * decremented before we're called. 491 1.1 cherry * 492 1.1 cherry * XXX: will avail_end == start if avail_start < avail_end? 493 1.1 cherry */ 494 1.1 cherry 495 1.1 cherry /* try from front */ 496 1.1 cherry if (seg->avail_start == seg->start && 497 1.1 cherry seg->avail_start < seg->avail_end) { 498 1.1 cherry *paddrp = ctob(seg->avail_start); 499 1.1 cherry return uvm_physseg_unplug(seg->avail_start, 1); 500 1.1 cherry } 501 1.1 cherry 502 1.1 cherry /* try from rear */ 503 1.1 cherry if (seg->avail_end == seg->end && 504 1.1 cherry seg->avail_start < seg->avail_end) { 505 1.1 cherry *paddrp = ctob(seg->avail_end - 1); 506 1.1 cherry return uvm_physseg_unplug(seg->avail_end - 1, 1); 507 1.1 cherry } 508 1.1 cherry 509 1.1 cherry return false; 510 1.1 cherry } 511 1.1 cherry 512 1.1 cherry bool 513 1.1 cherry uvm_page_physunload_force(uvm_physseg_t upm, int freelist, paddr_t *paddrp) 514 1.1 cherry { 515 1.1 cherry struct uvm_physseg *seg; 516 1.1 cherry 517 1.1 cherry seg = HANDLE_TO_PHYSSEG_NODE(upm); 518 1.1 cherry 519 1.1 cherry if (__predict_true(uvm.page_init_done == true)) 520 1.1 cherry panic("%s: unload attempted after uvm_page_init()\n", __func__); 521 1.1 cherry /* any room in this bank? */ 522 1.1 cherry if (seg->avail_start >= seg->avail_end) { 523 1.1 cherry return false; /* nope */ 524 1.1 cherry } 525 1.1 cherry 526 1.1 cherry *paddrp = ctob(seg->avail_start); 527 1.1 cherry 528 1.1 cherry /* Always unplug from front */ 529 1.1 cherry return uvm_physseg_unplug(seg->avail_start, 1); 530 1.1 cherry } 531 1.1 cherry 532 1.1 cherry 533 1.1 cherry /* 534 1.1 cherry * vm_physseg_find: find vm_physseg structure that belongs to a PA 535 1.1 cherry */ 536 1.1 cherry uvm_physseg_t 537 1.1 cherry uvm_physseg_find(paddr_t pframe, psize_t *offp) 538 1.1 cherry { 539 1.1 cherry struct uvm_physseg * ps = NULL; 540 1.1 cherry 541 1.1 cherry ps = rb_tree_find_node(&(uvm_physseg_graph.rb_tree), &pframe); 542 1.1 cherry 543 1.1 cherry if(ps != NULL && offp != NULL) 544 1.1 cherry *offp = pframe - ps->start; 545 1.1 cherry 546 1.1 cherry return ps; 547 1.1 cherry } 548 1.1 cherry 549 1.1 cherry #else /* UVM_HOTPLUG */ 550 1.1 cherry 551 1.1 cherry /* 552 1.1 cherry * physical memory config is stored in vm_physmem. 553 1.1 cherry */ 554 1.1 cherry 555 1.1 cherry #define VM_PHYSMEM_PTR(i) (&vm_physmem[i]) 556 1.1 cherry #if VM_PHYSSEG_MAX == 1 557 1.1 cherry #define VM_PHYSMEM_PTR_SWAP(i, j) /* impossible */ 558 1.1 cherry #else 559 1.1 cherry #define VM_PHYSMEM_PTR_SWAP(i, j) \ 560 1.1 cherry do { vm_physmem[(i)] = vm_physmem[(j)]; } while (0) 561 1.1 cherry #endif 562 1.1 cherry 563 1.1 cherry #define HANDLE_TO_PHYSSEG_NODE(h) (VM_PHYSMEM_PTR((int)h)) 564 1.1 cherry #define PHYSSEG_NODE_TO_HANDLE(u) ((int)((vsize_t) (u - vm_physmem) / sizeof(struct uvm_physseg))) 565 1.1 cherry 566 1.19 ad /* XXXCDC: uvm.physmem */ 567 1.19 ad static struct uvm_physseg vm_physmem[VM_PHYSSEG_MAX] __read_mostly; 568 1.19 ad /* XXXCDC: uvm.nphysseg */ 569 1.19 ad static int vm_nphysseg __read_mostly = 0; 570 1.1 cherry #define vm_nphysmem vm_nphysseg 571 1.1 cherry 572 1.1 cherry void 573 1.1 cherry uvm_physseg_init(void) 574 1.1 cherry { 575 1.1 cherry /* XXX: Provisioning for rb_tree related init(s) */ 576 1.1 cherry return; 577 1.1 cherry } 578 1.1 cherry 579 1.1 cherry int 580 1.1 cherry uvm_physseg_get_next(uvm_physseg_t lcv) 581 1.1 cherry { 582 1.1 cherry /* next of invalid is invalid, not fatal */ 583 1.2 cherry if (uvm_physseg_valid_p(lcv) == false) 584 1.1 cherry return UVM_PHYSSEG_TYPE_INVALID; 585 1.1 cherry 586 1.1 cherry return (lcv + 1); 587 1.1 cherry } 588 1.1 cherry 589 1.1 cherry int 590 1.1 cherry uvm_physseg_get_prev(uvm_physseg_t lcv) 591 1.1 cherry { 592 1.1 cherry /* prev of invalid is invalid, not fatal */ 593 1.2 cherry if (uvm_physseg_valid_p(lcv) == false) 594 1.1 cherry return UVM_PHYSSEG_TYPE_INVALID; 595 1.1 cherry 596 1.1 cherry return (lcv - 1); 597 1.1 cherry } 598 1.1 cherry 599 1.1 cherry int 600 1.1 cherry uvm_physseg_get_last(void) 601 1.1 cherry { 602 1.1 cherry return (vm_nphysseg - 1); 603 1.1 cherry } 604 1.1 cherry 605 1.1 cherry int 606 1.1 cherry uvm_physseg_get_first(void) 607 1.1 cherry { 608 1.1 cherry return 0; 609 1.1 cherry } 610 1.1 cherry 611 1.1 cherry paddr_t 612 1.1 cherry uvm_physseg_get_highest_frame(void) 613 1.1 cherry { 614 1.1 cherry int lcv; 615 1.1 cherry paddr_t last = 0; 616 1.1 cherry struct uvm_physseg *ps; 617 1.1 cherry 618 1.1 cherry for (lcv = 0; lcv < vm_nphysseg; lcv++) { 619 1.1 cherry ps = VM_PHYSMEM_PTR(lcv); 620 1.1 cherry if (last < ps->end) 621 1.1 cherry last = ps->end; 622 1.1 cherry } 623 1.1 cherry 624 1.1 cherry return last; 625 1.1 cherry } 626 1.1 cherry 627 1.1 cherry 628 1.1 cherry static struct vm_page * 629 1.1 cherry uvm_post_preload_check(void) 630 1.1 cherry { 631 1.1 cherry int preload, lcv; 632 1.1 cherry 633 1.1 cherry /* 634 1.1 cherry * check to see if this is a "preload" (i.e. uvm_page_init hasn't been 635 1.1 cherry * called yet, so kmem is not available). 636 1.1 cherry */ 637 1.1 cherry 638 1.1 cherry for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) { 639 1.1 cherry if (VM_PHYSMEM_PTR(lcv)->pgs) 640 1.1 cherry break; 641 1.1 cherry } 642 1.1 cherry preload = (lcv == vm_nphysmem); 643 1.1 cherry 644 1.1 cherry /* 645 1.1 cherry * if VM is already running, attempt to kmem_alloc vm_page structures 646 1.1 cherry */ 647 1.1 cherry 648 1.1 cherry if (!preload) { 649 1.1 cherry panic("Tried to add RAM after uvm_page_init"); 650 1.1 cherry } 651 1.1 cherry 652 1.1 cherry return NULL; 653 1.1 cherry } 654 1.1 cherry 655 1.1 cherry /* 656 1.1 cherry * uvm_page_physunload: unload physical memory and return it to 657 1.1 cherry * caller. 658 1.1 cherry */ 659 1.1 cherry bool 660 1.1 cherry uvm_page_physunload(uvm_physseg_t psi, int freelist, paddr_t *paddrp) 661 1.1 cherry { 662 1.1 cherry int x; 663 1.1 cherry struct uvm_physseg *seg; 664 1.1 cherry 665 1.1 cherry uvm_post_preload_check(); 666 1.1 cherry 667 1.1 cherry seg = VM_PHYSMEM_PTR(psi); 668 1.1 cherry 669 1.1 cherry if (seg->free_list != freelist) { 670 1.1 cherry return false; 671 1.1 cherry } 672 1.1 cherry 673 1.1 cherry /* try from front */ 674 1.1 cherry if (seg->avail_start == seg->start && 675 1.1 cherry seg->avail_start < seg->avail_end) { 676 1.1 cherry *paddrp = ctob(seg->avail_start); 677 1.1 cherry seg->avail_start++; 678 1.1 cherry seg->start++; 679 1.1 cherry /* nothing left? nuke it */ 680 1.1 cherry if (seg->avail_start == seg->end) { 681 1.1 cherry if (vm_nphysmem == 1) 682 1.1 cherry panic("uvm_page_physget: out of memory!"); 683 1.1 cherry vm_nphysmem--; 684 1.1 cherry for (x = psi ; x < vm_nphysmem ; x++) 685 1.1 cherry /* structure copy */ 686 1.1 cherry VM_PHYSMEM_PTR_SWAP(x, x + 1); 687 1.1 cherry } 688 1.1 cherry return (true); 689 1.1 cherry } 690 1.1 cherry 691 1.1 cherry /* try from rear */ 692 1.1 cherry if (seg->avail_end == seg->end && 693 1.1 cherry seg->avail_start < seg->avail_end) { 694 1.1 cherry *paddrp = ctob(seg->avail_end - 1); 695 1.1 cherry seg->avail_end--; 696 1.1 cherry seg->end--; 697 1.1 cherry /* nothing left? nuke it */ 698 1.1 cherry if (seg->avail_end == seg->start) { 699 1.1 cherry if (vm_nphysmem == 1) 700 1.1 cherry panic("uvm_page_physget: out of memory!"); 701 1.1 cherry vm_nphysmem--; 702 1.1 cherry for (x = psi ; x < vm_nphysmem ; x++) 703 1.1 cherry /* structure copy */ 704 1.1 cherry VM_PHYSMEM_PTR_SWAP(x, x + 1); 705 1.1 cherry } 706 1.1 cherry return (true); 707 1.1 cherry } 708 1.1 cherry 709 1.1 cherry return false; 710 1.1 cherry } 711 1.1 cherry 712 1.1 cherry bool 713 1.1 cherry uvm_page_physunload_force(uvm_physseg_t psi, int freelist, paddr_t *paddrp) 714 1.1 cherry { 715 1.1 cherry int x; 716 1.1 cherry struct uvm_physseg *seg; 717 1.1 cherry 718 1.1 cherry uvm_post_preload_check(); 719 1.1 cherry 720 1.1 cherry seg = VM_PHYSMEM_PTR(psi); 721 1.1 cherry 722 1.1 cherry /* any room in this bank? */ 723 1.1 cherry if (seg->avail_start >= seg->avail_end) { 724 1.1 cherry return false; /* nope */ 725 1.1 cherry } 726 1.1 cherry 727 1.1 cherry *paddrp = ctob(seg->avail_start); 728 1.1 cherry seg->avail_start++; 729 1.1 cherry /* truncate! */ 730 1.1 cherry seg->start = seg->avail_start; 731 1.1 cherry 732 1.1 cherry /* nothing left? nuke it */ 733 1.1 cherry if (seg->avail_start == seg->end) { 734 1.1 cherry if (vm_nphysmem == 1) 735 1.1 cherry panic("uvm_page_physget: out of memory!"); 736 1.1 cherry vm_nphysmem--; 737 1.1 cherry for (x = psi ; x < vm_nphysmem ; x++) 738 1.1 cherry /* structure copy */ 739 1.1 cherry VM_PHYSMEM_PTR_SWAP(x, x + 1); 740 1.1 cherry } 741 1.1 cherry return (true); 742 1.1 cherry } 743 1.1 cherry 744 1.1 cherry bool 745 1.1 cherry uvm_physseg_plug(paddr_t pfn, size_t pages, uvm_physseg_t *psp) 746 1.1 cherry { 747 1.1 cherry int lcv; 748 1.1 cherry struct vm_page *pgs; 749 1.1 cherry struct uvm_physseg *ps; 750 1.1 cherry 751 1.1 cherry #ifdef DEBUG 752 1.1 cherry paddr_t off; 753 1.1 cherry uvm_physseg_t upm; 754 1.1 cherry upm = uvm_physseg_find(pfn, &off); 755 1.1 cherry 756 1.2 cherry if (uvm_physseg_valid_p(upm)) /* XXX; do we allow "update" plugs ? */ 757 1.1 cherry return false; 758 1.1 cherry #endif 759 1.1 cherry 760 1.1 cherry paddr_t start = pfn; 761 1.1 cherry paddr_t end = pfn + pages; 762 1.1 cherry paddr_t avail_start = start; 763 1.1 cherry paddr_t avail_end = end; 764 1.1 cherry 765 1.1 cherry if (uvmexp.pagesize == 0) 766 1.1 cherry panic("uvm_page_physload: page size not set!"); 767 1.1 cherry 768 1.1 cherry /* 769 1.1 cherry * do we have room? 770 1.1 cherry */ 771 1.1 cherry 772 1.1 cherry if (vm_nphysmem == VM_PHYSSEG_MAX) { 773 1.1 cherry printf("uvm_page_physload: unable to load physical memory " 774 1.1 cherry "segment\n"); 775 1.1 cherry printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n", 776 1.1 cherry VM_PHYSSEG_MAX, (long long)start, (long long)end); 777 1.1 cherry printf("\tincrease VM_PHYSSEG_MAX\n"); 778 1.1 cherry if (psp != NULL) 779 1.1 cherry *psp = UVM_PHYSSEG_TYPE_INVALID_OVERFLOW; 780 1.1 cherry return false; 781 1.1 cherry } 782 1.1 cherry 783 1.1 cherry /* 784 1.1 cherry * check to see if this is a "preload" (i.e. uvm_page_init hasn't been 785 1.1 cherry * called yet, so kmem is not available). 786 1.1 cherry */ 787 1.1 cherry pgs = uvm_post_preload_check(); 788 1.1 cherry 789 1.1 cherry /* 790 1.1 cherry * now insert us in the proper place in vm_physmem[] 791 1.1 cherry */ 792 1.1 cherry 793 1.1 cherry #if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM) 794 1.1 cherry /* random: put it at the end (easy!) */ 795 1.1 cherry ps = VM_PHYSMEM_PTR(vm_nphysmem); 796 1.3 cherry lcv = vm_nphysmem; 797 1.1 cherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) 798 1.1 cherry { 799 1.1 cherry int x; 800 1.1 cherry /* sort by address for binary search */ 801 1.1 cherry for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) 802 1.1 cherry if (start < VM_PHYSMEM_PTR(lcv)->start) 803 1.1 cherry break; 804 1.1 cherry ps = VM_PHYSMEM_PTR(lcv); 805 1.1 cherry /* move back other entries, if necessary ... */ 806 1.1 cherry for (x = vm_nphysmem ; x > lcv ; x--) 807 1.1 cherry /* structure copy */ 808 1.1 cherry VM_PHYSMEM_PTR_SWAP(x, x - 1); 809 1.1 cherry } 810 1.1 cherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST) 811 1.1 cherry { 812 1.1 cherry int x; 813 1.1 cherry /* sort by largest segment first */ 814 1.1 cherry for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) 815 1.1 cherry if ((end - start) > 816 1.1 cherry (VM_PHYSMEM_PTR(lcv)->end - VM_PHYSMEM_PTR(lcv)->start)) 817 1.1 cherry break; 818 1.1 cherry ps = VM_PHYSMEM_PTR(lcv); 819 1.1 cherry /* move back other entries, if necessary ... */ 820 1.1 cherry for (x = vm_nphysmem ; x > lcv ; x--) 821 1.1 cherry /* structure copy */ 822 1.1 cherry VM_PHYSMEM_PTR_SWAP(x, x - 1); 823 1.1 cherry } 824 1.1 cherry #else 825 1.1 cherry panic("uvm_page_physload: unknown physseg strategy selected!"); 826 1.1 cherry #endif 827 1.1 cherry 828 1.1 cherry ps->start = start; 829 1.1 cherry ps->end = end; 830 1.1 cherry ps->avail_start = avail_start; 831 1.1 cherry ps->avail_end = avail_end; 832 1.1 cherry 833 1.1 cherry ps->pgs = pgs; 834 1.1 cherry 835 1.1 cherry vm_nphysmem++; 836 1.1 cherry 837 1.1 cherry if (psp != NULL) 838 1.1 cherry *psp = lcv; 839 1.1 cherry 840 1.1 cherry return true; 841 1.1 cherry } 842 1.1 cherry 843 1.1 cherry /* 844 1.1 cherry * when VM_PHYSSEG_MAX is 1, we can simplify these functions 845 1.1 cherry */ 846 1.1 cherry 847 1.1 cherry #if VM_PHYSSEG_MAX == 1 848 1.1 cherry static inline int vm_physseg_find_contig(struct uvm_physseg *, int, paddr_t, psize_t *); 849 1.1 cherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) 850 1.1 cherry static inline int vm_physseg_find_bsearch(struct uvm_physseg *, int, paddr_t, psize_t *); 851 1.1 cherry #else 852 1.1 cherry static inline int vm_physseg_find_linear(struct uvm_physseg *, int, paddr_t, psize_t *); 853 1.1 cherry #endif 854 1.1 cherry 855 1.1 cherry /* 856 1.1 cherry * vm_physseg_find: find vm_physseg structure that belongs to a PA 857 1.1 cherry */ 858 1.19 ad inline int 859 1.1 cherry uvm_physseg_find(paddr_t pframe, psize_t *offp) 860 1.1 cherry { 861 1.1 cherry 862 1.1 cherry #if VM_PHYSSEG_MAX == 1 863 1.1 cherry return vm_physseg_find_contig(vm_physmem, vm_nphysseg, pframe, offp); 864 1.1 cherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) 865 1.1 cherry return vm_physseg_find_bsearch(vm_physmem, vm_nphysseg, pframe, offp); 866 1.1 cherry #else 867 1.1 cherry return vm_physseg_find_linear(vm_physmem, vm_nphysseg, pframe, offp); 868 1.1 cherry #endif 869 1.1 cherry } 870 1.1 cherry 871 1.1 cherry #if VM_PHYSSEG_MAX == 1 872 1.1 cherry static inline int 873 1.1 cherry vm_physseg_find_contig(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp) 874 1.1 cherry { 875 1.1 cherry 876 1.1 cherry /* 'contig' case */ 877 1.1 cherry if (pframe >= segs[0].start && pframe < segs[0].end) { 878 1.1 cherry if (offp) 879 1.1 cherry *offp = pframe - segs[0].start; 880 1.1 cherry return(0); 881 1.1 cherry } 882 1.1 cherry return(-1); 883 1.1 cherry } 884 1.1 cherry 885 1.1 cherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) 886 1.1 cherry 887 1.1 cherry static inline int 888 1.1 cherry vm_physseg_find_bsearch(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp) 889 1.1 cherry { 890 1.1 cherry /* binary search for it */ 891 1.1 cherry int start, len, guess; 892 1.1 cherry 893 1.1 cherry /* 894 1.1 cherry * if try is too large (thus target is less than try) we reduce 895 1.1 cherry * the length to trunc(len/2) [i.e. everything smaller than "try"] 896 1.1 cherry * 897 1.1 cherry * if the try is too small (thus target is greater than try) then 898 1.1 cherry * we set the new start to be (try + 1). this means we need to 899 1.1 cherry * reduce the length to (round(len/2) - 1). 900 1.1 cherry * 901 1.1 cherry * note "adjust" below which takes advantage of the fact that 902 1.1 cherry * (round(len/2) - 1) == trunc((len - 1) / 2) 903 1.1 cherry * for any value of len we may have 904 1.1 cherry */ 905 1.1 cherry 906 1.1 cherry for (start = 0, len = nsegs ; len != 0 ; len = len / 2) { 907 1.1 cherry guess = start + (len / 2); /* try in the middle */ 908 1.1 cherry 909 1.1 cherry /* start past our try? */ 910 1.1 cherry if (pframe >= segs[guess].start) { 911 1.1 cherry /* was try correct? */ 912 1.1 cherry if (pframe < segs[guess].end) { 913 1.1 cherry if (offp) 914 1.1 cherry *offp = pframe - segs[guess].start; 915 1.1 cherry return guess; /* got it */ 916 1.1 cherry } 917 1.1 cherry start = guess + 1; /* next time, start here */ 918 1.1 cherry len--; /* "adjust" */ 919 1.1 cherry } else { 920 1.1 cherry /* 921 1.1 cherry * pframe before try, just reduce length of 922 1.1 cherry * region, done in "for" loop 923 1.1 cherry */ 924 1.1 cherry } 925 1.1 cherry } 926 1.1 cherry return(-1); 927 1.1 cherry } 928 1.1 cherry 929 1.1 cherry #else 930 1.1 cherry 931 1.1 cherry static inline int 932 1.1 cherry vm_physseg_find_linear(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp) 933 1.1 cherry { 934 1.1 cherry /* linear search for it */ 935 1.1 cherry int lcv; 936 1.1 cherry 937 1.1 cherry for (lcv = 0; lcv < nsegs; lcv++) { 938 1.1 cherry if (pframe >= segs[lcv].start && 939 1.1 cherry pframe < segs[lcv].end) { 940 1.1 cherry if (offp) 941 1.1 cherry *offp = pframe - segs[lcv].start; 942 1.1 cherry return(lcv); /* got it */ 943 1.1 cherry } 944 1.1 cherry } 945 1.1 cherry return(-1); 946 1.1 cherry } 947 1.1 cherry #endif 948 1.1 cherry #endif /* UVM_HOTPLUG */ 949 1.1 cherry 950 1.19 ad /* 951 1.19 ad * PHYS_TO_VM_PAGE: find vm_page for a PA. used by MI code to get vm_pages 952 1.19 ad * back from an I/O mapping (ugh!). used in some MD code as well. it can 953 1.19 ad * be prominent in flamegraphs, so optimise it and try to make it easy for 954 1.19 ad * the compiler by including next to the inline lookup routines. 955 1.19 ad */ 956 1.19 ad struct vm_page * 957 1.19 ad uvm_phys_to_vm_page(paddr_t pa) 958 1.19 ad { 959 1.19 ad #if VM_PHYSSEG_STRAT != VM_PSTRAT_BSEARCH 960 1.19 ad /* 'contig' and linear cases */ 961 1.19 ad KASSERT(vm_nphysseg > 0); 962 1.19 ad struct uvm_physseg *ps = &vm_physmem[0]; 963 1.19 ad struct uvm_physseg *end = &vm_physmem[vm_nphysseg]; 964 1.19 ad paddr_t pframe = atop(pa); 965 1.19 ad do { 966 1.19 ad if (pframe >= ps->start && pframe < ps->end) { 967 1.19 ad return &ps->pgs[pframe - ps->start]; 968 1.19 ad } 969 1.19 ad } while (VM_PHYSSEG_MAX > 1 && __predict_false(++ps < end)); 970 1.19 ad return NULL; 971 1.19 ad #else 972 1.19 ad /* binary search for it */ 973 1.19 ad paddr_t pf = atop(pa); 974 1.19 ad paddr_t off; 975 1.19 ad uvm_physseg_t upm; 976 1.19 ad 977 1.19 ad upm = uvm_physseg_find(pf, &off); 978 1.19 ad if (upm != UVM_PHYSSEG_TYPE_INVALID) 979 1.19 ad return uvm_physseg_get_pg(upm, off); 980 1.19 ad return(NULL); 981 1.19 ad #endif 982 1.19 ad } 983 1.19 ad 984 1.1 cherry bool 985 1.2 cherry uvm_physseg_valid_p(uvm_physseg_t upm) 986 1.1 cherry { 987 1.1 cherry struct uvm_physseg *ps; 988 1.1 cherry 989 1.1 cherry if (upm == UVM_PHYSSEG_TYPE_INVALID || 990 1.1 cherry upm == UVM_PHYSSEG_TYPE_INVALID_EMPTY || 991 1.1 cherry upm == UVM_PHYSSEG_TYPE_INVALID_OVERFLOW) 992 1.1 cherry return false; 993 1.1 cherry 994 1.1 cherry /* 995 1.1 cherry * This is the delicate init dance - 996 1.1 cherry * needs to go with the dance. 997 1.1 cherry */ 998 1.1 cherry if (uvm.page_init_done != true) 999 1.1 cherry return true; 1000 1.1 cherry 1001 1.1 cherry ps = HANDLE_TO_PHYSSEG_NODE(upm); 1002 1.1 cherry 1003 1.1 cherry /* Extra checks needed only post uvm_page_init() */ 1004 1.1 cherry if (ps->pgs == NULL) 1005 1.1 cherry return false; 1006 1.1 cherry 1007 1.1 cherry /* XXX: etc. */ 1008 1.1 cherry 1009 1.1 cherry return true; 1010 1.1 cherry 1011 1.1 cherry } 1012 1.1 cherry 1013 1.1 cherry /* 1014 1.1 cherry * Boot protocol dictates that these must be able to return partially 1015 1.1 cherry * initialised segments. 1016 1.1 cherry */ 1017 1.1 cherry paddr_t 1018 1.1 cherry uvm_physseg_get_start(uvm_physseg_t upm) 1019 1.1 cherry { 1020 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 1021 1.1 cherry return (paddr_t) -1; 1022 1.1 cherry 1023 1.1 cherry return HANDLE_TO_PHYSSEG_NODE(upm)->start; 1024 1.1 cherry } 1025 1.1 cherry 1026 1.1 cherry paddr_t 1027 1.1 cherry uvm_physseg_get_end(uvm_physseg_t upm) 1028 1.1 cherry { 1029 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 1030 1.1 cherry return (paddr_t) -1; 1031 1.1 cherry 1032 1.1 cherry return HANDLE_TO_PHYSSEG_NODE(upm)->end; 1033 1.1 cherry } 1034 1.1 cherry 1035 1.1 cherry paddr_t 1036 1.1 cherry uvm_physseg_get_avail_start(uvm_physseg_t upm) 1037 1.1 cherry { 1038 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 1039 1.1 cherry return (paddr_t) -1; 1040 1.1 cherry 1041 1.1 cherry return HANDLE_TO_PHYSSEG_NODE(upm)->avail_start; 1042 1.1 cherry } 1043 1.1 cherry 1044 1.6 rin #if defined(UVM_PHYSSEG_LEGACY) 1045 1.4 christos void 1046 1.4 christos uvm_physseg_set_avail_start(uvm_physseg_t upm, paddr_t avail_start) 1047 1.4 christos { 1048 1.5 cherry struct uvm_physseg *ps = HANDLE_TO_PHYSSEG_NODE(upm); 1049 1.5 cherry 1050 1.5 cherry #if defined(DIAGNOSTIC) 1051 1.5 cherry paddr_t avail_end; 1052 1.5 cherry avail_end = uvm_physseg_get_avail_end(upm); 1053 1.4 christos KASSERT(uvm_physseg_valid_p(upm)); 1054 1.18 riastrad KASSERT(avail_start < avail_end); 1055 1.18 riastrad KASSERT(avail_start >= ps->start); 1056 1.5 cherry #endif 1057 1.5 cherry 1058 1.5 cherry ps->avail_start = avail_start; 1059 1.4 christos } 1060 1.12 ad 1061 1.12 ad void 1062 1.12 ad uvm_physseg_set_avail_end(uvm_physseg_t upm, paddr_t avail_end) 1063 1.5 cherry { 1064 1.5 cherry struct uvm_physseg *ps = HANDLE_TO_PHYSSEG_NODE(upm); 1065 1.5 cherry 1066 1.5 cherry #if defined(DIAGNOSTIC) 1067 1.5 cherry paddr_t avail_start; 1068 1.5 cherry avail_start = uvm_physseg_get_avail_start(upm); 1069 1.5 cherry KASSERT(uvm_physseg_valid_p(upm)); 1070 1.18 riastrad KASSERT(avail_end > avail_start); 1071 1.18 riastrad KASSERT(avail_end <= ps->end); 1072 1.4 christos #endif 1073 1.4 christos 1074 1.5 cherry ps->avail_end = avail_end; 1075 1.5 cherry } 1076 1.5 cherry 1077 1.6 rin #endif /* UVM_PHYSSEG_LEGACY */ 1078 1.5 cherry 1079 1.1 cherry paddr_t 1080 1.1 cherry uvm_physseg_get_avail_end(uvm_physseg_t upm) 1081 1.1 cherry { 1082 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 1083 1.1 cherry return (paddr_t) -1; 1084 1.1 cherry 1085 1.1 cherry return HANDLE_TO_PHYSSEG_NODE(upm)->avail_end; 1086 1.1 cherry } 1087 1.1 cherry 1088 1.19 ad inline struct vm_page * 1089 1.1 cherry uvm_physseg_get_pg(uvm_physseg_t upm, paddr_t idx) 1090 1.1 cherry { 1091 1.2 cherry KASSERT(uvm_physseg_valid_p(upm)); 1092 1.1 cherry return &HANDLE_TO_PHYSSEG_NODE(upm)->pgs[idx]; 1093 1.1 cherry } 1094 1.1 cherry 1095 1.1 cherry #ifdef __HAVE_PMAP_PHYSSEG 1096 1.1 cherry struct pmap_physseg * 1097 1.1 cherry uvm_physseg_get_pmseg(uvm_physseg_t upm) 1098 1.1 cherry { 1099 1.2 cherry KASSERT(uvm_physseg_valid_p(upm)); 1100 1.1 cherry return &(HANDLE_TO_PHYSSEG_NODE(upm)->pmseg); 1101 1.1 cherry } 1102 1.1 cherry #endif 1103 1.1 cherry 1104 1.1 cherry int 1105 1.1 cherry uvm_physseg_get_free_list(uvm_physseg_t upm) 1106 1.1 cherry { 1107 1.2 cherry KASSERT(uvm_physseg_valid_p(upm)); 1108 1.1 cherry return HANDLE_TO_PHYSSEG_NODE(upm)->free_list; 1109 1.1 cherry } 1110 1.1 cherry 1111 1.20 tnn u_long 1112 1.1 cherry uvm_physseg_get_start_hint(uvm_physseg_t upm) 1113 1.1 cherry { 1114 1.2 cherry KASSERT(uvm_physseg_valid_p(upm)); 1115 1.1 cherry return HANDLE_TO_PHYSSEG_NODE(upm)->start_hint; 1116 1.1 cherry } 1117 1.1 cherry 1118 1.1 cherry bool 1119 1.20 tnn uvm_physseg_set_start_hint(uvm_physseg_t upm, u_long start_hint) 1120 1.1 cherry { 1121 1.2 cherry if (uvm_physseg_valid_p(upm) == false) 1122 1.1 cherry return false; 1123 1.1 cherry 1124 1.1 cherry HANDLE_TO_PHYSSEG_NODE(upm)->start_hint = start_hint; 1125 1.1 cherry return true; 1126 1.1 cherry } 1127 1.1 cherry 1128 1.1 cherry void 1129 1.1 cherry uvm_physseg_init_seg(uvm_physseg_t upm, struct vm_page *pgs) 1130 1.1 cherry { 1131 1.1 cherry psize_t i; 1132 1.1 cherry psize_t n; 1133 1.1 cherry paddr_t paddr; 1134 1.1 cherry struct uvm_physseg *seg; 1135 1.11 ad struct vm_page *pg; 1136 1.1 cherry 1137 1.18 riastrad KASSERT(upm != UVM_PHYSSEG_TYPE_INVALID); 1138 1.18 riastrad KASSERT(pgs != NULL); 1139 1.1 cherry 1140 1.1 cherry seg = HANDLE_TO_PHYSSEG_NODE(upm); 1141 1.1 cherry KASSERT(seg != NULL); 1142 1.1 cherry KASSERT(seg->pgs == NULL); 1143 1.1 cherry 1144 1.1 cherry n = seg->end - seg->start; 1145 1.1 cherry seg->pgs = pgs; 1146 1.1 cherry 1147 1.1 cherry /* init and free vm_pages (we've already zeroed them) */ 1148 1.1 cherry paddr = ctob(seg->start); 1149 1.1 cherry for (i = 0 ; i < n ; i++, paddr += PAGE_SIZE) { 1150 1.13 ad pg = &seg->pgs[i]; 1151 1.13 ad pg->phys_addr = paddr; 1152 1.1 cherry #ifdef __HAVE_VM_PAGE_MD 1153 1.13 ad VM_MDPAGE_INIT(pg); 1154 1.1 cherry #endif 1155 1.1 cherry if (atop(paddr) >= seg->avail_start && 1156 1.1 cherry atop(paddr) < seg->avail_end) { 1157 1.1 cherry uvmexp.npages++; 1158 1.1 cherry /* add page to free pool */ 1159 1.13 ad uvm_page_set_freelist(pg, 1160 1.13 ad uvm_page_lookup_freelist(pg)); 1161 1.11 ad /* Disable LOCKDEBUG: too many and too early. */ 1162 1.11 ad mutex_init(&pg->interlock, MUTEX_NODEBUG, IPL_NONE); 1163 1.11 ad uvm_pagefree(pg); 1164 1.1 cherry } 1165 1.1 cherry } 1166 1.1 cherry } 1167 1.1 cherry 1168 1.1 cherry void 1169 1.1 cherry uvm_physseg_seg_chomp_slab(uvm_physseg_t upm, struct vm_page *pgs, size_t n) 1170 1.1 cherry { 1171 1.1 cherry struct uvm_physseg *seg = HANDLE_TO_PHYSSEG_NODE(upm); 1172 1.1 cherry 1173 1.1 cherry /* max number of pre-boot unplug()s allowed */ 1174 1.1 cherry #define UVM_PHYSSEG_BOOT_UNPLUG_MAX VM_PHYSSEG_MAX 1175 1.1 cherry 1176 1.1 cherry static char btslab_ex_storage[EXTENT_FIXED_STORAGE_SIZE(UVM_PHYSSEG_BOOT_UNPLUG_MAX)]; 1177 1.1 cherry 1178 1.1 cherry if (__predict_false(uvm.page_init_done == false)) { 1179 1.1 cherry seg->ext = extent_create("Boot time slab", (u_long) pgs, (u_long) (pgs + n), 1180 1.1 cherry (void *)btslab_ex_storage, sizeof(btslab_ex_storage), 0); 1181 1.1 cherry } else { 1182 1.1 cherry seg->ext = extent_create("Hotplug slab", (u_long) pgs, (u_long) (pgs + n), NULL, 0, 0); 1183 1.1 cherry } 1184 1.1 cherry 1185 1.1 cherry KASSERT(seg->ext != NULL); 1186 1.1 cherry 1187 1.1 cherry } 1188 1.1 cherry 1189 1.1 cherry struct vm_page * 1190 1.1 cherry uvm_physseg_seg_alloc_from_slab(uvm_physseg_t upm, size_t pages) 1191 1.1 cherry { 1192 1.1 cherry int err; 1193 1.1 cherry struct uvm_physseg *seg; 1194 1.1 cherry struct vm_page *pgs = NULL; 1195 1.1 cherry 1196 1.9 christos KASSERT(pages > 0); 1197 1.9 christos 1198 1.1 cherry seg = HANDLE_TO_PHYSSEG_NODE(upm); 1199 1.1 cherry 1200 1.1 cherry if (__predict_false(seg->ext == NULL)) { 1201 1.1 cherry /* 1202 1.1 cherry * This is a situation unique to boot time. 1203 1.1 cherry * It shouldn't happen at any point other than from 1204 1.1 cherry * the first uvm_page.c:uvm_page_init() call 1205 1.1 cherry * Since we're in a loop, we can get away with the 1206 1.1 cherry * below. 1207 1.1 cherry */ 1208 1.1 cherry KASSERT(uvm.page_init_done != true); 1209 1.1 cherry 1210 1.9 christos uvm_physseg_t upmp = uvm_physseg_get_prev(upm); 1211 1.9 christos KASSERT(upmp != UVM_PHYSSEG_TYPE_INVALID); 1212 1.9 christos 1213 1.9 christos seg->ext = HANDLE_TO_PHYSSEG_NODE(upmp)->ext; 1214 1.1 cherry 1215 1.1 cherry KASSERT(seg->ext != NULL); 1216 1.1 cherry } 1217 1.1 cherry 1218 1.1 cherry /* We allocate enough for this segment */ 1219 1.1 cherry err = extent_alloc(seg->ext, sizeof(*pgs) * pages, 1, 0, EX_BOUNDZERO, (u_long *)&pgs); 1220 1.1 cherry 1221 1.1 cherry if (err != 0) { 1222 1.1 cherry #ifdef DEBUG 1223 1.1 cherry printf("%s: extent_alloc failed with error: %d \n", 1224 1.1 cherry __func__, err); 1225 1.1 cherry #endif 1226 1.1 cherry } 1227 1.1 cherry 1228 1.1 cherry return pgs; 1229 1.1 cherry } 1230 1.1 cherry 1231 1.1 cherry /* 1232 1.1 cherry * uvm_page_physload: load physical memory into VM system 1233 1.1 cherry * 1234 1.1 cherry * => all args are PFs 1235 1.1 cherry * => all pages in start/end get vm_page structures 1236 1.1 cherry * => areas marked by avail_start/avail_end get added to the free page pool 1237 1.1 cherry * => we are limited to VM_PHYSSEG_MAX physical memory segments 1238 1.1 cherry */ 1239 1.1 cherry 1240 1.1 cherry uvm_physseg_t 1241 1.1 cherry uvm_page_physload(paddr_t start, paddr_t end, paddr_t avail_start, 1242 1.1 cherry paddr_t avail_end, int free_list) 1243 1.1 cherry { 1244 1.1 cherry struct uvm_physseg *ps; 1245 1.1 cherry uvm_physseg_t upm; 1246 1.1 cherry 1247 1.1 cherry if (__predict_true(uvm.page_init_done == true)) 1248 1.1 cherry panic("%s: unload attempted after uvm_page_init()\n", __func__); 1249 1.1 cherry if (uvmexp.pagesize == 0) 1250 1.1 cherry panic("uvm_page_physload: page size not set!"); 1251 1.1 cherry if (free_list >= VM_NFREELIST || free_list < VM_FREELIST_DEFAULT) 1252 1.1 cherry panic("uvm_page_physload: bad free list %d", free_list); 1253 1.1 cherry if (start >= end) 1254 1.17 rin panic("uvm_page_physload: start[%" PRIxPADDR "] >= end[%" 1255 1.17 rin PRIxPADDR "]", start, end); 1256 1.1 cherry 1257 1.1 cherry if (uvm_physseg_plug(start, end - start, &upm) == false) { 1258 1.1 cherry panic("uvm_physseg_plug() failed at boot."); 1259 1.1 cherry /* NOTREACHED */ 1260 1.1 cherry return UVM_PHYSSEG_TYPE_INVALID; /* XXX: correct type */ 1261 1.1 cherry } 1262 1.1 cherry 1263 1.1 cherry ps = HANDLE_TO_PHYSSEG_NODE(upm); 1264 1.1 cherry 1265 1.1 cherry /* Legacy */ 1266 1.1 cherry ps->avail_start = avail_start; 1267 1.1 cherry ps->avail_end = avail_end; 1268 1.1 cherry 1269 1.1 cherry ps->free_list = free_list; /* XXX: */ 1270 1.1 cherry 1271 1.1 cherry 1272 1.1 cherry return upm; 1273 1.1 cherry } 1274 1.1 cherry 1275 1.1 cherry bool 1276 1.1 cherry uvm_physseg_unplug(paddr_t pfn, size_t pages) 1277 1.1 cherry { 1278 1.1 cherry uvm_physseg_t upm; 1279 1.8 riastrad paddr_t off = 0, start __diagused, end; 1280 1.1 cherry struct uvm_physseg *seg; 1281 1.1 cherry 1282 1.1 cherry upm = uvm_physseg_find(pfn, &off); 1283 1.1 cherry 1284 1.2 cherry if (!uvm_physseg_valid_p(upm)) { 1285 1.1 cherry printf("%s: Tried to unplug from unknown offset\n", __func__); 1286 1.1 cherry return false; 1287 1.1 cherry } 1288 1.1 cherry 1289 1.1 cherry seg = HANDLE_TO_PHYSSEG_NODE(upm); 1290 1.1 cherry 1291 1.1 cherry start = uvm_physseg_get_start(upm); 1292 1.1 cherry end = uvm_physseg_get_end(upm); 1293 1.1 cherry 1294 1.1 cherry if (end < (pfn + pages)) { 1295 1.1 cherry printf("%s: Tried to unplug oversized span \n", __func__); 1296 1.1 cherry return false; 1297 1.1 cherry } 1298 1.1 cherry 1299 1.1 cherry KASSERT(pfn == start + off); /* sanity */ 1300 1.1 cherry 1301 1.1 cherry if (__predict_true(uvm.page_init_done == true)) { 1302 1.1 cherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */ 1303 1.1 cherry if (extent_free(seg->ext, (u_long)(seg->pgs + off), sizeof(struct vm_page) * pages, EX_MALLOCOK | EX_NOWAIT) != 0) 1304 1.1 cherry return false; 1305 1.1 cherry } 1306 1.1 cherry 1307 1.1 cherry if (off == 0 && (pfn + pages) == end) { 1308 1.1 cherry #if defined(UVM_HOTPLUG) /* rbtree implementation */ 1309 1.1 cherry int segcount = 0; 1310 1.1 cherry struct uvm_physseg *current_ps; 1311 1.1 cherry /* Complete segment */ 1312 1.1 cherry if (uvm_physseg_graph.nentries == 1) 1313 1.1 cherry panic("%s: out of memory!", __func__); 1314 1.1 cherry 1315 1.1 cherry if (__predict_true(uvm.page_init_done == true)) { 1316 1.1 cherry RB_TREE_FOREACH(current_ps, &(uvm_physseg_graph.rb_tree)) { 1317 1.1 cherry if (seg->ext == current_ps->ext) 1318 1.1 cherry segcount++; 1319 1.1 cherry } 1320 1.1 cherry KASSERT(segcount > 0); 1321 1.1 cherry 1322 1.1 cherry if (segcount == 1) { 1323 1.1 cherry extent_destroy(seg->ext); 1324 1.1 cherry } 1325 1.1 cherry 1326 1.1 cherry /* 1327 1.1 cherry * We assume that the unplug will succeed from 1328 1.1 cherry * this point onwards 1329 1.1 cherry */ 1330 1.1 cherry uvmexp.npages -= (int) pages; 1331 1.1 cherry } 1332 1.1 cherry 1333 1.1 cherry rb_tree_remove_node(&(uvm_physseg_graph.rb_tree), upm); 1334 1.1 cherry memset(seg, 0, sizeof(struct uvm_physseg)); 1335 1.1 cherry uvm_physseg_free(seg, sizeof(struct uvm_physseg)); 1336 1.1 cherry uvm_physseg_graph.nentries--; 1337 1.1 cherry #else /* UVM_HOTPLUG */ 1338 1.1 cherry int x; 1339 1.1 cherry if (vm_nphysmem == 1) 1340 1.1 cherry panic("uvm_page_physget: out of memory!"); 1341 1.1 cherry vm_nphysmem--; 1342 1.1 cherry for (x = upm ; x < vm_nphysmem ; x++) 1343 1.1 cherry /* structure copy */ 1344 1.1 cherry VM_PHYSMEM_PTR_SWAP(x, x + 1); 1345 1.1 cherry #endif /* UVM_HOTPLUG */ 1346 1.1 cherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */ 1347 1.1 cherry return true; 1348 1.1 cherry } 1349 1.1 cherry 1350 1.1 cherry if (off > 0 && 1351 1.1 cherry (pfn + pages) < end) { 1352 1.1 cherry #if defined(UVM_HOTPLUG) /* rbtree implementation */ 1353 1.1 cherry /* middle chunk - need a new segment */ 1354 1.1 cherry struct uvm_physseg *ps, *current_ps; 1355 1.1 cherry ps = uvm_physseg_alloc(sizeof (struct uvm_physseg)); 1356 1.1 cherry if (ps == NULL) { 1357 1.1 cherry printf("%s: Unable to allocated new fragment vm_physseg \n", 1358 1.1 cherry __func__); 1359 1.1 cherry return false; 1360 1.1 cherry } 1361 1.1 cherry 1362 1.1 cherry /* Remove middle chunk */ 1363 1.1 cherry if (__predict_true(uvm.page_init_done == true)) { 1364 1.1 cherry KASSERT(seg->ext != NULL); 1365 1.1 cherry ps->ext = seg->ext; 1366 1.1 cherry 1367 1.1 cherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */ 1368 1.1 cherry /* 1369 1.1 cherry * We assume that the unplug will succeed from 1370 1.1 cherry * this point onwards 1371 1.1 cherry */ 1372 1.1 cherry uvmexp.npages -= (int) pages; 1373 1.1 cherry } 1374 1.1 cherry 1375 1.1 cherry ps->start = pfn + pages; 1376 1.1 cherry ps->avail_start = ps->start; /* XXX: Legacy */ 1377 1.1 cherry 1378 1.1 cherry ps->end = seg->end; 1379 1.1 cherry ps->avail_end = ps->end; /* XXX: Legacy */ 1380 1.1 cherry 1381 1.1 cherry seg->end = pfn; 1382 1.1 cherry seg->avail_end = seg->end; /* XXX: Legacy */ 1383 1.1 cherry 1384 1.1 cherry 1385 1.1 cherry /* 1386 1.1 cherry * The new pgs array points to the beginning of the 1387 1.1 cherry * tail fragment. 1388 1.1 cherry */ 1389 1.1 cherry if (__predict_true(uvm.page_init_done == true)) 1390 1.1 cherry ps->pgs = seg->pgs + off + pages; 1391 1.1 cherry 1392 1.1 cherry current_ps = rb_tree_insert_node(&(uvm_physseg_graph.rb_tree), ps); 1393 1.1 cherry if (current_ps != ps) { 1394 1.1 cherry panic("uvm_page_physload: Duplicate address range detected!"); 1395 1.1 cherry } 1396 1.1 cherry uvm_physseg_graph.nentries++; 1397 1.1 cherry #else /* UVM_HOTPLUG */ 1398 1.1 cherry panic("%s: can't unplug() from the middle of a segment without" 1399 1.7 uwe " UVM_HOTPLUG\n", __func__); 1400 1.1 cherry /* NOTREACHED */ 1401 1.1 cherry #endif /* UVM_HOTPLUG */ 1402 1.1 cherry return true; 1403 1.1 cherry } 1404 1.1 cherry 1405 1.1 cherry if (off == 0 && (pfn + pages) < end) { 1406 1.1 cherry /* Remove front chunk */ 1407 1.1 cherry if (__predict_true(uvm.page_init_done == true)) { 1408 1.1 cherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */ 1409 1.1 cherry /* 1410 1.1 cherry * We assume that the unplug will succeed from 1411 1.1 cherry * this point onwards 1412 1.1 cherry */ 1413 1.1 cherry uvmexp.npages -= (int) pages; 1414 1.1 cherry } 1415 1.1 cherry 1416 1.1 cherry /* Truncate */ 1417 1.1 cherry seg->start = pfn + pages; 1418 1.1 cherry seg->avail_start = seg->start; /* XXX: Legacy */ 1419 1.1 cherry 1420 1.1 cherry /* 1421 1.1 cherry * Move the pgs array start to the beginning of the 1422 1.1 cherry * tail end. 1423 1.1 cherry */ 1424 1.1 cherry if (__predict_true(uvm.page_init_done == true)) 1425 1.1 cherry seg->pgs += pages; 1426 1.1 cherry 1427 1.1 cherry return true; 1428 1.1 cherry } 1429 1.1 cherry 1430 1.1 cherry if (off > 0 && (pfn + pages) == end) { 1431 1.1 cherry /* back chunk */ 1432 1.1 cherry 1433 1.1 cherry 1434 1.1 cherry /* Truncate! */ 1435 1.1 cherry seg->end = pfn; 1436 1.1 cherry seg->avail_end = seg->end; /* XXX: Legacy */ 1437 1.1 cherry 1438 1.1 cherry uvmexp.npages -= (int) pages; 1439 1.1 cherry 1440 1.1 cherry return true; 1441 1.1 cherry } 1442 1.1 cherry 1443 1.1 cherry printf("%s: Tried to unplug unknown range \n", __func__); 1444 1.1 cherry 1445 1.1 cherry return false; 1446 1.1 cherry } 1447