1*ecaf2f40Stnn /* $NetBSD: uvm_physseg.c,v 1.20 2024/01/13 09:44:42 tnn Exp $ */
207acf3c0Scherry
307acf3c0Scherry /*
407acf3c0Scherry * Copyright (c) 1997 Charles D. Cranor and Washington University.
507acf3c0Scherry * Copyright (c) 1991, 1993, The Regents of the University of California.
607acf3c0Scherry *
707acf3c0Scherry * All rights reserved.
807acf3c0Scherry *
907acf3c0Scherry * This code is derived from software contributed to Berkeley by
1007acf3c0Scherry * The Mach Operating System project at Carnegie-Mellon University.
1107acf3c0Scherry *
1207acf3c0Scherry * Redistribution and use in source and binary forms, with or without
1307acf3c0Scherry * modification, are permitted provided that the following conditions
1407acf3c0Scherry * are met:
1507acf3c0Scherry * 1. Redistributions of source code must retain the above copyright
1607acf3c0Scherry * notice, this list of conditions and the following disclaimer.
1707acf3c0Scherry * 2. Redistributions in binary form must reproduce the above copyright
1807acf3c0Scherry * notice, this list of conditions and the following disclaimer in the
1907acf3c0Scherry * documentation and/or other materials provided with the distribution.
2007acf3c0Scherry * 3. Neither the name of the University nor the names of its contributors
2107acf3c0Scherry * may be used to endorse or promote products derived from this software
2207acf3c0Scherry * without specific prior written permission.
2307acf3c0Scherry *
2407acf3c0Scherry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2507acf3c0Scherry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2607acf3c0Scherry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2707acf3c0Scherry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2807acf3c0Scherry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2907acf3c0Scherry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3007acf3c0Scherry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3107acf3c0Scherry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3207acf3c0Scherry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3307acf3c0Scherry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3407acf3c0Scherry * SUCH DAMAGE.
3507acf3c0Scherry *
3607acf3c0Scherry * @(#)vm_page.h 7.3 (Berkeley) 4/21/91
3707acf3c0Scherry * from: Id: uvm_page.h,v 1.1.2.6 1998/02/04 02:31:42 chuck Exp
3807acf3c0Scherry *
3907acf3c0Scherry *
4007acf3c0Scherry * Copyright (c) 1987, 1990 Carnegie-Mellon University.
4107acf3c0Scherry * All rights reserved.
4207acf3c0Scherry *
4307acf3c0Scherry * Permission to use, copy, modify and distribute this software and
4407acf3c0Scherry * its documentation is hereby granted, provided that both the copyright
4507acf3c0Scherry * notice and this permission notice appear in all copies of the
4607acf3c0Scherry * software, derivative works or modified versions, and any portions
4707acf3c0Scherry * thereof, and that both notices appear in supporting documentation.
4807acf3c0Scherry *
4907acf3c0Scherry * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
5007acf3c0Scherry * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
5107acf3c0Scherry * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
5207acf3c0Scherry *
5307acf3c0Scherry * Carnegie Mellon requests users of this software to return to
5407acf3c0Scherry *
5507acf3c0Scherry * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
5607acf3c0Scherry * School of Computer Science
5707acf3c0Scherry * Carnegie Mellon University
5807acf3c0Scherry * Pittsburgh PA 15213-3890
5907acf3c0Scherry *
6007acf3c0Scherry * any improvements or extensions that they make and grant Carnegie the
6107acf3c0Scherry * rights to redistribute these changes.
6207acf3c0Scherry */
6307acf3c0Scherry
6407acf3c0Scherry /*
6507acf3c0Scherry * Consolidated API from uvm_page.c and others.
6607acf3c0Scherry * Consolidated and designed by Cherry G. Mathew <cherry@zyx.in>
6707acf3c0Scherry * rbtree(3) backing implementation by:
6807acf3c0Scherry * Santhosh N. Raju <santhosh.raju@gmail.com>
6907acf3c0Scherry */
7007acf3c0Scherry
7107acf3c0Scherry #ifdef _KERNEL_OPT
7207acf3c0Scherry #include "opt_uvm.h"
7307acf3c0Scherry #endif
7407acf3c0Scherry
7507acf3c0Scherry #include <sys/param.h>
7607acf3c0Scherry #include <sys/types.h>
7707acf3c0Scherry #include <sys/extent.h>
7807acf3c0Scherry #include <sys/kmem.h>
7907acf3c0Scherry
8007acf3c0Scherry #include <uvm/uvm.h>
8107acf3c0Scherry #include <uvm/uvm_page.h>
8207acf3c0Scherry #include <uvm/uvm_param.h>
8307acf3c0Scherry #include <uvm/uvm_pdpolicy.h>
8407acf3c0Scherry #include <uvm/uvm_physseg.h>
8507acf3c0Scherry
8607acf3c0Scherry /*
8707acf3c0Scherry * uvm_physseg: describes one segment of physical memory
8807acf3c0Scherry */
8907acf3c0Scherry struct uvm_physseg {
909887ecbeSad /* used during RB tree lookup for PHYS_TO_VM_PAGE(). */
91128aefc0Sad #if defined(UVM_HOTPLUG)
9207acf3c0Scherry struct rb_node rb_node; /* tree information */
93128aefc0Sad #endif
9407acf3c0Scherry paddr_t start; /* PF# of first page in segment */
9507acf3c0Scherry paddr_t end; /* (PF# of last page in segment) + 1 */
969887ecbeSad struct vm_page *pgs; /* vm_page structures (from start) */
979887ecbeSad
989887ecbeSad /* less performance sensitive fields. */
9907acf3c0Scherry paddr_t avail_start; /* PF# of first free page in segment */
10007acf3c0Scherry paddr_t avail_end; /* (PF# of last free page in segment) +1 */
10107acf3c0Scherry struct extent *ext; /* extent(9) structure to manage pgs[] */
10207acf3c0Scherry int free_list; /* which free list they belong on */
103*ecaf2f40Stnn u_long start_hint; /* start looking for free pages here */
10407acf3c0Scherry #ifdef __HAVE_PMAP_PHYSSEG
10507acf3c0Scherry struct pmap_physseg pmseg; /* pmap specific (MD) data */
10607acf3c0Scherry #endif
10707acf3c0Scherry };
10807acf3c0Scherry
10907acf3c0Scherry /*
11007acf3c0Scherry * These functions are reserved for uvm(9) internal use and are not
11107acf3c0Scherry * exported in the header file uvm_physseg.h
11207acf3c0Scherry *
11307acf3c0Scherry * Thus they are redefined here.
11407acf3c0Scherry */
11507acf3c0Scherry void uvm_physseg_init_seg(uvm_physseg_t, struct vm_page *);
11607acf3c0Scherry void uvm_physseg_seg_chomp_slab(uvm_physseg_t, struct vm_page *, size_t);
11707acf3c0Scherry
11807acf3c0Scherry /* returns a pgs array */
11907acf3c0Scherry struct vm_page *uvm_physseg_seg_alloc_from_slab(uvm_physseg_t, size_t);
12007acf3c0Scherry
12107acf3c0Scherry #if defined(UVM_HOTPLUG) /* rbtree impementation */
12207acf3c0Scherry
12307acf3c0Scherry #define HANDLE_TO_PHYSSEG_NODE(h) ((struct uvm_physseg *)(h))
12407acf3c0Scherry #define PHYSSEG_NODE_TO_HANDLE(u) ((uvm_physseg_t)(u))
12507acf3c0Scherry
12607acf3c0Scherry struct uvm_physseg_graph {
12707acf3c0Scherry struct rb_tree rb_tree; /* Tree for entries */
12807acf3c0Scherry int nentries; /* Number of entries */
1299887ecbeSad } __aligned(COHERENCY_UNIT);
13007acf3c0Scherry
1319887ecbeSad static struct uvm_physseg_graph uvm_physseg_graph __read_mostly;
13207acf3c0Scherry
13307acf3c0Scherry /*
13407acf3c0Scherry * Note on kmem(9) allocator usage:
13507acf3c0Scherry * We take the conservative approach that plug/unplug are allowed to
13607acf3c0Scherry * fail in high memory stress situations.
13707acf3c0Scherry *
13807acf3c0Scherry * We want to avoid re-entrant situations in which one plug/unplug
13907acf3c0Scherry * operation is waiting on a previous one to complete, since this
14007acf3c0Scherry * makes the design more complicated than necessary.
14107acf3c0Scherry *
14207acf3c0Scherry * We may review this and change its behaviour, once the use cases
14307acf3c0Scherry * become more obvious.
14407acf3c0Scherry */
14507acf3c0Scherry
14607acf3c0Scherry /*
14707acf3c0Scherry * Special alloc()/free() functions for boot time support:
14807acf3c0Scherry * We assume that alloc() at boot time is only for new 'vm_physseg's
14907acf3c0Scherry * This allows us to use a static array for memory allocation at boot
15007acf3c0Scherry * time. Thus we avoid using kmem(9) which is not ready at this point
15107acf3c0Scherry * in boot.
15207acf3c0Scherry *
15307acf3c0Scherry * After kmem(9) is ready, we use it. We currently discard any free()s
15407acf3c0Scherry * to this static array, since the size is small enough to be a
15507acf3c0Scherry * trivial waste on all architectures we run on.
15607acf3c0Scherry */
15707acf3c0Scherry
15807acf3c0Scherry static size_t nseg = 0;
15907acf3c0Scherry static struct uvm_physseg uvm_physseg[VM_PHYSSEG_MAX];
16007acf3c0Scherry
16107acf3c0Scherry static void *
uvm_physseg_alloc(size_t sz)16207acf3c0Scherry uvm_physseg_alloc(size_t sz)
16307acf3c0Scherry {
16407acf3c0Scherry /*
16507acf3c0Scherry * During boot time, we only support allocating vm_physseg
16607acf3c0Scherry * entries from the static array.
16707acf3c0Scherry * We need to assert for this.
16807acf3c0Scherry */
16907acf3c0Scherry
17007acf3c0Scherry if (__predict_false(uvm.page_init_done == false)) {
17107acf3c0Scherry if (sz % sizeof(struct uvm_physseg))
17207acf3c0Scherry panic("%s: tried to alloc size other than multiple"
17307acf3c0Scherry " of struct uvm_physseg at boot\n", __func__);
17407acf3c0Scherry
17507acf3c0Scherry size_t n = sz / sizeof(struct uvm_physseg);
17607acf3c0Scherry nseg += n;
17707acf3c0Scherry
178a83cdbecSriastradh KASSERT(nseg > 0);
179a83cdbecSriastradh KASSERT(nseg <= VM_PHYSSEG_MAX);
18007acf3c0Scherry
18107acf3c0Scherry return &uvm_physseg[nseg - n];
18207acf3c0Scherry }
18307acf3c0Scherry
18407acf3c0Scherry return kmem_zalloc(sz, KM_NOSLEEP);
18507acf3c0Scherry }
18607acf3c0Scherry
18707acf3c0Scherry static void
uvm_physseg_free(void * p,size_t sz)18807acf3c0Scherry uvm_physseg_free(void *p, size_t sz)
18907acf3c0Scherry {
19007acf3c0Scherry /*
19107acf3c0Scherry * This is a bit tricky. We do allow simulation of free()
19207acf3c0Scherry * during boot (for eg: when MD code is "steal"ing memory,
19307acf3c0Scherry * and the segment has been exhausted (and thus needs to be
19407acf3c0Scherry * free() - ed.
19507acf3c0Scherry * free() also complicates things because we leak the
19607acf3c0Scherry * free(). Therefore calling code can't assume that free()-ed
19707acf3c0Scherry * memory is available for alloc() again, at boot time.
19807acf3c0Scherry *
19907acf3c0Scherry * Thus we can't explicitly disallow free()s during
20007acf3c0Scherry * boot time. However, the same restriction for alloc()
20107acf3c0Scherry * applies to free(). We only allow uvm_physseg related free()s
20207acf3c0Scherry * via this function during boot time.
20307acf3c0Scherry */
20407acf3c0Scherry
20507acf3c0Scherry if (__predict_false(uvm.page_init_done == false)) {
20607acf3c0Scherry if (sz % sizeof(struct uvm_physseg))
20707acf3c0Scherry panic("%s: tried to free size other than struct uvm_physseg"
20807acf3c0Scherry " at boot\n", __func__);
20907acf3c0Scherry
21007acf3c0Scherry }
21107acf3c0Scherry
21207acf3c0Scherry /*
21307acf3c0Scherry * Could have been in a single if(){} block - split for
21407acf3c0Scherry * clarity
21507acf3c0Scherry */
21607acf3c0Scherry
21707acf3c0Scherry if ((struct uvm_physseg *)p >= uvm_physseg &&
21807acf3c0Scherry (struct uvm_physseg *)p < (uvm_physseg + VM_PHYSSEG_MAX)) {
21907acf3c0Scherry if (sz % sizeof(struct uvm_physseg))
22007acf3c0Scherry panic("%s: tried to free() other than struct uvm_physseg"
22107acf3c0Scherry " from static array\n", __func__);
22207acf3c0Scherry
22307acf3c0Scherry if ((sz / sizeof(struct uvm_physseg)) >= VM_PHYSSEG_MAX)
22407acf3c0Scherry panic("%s: tried to free() the entire static array!", __func__);
22507acf3c0Scherry return; /* Nothing to free */
22607acf3c0Scherry }
22707acf3c0Scherry
22807acf3c0Scherry kmem_free(p, sz);
22907acf3c0Scherry }
23007acf3c0Scherry
23107acf3c0Scherry /* XXX: Multi page size */
23207acf3c0Scherry bool
uvm_physseg_plug(paddr_t pfn,size_t pages,uvm_physseg_t * psp)23307acf3c0Scherry uvm_physseg_plug(paddr_t pfn, size_t pages, uvm_physseg_t *psp)
23407acf3c0Scherry {
23507acf3c0Scherry int preload;
23607acf3c0Scherry size_t slabpages;
23707acf3c0Scherry struct uvm_physseg *ps, *current_ps = NULL;
23807acf3c0Scherry struct vm_page *slab = NULL, *pgs = NULL;
23907acf3c0Scherry
24007acf3c0Scherry #ifdef DEBUG
24107acf3c0Scherry paddr_t off;
24207acf3c0Scherry uvm_physseg_t upm;
24307acf3c0Scherry upm = uvm_physseg_find(pfn, &off);
24407acf3c0Scherry
24507acf3c0Scherry ps = HANDLE_TO_PHYSSEG_NODE(upm);
24607acf3c0Scherry
24707acf3c0Scherry if (ps != NULL) /* XXX; do we allow "update" plugs ? */
24807acf3c0Scherry return false;
24907acf3c0Scherry #endif
25007acf3c0Scherry
25107acf3c0Scherry /*
25207acf3c0Scherry * do we have room?
25307acf3c0Scherry */
25407acf3c0Scherry
25507acf3c0Scherry ps = uvm_physseg_alloc(sizeof (struct uvm_physseg));
25607acf3c0Scherry if (ps == NULL) {
25707acf3c0Scherry printf("uvm_page_physload: unable to load physical memory "
25807acf3c0Scherry "segment\n");
25907acf3c0Scherry printf("\t%d segments allocated, ignoring 0x%"PRIxPADDR" -> 0x%"PRIxPADDR"\n",
26007acf3c0Scherry VM_PHYSSEG_MAX, pfn, pfn + pages + 1);
26107acf3c0Scherry printf("\tincrease VM_PHYSSEG_MAX\n");
26207acf3c0Scherry return false;
26307acf3c0Scherry }
26407acf3c0Scherry
26507acf3c0Scherry /* span init */
26607acf3c0Scherry ps->start = pfn;
26707acf3c0Scherry ps->end = pfn + pages;
26807acf3c0Scherry
26907acf3c0Scherry /*
27007acf3c0Scherry * XXX: Ugly hack because uvmexp.npages accounts for only
27107acf3c0Scherry * those pages in the segment included below as well - this
27207acf3c0Scherry * should be legacy and removed.
27307acf3c0Scherry */
27407acf3c0Scherry
27507acf3c0Scherry ps->avail_start = ps->start;
27607acf3c0Scherry ps->avail_end = ps->end;
27707acf3c0Scherry
27807acf3c0Scherry /*
27907acf3c0Scherry * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
28007acf3c0Scherry * called yet, so kmem is not available).
28107acf3c0Scherry */
28207acf3c0Scherry
28307acf3c0Scherry preload = 1; /* We are going to assume it is a preload */
28407acf3c0Scherry
28507acf3c0Scherry RB_TREE_FOREACH(current_ps, &(uvm_physseg_graph.rb_tree)) {
28607acf3c0Scherry /* If there are non NULL pages then we are not in a preload */
28707acf3c0Scherry if (current_ps->pgs != NULL) {
28807acf3c0Scherry preload = 0;
28907acf3c0Scherry /* Try to scavenge from earlier unplug()s. */
29007acf3c0Scherry pgs = uvm_physseg_seg_alloc_from_slab(current_ps, pages);
29107acf3c0Scherry
29207acf3c0Scherry if (pgs != NULL) {
29307acf3c0Scherry break;
29407acf3c0Scherry }
29507acf3c0Scherry }
29607acf3c0Scherry }
29707acf3c0Scherry
29807acf3c0Scherry
29907acf3c0Scherry /*
30007acf3c0Scherry * if VM is already running, attempt to kmem_alloc vm_page structures
30107acf3c0Scherry */
30207acf3c0Scherry
30307acf3c0Scherry if (!preload) {
30407acf3c0Scherry if (pgs == NULL) { /* Brand new */
30507acf3c0Scherry /* Iteratively try alloc down from uvmexp.npages */
30607acf3c0Scherry for (slabpages = (size_t) uvmexp.npages; slabpages >= pages; slabpages--) {
30707acf3c0Scherry slab = kmem_zalloc(sizeof *pgs * (long unsigned int)slabpages, KM_NOSLEEP);
30807acf3c0Scherry if (slab != NULL)
30907acf3c0Scherry break;
31007acf3c0Scherry }
31107acf3c0Scherry
31207acf3c0Scherry if (slab == NULL) {
31307acf3c0Scherry uvm_physseg_free(ps, sizeof(struct uvm_physseg));
31407acf3c0Scherry return false;
31507acf3c0Scherry }
31607acf3c0Scherry
31707acf3c0Scherry uvm_physseg_seg_chomp_slab(ps, slab, (size_t) slabpages);
31807acf3c0Scherry /* We allocate enough for this plug */
31907acf3c0Scherry pgs = uvm_physseg_seg_alloc_from_slab(ps, pages);
32007acf3c0Scherry
32107acf3c0Scherry if (pgs == NULL) {
32207acf3c0Scherry printf("unable to uvm_physseg_seg_alloc_from_slab() from backend\n");
32307acf3c0Scherry return false;
32407acf3c0Scherry }
32507acf3c0Scherry } else {
32607acf3c0Scherry /* Reuse scavenged extent */
32707acf3c0Scherry ps->ext = current_ps->ext;
32807acf3c0Scherry }
32907acf3c0Scherry
33007acf3c0Scherry physmem += pages;
33107acf3c0Scherry uvmpdpol_reinit();
33207acf3c0Scherry } else { /* Boot time - see uvm_page.c:uvm_page_init() */
33307acf3c0Scherry pgs = NULL;
33407acf3c0Scherry ps->pgs = pgs;
33507acf3c0Scherry }
33607acf3c0Scherry
33707acf3c0Scherry /*
33807acf3c0Scherry * now insert us in the proper place in uvm_physseg_graph.rb_tree
33907acf3c0Scherry */
34007acf3c0Scherry
34107acf3c0Scherry current_ps = rb_tree_insert_node(&(uvm_physseg_graph.rb_tree), ps);
34207acf3c0Scherry if (current_ps != ps) {
34307acf3c0Scherry panic("uvm_page_physload: Duplicate address range detected!");
34407acf3c0Scherry }
34507acf3c0Scherry uvm_physseg_graph.nentries++;
34607acf3c0Scherry
34707acf3c0Scherry /*
34807acf3c0Scherry * uvm_pagefree() requires the PHYS_TO_VM_PAGE(pgs[i]) on the
34907acf3c0Scherry * newly allocated pgs[] to return the correct value. This is
35007acf3c0Scherry * a bit of a chicken and egg problem, since it needs
35107acf3c0Scherry * uvm_physseg_find() to succeed. For this, the node needs to
35207acf3c0Scherry * be inserted *before* uvm_physseg_init_seg() happens.
35307acf3c0Scherry *
35407acf3c0Scherry * During boot, this happens anyway, since
35507acf3c0Scherry * uvm_physseg_init_seg() is called later on and separately
35607acf3c0Scherry * from uvm_page.c:uvm_page_init().
35707acf3c0Scherry * In the case of hotplug we need to ensure this.
35807acf3c0Scherry */
35907acf3c0Scherry
36007acf3c0Scherry if (__predict_true(!preload))
36107acf3c0Scherry uvm_physseg_init_seg(ps, pgs);
36207acf3c0Scherry
36307acf3c0Scherry if (psp != NULL)
36407acf3c0Scherry *psp = ps;
36507acf3c0Scherry
36607acf3c0Scherry return true;
36707acf3c0Scherry }
36807acf3c0Scherry
36907acf3c0Scherry static int
uvm_physseg_compare_nodes(void * ctx,const void * nnode1,const void * nnode2)37007acf3c0Scherry uvm_physseg_compare_nodes(void *ctx, const void *nnode1, const void *nnode2)
37107acf3c0Scherry {
37207acf3c0Scherry const struct uvm_physseg *enode1 = nnode1;
37307acf3c0Scherry const struct uvm_physseg *enode2 = nnode2;
37407acf3c0Scherry
37507acf3c0Scherry KASSERT(enode1->start < enode2->start || enode1->start >= enode2->end);
37607acf3c0Scherry KASSERT(enode2->start < enode1->start || enode2->start >= enode1->end);
37707acf3c0Scherry
37807acf3c0Scherry if (enode1->start < enode2->start)
37907acf3c0Scherry return -1;
38007acf3c0Scherry if (enode1->start >= enode2->end)
38107acf3c0Scherry return 1;
38207acf3c0Scherry return 0;
38307acf3c0Scherry }
38407acf3c0Scherry
38507acf3c0Scherry static int
uvm_physseg_compare_key(void * ctx,const void * nnode,const void * pkey)38607acf3c0Scherry uvm_physseg_compare_key(void *ctx, const void *nnode, const void *pkey)
38707acf3c0Scherry {
38807acf3c0Scherry const struct uvm_physseg *enode = nnode;
38907acf3c0Scherry const paddr_t pa = *(const paddr_t *) pkey;
39007acf3c0Scherry
39107acf3c0Scherry if(enode->start <= pa && pa < enode->end)
39207acf3c0Scherry return 0;
39307acf3c0Scherry if (enode->start < pa)
39407acf3c0Scherry return -1;
39507acf3c0Scherry if (enode->end > pa)
39607acf3c0Scherry return 1;
39707acf3c0Scherry
39807acf3c0Scherry return 0;
39907acf3c0Scherry }
40007acf3c0Scherry
40107acf3c0Scherry static const rb_tree_ops_t uvm_physseg_tree_ops = {
40207acf3c0Scherry .rbto_compare_nodes = uvm_physseg_compare_nodes,
40307acf3c0Scherry .rbto_compare_key = uvm_physseg_compare_key,
40407acf3c0Scherry .rbto_node_offset = offsetof(struct uvm_physseg, rb_node),
40507acf3c0Scherry .rbto_context = NULL
40607acf3c0Scherry };
40707acf3c0Scherry
40807acf3c0Scherry /*
40907acf3c0Scherry * uvm_physseg_init: init the physmem
41007acf3c0Scherry *
41107acf3c0Scherry * => physmem unit should not be in use at this point
41207acf3c0Scherry */
41307acf3c0Scherry
41407acf3c0Scherry void
uvm_physseg_init(void)41507acf3c0Scherry uvm_physseg_init(void)
41607acf3c0Scherry {
41707acf3c0Scherry rb_tree_init(&(uvm_physseg_graph.rb_tree), &uvm_physseg_tree_ops);
41807acf3c0Scherry uvm_physseg_graph.nentries = 0;
41907acf3c0Scherry }
42007acf3c0Scherry
42107acf3c0Scherry uvm_physseg_t
uvm_physseg_get_next(uvm_physseg_t upm)42207acf3c0Scherry uvm_physseg_get_next(uvm_physseg_t upm)
42307acf3c0Scherry {
42407acf3c0Scherry /* next of invalid is invalid, not fatal */
425e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
42607acf3c0Scherry return UVM_PHYSSEG_TYPE_INVALID;
42707acf3c0Scherry
42807acf3c0Scherry return (uvm_physseg_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm,
42907acf3c0Scherry RB_DIR_RIGHT);
43007acf3c0Scherry }
43107acf3c0Scherry
43207acf3c0Scherry uvm_physseg_t
uvm_physseg_get_prev(uvm_physseg_t upm)43307acf3c0Scherry uvm_physseg_get_prev(uvm_physseg_t upm)
43407acf3c0Scherry {
43507acf3c0Scherry /* prev of invalid is invalid, not fatal */
436e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
43707acf3c0Scherry return UVM_PHYSSEG_TYPE_INVALID;
43807acf3c0Scherry
43907acf3c0Scherry return (uvm_physseg_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm,
44007acf3c0Scherry RB_DIR_LEFT);
44107acf3c0Scherry }
44207acf3c0Scherry
44307acf3c0Scherry uvm_physseg_t
uvm_physseg_get_last(void)44407acf3c0Scherry uvm_physseg_get_last(void)
44507acf3c0Scherry {
44607acf3c0Scherry return (uvm_physseg_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree));
44707acf3c0Scherry }
44807acf3c0Scherry
44907acf3c0Scherry uvm_physseg_t
uvm_physseg_get_first(void)45007acf3c0Scherry uvm_physseg_get_first(void)
45107acf3c0Scherry {
45207acf3c0Scherry return (uvm_physseg_t) RB_TREE_MIN(&(uvm_physseg_graph.rb_tree));
45307acf3c0Scherry }
45407acf3c0Scherry
45507acf3c0Scherry paddr_t
uvm_physseg_get_highest_frame(void)45607acf3c0Scherry uvm_physseg_get_highest_frame(void)
45707acf3c0Scherry {
45807acf3c0Scherry struct uvm_physseg *ps =
45907acf3c0Scherry (uvm_physseg_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree));
46007acf3c0Scherry
46107acf3c0Scherry return ps->end - 1;
46207acf3c0Scherry }
46307acf3c0Scherry
46407acf3c0Scherry /*
46507acf3c0Scherry * uvm_page_physunload: unload physical memory and return it to
46607acf3c0Scherry * caller.
46707acf3c0Scherry */
46807acf3c0Scherry bool
uvm_page_physunload(uvm_physseg_t upm,int freelist,paddr_t * paddrp)46907acf3c0Scherry uvm_page_physunload(uvm_physseg_t upm, int freelist, paddr_t *paddrp)
47007acf3c0Scherry {
47107acf3c0Scherry struct uvm_physseg *seg;
47207acf3c0Scherry
47307acf3c0Scherry if (__predict_true(uvm.page_init_done == true))
47407acf3c0Scherry panic("%s: unload attempted after uvm_page_init()\n", __func__);
47507acf3c0Scherry
47607acf3c0Scherry seg = HANDLE_TO_PHYSSEG_NODE(upm);
47707acf3c0Scherry
47807acf3c0Scherry if (seg->free_list != freelist) {
47907acf3c0Scherry return false;
48007acf3c0Scherry }
48107acf3c0Scherry
48207acf3c0Scherry /*
48307acf3c0Scherry * During cold boot, what we're about to unplug hasn't been
48407acf3c0Scherry * put on the uvm freelist, nor has uvmexp.npages been
48507acf3c0Scherry * updated. (This happens in uvm_page.c:uvm_page_init())
48607acf3c0Scherry *
48707acf3c0Scherry * For hotplug, we assume here that the pages being unloaded
48807acf3c0Scherry * here are completely out of sight of uvm (ie; not on any uvm
48907acf3c0Scherry * lists), and that uvmexp.npages has been suitably
49007acf3c0Scherry * decremented before we're called.
49107acf3c0Scherry *
49207acf3c0Scherry * XXX: will avail_end == start if avail_start < avail_end?
49307acf3c0Scherry */
49407acf3c0Scherry
49507acf3c0Scherry /* try from front */
49607acf3c0Scherry if (seg->avail_start == seg->start &&
49707acf3c0Scherry seg->avail_start < seg->avail_end) {
49807acf3c0Scherry *paddrp = ctob(seg->avail_start);
49907acf3c0Scherry return uvm_physseg_unplug(seg->avail_start, 1);
50007acf3c0Scherry }
50107acf3c0Scherry
50207acf3c0Scherry /* try from rear */
50307acf3c0Scherry if (seg->avail_end == seg->end &&
50407acf3c0Scherry seg->avail_start < seg->avail_end) {
50507acf3c0Scherry *paddrp = ctob(seg->avail_end - 1);
50607acf3c0Scherry return uvm_physseg_unplug(seg->avail_end - 1, 1);
50707acf3c0Scherry }
50807acf3c0Scherry
50907acf3c0Scherry return false;
51007acf3c0Scherry }
51107acf3c0Scherry
51207acf3c0Scherry bool
uvm_page_physunload_force(uvm_physseg_t upm,int freelist,paddr_t * paddrp)51307acf3c0Scherry uvm_page_physunload_force(uvm_physseg_t upm, int freelist, paddr_t *paddrp)
51407acf3c0Scherry {
51507acf3c0Scherry struct uvm_physseg *seg;
51607acf3c0Scherry
51707acf3c0Scherry seg = HANDLE_TO_PHYSSEG_NODE(upm);
51807acf3c0Scherry
51907acf3c0Scherry if (__predict_true(uvm.page_init_done == true))
52007acf3c0Scherry panic("%s: unload attempted after uvm_page_init()\n", __func__);
52107acf3c0Scherry /* any room in this bank? */
52207acf3c0Scherry if (seg->avail_start >= seg->avail_end) {
52307acf3c0Scherry return false; /* nope */
52407acf3c0Scherry }
52507acf3c0Scherry
52607acf3c0Scherry *paddrp = ctob(seg->avail_start);
52707acf3c0Scherry
52807acf3c0Scherry /* Always unplug from front */
52907acf3c0Scherry return uvm_physseg_unplug(seg->avail_start, 1);
53007acf3c0Scherry }
53107acf3c0Scherry
53207acf3c0Scherry
53307acf3c0Scherry /*
53407acf3c0Scherry * vm_physseg_find: find vm_physseg structure that belongs to a PA
53507acf3c0Scherry */
53607acf3c0Scherry uvm_physseg_t
uvm_physseg_find(paddr_t pframe,psize_t * offp)53707acf3c0Scherry uvm_physseg_find(paddr_t pframe, psize_t *offp)
53807acf3c0Scherry {
53907acf3c0Scherry struct uvm_physseg * ps = NULL;
54007acf3c0Scherry
54107acf3c0Scherry ps = rb_tree_find_node(&(uvm_physseg_graph.rb_tree), &pframe);
54207acf3c0Scherry
54307acf3c0Scherry if(ps != NULL && offp != NULL)
54407acf3c0Scherry *offp = pframe - ps->start;
54507acf3c0Scherry
54607acf3c0Scherry return ps;
54707acf3c0Scherry }
54807acf3c0Scherry
54907acf3c0Scherry #else /* UVM_HOTPLUG */
55007acf3c0Scherry
55107acf3c0Scherry /*
55207acf3c0Scherry * physical memory config is stored in vm_physmem.
55307acf3c0Scherry */
55407acf3c0Scherry
55507acf3c0Scherry #define VM_PHYSMEM_PTR(i) (&vm_physmem[i])
55607acf3c0Scherry #if VM_PHYSSEG_MAX == 1
55707acf3c0Scherry #define VM_PHYSMEM_PTR_SWAP(i, j) /* impossible */
55807acf3c0Scherry #else
55907acf3c0Scherry #define VM_PHYSMEM_PTR_SWAP(i, j) \
56007acf3c0Scherry do { vm_physmem[(i)] = vm_physmem[(j)]; } while (0)
56107acf3c0Scherry #endif
56207acf3c0Scherry
56307acf3c0Scherry #define HANDLE_TO_PHYSSEG_NODE(h) (VM_PHYSMEM_PTR((int)h))
56407acf3c0Scherry #define PHYSSEG_NODE_TO_HANDLE(u) ((int)((vsize_t) (u - vm_physmem) / sizeof(struct uvm_physseg)))
56507acf3c0Scherry
566128aefc0Sad /* XXXCDC: uvm.physmem */
567128aefc0Sad static struct uvm_physseg vm_physmem[VM_PHYSSEG_MAX] __read_mostly;
568128aefc0Sad /* XXXCDC: uvm.nphysseg */
569128aefc0Sad static int vm_nphysseg __read_mostly = 0;
57007acf3c0Scherry #define vm_nphysmem vm_nphysseg
57107acf3c0Scherry
57207acf3c0Scherry void
uvm_physseg_init(void)57307acf3c0Scherry uvm_physseg_init(void)
57407acf3c0Scherry {
57507acf3c0Scherry /* XXX: Provisioning for rb_tree related init(s) */
57607acf3c0Scherry return;
57707acf3c0Scherry }
57807acf3c0Scherry
57907acf3c0Scherry int
uvm_physseg_get_next(uvm_physseg_t lcv)58007acf3c0Scherry uvm_physseg_get_next(uvm_physseg_t lcv)
58107acf3c0Scherry {
58207acf3c0Scherry /* next of invalid is invalid, not fatal */
583e6ff351eScherry if (uvm_physseg_valid_p(lcv) == false)
58407acf3c0Scherry return UVM_PHYSSEG_TYPE_INVALID;
58507acf3c0Scherry
58607acf3c0Scherry return (lcv + 1);
58707acf3c0Scherry }
58807acf3c0Scherry
58907acf3c0Scherry int
uvm_physseg_get_prev(uvm_physseg_t lcv)59007acf3c0Scherry uvm_physseg_get_prev(uvm_physseg_t lcv)
59107acf3c0Scherry {
59207acf3c0Scherry /* prev of invalid is invalid, not fatal */
593e6ff351eScherry if (uvm_physseg_valid_p(lcv) == false)
59407acf3c0Scherry return UVM_PHYSSEG_TYPE_INVALID;
59507acf3c0Scherry
59607acf3c0Scherry return (lcv - 1);
59707acf3c0Scherry }
59807acf3c0Scherry
59907acf3c0Scherry int
uvm_physseg_get_last(void)60007acf3c0Scherry uvm_physseg_get_last(void)
60107acf3c0Scherry {
60207acf3c0Scherry return (vm_nphysseg - 1);
60307acf3c0Scherry }
60407acf3c0Scherry
60507acf3c0Scherry int
uvm_physseg_get_first(void)60607acf3c0Scherry uvm_physseg_get_first(void)
60707acf3c0Scherry {
60807acf3c0Scherry return 0;
60907acf3c0Scherry }
61007acf3c0Scherry
61107acf3c0Scherry paddr_t
uvm_physseg_get_highest_frame(void)61207acf3c0Scherry uvm_physseg_get_highest_frame(void)
61307acf3c0Scherry {
61407acf3c0Scherry int lcv;
61507acf3c0Scherry paddr_t last = 0;
61607acf3c0Scherry struct uvm_physseg *ps;
61707acf3c0Scherry
61807acf3c0Scherry for (lcv = 0; lcv < vm_nphysseg; lcv++) {
61907acf3c0Scherry ps = VM_PHYSMEM_PTR(lcv);
62007acf3c0Scherry if (last < ps->end)
62107acf3c0Scherry last = ps->end;
62207acf3c0Scherry }
62307acf3c0Scherry
62407acf3c0Scherry return last;
62507acf3c0Scherry }
62607acf3c0Scherry
62707acf3c0Scherry
62807acf3c0Scherry static struct vm_page *
uvm_post_preload_check(void)62907acf3c0Scherry uvm_post_preload_check(void)
63007acf3c0Scherry {
63107acf3c0Scherry int preload, lcv;
63207acf3c0Scherry
63307acf3c0Scherry /*
63407acf3c0Scherry * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
63507acf3c0Scherry * called yet, so kmem is not available).
63607acf3c0Scherry */
63707acf3c0Scherry
63807acf3c0Scherry for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
63907acf3c0Scherry if (VM_PHYSMEM_PTR(lcv)->pgs)
64007acf3c0Scherry break;
64107acf3c0Scherry }
64207acf3c0Scherry preload = (lcv == vm_nphysmem);
64307acf3c0Scherry
64407acf3c0Scherry /*
64507acf3c0Scherry * if VM is already running, attempt to kmem_alloc vm_page structures
64607acf3c0Scherry */
64707acf3c0Scherry
64807acf3c0Scherry if (!preload) {
64907acf3c0Scherry panic("Tried to add RAM after uvm_page_init");
65007acf3c0Scherry }
65107acf3c0Scherry
65207acf3c0Scherry return NULL;
65307acf3c0Scherry }
65407acf3c0Scherry
65507acf3c0Scherry /*
65607acf3c0Scherry * uvm_page_physunload: unload physical memory and return it to
65707acf3c0Scherry * caller.
65807acf3c0Scherry */
65907acf3c0Scherry bool
uvm_page_physunload(uvm_physseg_t psi,int freelist,paddr_t * paddrp)66007acf3c0Scherry uvm_page_physunload(uvm_physseg_t psi, int freelist, paddr_t *paddrp)
66107acf3c0Scherry {
66207acf3c0Scherry int x;
66307acf3c0Scherry struct uvm_physseg *seg;
66407acf3c0Scherry
66507acf3c0Scherry uvm_post_preload_check();
66607acf3c0Scherry
66707acf3c0Scherry seg = VM_PHYSMEM_PTR(psi);
66807acf3c0Scherry
66907acf3c0Scherry if (seg->free_list != freelist) {
67007acf3c0Scherry return false;
67107acf3c0Scherry }
67207acf3c0Scherry
67307acf3c0Scherry /* try from front */
67407acf3c0Scherry if (seg->avail_start == seg->start &&
67507acf3c0Scherry seg->avail_start < seg->avail_end) {
67607acf3c0Scherry *paddrp = ctob(seg->avail_start);
67707acf3c0Scherry seg->avail_start++;
67807acf3c0Scherry seg->start++;
67907acf3c0Scherry /* nothing left? nuke it */
68007acf3c0Scherry if (seg->avail_start == seg->end) {
68107acf3c0Scherry if (vm_nphysmem == 1)
68207acf3c0Scherry panic("uvm_page_physget: out of memory!");
68307acf3c0Scherry vm_nphysmem--;
68407acf3c0Scherry for (x = psi ; x < vm_nphysmem ; x++)
68507acf3c0Scherry /* structure copy */
68607acf3c0Scherry VM_PHYSMEM_PTR_SWAP(x, x + 1);
68707acf3c0Scherry }
68807acf3c0Scherry return (true);
68907acf3c0Scherry }
69007acf3c0Scherry
69107acf3c0Scherry /* try from rear */
69207acf3c0Scherry if (seg->avail_end == seg->end &&
69307acf3c0Scherry seg->avail_start < seg->avail_end) {
69407acf3c0Scherry *paddrp = ctob(seg->avail_end - 1);
69507acf3c0Scherry seg->avail_end--;
69607acf3c0Scherry seg->end--;
69707acf3c0Scherry /* nothing left? nuke it */
69807acf3c0Scherry if (seg->avail_end == seg->start) {
69907acf3c0Scherry if (vm_nphysmem == 1)
70007acf3c0Scherry panic("uvm_page_physget: out of memory!");
70107acf3c0Scherry vm_nphysmem--;
70207acf3c0Scherry for (x = psi ; x < vm_nphysmem ; x++)
70307acf3c0Scherry /* structure copy */
70407acf3c0Scherry VM_PHYSMEM_PTR_SWAP(x, x + 1);
70507acf3c0Scherry }
70607acf3c0Scherry return (true);
70707acf3c0Scherry }
70807acf3c0Scherry
70907acf3c0Scherry return false;
71007acf3c0Scherry }
71107acf3c0Scherry
71207acf3c0Scherry bool
uvm_page_physunload_force(uvm_physseg_t psi,int freelist,paddr_t * paddrp)71307acf3c0Scherry uvm_page_physunload_force(uvm_physseg_t psi, int freelist, paddr_t *paddrp)
71407acf3c0Scherry {
71507acf3c0Scherry int x;
71607acf3c0Scherry struct uvm_physseg *seg;
71707acf3c0Scherry
71807acf3c0Scherry uvm_post_preload_check();
71907acf3c0Scherry
72007acf3c0Scherry seg = VM_PHYSMEM_PTR(psi);
72107acf3c0Scherry
72207acf3c0Scherry /* any room in this bank? */
72307acf3c0Scherry if (seg->avail_start >= seg->avail_end) {
72407acf3c0Scherry return false; /* nope */
72507acf3c0Scherry }
72607acf3c0Scherry
72707acf3c0Scherry *paddrp = ctob(seg->avail_start);
72807acf3c0Scherry seg->avail_start++;
72907acf3c0Scherry /* truncate! */
73007acf3c0Scherry seg->start = seg->avail_start;
73107acf3c0Scherry
73207acf3c0Scherry /* nothing left? nuke it */
73307acf3c0Scherry if (seg->avail_start == seg->end) {
73407acf3c0Scherry if (vm_nphysmem == 1)
73507acf3c0Scherry panic("uvm_page_physget: out of memory!");
73607acf3c0Scherry vm_nphysmem--;
73707acf3c0Scherry for (x = psi ; x < vm_nphysmem ; x++)
73807acf3c0Scherry /* structure copy */
73907acf3c0Scherry VM_PHYSMEM_PTR_SWAP(x, x + 1);
74007acf3c0Scherry }
74107acf3c0Scherry return (true);
74207acf3c0Scherry }
74307acf3c0Scherry
74407acf3c0Scherry bool
uvm_physseg_plug(paddr_t pfn,size_t pages,uvm_physseg_t * psp)74507acf3c0Scherry uvm_physseg_plug(paddr_t pfn, size_t pages, uvm_physseg_t *psp)
74607acf3c0Scherry {
74707acf3c0Scherry int lcv;
74807acf3c0Scherry struct vm_page *pgs;
74907acf3c0Scherry struct uvm_physseg *ps;
75007acf3c0Scherry
75107acf3c0Scherry #ifdef DEBUG
75207acf3c0Scherry paddr_t off;
75307acf3c0Scherry uvm_physseg_t upm;
75407acf3c0Scherry upm = uvm_physseg_find(pfn, &off);
75507acf3c0Scherry
756e6ff351eScherry if (uvm_physseg_valid_p(upm)) /* XXX; do we allow "update" plugs ? */
75707acf3c0Scherry return false;
75807acf3c0Scherry #endif
75907acf3c0Scherry
76007acf3c0Scherry paddr_t start = pfn;
76107acf3c0Scherry paddr_t end = pfn + pages;
76207acf3c0Scherry paddr_t avail_start = start;
76307acf3c0Scherry paddr_t avail_end = end;
76407acf3c0Scherry
76507acf3c0Scherry if (uvmexp.pagesize == 0)
76607acf3c0Scherry panic("uvm_page_physload: page size not set!");
76707acf3c0Scherry
76807acf3c0Scherry /*
76907acf3c0Scherry * do we have room?
77007acf3c0Scherry */
77107acf3c0Scherry
77207acf3c0Scherry if (vm_nphysmem == VM_PHYSSEG_MAX) {
77307acf3c0Scherry printf("uvm_page_physload: unable to load physical memory "
77407acf3c0Scherry "segment\n");
77507acf3c0Scherry printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n",
77607acf3c0Scherry VM_PHYSSEG_MAX, (long long)start, (long long)end);
77707acf3c0Scherry printf("\tincrease VM_PHYSSEG_MAX\n");
77807acf3c0Scherry if (psp != NULL)
77907acf3c0Scherry *psp = UVM_PHYSSEG_TYPE_INVALID_OVERFLOW;
78007acf3c0Scherry return false;
78107acf3c0Scherry }
78207acf3c0Scherry
78307acf3c0Scherry /*
78407acf3c0Scherry * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
78507acf3c0Scherry * called yet, so kmem is not available).
78607acf3c0Scherry */
78707acf3c0Scherry pgs = uvm_post_preload_check();
78807acf3c0Scherry
78907acf3c0Scherry /*
79007acf3c0Scherry * now insert us in the proper place in vm_physmem[]
79107acf3c0Scherry */
79207acf3c0Scherry
79307acf3c0Scherry #if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM)
79407acf3c0Scherry /* random: put it at the end (easy!) */
79507acf3c0Scherry ps = VM_PHYSMEM_PTR(vm_nphysmem);
796a9cac8faScherry lcv = vm_nphysmem;
79707acf3c0Scherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
79807acf3c0Scherry {
79907acf3c0Scherry int x;
80007acf3c0Scherry /* sort by address for binary search */
80107acf3c0Scherry for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
80207acf3c0Scherry if (start < VM_PHYSMEM_PTR(lcv)->start)
80307acf3c0Scherry break;
80407acf3c0Scherry ps = VM_PHYSMEM_PTR(lcv);
80507acf3c0Scherry /* move back other entries, if necessary ... */
80607acf3c0Scherry for (x = vm_nphysmem ; x > lcv ; x--)
80707acf3c0Scherry /* structure copy */
80807acf3c0Scherry VM_PHYSMEM_PTR_SWAP(x, x - 1);
80907acf3c0Scherry }
81007acf3c0Scherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
81107acf3c0Scherry {
81207acf3c0Scherry int x;
81307acf3c0Scherry /* sort by largest segment first */
81407acf3c0Scherry for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
81507acf3c0Scherry if ((end - start) >
81607acf3c0Scherry (VM_PHYSMEM_PTR(lcv)->end - VM_PHYSMEM_PTR(lcv)->start))
81707acf3c0Scherry break;
81807acf3c0Scherry ps = VM_PHYSMEM_PTR(lcv);
81907acf3c0Scherry /* move back other entries, if necessary ... */
82007acf3c0Scherry for (x = vm_nphysmem ; x > lcv ; x--)
82107acf3c0Scherry /* structure copy */
82207acf3c0Scherry VM_PHYSMEM_PTR_SWAP(x, x - 1);
82307acf3c0Scherry }
82407acf3c0Scherry #else
82507acf3c0Scherry panic("uvm_page_physload: unknown physseg strategy selected!");
82607acf3c0Scherry #endif
82707acf3c0Scherry
82807acf3c0Scherry ps->start = start;
82907acf3c0Scherry ps->end = end;
83007acf3c0Scherry ps->avail_start = avail_start;
83107acf3c0Scherry ps->avail_end = avail_end;
83207acf3c0Scherry
83307acf3c0Scherry ps->pgs = pgs;
83407acf3c0Scherry
83507acf3c0Scherry vm_nphysmem++;
83607acf3c0Scherry
83707acf3c0Scherry if (psp != NULL)
83807acf3c0Scherry *psp = lcv;
83907acf3c0Scherry
84007acf3c0Scherry return true;
84107acf3c0Scherry }
84207acf3c0Scherry
84307acf3c0Scherry /*
84407acf3c0Scherry * when VM_PHYSSEG_MAX is 1, we can simplify these functions
84507acf3c0Scherry */
84607acf3c0Scherry
84707acf3c0Scherry #if VM_PHYSSEG_MAX == 1
84807acf3c0Scherry static inline int vm_physseg_find_contig(struct uvm_physseg *, int, paddr_t, psize_t *);
84907acf3c0Scherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
85007acf3c0Scherry static inline int vm_physseg_find_bsearch(struct uvm_physseg *, int, paddr_t, psize_t *);
85107acf3c0Scherry #else
85207acf3c0Scherry static inline int vm_physseg_find_linear(struct uvm_physseg *, int, paddr_t, psize_t *);
85307acf3c0Scherry #endif
85407acf3c0Scherry
85507acf3c0Scherry /*
85607acf3c0Scherry * vm_physseg_find: find vm_physseg structure that belongs to a PA
85707acf3c0Scherry */
858128aefc0Sad inline int
uvm_physseg_find(paddr_t pframe,psize_t * offp)85907acf3c0Scherry uvm_physseg_find(paddr_t pframe, psize_t *offp)
86007acf3c0Scherry {
86107acf3c0Scherry
86207acf3c0Scherry #if VM_PHYSSEG_MAX == 1
86307acf3c0Scherry return vm_physseg_find_contig(vm_physmem, vm_nphysseg, pframe, offp);
86407acf3c0Scherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
86507acf3c0Scherry return vm_physseg_find_bsearch(vm_physmem, vm_nphysseg, pframe, offp);
86607acf3c0Scherry #else
86707acf3c0Scherry return vm_physseg_find_linear(vm_physmem, vm_nphysseg, pframe, offp);
86807acf3c0Scherry #endif
86907acf3c0Scherry }
87007acf3c0Scherry
87107acf3c0Scherry #if VM_PHYSSEG_MAX == 1
87207acf3c0Scherry static inline int
vm_physseg_find_contig(struct uvm_physseg * segs,int nsegs,paddr_t pframe,psize_t * offp)87307acf3c0Scherry vm_physseg_find_contig(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
87407acf3c0Scherry {
87507acf3c0Scherry
87607acf3c0Scherry /* 'contig' case */
87707acf3c0Scherry if (pframe >= segs[0].start && pframe < segs[0].end) {
87807acf3c0Scherry if (offp)
87907acf3c0Scherry *offp = pframe - segs[0].start;
88007acf3c0Scherry return(0);
88107acf3c0Scherry }
88207acf3c0Scherry return(-1);
88307acf3c0Scherry }
88407acf3c0Scherry
88507acf3c0Scherry #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
88607acf3c0Scherry
88707acf3c0Scherry static inline int
vm_physseg_find_bsearch(struct uvm_physseg * segs,int nsegs,paddr_t pframe,psize_t * offp)88807acf3c0Scherry vm_physseg_find_bsearch(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
88907acf3c0Scherry {
89007acf3c0Scherry /* binary search for it */
89107acf3c0Scherry int start, len, guess;
89207acf3c0Scherry
89307acf3c0Scherry /*
89407acf3c0Scherry * if try is too large (thus target is less than try) we reduce
89507acf3c0Scherry * the length to trunc(len/2) [i.e. everything smaller than "try"]
89607acf3c0Scherry *
89707acf3c0Scherry * if the try is too small (thus target is greater than try) then
89807acf3c0Scherry * we set the new start to be (try + 1). this means we need to
89907acf3c0Scherry * reduce the length to (round(len/2) - 1).
90007acf3c0Scherry *
90107acf3c0Scherry * note "adjust" below which takes advantage of the fact that
90207acf3c0Scherry * (round(len/2) - 1) == trunc((len - 1) / 2)
90307acf3c0Scherry * for any value of len we may have
90407acf3c0Scherry */
90507acf3c0Scherry
90607acf3c0Scherry for (start = 0, len = nsegs ; len != 0 ; len = len / 2) {
90707acf3c0Scherry guess = start + (len / 2); /* try in the middle */
90807acf3c0Scherry
90907acf3c0Scherry /* start past our try? */
91007acf3c0Scherry if (pframe >= segs[guess].start) {
91107acf3c0Scherry /* was try correct? */
91207acf3c0Scherry if (pframe < segs[guess].end) {
91307acf3c0Scherry if (offp)
91407acf3c0Scherry *offp = pframe - segs[guess].start;
91507acf3c0Scherry return guess; /* got it */
91607acf3c0Scherry }
91707acf3c0Scherry start = guess + 1; /* next time, start here */
91807acf3c0Scherry len--; /* "adjust" */
91907acf3c0Scherry } else {
92007acf3c0Scherry /*
92107acf3c0Scherry * pframe before try, just reduce length of
92207acf3c0Scherry * region, done in "for" loop
92307acf3c0Scherry */
92407acf3c0Scherry }
92507acf3c0Scherry }
92607acf3c0Scherry return(-1);
92707acf3c0Scherry }
92807acf3c0Scherry
92907acf3c0Scherry #else
93007acf3c0Scherry
93107acf3c0Scherry static inline int
vm_physseg_find_linear(struct uvm_physseg * segs,int nsegs,paddr_t pframe,psize_t * offp)93207acf3c0Scherry vm_physseg_find_linear(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
93307acf3c0Scherry {
93407acf3c0Scherry /* linear search for it */
93507acf3c0Scherry int lcv;
93607acf3c0Scherry
93707acf3c0Scherry for (lcv = 0; lcv < nsegs; lcv++) {
93807acf3c0Scherry if (pframe >= segs[lcv].start &&
93907acf3c0Scherry pframe < segs[lcv].end) {
94007acf3c0Scherry if (offp)
94107acf3c0Scherry *offp = pframe - segs[lcv].start;
94207acf3c0Scherry return(lcv); /* got it */
94307acf3c0Scherry }
94407acf3c0Scherry }
94507acf3c0Scherry return(-1);
94607acf3c0Scherry }
94707acf3c0Scherry #endif
94807acf3c0Scherry #endif /* UVM_HOTPLUG */
94907acf3c0Scherry
950128aefc0Sad /*
951128aefc0Sad * PHYS_TO_VM_PAGE: find vm_page for a PA. used by MI code to get vm_pages
952128aefc0Sad * back from an I/O mapping (ugh!). used in some MD code as well. it can
953128aefc0Sad * be prominent in flamegraphs, so optimise it and try to make it easy for
954128aefc0Sad * the compiler by including next to the inline lookup routines.
955128aefc0Sad */
956128aefc0Sad struct vm_page *
uvm_phys_to_vm_page(paddr_t pa)957128aefc0Sad uvm_phys_to_vm_page(paddr_t pa)
958128aefc0Sad {
959128aefc0Sad #if VM_PHYSSEG_STRAT != VM_PSTRAT_BSEARCH
960128aefc0Sad /* 'contig' and linear cases */
961128aefc0Sad KASSERT(vm_nphysseg > 0);
962128aefc0Sad struct uvm_physseg *ps = &vm_physmem[0];
963128aefc0Sad struct uvm_physseg *end = &vm_physmem[vm_nphysseg];
964128aefc0Sad paddr_t pframe = atop(pa);
965128aefc0Sad do {
966128aefc0Sad if (pframe >= ps->start && pframe < ps->end) {
967128aefc0Sad return &ps->pgs[pframe - ps->start];
968128aefc0Sad }
969128aefc0Sad } while (VM_PHYSSEG_MAX > 1 && __predict_false(++ps < end));
970128aefc0Sad return NULL;
971128aefc0Sad #else
972128aefc0Sad /* binary search for it */
973128aefc0Sad paddr_t pf = atop(pa);
974128aefc0Sad paddr_t off;
975128aefc0Sad uvm_physseg_t upm;
976128aefc0Sad
977128aefc0Sad upm = uvm_physseg_find(pf, &off);
978128aefc0Sad if (upm != UVM_PHYSSEG_TYPE_INVALID)
979128aefc0Sad return uvm_physseg_get_pg(upm, off);
980128aefc0Sad return(NULL);
981128aefc0Sad #endif
982128aefc0Sad }
983128aefc0Sad
98407acf3c0Scherry bool
uvm_physseg_valid_p(uvm_physseg_t upm)985e6ff351eScherry uvm_physseg_valid_p(uvm_physseg_t upm)
98607acf3c0Scherry {
98707acf3c0Scherry struct uvm_physseg *ps;
98807acf3c0Scherry
98907acf3c0Scherry if (upm == UVM_PHYSSEG_TYPE_INVALID ||
99007acf3c0Scherry upm == UVM_PHYSSEG_TYPE_INVALID_EMPTY ||
99107acf3c0Scherry upm == UVM_PHYSSEG_TYPE_INVALID_OVERFLOW)
99207acf3c0Scherry return false;
99307acf3c0Scherry
99407acf3c0Scherry /*
99507acf3c0Scherry * This is the delicate init dance -
99607acf3c0Scherry * needs to go with the dance.
99707acf3c0Scherry */
99807acf3c0Scherry if (uvm.page_init_done != true)
99907acf3c0Scherry return true;
100007acf3c0Scherry
100107acf3c0Scherry ps = HANDLE_TO_PHYSSEG_NODE(upm);
100207acf3c0Scherry
100307acf3c0Scherry /* Extra checks needed only post uvm_page_init() */
100407acf3c0Scherry if (ps->pgs == NULL)
100507acf3c0Scherry return false;
100607acf3c0Scherry
100707acf3c0Scherry /* XXX: etc. */
100807acf3c0Scherry
100907acf3c0Scherry return true;
101007acf3c0Scherry
101107acf3c0Scherry }
101207acf3c0Scherry
101307acf3c0Scherry /*
101407acf3c0Scherry * Boot protocol dictates that these must be able to return partially
101507acf3c0Scherry * initialised segments.
101607acf3c0Scherry */
101707acf3c0Scherry paddr_t
uvm_physseg_get_start(uvm_physseg_t upm)101807acf3c0Scherry uvm_physseg_get_start(uvm_physseg_t upm)
101907acf3c0Scherry {
1020e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
102107acf3c0Scherry return (paddr_t) -1;
102207acf3c0Scherry
102307acf3c0Scherry return HANDLE_TO_PHYSSEG_NODE(upm)->start;
102407acf3c0Scherry }
102507acf3c0Scherry
102607acf3c0Scherry paddr_t
uvm_physseg_get_end(uvm_physseg_t upm)102707acf3c0Scherry uvm_physseg_get_end(uvm_physseg_t upm)
102807acf3c0Scherry {
1029e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
103007acf3c0Scherry return (paddr_t) -1;
103107acf3c0Scherry
103207acf3c0Scherry return HANDLE_TO_PHYSSEG_NODE(upm)->end;
103307acf3c0Scherry }
103407acf3c0Scherry
103507acf3c0Scherry paddr_t
uvm_physseg_get_avail_start(uvm_physseg_t upm)103607acf3c0Scherry uvm_physseg_get_avail_start(uvm_physseg_t upm)
103707acf3c0Scherry {
1038e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
103907acf3c0Scherry return (paddr_t) -1;
104007acf3c0Scherry
104107acf3c0Scherry return HANDLE_TO_PHYSSEG_NODE(upm)->avail_start;
104207acf3c0Scherry }
104307acf3c0Scherry
1044c7ed8c6fSrin #if defined(UVM_PHYSSEG_LEGACY)
10456419995eSchristos void
uvm_physseg_set_avail_start(uvm_physseg_t upm,paddr_t avail_start)10466419995eSchristos uvm_physseg_set_avail_start(uvm_physseg_t upm, paddr_t avail_start)
10476419995eSchristos {
10486b706f88Scherry struct uvm_physseg *ps = HANDLE_TO_PHYSSEG_NODE(upm);
10496b706f88Scherry
10506b706f88Scherry #if defined(DIAGNOSTIC)
10516b706f88Scherry paddr_t avail_end;
10526b706f88Scherry avail_end = uvm_physseg_get_avail_end(upm);
10536419995eSchristos KASSERT(uvm_physseg_valid_p(upm));
1054a83cdbecSriastradh KASSERT(avail_start < avail_end);
1055a83cdbecSriastradh KASSERT(avail_start >= ps->start);
10566419995eSchristos #endif
10576419995eSchristos
10586b706f88Scherry ps->avail_start = avail_start;
10596b706f88Scherry }
1060519577eeSad
1061519577eeSad void
uvm_physseg_set_avail_end(uvm_physseg_t upm,paddr_t avail_end)1062519577eeSad uvm_physseg_set_avail_end(uvm_physseg_t upm, paddr_t avail_end)
10636b706f88Scherry {
10646b706f88Scherry struct uvm_physseg *ps = HANDLE_TO_PHYSSEG_NODE(upm);
10656b706f88Scherry
10666b706f88Scherry #if defined(DIAGNOSTIC)
10676b706f88Scherry paddr_t avail_start;
10686b706f88Scherry avail_start = uvm_physseg_get_avail_start(upm);
10696b706f88Scherry KASSERT(uvm_physseg_valid_p(upm));
1070a83cdbecSriastradh KASSERT(avail_end > avail_start);
1071a83cdbecSriastradh KASSERT(avail_end <= ps->end);
10726b706f88Scherry #endif
10736b706f88Scherry
10746b706f88Scherry ps->avail_end = avail_end;
10756b706f88Scherry }
10766b706f88Scherry
1077c7ed8c6fSrin #endif /* UVM_PHYSSEG_LEGACY */
10786b706f88Scherry
107907acf3c0Scherry paddr_t
uvm_physseg_get_avail_end(uvm_physseg_t upm)108007acf3c0Scherry uvm_physseg_get_avail_end(uvm_physseg_t upm)
108107acf3c0Scherry {
1082e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
108307acf3c0Scherry return (paddr_t) -1;
108407acf3c0Scherry
108507acf3c0Scherry return HANDLE_TO_PHYSSEG_NODE(upm)->avail_end;
108607acf3c0Scherry }
108707acf3c0Scherry
1088128aefc0Sad inline struct vm_page *
uvm_physseg_get_pg(uvm_physseg_t upm,paddr_t idx)108907acf3c0Scherry uvm_physseg_get_pg(uvm_physseg_t upm, paddr_t idx)
109007acf3c0Scherry {
1091e6ff351eScherry KASSERT(uvm_physseg_valid_p(upm));
109207acf3c0Scherry return &HANDLE_TO_PHYSSEG_NODE(upm)->pgs[idx];
109307acf3c0Scherry }
109407acf3c0Scherry
109507acf3c0Scherry #ifdef __HAVE_PMAP_PHYSSEG
109607acf3c0Scherry struct pmap_physseg *
uvm_physseg_get_pmseg(uvm_physseg_t upm)109707acf3c0Scherry uvm_physseg_get_pmseg(uvm_physseg_t upm)
109807acf3c0Scherry {
1099e6ff351eScherry KASSERT(uvm_physseg_valid_p(upm));
110007acf3c0Scherry return &(HANDLE_TO_PHYSSEG_NODE(upm)->pmseg);
110107acf3c0Scherry }
110207acf3c0Scherry #endif
110307acf3c0Scherry
110407acf3c0Scherry int
uvm_physseg_get_free_list(uvm_physseg_t upm)110507acf3c0Scherry uvm_physseg_get_free_list(uvm_physseg_t upm)
110607acf3c0Scherry {
1107e6ff351eScherry KASSERT(uvm_physseg_valid_p(upm));
110807acf3c0Scherry return HANDLE_TO_PHYSSEG_NODE(upm)->free_list;
110907acf3c0Scherry }
111007acf3c0Scherry
1111*ecaf2f40Stnn u_long
uvm_physseg_get_start_hint(uvm_physseg_t upm)111207acf3c0Scherry uvm_physseg_get_start_hint(uvm_physseg_t upm)
111307acf3c0Scherry {
1114e6ff351eScherry KASSERT(uvm_physseg_valid_p(upm));
111507acf3c0Scherry return HANDLE_TO_PHYSSEG_NODE(upm)->start_hint;
111607acf3c0Scherry }
111707acf3c0Scherry
111807acf3c0Scherry bool
uvm_physseg_set_start_hint(uvm_physseg_t upm,u_long start_hint)1119*ecaf2f40Stnn uvm_physseg_set_start_hint(uvm_physseg_t upm, u_long start_hint)
112007acf3c0Scherry {
1121e6ff351eScherry if (uvm_physseg_valid_p(upm) == false)
112207acf3c0Scherry return false;
112307acf3c0Scherry
112407acf3c0Scherry HANDLE_TO_PHYSSEG_NODE(upm)->start_hint = start_hint;
112507acf3c0Scherry return true;
112607acf3c0Scherry }
112707acf3c0Scherry
112807acf3c0Scherry void
uvm_physseg_init_seg(uvm_physseg_t upm,struct vm_page * pgs)112907acf3c0Scherry uvm_physseg_init_seg(uvm_physseg_t upm, struct vm_page *pgs)
113007acf3c0Scherry {
113107acf3c0Scherry psize_t i;
113207acf3c0Scherry psize_t n;
113307acf3c0Scherry paddr_t paddr;
113407acf3c0Scherry struct uvm_physseg *seg;
11355978ddc6Sad struct vm_page *pg;
113607acf3c0Scherry
1137a83cdbecSriastradh KASSERT(upm != UVM_PHYSSEG_TYPE_INVALID);
1138a83cdbecSriastradh KASSERT(pgs != NULL);
113907acf3c0Scherry
114007acf3c0Scherry seg = HANDLE_TO_PHYSSEG_NODE(upm);
114107acf3c0Scherry KASSERT(seg != NULL);
114207acf3c0Scherry KASSERT(seg->pgs == NULL);
114307acf3c0Scherry
114407acf3c0Scherry n = seg->end - seg->start;
114507acf3c0Scherry seg->pgs = pgs;
114607acf3c0Scherry
114707acf3c0Scherry /* init and free vm_pages (we've already zeroed them) */
114807acf3c0Scherry paddr = ctob(seg->start);
114907acf3c0Scherry for (i = 0 ; i < n ; i++, paddr += PAGE_SIZE) {
1150a7b92da9Sad pg = &seg->pgs[i];
1151a7b92da9Sad pg->phys_addr = paddr;
115207acf3c0Scherry #ifdef __HAVE_VM_PAGE_MD
1153a7b92da9Sad VM_MDPAGE_INIT(pg);
115407acf3c0Scherry #endif
115507acf3c0Scherry if (atop(paddr) >= seg->avail_start &&
115607acf3c0Scherry atop(paddr) < seg->avail_end) {
115707acf3c0Scherry uvmexp.npages++;
115807acf3c0Scherry /* add page to free pool */
1159a7b92da9Sad uvm_page_set_freelist(pg,
1160a7b92da9Sad uvm_page_lookup_freelist(pg));
11615978ddc6Sad /* Disable LOCKDEBUG: too many and too early. */
11625978ddc6Sad mutex_init(&pg->interlock, MUTEX_NODEBUG, IPL_NONE);
11635978ddc6Sad uvm_pagefree(pg);
116407acf3c0Scherry }
116507acf3c0Scherry }
116607acf3c0Scherry }
116707acf3c0Scherry
116807acf3c0Scherry void
uvm_physseg_seg_chomp_slab(uvm_physseg_t upm,struct vm_page * pgs,size_t n)116907acf3c0Scherry uvm_physseg_seg_chomp_slab(uvm_physseg_t upm, struct vm_page *pgs, size_t n)
117007acf3c0Scherry {
117107acf3c0Scherry struct uvm_physseg *seg = HANDLE_TO_PHYSSEG_NODE(upm);
117207acf3c0Scherry
117307acf3c0Scherry /* max number of pre-boot unplug()s allowed */
117407acf3c0Scherry #define UVM_PHYSSEG_BOOT_UNPLUG_MAX VM_PHYSSEG_MAX
117507acf3c0Scherry
117607acf3c0Scherry static char btslab_ex_storage[EXTENT_FIXED_STORAGE_SIZE(UVM_PHYSSEG_BOOT_UNPLUG_MAX)];
117707acf3c0Scherry
117807acf3c0Scherry if (__predict_false(uvm.page_init_done == false)) {
117907acf3c0Scherry seg->ext = extent_create("Boot time slab", (u_long) pgs, (u_long) (pgs + n),
118007acf3c0Scherry (void *)btslab_ex_storage, sizeof(btslab_ex_storage), 0);
118107acf3c0Scherry } else {
118207acf3c0Scherry seg->ext = extent_create("Hotplug slab", (u_long) pgs, (u_long) (pgs + n), NULL, 0, 0);
118307acf3c0Scherry }
118407acf3c0Scherry
118507acf3c0Scherry KASSERT(seg->ext != NULL);
118607acf3c0Scherry
118707acf3c0Scherry }
118807acf3c0Scherry
118907acf3c0Scherry struct vm_page *
uvm_physseg_seg_alloc_from_slab(uvm_physseg_t upm,size_t pages)119007acf3c0Scherry uvm_physseg_seg_alloc_from_slab(uvm_physseg_t upm, size_t pages)
119107acf3c0Scherry {
119207acf3c0Scherry int err;
119307acf3c0Scherry struct uvm_physseg *seg;
119407acf3c0Scherry struct vm_page *pgs = NULL;
119507acf3c0Scherry
119607acf3c0Scherry KASSERT(pages > 0);
119707acf3c0Scherry
11984af99c27Schristos seg = HANDLE_TO_PHYSSEG_NODE(upm);
11994af99c27Schristos
120007acf3c0Scherry if (__predict_false(seg->ext == NULL)) {
120107acf3c0Scherry /*
120207acf3c0Scherry * This is a situation unique to boot time.
120307acf3c0Scherry * It shouldn't happen at any point other than from
120407acf3c0Scherry * the first uvm_page.c:uvm_page_init() call
120507acf3c0Scherry * Since we're in a loop, we can get away with the
120607acf3c0Scherry * below.
120707acf3c0Scherry */
120807acf3c0Scherry KASSERT(uvm.page_init_done != true);
120907acf3c0Scherry
12104af99c27Schristos uvm_physseg_t upmp = uvm_physseg_get_prev(upm);
12114af99c27Schristos KASSERT(upmp != UVM_PHYSSEG_TYPE_INVALID);
12124af99c27Schristos
12134af99c27Schristos seg->ext = HANDLE_TO_PHYSSEG_NODE(upmp)->ext;
121407acf3c0Scherry
121507acf3c0Scherry KASSERT(seg->ext != NULL);
121607acf3c0Scherry }
121707acf3c0Scherry
121807acf3c0Scherry /* We allocate enough for this segment */
121907acf3c0Scherry err = extent_alloc(seg->ext, sizeof(*pgs) * pages, 1, 0, EX_BOUNDZERO, (u_long *)&pgs);
122007acf3c0Scherry
122107acf3c0Scherry if (err != 0) {
122207acf3c0Scherry #ifdef DEBUG
122307acf3c0Scherry printf("%s: extent_alloc failed with error: %d \n",
122407acf3c0Scherry __func__, err);
122507acf3c0Scherry #endif
122607acf3c0Scherry }
122707acf3c0Scherry
122807acf3c0Scherry return pgs;
122907acf3c0Scherry }
123007acf3c0Scherry
123107acf3c0Scherry /*
123207acf3c0Scherry * uvm_page_physload: load physical memory into VM system
123307acf3c0Scherry *
123407acf3c0Scherry * => all args are PFs
123507acf3c0Scherry * => all pages in start/end get vm_page structures
123607acf3c0Scherry * => areas marked by avail_start/avail_end get added to the free page pool
123707acf3c0Scherry * => we are limited to VM_PHYSSEG_MAX physical memory segments
123807acf3c0Scherry */
123907acf3c0Scherry
124007acf3c0Scherry uvm_physseg_t
uvm_page_physload(paddr_t start,paddr_t end,paddr_t avail_start,paddr_t avail_end,int free_list)124107acf3c0Scherry uvm_page_physload(paddr_t start, paddr_t end, paddr_t avail_start,
124207acf3c0Scherry paddr_t avail_end, int free_list)
124307acf3c0Scherry {
124407acf3c0Scherry struct uvm_physseg *ps;
124507acf3c0Scherry uvm_physseg_t upm;
124607acf3c0Scherry
124707acf3c0Scherry if (__predict_true(uvm.page_init_done == true))
124807acf3c0Scherry panic("%s: unload attempted after uvm_page_init()\n", __func__);
124907acf3c0Scherry if (uvmexp.pagesize == 0)
125007acf3c0Scherry panic("uvm_page_physload: page size not set!");
125107acf3c0Scherry if (free_list >= VM_NFREELIST || free_list < VM_FREELIST_DEFAULT)
125207acf3c0Scherry panic("uvm_page_physload: bad free list %d", free_list);
125307acf3c0Scherry if (start >= end)
1254979cf575Srin panic("uvm_page_physload: start[%" PRIxPADDR "] >= end[%"
1255979cf575Srin PRIxPADDR "]", start, end);
125607acf3c0Scherry
125707acf3c0Scherry if (uvm_physseg_plug(start, end - start, &upm) == false) {
125807acf3c0Scherry panic("uvm_physseg_plug() failed at boot.");
125907acf3c0Scherry /* NOTREACHED */
126007acf3c0Scherry return UVM_PHYSSEG_TYPE_INVALID; /* XXX: correct type */
126107acf3c0Scherry }
126207acf3c0Scherry
126307acf3c0Scherry ps = HANDLE_TO_PHYSSEG_NODE(upm);
126407acf3c0Scherry
126507acf3c0Scherry /* Legacy */
126607acf3c0Scherry ps->avail_start = avail_start;
126707acf3c0Scherry ps->avail_end = avail_end;
126807acf3c0Scherry
126907acf3c0Scherry ps->free_list = free_list; /* XXX: */
127007acf3c0Scherry
127107acf3c0Scherry
127207acf3c0Scherry return upm;
127307acf3c0Scherry }
127407acf3c0Scherry
127507acf3c0Scherry bool
uvm_physseg_unplug(paddr_t pfn,size_t pages)127607acf3c0Scherry uvm_physseg_unplug(paddr_t pfn, size_t pages)
127707acf3c0Scherry {
127807acf3c0Scherry uvm_physseg_t upm;
12794ad0abb1Sriastradh paddr_t off = 0, start __diagused, end;
128007acf3c0Scherry struct uvm_physseg *seg;
128107acf3c0Scherry
128207acf3c0Scherry upm = uvm_physseg_find(pfn, &off);
128307acf3c0Scherry
1284e6ff351eScherry if (!uvm_physseg_valid_p(upm)) {
128507acf3c0Scherry printf("%s: Tried to unplug from unknown offset\n", __func__);
128607acf3c0Scherry return false;
128707acf3c0Scherry }
128807acf3c0Scherry
128907acf3c0Scherry seg = HANDLE_TO_PHYSSEG_NODE(upm);
129007acf3c0Scherry
129107acf3c0Scherry start = uvm_physseg_get_start(upm);
129207acf3c0Scherry end = uvm_physseg_get_end(upm);
129307acf3c0Scherry
129407acf3c0Scherry if (end < (pfn + pages)) {
129507acf3c0Scherry printf("%s: Tried to unplug oversized span \n", __func__);
129607acf3c0Scherry return false;
129707acf3c0Scherry }
129807acf3c0Scherry
129907acf3c0Scherry KASSERT(pfn == start + off); /* sanity */
130007acf3c0Scherry
130107acf3c0Scherry if (__predict_true(uvm.page_init_done == true)) {
130207acf3c0Scherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
130307acf3c0Scherry if (extent_free(seg->ext, (u_long)(seg->pgs + off), sizeof(struct vm_page) * pages, EX_MALLOCOK | EX_NOWAIT) != 0)
130407acf3c0Scherry return false;
130507acf3c0Scherry }
130607acf3c0Scherry
130707acf3c0Scherry if (off == 0 && (pfn + pages) == end) {
130807acf3c0Scherry #if defined(UVM_HOTPLUG) /* rbtree implementation */
130907acf3c0Scherry int segcount = 0;
131007acf3c0Scherry struct uvm_physseg *current_ps;
131107acf3c0Scherry /* Complete segment */
131207acf3c0Scherry if (uvm_physseg_graph.nentries == 1)
131307acf3c0Scherry panic("%s: out of memory!", __func__);
131407acf3c0Scherry
131507acf3c0Scherry if (__predict_true(uvm.page_init_done == true)) {
131607acf3c0Scherry RB_TREE_FOREACH(current_ps, &(uvm_physseg_graph.rb_tree)) {
131707acf3c0Scherry if (seg->ext == current_ps->ext)
131807acf3c0Scherry segcount++;
131907acf3c0Scherry }
132007acf3c0Scherry KASSERT(segcount > 0);
132107acf3c0Scherry
132207acf3c0Scherry if (segcount == 1) {
132307acf3c0Scherry extent_destroy(seg->ext);
132407acf3c0Scherry }
132507acf3c0Scherry
132607acf3c0Scherry /*
132707acf3c0Scherry * We assume that the unplug will succeed from
132807acf3c0Scherry * this point onwards
132907acf3c0Scherry */
133007acf3c0Scherry uvmexp.npages -= (int) pages;
133107acf3c0Scherry }
133207acf3c0Scherry
133307acf3c0Scherry rb_tree_remove_node(&(uvm_physseg_graph.rb_tree), upm);
133407acf3c0Scherry memset(seg, 0, sizeof(struct uvm_physseg));
133507acf3c0Scherry uvm_physseg_free(seg, sizeof(struct uvm_physseg));
133607acf3c0Scherry uvm_physseg_graph.nentries--;
133707acf3c0Scherry #else /* UVM_HOTPLUG */
133807acf3c0Scherry int x;
133907acf3c0Scherry if (vm_nphysmem == 1)
134007acf3c0Scherry panic("uvm_page_physget: out of memory!");
134107acf3c0Scherry vm_nphysmem--;
134207acf3c0Scherry for (x = upm ; x < vm_nphysmem ; x++)
134307acf3c0Scherry /* structure copy */
134407acf3c0Scherry VM_PHYSMEM_PTR_SWAP(x, x + 1);
134507acf3c0Scherry #endif /* UVM_HOTPLUG */
134607acf3c0Scherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
134707acf3c0Scherry return true;
134807acf3c0Scherry }
134907acf3c0Scherry
135007acf3c0Scherry if (off > 0 &&
135107acf3c0Scherry (pfn + pages) < end) {
135207acf3c0Scherry #if defined(UVM_HOTPLUG) /* rbtree implementation */
135307acf3c0Scherry /* middle chunk - need a new segment */
135407acf3c0Scherry struct uvm_physseg *ps, *current_ps;
135507acf3c0Scherry ps = uvm_physseg_alloc(sizeof (struct uvm_physseg));
135607acf3c0Scherry if (ps == NULL) {
135707acf3c0Scherry printf("%s: Unable to allocated new fragment vm_physseg \n",
135807acf3c0Scherry __func__);
135907acf3c0Scherry return false;
136007acf3c0Scherry }
136107acf3c0Scherry
136207acf3c0Scherry /* Remove middle chunk */
136307acf3c0Scherry if (__predict_true(uvm.page_init_done == true)) {
136407acf3c0Scherry KASSERT(seg->ext != NULL);
136507acf3c0Scherry ps->ext = seg->ext;
136607acf3c0Scherry
136707acf3c0Scherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
136807acf3c0Scherry /*
136907acf3c0Scherry * We assume that the unplug will succeed from
137007acf3c0Scherry * this point onwards
137107acf3c0Scherry */
137207acf3c0Scherry uvmexp.npages -= (int) pages;
137307acf3c0Scherry }
137407acf3c0Scherry
137507acf3c0Scherry ps->start = pfn + pages;
137607acf3c0Scherry ps->avail_start = ps->start; /* XXX: Legacy */
137707acf3c0Scherry
137807acf3c0Scherry ps->end = seg->end;
137907acf3c0Scherry ps->avail_end = ps->end; /* XXX: Legacy */
138007acf3c0Scherry
138107acf3c0Scherry seg->end = pfn;
138207acf3c0Scherry seg->avail_end = seg->end; /* XXX: Legacy */
138307acf3c0Scherry
138407acf3c0Scherry
138507acf3c0Scherry /*
138607acf3c0Scherry * The new pgs array points to the beginning of the
138707acf3c0Scherry * tail fragment.
138807acf3c0Scherry */
138907acf3c0Scherry if (__predict_true(uvm.page_init_done == true))
139007acf3c0Scherry ps->pgs = seg->pgs + off + pages;
139107acf3c0Scherry
139207acf3c0Scherry current_ps = rb_tree_insert_node(&(uvm_physseg_graph.rb_tree), ps);
139307acf3c0Scherry if (current_ps != ps) {
139407acf3c0Scherry panic("uvm_page_physload: Duplicate address range detected!");
139507acf3c0Scherry }
139607acf3c0Scherry uvm_physseg_graph.nentries++;
139707acf3c0Scherry #else /* UVM_HOTPLUG */
139807acf3c0Scherry panic("%s: can't unplug() from the middle of a segment without"
139907acf3c0Scherry " UVM_HOTPLUG\n", __func__);
140007acf3c0Scherry /* NOTREACHED */
140107acf3c0Scherry #endif /* UVM_HOTPLUG */
140207acf3c0Scherry return true;
140307acf3c0Scherry }
140407acf3c0Scherry
140507acf3c0Scherry if (off == 0 && (pfn + pages) < end) {
140607acf3c0Scherry /* Remove front chunk */
140707acf3c0Scherry if (__predict_true(uvm.page_init_done == true)) {
140807acf3c0Scherry /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
140907acf3c0Scherry /*
141007acf3c0Scherry * We assume that the unplug will succeed from
141107acf3c0Scherry * this point onwards
141207acf3c0Scherry */
141307acf3c0Scherry uvmexp.npages -= (int) pages;
141407acf3c0Scherry }
141507acf3c0Scherry
141607acf3c0Scherry /* Truncate */
141707acf3c0Scherry seg->start = pfn + pages;
141807acf3c0Scherry seg->avail_start = seg->start; /* XXX: Legacy */
141907acf3c0Scherry
142007acf3c0Scherry /*
142107acf3c0Scherry * Move the pgs array start to the beginning of the
142207acf3c0Scherry * tail end.
142307acf3c0Scherry */
142407acf3c0Scherry if (__predict_true(uvm.page_init_done == true))
142507acf3c0Scherry seg->pgs += pages;
142607acf3c0Scherry
142707acf3c0Scherry return true;
142807acf3c0Scherry }
142907acf3c0Scherry
143007acf3c0Scherry if (off > 0 && (pfn + pages) == end) {
143107acf3c0Scherry /* back chunk */
143207acf3c0Scherry
143307acf3c0Scherry
143407acf3c0Scherry /* Truncate! */
143507acf3c0Scherry seg->end = pfn;
143607acf3c0Scherry seg->avail_end = seg->end; /* XXX: Legacy */
143707acf3c0Scherry
143807acf3c0Scherry uvmexp.npages -= (int) pages;
143907acf3c0Scherry
144007acf3c0Scherry return true;
144107acf3c0Scherry }
144207acf3c0Scherry
144307acf3c0Scherry printf("%s: Tried to unplug unknown range \n", __func__);
144407acf3c0Scherry
144507acf3c0Scherry return false;
144607acf3c0Scherry }
1447