xref: /onnv-gate/usr/src/uts/sun4/os/memlist.c (revision 7142)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55084Sjohnlev  * Common Development and Distribution License (the "License").
65084Sjohnlev  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7142Skchow  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/signal.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/user.h>
340Sstevel@tonic-gate #include <sys/mman.h>
350Sstevel@tonic-gate #include <sys/class.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/procfs.h>
380Sstevel@tonic-gate #include <sys/kmem.h>
390Sstevel@tonic-gate #include <sys/cred.h>
400Sstevel@tonic-gate #include <sys/archsystm.h>
410Sstevel@tonic-gate #include <sys/machsystm.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <sys/reboot.h>
440Sstevel@tonic-gate #include <sys/uadmin.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #include <sys/vfs.h>
470Sstevel@tonic-gate #include <sys/vnode.h>
480Sstevel@tonic-gate #include <sys/session.h>
490Sstevel@tonic-gate #include <sys/ucontext.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include <sys/dnlc.h>
520Sstevel@tonic-gate #include <sys/var.h>
530Sstevel@tonic-gate #include <sys/cmn_err.h>
540Sstevel@tonic-gate #include <sys/debug.h>
550Sstevel@tonic-gate #include <sys/thread.h>
560Sstevel@tonic-gate #include <sys/vtrace.h>
570Sstevel@tonic-gate #include <sys/consdev.h>
580Sstevel@tonic-gate #include <sys/frame.h>
590Sstevel@tonic-gate #include <sys/stack.h>
600Sstevel@tonic-gate #include <sys/swap.h>
610Sstevel@tonic-gate #include <sys/vmparam.h>
620Sstevel@tonic-gate #include <sys/cpuvar.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #include <sys/privregs.h>
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #include <vm/hat.h>
670Sstevel@tonic-gate #include <vm/anon.h>
680Sstevel@tonic-gate #include <vm/as.h>
690Sstevel@tonic-gate #include <vm/page.h>
700Sstevel@tonic-gate #include <vm/seg.h>
710Sstevel@tonic-gate #include <vm/seg_kmem.h>
720Sstevel@tonic-gate #include <vm/seg_map.h>
730Sstevel@tonic-gate #include <vm/seg_vn.h>
74*7142Skchow #include <vm/vm_dep.h>
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #include <sys/exec.h>
770Sstevel@tonic-gate #include <sys/acct.h>
780Sstevel@tonic-gate #include <sys/modctl.h>
790Sstevel@tonic-gate #include <sys/tuneable.h>
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #include <c2/audit.h>
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #include <sys/trap.h>
840Sstevel@tonic-gate #include <sys/sunddi.h>
850Sstevel@tonic-gate #include <sys/bootconf.h>
860Sstevel@tonic-gate #include <sys/memlist.h>
870Sstevel@tonic-gate #include <sys/memlist_plat.h>
880Sstevel@tonic-gate #include <sys/systeminfo.h>
890Sstevel@tonic-gate #include <sys/promif.h>
905648Ssetje #include <sys/prom_plat.h>
910Sstevel@tonic-gate 
920Sstevel@tonic-gate u_longlong_t	spec_hole_start = 0x80000000000ull;
930Sstevel@tonic-gate u_longlong_t	spec_hole_end = 0xfffff80000000000ull;
940Sstevel@tonic-gate 
955084Sjohnlev pgcnt_t
965084Sjohnlev num_phys_pages()
975084Sjohnlev {
985084Sjohnlev 	pgcnt_t npages = 0;
995084Sjohnlev 	struct memlist *mp;
1005084Sjohnlev 
1015084Sjohnlev 	for (mp = phys_install; mp != NULL; mp = mp->next)
1025084Sjohnlev 		npages += mp->size >> PAGESHIFT;
1035084Sjohnlev 
1045084Sjohnlev 	return (npages);
1055084Sjohnlev }
1065084Sjohnlev 
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate pgcnt_t
1095648Ssetje size_virtalloc(prom_memlist_t *avail, size_t nelems)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	u_longlong_t	start, end;
1130Sstevel@tonic-gate 	pgcnt_t		allocpages = 0;
1140Sstevel@tonic-gate 	uint_t		hole_allocated = 0;
1150Sstevel@tonic-gate 	uint_t		i;
1160Sstevel@tonic-gate 
1175648Ssetje 	for (i = 0; i < nelems - 1; i++) {
1180Sstevel@tonic-gate 
1195648Ssetje 		start = avail[i].addr + avail[i].size;
1205648Ssetje 		end = avail[i + 1].addr;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 		/*
1230Sstevel@tonic-gate 		 * Notes:
1240Sstevel@tonic-gate 		 *
1250Sstevel@tonic-gate 		 * (1) OBP on platforms with US I/II pre-allocates the hole
1260Sstevel@tonic-gate 		 * represented by [spec_hole_start, spec_hole_end);
1270Sstevel@tonic-gate 		 * pre-allocation is done to make this range unavailable
1280Sstevel@tonic-gate 		 * for any allocation.
1290Sstevel@tonic-gate 		 *
1300Sstevel@tonic-gate 		 * (2) OBP on starcat always pre-allocates the hole similar to
1310Sstevel@tonic-gate 		 * platforms with US I/II.
1320Sstevel@tonic-gate 		 *
1330Sstevel@tonic-gate 		 * (3) OBP on serengeti does _not_ pre-allocate the hole.
1340Sstevel@tonic-gate 		 *
1350Sstevel@tonic-gate 		 * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_
1360Sstevel@tonic-gate 		 * fill up or pre-allocate an additional 4GB on both sides
1370Sstevel@tonic-gate 		 * of the hole.
1380Sstevel@tonic-gate 		 *
1390Sstevel@tonic-gate 		 * (5) kernel virtual range [spec_hole_start, spec_hole_end)
1400Sstevel@tonic-gate 		 * is _not_ used on any platform including those with
1410Sstevel@tonic-gate 		 * UltraSPARC III where there is no hole.
1420Sstevel@tonic-gate 		 *
1430Sstevel@tonic-gate 		 * Algorithm:
1440Sstevel@tonic-gate 		 *
1450Sstevel@tonic-gate 		 * Check if range [spec_hole_start, spec_hole_end) is
1460Sstevel@tonic-gate 		 * pre-allocated by OBP; if so, subtract that range from
1470Sstevel@tonic-gate 		 * allocpages.
1480Sstevel@tonic-gate 		 */
1490Sstevel@tonic-gate 		if (end >= spec_hole_end && start <= spec_hole_start)
1500Sstevel@tonic-gate 			hole_allocated = 1;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 		allocpages += btopr(end - start);
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	if (hole_allocated)
1560Sstevel@tonic-gate 		allocpages -= btop(spec_hole_end - spec_hole_start);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	return (allocpages);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * Returns the max contiguous physical memory present in the
1630Sstevel@tonic-gate  * memlist "physavail".
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate uint64_t
1660Sstevel@tonic-gate get_max_phys_size(
1670Sstevel@tonic-gate 	struct memlist	*physavail)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	uint64_t	max_size = 0;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	for (; physavail; physavail = physavail->next) {
1720Sstevel@tonic-gate 		if (physavail->size > max_size)
1730Sstevel@tonic-gate 			max_size = physavail->size;
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (max_size);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate struct vnode prom_ppages;
1820Sstevel@tonic-gate 
1835648Ssetje static void
1845648Ssetje more_pages(uint64_t base, uint64_t len)
1850Sstevel@tonic-gate {
1865648Ssetje 	void kphysm_add();
1875648Ssetje 
1885648Ssetje 	kphysm_add(base, len, 1);
1895648Ssetje }
1905648Ssetje 
1915648Ssetje static void
1925648Ssetje less_pages(uint64_t base, uint64_t len)
1935648Ssetje {
1945648Ssetje 	uint64_t pa, end = base + len;
1950Sstevel@tonic-gate 	extern int kcage_on;
1960Sstevel@tonic-gate 
1975648Ssetje 	for (pa = base; pa < end; pa += PAGESIZE) {
1980Sstevel@tonic-gate 		pfn_t pfnum;
1990Sstevel@tonic-gate 		page_t *pp;
2000Sstevel@tonic-gate 
2015648Ssetje 		pfnum = (pfn_t)(pa >> PAGESHIFT);
2025648Ssetje 		if ((pp = page_numtopp_nolock(pfnum)) == NULL)
2035648Ssetje 			cmn_err(CE_PANIC, "missing pfnum %lx", pfnum);
2045648Ssetje 
2055648Ssetje 		/*
2065648Ssetje 		 * must break up any large pages that may have
2075648Ssetje 		 * constituent pages being utilized for
2085648Ssetje 		 * prom_alloc()'s. page_reclaim() can't handle
2095648Ssetje 		 * large pages.
2105648Ssetje 		 */
2115648Ssetje 		if (pp->p_szc != 0)
2125648Ssetje 			page_boot_demote(pp);
2135648Ssetje 
2145648Ssetje 		if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) {
2155648Ssetje 			/*
2165648Ssetje 			 * Ahhh yes, a prom page,
2175648Ssetje 			 * suck it off the freelist,
2185648Ssetje 			 * lock it, and hashin on prom_pages vp.
2195648Ssetje 			 */
2205648Ssetje 			if (page_trylock(pp, SE_EXCL) == 0)
2215648Ssetje 				cmn_err(CE_PANIC, "prom page locked");
2225648Ssetje 
2235648Ssetje 			(void) page_reclaim(pp, NULL);
2245648Ssetje 			/*
2255648Ssetje 			 * vnode offsets on the prom_ppages vnode
2265648Ssetje 			 * are page numbers (gack) for >32 bit
2275648Ssetje 			 * physical memory machines.
2285648Ssetje 			 */
2295648Ssetje 			(void) page_hashin(pp, &prom_ppages,
2305648Ssetje 			    (offset_t)pfnum, NULL);
2315648Ssetje 
2325648Ssetje 			if (kcage_on) {
2335648Ssetje 				ASSERT(pp->p_szc == 0);
234*7142Skchow 				if (PP_ISNORELOC(pp) == 0) {
235*7142Skchow 					PP_SETNORELOC(pp);
236*7142Skchow 					PLCNT_XFER_NORELOC(pp);
237*7142Skchow 				}
2385648Ssetje 			}
2395648Ssetje 			(void) page_pp_lock(pp, 0, 1);
2405648Ssetje 		}
2415648Ssetje 	}
2425648Ssetje }
2435648Ssetje 
2445648Ssetje void
2455648Ssetje diff_memlists(struct memlist *proto, struct memlist *diff, void (*func)())
2465648Ssetje {
2475648Ssetje 	uint64_t p_base, p_end, d_base, d_end;
2485648Ssetje 
2495648Ssetje 	while (proto != NULL) {
2505648Ssetje 		/*
2515648Ssetje 		 * find diff item which may overlap with proto item
2525648Ssetje 		 * if none, apply func to all of proto item
2535648Ssetje 		 */
2545648Ssetje 		while (diff != NULL &&
2555648Ssetje 		    proto->address >= diff->address + diff->size)
2565648Ssetje 			diff = diff->next;
2575648Ssetje 		if (diff == NULL) {
2585648Ssetje 			(*func)(proto->address, proto->size);
2595648Ssetje 			proto = proto->next;
2605648Ssetje 			continue;
2615648Ssetje 		}
2625648Ssetje 		if (proto->address == diff->address &&
2635648Ssetje 		    proto->size == diff->size) {
2645648Ssetje 			proto = proto->next;
2655648Ssetje 			diff = diff->next;
2665648Ssetje 			continue;
2675648Ssetje 		}
2685648Ssetje 
2695648Ssetje 		p_base = proto->address;
2705648Ssetje 		p_end = p_base + proto->size;
2715648Ssetje 		d_base = diff->address;
2725648Ssetje 		d_end = d_base + diff->size;
2735648Ssetje 		/*
2745648Ssetje 		 * here p_base < d_end
2755648Ssetje 		 * there are 5 cases
2765648Ssetje 		 */
2775648Ssetje 
2785648Ssetje 		/*
2795648Ssetje 		 *	d_end
2805648Ssetje 		 *	d_base
2815648Ssetje 		 *  p_end
2825648Ssetje 		 *  p_base
2835648Ssetje 		 *
2845648Ssetje 		 * apply func to all of proto item
2855648Ssetje 		 */
2865648Ssetje 		if (p_end <= d_base) {
2875648Ssetje 			(*func)(p_base, proto->size);
2885648Ssetje 			proto = proto->next;
2890Sstevel@tonic-gate 			continue;
2900Sstevel@tonic-gate 		}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		/*
2935648Ssetje 		 * ...
2945648Ssetje 		 *	d_base
2955648Ssetje 		 *  p_base
2965648Ssetje 		 *
2975648Ssetje 		 * normalize by applying func from p_base to d_base
2980Sstevel@tonic-gate 		 */
2995648Ssetje 		if (p_base < d_base)
3005648Ssetje 			(*func)(p_base, d_base - p_base);
3010Sstevel@tonic-gate 
3025648Ssetje 		if (p_end <= d_end) {
3030Sstevel@tonic-gate 			/*
3045648Ssetje 			 *	d_end
3055648Ssetje 			 *  p_end
3065648Ssetje 			 *	d_base
3075648Ssetje 			 *  p_base
3085648Ssetje 			 *
3095648Ssetje 			 *	-or-
3105648Ssetje 			 *
3115648Ssetje 			 *	d_end
3125648Ssetje 			 *  p_end
3135648Ssetje 			 *  p_base
3145648Ssetje 			 *	d_base
3155648Ssetje 			 *
3165648Ssetje 			 * any non-overlapping ranges applied above,
3175648Ssetje 			 * so just continue
3180Sstevel@tonic-gate 			 */
3195648Ssetje 			proto = proto->next;
3205648Ssetje 			continue;
3215648Ssetje 		}
3220Sstevel@tonic-gate 
3235648Ssetje 		/*
3245648Ssetje 		 *  p_end
3255648Ssetje 		 *	d_end
3265648Ssetje 		 *	d_base
3275648Ssetje 		 *  p_base
3285648Ssetje 		 *
3295648Ssetje 		 *	-or-
3305648Ssetje 		 *
3315648Ssetje 		 *  p_end
3325648Ssetje 		 *	d_end
3335648Ssetje 		 *  p_base
3345648Ssetje 		 *	d_base
3355648Ssetje 		 *
3365648Ssetje 		 * Find overlapping d_base..d_end ranges, and apply func
3375648Ssetje 		 * where no overlap occurs.  Stop when d_base is above
3385648Ssetje 		 * p_end
3395648Ssetje 		 */
3405648Ssetje 		for (p_base = d_end, diff = diff->next; diff != NULL;
3415648Ssetje 		    p_base = d_end, diff = diff->next) {
3425648Ssetje 			d_base = diff->address;
3435648Ssetje 			d_end = d_base + diff->size;
3445648Ssetje 			if (p_end <= d_base) {
3455648Ssetje 				(*func)(p_base, p_end - p_base);
3465648Ssetje 				break;
3475648Ssetje 			} else
3485648Ssetje 				(*func)(p_base, d_base - p_base);
3490Sstevel@tonic-gate 		}
3505648Ssetje 		if (diff == NULL)
3515648Ssetje 			(*func)(p_base, p_end - p_base);
3525648Ssetje 		proto = proto->next;
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3565648Ssetje void
3575648Ssetje sync_memlists(struct memlist *orig, struct memlist *new)
3585648Ssetje {
3595648Ssetje 
3605648Ssetje 	/*
3615648Ssetje 	 * Find pages allocated via prom by looking for
3625648Ssetje 	 * pages on orig, but no on new.
3635648Ssetje 	 */
3645648Ssetje 	diff_memlists(orig, new, less_pages);
3655648Ssetje 
3665648Ssetje 	/*
3675648Ssetje 	 * Find pages free'd via prom by looking for
3685648Ssetje 	 * pages on new, but not on orig.
3695648Ssetje 	 */
3705648Ssetje 	diff_memlists(new, orig, more_pages);
3715648Ssetje }
3725648Ssetje 
3735648Ssetje 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * Find the page number of the highest installed physical
3760Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
3770Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
3780Sstevel@tonic-gate  * contiguous).
3790Sstevel@tonic-gate  */
3800Sstevel@tonic-gate void
3810Sstevel@tonic-gate installed_top_size_memlist_array(
3825648Ssetje 	prom_memlist_t *list,	/* base of array */
3830Sstevel@tonic-gate 	size_t	nelems,		/* number of elements */
3840Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
3850Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	pfn_t top = 0;
3880Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
3890Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
3900Sstevel@tonic-gate 	size_t i;
3910Sstevel@tonic-gate 
3925648Ssetje 	for (i = 0; i < nelems; list++, i++) {
3935648Ssetje 		highp = (list->addr + list->size - 1) >> PAGESHIFT;
3940Sstevel@tonic-gate 		if (top < highp)
3950Sstevel@tonic-gate 			top = highp;
3965648Ssetje 		sumpages += (list->size >> PAGESHIFT);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	*topp = top;
4000Sstevel@tonic-gate 	*sumpagesp = sumpages;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate /*
4040Sstevel@tonic-gate  * Copy a memory list.  Used in startup() to copy boot's
4050Sstevel@tonic-gate  * memory lists to the kernel.
4060Sstevel@tonic-gate  */
4070Sstevel@tonic-gate void
4080Sstevel@tonic-gate copy_memlist(
4095648Ssetje 	prom_memlist_t	*src,
4100Sstevel@tonic-gate 	size_t		nelems,
4110Sstevel@tonic-gate 	struct memlist	**dstp)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	struct memlist *dst, *prev;
4140Sstevel@tonic-gate 	size_t	i;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	dst = *dstp;
4170Sstevel@tonic-gate 	prev = dst;
4180Sstevel@tonic-gate 
4195648Ssetje 	for (i = 0; i < nelems; src++, i++) {
4205648Ssetje 		dst->address = src->addr;
4215648Ssetje 		dst->size = src->size;
4220Sstevel@tonic-gate 		dst->next = 0;
4230Sstevel@tonic-gate 		if (prev == dst) {
4240Sstevel@tonic-gate 			dst->prev = 0;
4250Sstevel@tonic-gate 			dst++;
4260Sstevel@tonic-gate 		} else {
4270Sstevel@tonic-gate 			dst->prev = prev;
4280Sstevel@tonic-gate 			prev->next = dst;
4290Sstevel@tonic-gate 			dst++;
4300Sstevel@tonic-gate 			prev++;
4310Sstevel@tonic-gate 		}
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	*dstp = dst;
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate 
4375648Ssetje 
4380Sstevel@tonic-gate static struct bootmem_props {
4395648Ssetje 	prom_memlist_t	*ptr;
4400Sstevel@tonic-gate 	size_t		nelems;		/* actual number of elements */
4415648Ssetje 	size_t		maxsize;	/* max buffer */
4425648Ssetje } bootmem_props[3];
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate #define	PHYSINSTALLED	0
4450Sstevel@tonic-gate #define	PHYSAVAIL	1
4460Sstevel@tonic-gate #define	VIRTAVAIL	2
4470Sstevel@tonic-gate 
4485648Ssetje /*
4495648Ssetje  * Comapct contiguous memory list elements
4505648Ssetje  */
4515648Ssetje static void
4525648Ssetje compact_promlist(struct bootmem_props *bpp)
4530Sstevel@tonic-gate {
4545648Ssetje 	int i = 0, j;
4555648Ssetje 	struct prom_memlist *pmp = bpp->ptr;
4560Sstevel@tonic-gate 
4575648Ssetje 	for (;;) {
4585648Ssetje 		if (pmp[i].addr + pmp[i].size == pmp[i+1].addr) {
4595648Ssetje 			pmp[i].size += pmp[i+1].size;
4605648Ssetje 			bpp->nelems--;
4615648Ssetje 			for (j = i + 1; j < bpp->nelems; j++)
4625648Ssetje 				pmp[j] = pmp[j+1];
4635648Ssetje 			pmp[j].addr = 0;
4645648Ssetje 		} else
4655648Ssetje 			i++;
4665648Ssetje 		if (i == bpp->nelems)
4675648Ssetje 			break;
4685648Ssetje 	}
4695648Ssetje }
4705648Ssetje 
4715648Ssetje /*
4725648Ssetje  *  Sort prom memory lists into ascending order
4735648Ssetje  */
4745648Ssetje static void
4755648Ssetje sort_promlist(struct bootmem_props *bpp)
4765648Ssetje {
4775648Ssetje 	int i, j, min;
4785648Ssetje 	struct prom_memlist *pmp = bpp->ptr;
4795648Ssetje 	struct prom_memlist temp;
4805648Ssetje 
4815648Ssetje 	for (i = 0; i < bpp->nelems; i++) {
4825648Ssetje 		min = i;
4835648Ssetje 
4845648Ssetje 		for (j = i+1; j < bpp->nelems; j++)  {
4855648Ssetje 			if (pmp[j].addr < pmp[min].addr)
4865648Ssetje 				min = j;
4870Sstevel@tonic-gate 		}
4880Sstevel@tonic-gate 
4895648Ssetje 		if (i != min)  {
4905648Ssetje 			/* Swap pmp[i] and pmp[min] */
4915648Ssetje 			temp = pmp[min];
4925648Ssetje 			pmp[min] = pmp[i];
4935648Ssetje 			pmp[i] = temp;
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 	}
4965648Ssetje }
4975648Ssetje 
4985648Ssetje static int max_bootlist_sz;
4995648Ssetje 
5005648Ssetje void
5015648Ssetje init_boot_memlists(void)
5025648Ssetje {
5035648Ssetje 	size_t	size, len;
5045648Ssetje 	char *start;
5055648Ssetje 	struct bootmem_props *tmp;
5065648Ssetje 
5075648Ssetje 	/*
5085648Ssetje 	 * These lists can get fragmented as the prom allocates
5095648Ssetje 	 * memory, so generously round up.
5105648Ssetje 	 */
5115648Ssetje 	size = prom_phys_installed_len() + prom_phys_avail_len() +
5125648Ssetje 	    prom_virt_avail_len();
5135648Ssetje 	size *= 4;
5145648Ssetje 	size = roundup(size, PAGESIZE);
5155648Ssetje 	start = prom_alloc(0, size, BO_NO_ALIGN);
5165648Ssetje 
5175648Ssetje 	/*
5185648Ssetje 	 * Get physinstalled
5195648Ssetje 	 */
5205648Ssetje 	tmp = &bootmem_props[PHYSINSTALLED];
5215648Ssetje 	len = prom_phys_installed_len();
5225648Ssetje 	if (len == 0)
5235648Ssetje 		panic("no \"reg\" in /memory");
5245648Ssetje 	tmp->nelems = len / sizeof (struct prom_memlist);
5255648Ssetje 	tmp->maxsize = len;
5265648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
5275648Ssetje 	start += len;
5285648Ssetje 	size -= len;
5295648Ssetje 	(void) prom_phys_installed((caddr_t)tmp->ptr);
5305648Ssetje 	sort_promlist(tmp);
5315648Ssetje 	compact_promlist(tmp);
5325648Ssetje 
5335648Ssetje 	/*
5345648Ssetje 	 * Start out giving each half of available space
5355648Ssetje 	 */
5365648Ssetje 	max_bootlist_sz = size;
5375648Ssetje 	len = size / 2;
5385648Ssetje 	tmp = &bootmem_props[PHYSAVAIL];
5395648Ssetje 	tmp->maxsize = len;
5405648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
5415648Ssetje 	start += len;
5425648Ssetje 
5435648Ssetje 	tmp = &bootmem_props[VIRTAVAIL];
5445648Ssetje 	tmp->maxsize = len;
5455648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
5465648Ssetje }
5475648Ssetje 
5485648Ssetje 
5495648Ssetje void
5505648Ssetje copy_boot_memlists(
5515648Ssetje     prom_memlist_t **physinstalled, size_t *physinstalled_len,
5525648Ssetje     prom_memlist_t **physavail, size_t *physavail_len,
5535648Ssetje     prom_memlist_t **virtavail, size_t *virtavail_len)
5545648Ssetje {
5555648Ssetje 	size_t	plen, vlen, move = 0;
5565648Ssetje 	struct bootmem_props *il, *pl, *vl;
5575648Ssetje 
5585648Ssetje 	plen = prom_phys_avail_len();
5595648Ssetje 	if (plen == 0)
5605648Ssetje 		panic("no \"available\" in /memory");
5615648Ssetje 	vlen = prom_virt_avail_len();
5625648Ssetje 	if (vlen == 0)
5635648Ssetje 		panic("no \"available\" in /virtual-memory");
5645648Ssetje 	if (plen + vlen > max_bootlist_sz)
5655648Ssetje 		panic("ran out of prom_memlist space");
5665648Ssetje 
5675648Ssetje 	pl = &bootmem_props[PHYSAVAIL];
5685648Ssetje 	vl = &bootmem_props[VIRTAVAIL];
5695648Ssetje 
5705648Ssetje 	/*
5715648Ssetje 	 * re-adjust ptrs if needed
5725648Ssetje 	 */
5735648Ssetje 	if (plen > pl->maxsize) {
5745648Ssetje 		/* move virt avail up */
5755648Ssetje 		move = plen - pl->maxsize;
5765648Ssetje 		pl->maxsize = plen;
5775648Ssetje 		vl->ptr += move / sizeof (struct prom_memlist);
5785648Ssetje 		vl->maxsize -= move;
5795648Ssetje 	} else if (vlen > vl->maxsize) {
5805648Ssetje 		/* move virt avail down */
5815648Ssetje 		move = vlen - vl->maxsize;
5825648Ssetje 		vl->maxsize = vlen;
5835648Ssetje 		vl->ptr -= move / sizeof (struct prom_memlist);
5845648Ssetje 		pl->maxsize -= move;
5855648Ssetje 	}
5865648Ssetje 
5875648Ssetje 	pl->nelems = plen / sizeof (struct prom_memlist);
5885648Ssetje 	vl->nelems = vlen / sizeof (struct prom_memlist);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	/* now we can retrieve the properties */
5915648Ssetje 	(void) prom_phys_avail((caddr_t)pl->ptr);
5925648Ssetje 	(void) prom_virt_avail((caddr_t)vl->ptr);
5935648Ssetje 
5945648Ssetje 	/* .. and sort them */
5955648Ssetje 	sort_promlist(pl);
5965648Ssetje 	sort_promlist(vl);
5970Sstevel@tonic-gate 
5985648Ssetje 	il = &bootmem_props[PHYSINSTALLED];
5995648Ssetje 	*physinstalled = il->ptr;
6005648Ssetje 	*physinstalled_len = il->nelems;
6010Sstevel@tonic-gate 
6025648Ssetje 	*physavail = pl->ptr;
6035648Ssetje 	*physavail_len = pl->nelems;
6045648Ssetje 
6055648Ssetje 	*virtavail = vl->ptr;
6065648Ssetje 	*virtavail_len = vl->nelems;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate /*
6110Sstevel@tonic-gate  * Find the page number of the highest installed physical
6120Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
6130Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
6140Sstevel@tonic-gate  * contiguous).
6150Sstevel@tonic-gate  */
6160Sstevel@tonic-gate void
6170Sstevel@tonic-gate installed_top_size(
6180Sstevel@tonic-gate 	struct memlist *list,	/* pointer to start of installed list */
6190Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
6200Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate 	pfn_t top = 0;
6230Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
6240Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	for (; list; list = list->next) {
6270Sstevel@tonic-gate 		highp = (list->address + list->size - 1) >> PAGESHIFT;
6280Sstevel@tonic-gate 		if (top < highp)
6290Sstevel@tonic-gate 			top = highp;
6300Sstevel@tonic-gate 		sumpages += (uint_t)(list->size >> PAGESHIFT);
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	*topp = top;
6340Sstevel@tonic-gate 	*sumpagesp = sumpages;
6350Sstevel@tonic-gate }
636