xref: /onnv-gate/usr/src/uts/sun4/os/memlist.c (revision 11474:857f9db4ef05)
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*11474SJonathan.Adams@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/sysmacros.h>
290Sstevel@tonic-gate #include <sys/signal.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/user.h>
320Sstevel@tonic-gate #include <sys/mman.h>
330Sstevel@tonic-gate #include <sys/class.h>
340Sstevel@tonic-gate #include <sys/proc.h>
350Sstevel@tonic-gate #include <sys/procfs.h>
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <sys/cred.h>
380Sstevel@tonic-gate #include <sys/archsystm.h>
390Sstevel@tonic-gate #include <sys/machsystm.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include <sys/reboot.h>
420Sstevel@tonic-gate #include <sys/uadmin.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <sys/vfs.h>
450Sstevel@tonic-gate #include <sys/vnode.h>
460Sstevel@tonic-gate #include <sys/session.h>
470Sstevel@tonic-gate #include <sys/ucontext.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <sys/dnlc.h>
500Sstevel@tonic-gate #include <sys/var.h>
510Sstevel@tonic-gate #include <sys/cmn_err.h>
520Sstevel@tonic-gate #include <sys/debug.h>
530Sstevel@tonic-gate #include <sys/thread.h>
540Sstevel@tonic-gate #include <sys/vtrace.h>
550Sstevel@tonic-gate #include <sys/consdev.h>
560Sstevel@tonic-gate #include <sys/frame.h>
570Sstevel@tonic-gate #include <sys/stack.h>
580Sstevel@tonic-gate #include <sys/swap.h>
590Sstevel@tonic-gate #include <sys/vmparam.h>
600Sstevel@tonic-gate #include <sys/cpuvar.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #include <sys/privregs.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #include <vm/hat.h>
650Sstevel@tonic-gate #include <vm/anon.h>
660Sstevel@tonic-gate #include <vm/as.h>
670Sstevel@tonic-gate #include <vm/page.h>
680Sstevel@tonic-gate #include <vm/seg.h>
690Sstevel@tonic-gate #include <vm/seg_kmem.h>
700Sstevel@tonic-gate #include <vm/seg_map.h>
710Sstevel@tonic-gate #include <vm/seg_vn.h>
727142Skchow #include <vm/vm_dep.h>
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #include <sys/exec.h>
750Sstevel@tonic-gate #include <sys/acct.h>
760Sstevel@tonic-gate #include <sys/modctl.h>
770Sstevel@tonic-gate #include <sys/tuneable.h>
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #include <c2/audit.h>
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #include <sys/trap.h>
820Sstevel@tonic-gate #include <sys/sunddi.h>
830Sstevel@tonic-gate #include <sys/bootconf.h>
840Sstevel@tonic-gate #include <sys/memlist.h>
850Sstevel@tonic-gate #include <sys/memlist_plat.h>
860Sstevel@tonic-gate #include <sys/systeminfo.h>
870Sstevel@tonic-gate #include <sys/promif.h>
885648Ssetje #include <sys/prom_plat.h>
890Sstevel@tonic-gate 
900Sstevel@tonic-gate u_longlong_t	spec_hole_start = 0x80000000000ull;
910Sstevel@tonic-gate u_longlong_t	spec_hole_end = 0xfffff80000000000ull;
920Sstevel@tonic-gate 
935084Sjohnlev pgcnt_t
num_phys_pages()945084Sjohnlev num_phys_pages()
955084Sjohnlev {
965084Sjohnlev 	pgcnt_t npages = 0;
975084Sjohnlev 	struct memlist *mp;
985084Sjohnlev 
99*11474SJonathan.Adams@Sun.COM 	for (mp = phys_install; mp != NULL; mp = mp->ml_next)
100*11474SJonathan.Adams@Sun.COM 		npages += mp->ml_size >> PAGESHIFT;
1015084Sjohnlev 
1025084Sjohnlev 	return (npages);
1035084Sjohnlev }
1045084Sjohnlev 
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate pgcnt_t
size_virtalloc(prom_memlist_t * avail,size_t nelems)1075648Ssetje size_virtalloc(prom_memlist_t *avail, size_t nelems)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	u_longlong_t	start, end;
1110Sstevel@tonic-gate 	pgcnt_t		allocpages = 0;
1120Sstevel@tonic-gate 	uint_t		hole_allocated = 0;
1130Sstevel@tonic-gate 	uint_t		i;
1140Sstevel@tonic-gate 
1155648Ssetje 	for (i = 0; i < nelems - 1; i++) {
1160Sstevel@tonic-gate 
1175648Ssetje 		start = avail[i].addr + avail[i].size;
1185648Ssetje 		end = avail[i + 1].addr;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 		/*
1210Sstevel@tonic-gate 		 * Notes:
1220Sstevel@tonic-gate 		 *
1230Sstevel@tonic-gate 		 * (1) OBP on platforms with US I/II pre-allocates the hole
1240Sstevel@tonic-gate 		 * represented by [spec_hole_start, spec_hole_end);
1250Sstevel@tonic-gate 		 * pre-allocation is done to make this range unavailable
1260Sstevel@tonic-gate 		 * for any allocation.
1270Sstevel@tonic-gate 		 *
1280Sstevel@tonic-gate 		 * (2) OBP on starcat always pre-allocates the hole similar to
1290Sstevel@tonic-gate 		 * platforms with US I/II.
1300Sstevel@tonic-gate 		 *
1310Sstevel@tonic-gate 		 * (3) OBP on serengeti does _not_ pre-allocate the hole.
1320Sstevel@tonic-gate 		 *
1330Sstevel@tonic-gate 		 * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_
1340Sstevel@tonic-gate 		 * fill up or pre-allocate an additional 4GB on both sides
1350Sstevel@tonic-gate 		 * of the hole.
1360Sstevel@tonic-gate 		 *
1370Sstevel@tonic-gate 		 * (5) kernel virtual range [spec_hole_start, spec_hole_end)
1380Sstevel@tonic-gate 		 * is _not_ used on any platform including those with
1390Sstevel@tonic-gate 		 * UltraSPARC III where there is no hole.
1400Sstevel@tonic-gate 		 *
1410Sstevel@tonic-gate 		 * Algorithm:
1420Sstevel@tonic-gate 		 *
1430Sstevel@tonic-gate 		 * Check if range [spec_hole_start, spec_hole_end) is
1440Sstevel@tonic-gate 		 * pre-allocated by OBP; if so, subtract that range from
1450Sstevel@tonic-gate 		 * allocpages.
1460Sstevel@tonic-gate 		 */
1470Sstevel@tonic-gate 		if (end >= spec_hole_end && start <= spec_hole_start)
1480Sstevel@tonic-gate 			hole_allocated = 1;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 		allocpages += btopr(end - start);
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	if (hole_allocated)
1540Sstevel@tonic-gate 		allocpages -= btop(spec_hole_end - spec_hole_start);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	return (allocpages);
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * Returns the max contiguous physical memory present in the
1610Sstevel@tonic-gate  * memlist "physavail".
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate uint64_t
get_max_phys_size(struct memlist * physavail)1640Sstevel@tonic-gate get_max_phys_size(
1650Sstevel@tonic-gate 	struct memlist	*physavail)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate 	uint64_t	max_size = 0;
1680Sstevel@tonic-gate 
169*11474SJonathan.Adams@Sun.COM 	for (; physavail; physavail = physavail->ml_next) {
170*11474SJonathan.Adams@Sun.COM 		if (physavail->ml_size > max_size)
171*11474SJonathan.Adams@Sun.COM 			max_size = physavail->ml_size;
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	return (max_size);
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 
1785648Ssetje static void
more_pages(uint64_t base,uint64_t len)1795648Ssetje more_pages(uint64_t base, uint64_t len)
1800Sstevel@tonic-gate {
1815648Ssetje 	void kphysm_add();
1825648Ssetje 
1835648Ssetje 	kphysm_add(base, len, 1);
1845648Ssetje }
1855648Ssetje 
1865648Ssetje static void
less_pages(uint64_t base,uint64_t len)1875648Ssetje less_pages(uint64_t base, uint64_t len)
1885648Ssetje {
1895648Ssetje 	uint64_t pa, end = base + len;
1900Sstevel@tonic-gate 	extern int kcage_on;
1910Sstevel@tonic-gate 
1925648Ssetje 	for (pa = base; pa < end; pa += PAGESIZE) {
1930Sstevel@tonic-gate 		pfn_t pfnum;
1940Sstevel@tonic-gate 		page_t *pp;
1950Sstevel@tonic-gate 
1965648Ssetje 		pfnum = (pfn_t)(pa >> PAGESHIFT);
1975648Ssetje 		if ((pp = page_numtopp_nolock(pfnum)) == NULL)
1985648Ssetje 			cmn_err(CE_PANIC, "missing pfnum %lx", pfnum);
1995648Ssetje 
2005648Ssetje 		/*
2015648Ssetje 		 * must break up any large pages that may have
2025648Ssetje 		 * constituent pages being utilized for
2035648Ssetje 		 * prom_alloc()'s. page_reclaim() can't handle
2045648Ssetje 		 * large pages.
2055648Ssetje 		 */
2065648Ssetje 		if (pp->p_szc != 0)
2075648Ssetje 			page_boot_demote(pp);
2085648Ssetje 
2095648Ssetje 		if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) {
2105648Ssetje 			/*
2115648Ssetje 			 * Ahhh yes, a prom page,
2125648Ssetje 			 * suck it off the freelist,
2135648Ssetje 			 * lock it, and hashin on prom_pages vp.
2145648Ssetje 			 */
2155648Ssetje 			if (page_trylock(pp, SE_EXCL) == 0)
2165648Ssetje 				cmn_err(CE_PANIC, "prom page locked");
2175648Ssetje 
2185648Ssetje 			(void) page_reclaim(pp, NULL);
2195648Ssetje 			/*
2205648Ssetje 			 * vnode offsets on the prom_ppages vnode
2215648Ssetje 			 * are page numbers (gack) for >32 bit
2225648Ssetje 			 * physical memory machines.
2235648Ssetje 			 */
22411185SSean.McEnroe@Sun.COM 			(void) page_hashin(pp, &promvp,
2255648Ssetje 			    (offset_t)pfnum, NULL);
2265648Ssetje 
2275648Ssetje 			if (kcage_on) {
2285648Ssetje 				ASSERT(pp->p_szc == 0);
2297142Skchow 				if (PP_ISNORELOC(pp) == 0) {
2307142Skchow 					PP_SETNORELOC(pp);
2317142Skchow 					PLCNT_XFER_NORELOC(pp);
2327142Skchow 				}
2335648Ssetje 			}
2345648Ssetje 			(void) page_pp_lock(pp, 0, 1);
2355648Ssetje 		}
2365648Ssetje 	}
2375648Ssetje }
2385648Ssetje 
2395648Ssetje void
diff_memlists(struct memlist * proto,struct memlist * diff,void (* func)())2405648Ssetje diff_memlists(struct memlist *proto, struct memlist *diff, void (*func)())
2415648Ssetje {
2425648Ssetje 	uint64_t p_base, p_end, d_base, d_end;
2435648Ssetje 
2445648Ssetje 	while (proto != NULL) {
2455648Ssetje 		/*
2465648Ssetje 		 * find diff item which may overlap with proto item
2475648Ssetje 		 * if none, apply func to all of proto item
2485648Ssetje 		 */
2495648Ssetje 		while (diff != NULL &&
250*11474SJonathan.Adams@Sun.COM 		    proto->ml_address >= diff->ml_address + diff->ml_size)
251*11474SJonathan.Adams@Sun.COM 			diff = diff->ml_next;
2525648Ssetje 		if (diff == NULL) {
253*11474SJonathan.Adams@Sun.COM 			(*func)(proto->ml_address, proto->ml_size);
254*11474SJonathan.Adams@Sun.COM 			proto = proto->ml_next;
2555648Ssetje 			continue;
2565648Ssetje 		}
257*11474SJonathan.Adams@Sun.COM 		if (proto->ml_address == diff->ml_address &&
258*11474SJonathan.Adams@Sun.COM 		    proto->ml_size == diff->ml_size) {
259*11474SJonathan.Adams@Sun.COM 			proto = proto->ml_next;
260*11474SJonathan.Adams@Sun.COM 			diff = diff->ml_next;
2615648Ssetje 			continue;
2625648Ssetje 		}
2635648Ssetje 
264*11474SJonathan.Adams@Sun.COM 		p_base = proto->ml_address;
265*11474SJonathan.Adams@Sun.COM 		p_end = p_base + proto->ml_size;
266*11474SJonathan.Adams@Sun.COM 		d_base = diff->ml_address;
267*11474SJonathan.Adams@Sun.COM 		d_end = d_base + diff->ml_size;
2685648Ssetje 		/*
2695648Ssetje 		 * here p_base < d_end
2705648Ssetje 		 * there are 5 cases
2715648Ssetje 		 */
2725648Ssetje 
2735648Ssetje 		/*
2745648Ssetje 		 *	d_end
2755648Ssetje 		 *	d_base
2765648Ssetje 		 *  p_end
2775648Ssetje 		 *  p_base
2785648Ssetje 		 *
2795648Ssetje 		 * apply func to all of proto item
2805648Ssetje 		 */
2815648Ssetje 		if (p_end <= d_base) {
282*11474SJonathan.Adams@Sun.COM 			(*func)(p_base, proto->ml_size);
283*11474SJonathan.Adams@Sun.COM 			proto = proto->ml_next;
2840Sstevel@tonic-gate 			continue;
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		/*
2885648Ssetje 		 * ...
2895648Ssetje 		 *	d_base
2905648Ssetje 		 *  p_base
2915648Ssetje 		 *
2925648Ssetje 		 * normalize by applying func from p_base to d_base
2930Sstevel@tonic-gate 		 */
2945648Ssetje 		if (p_base < d_base)
2955648Ssetje 			(*func)(p_base, d_base - p_base);
2960Sstevel@tonic-gate 
2975648Ssetje 		if (p_end <= d_end) {
2980Sstevel@tonic-gate 			/*
2995648Ssetje 			 *	d_end
3005648Ssetje 			 *  p_end
3015648Ssetje 			 *	d_base
3025648Ssetje 			 *  p_base
3035648Ssetje 			 *
3045648Ssetje 			 *	-or-
3055648Ssetje 			 *
3065648Ssetje 			 *	d_end
3075648Ssetje 			 *  p_end
3085648Ssetje 			 *  p_base
3095648Ssetje 			 *	d_base
3105648Ssetje 			 *
3115648Ssetje 			 * any non-overlapping ranges applied above,
3125648Ssetje 			 * so just continue
3130Sstevel@tonic-gate 			 */
314*11474SJonathan.Adams@Sun.COM 			proto = proto->ml_next;
3155648Ssetje 			continue;
3165648Ssetje 		}
3170Sstevel@tonic-gate 
3185648Ssetje 		/*
3195648Ssetje 		 *  p_end
3205648Ssetje 		 *	d_end
3215648Ssetje 		 *	d_base
3225648Ssetje 		 *  p_base
3235648Ssetje 		 *
3245648Ssetje 		 *	-or-
3255648Ssetje 		 *
3265648Ssetje 		 *  p_end
3275648Ssetje 		 *	d_end
3285648Ssetje 		 *  p_base
3295648Ssetje 		 *	d_base
3305648Ssetje 		 *
3315648Ssetje 		 * Find overlapping d_base..d_end ranges, and apply func
3325648Ssetje 		 * where no overlap occurs.  Stop when d_base is above
3335648Ssetje 		 * p_end
3345648Ssetje 		 */
335*11474SJonathan.Adams@Sun.COM 		for (p_base = d_end, diff = diff->ml_next; diff != NULL;
336*11474SJonathan.Adams@Sun.COM 		    p_base = d_end, diff = diff->ml_next) {
337*11474SJonathan.Adams@Sun.COM 			d_base = diff->ml_address;
338*11474SJonathan.Adams@Sun.COM 			d_end = d_base + diff->ml_size;
3395648Ssetje 			if (p_end <= d_base) {
3405648Ssetje 				(*func)(p_base, p_end - p_base);
3415648Ssetje 				break;
3425648Ssetje 			} else
3435648Ssetje 				(*func)(p_base, d_base - p_base);
3440Sstevel@tonic-gate 		}
3455648Ssetje 		if (diff == NULL)
3465648Ssetje 			(*func)(p_base, p_end - p_base);
347*11474SJonathan.Adams@Sun.COM 		proto = proto->ml_next;
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3515648Ssetje void
sync_memlists(struct memlist * orig,struct memlist * new)3525648Ssetje sync_memlists(struct memlist *orig, struct memlist *new)
3535648Ssetje {
3545648Ssetje 
3555648Ssetje 	/*
3565648Ssetje 	 * Find pages allocated via prom by looking for
3575648Ssetje 	 * pages on orig, but no on new.
3585648Ssetje 	 */
3595648Ssetje 	diff_memlists(orig, new, less_pages);
3605648Ssetje 
3615648Ssetje 	/*
3625648Ssetje 	 * Find pages free'd via prom by looking for
3635648Ssetje 	 * pages on new, but not on orig.
3645648Ssetje 	 */
3655648Ssetje 	diff_memlists(new, orig, more_pages);
3665648Ssetje }
3675648Ssetje 
3685648Ssetje 
3690Sstevel@tonic-gate /*
3700Sstevel@tonic-gate  * Find the page number of the highest installed physical
3710Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
3720Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
3730Sstevel@tonic-gate  * contiguous).
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate void
installed_top_size_memlist_array(prom_memlist_t * list,size_t nelems,pfn_t * topp,pgcnt_t * sumpagesp)3760Sstevel@tonic-gate installed_top_size_memlist_array(
3775648Ssetje 	prom_memlist_t *list,	/* base of array */
3780Sstevel@tonic-gate 	size_t	nelems,		/* number of elements */
3790Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
3800Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 	pfn_t top = 0;
3830Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
3840Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
3850Sstevel@tonic-gate 	size_t i;
3860Sstevel@tonic-gate 
3875648Ssetje 	for (i = 0; i < nelems; list++, i++) {
3885648Ssetje 		highp = (list->addr + list->size - 1) >> PAGESHIFT;
3890Sstevel@tonic-gate 		if (top < highp)
3900Sstevel@tonic-gate 			top = highp;
3915648Ssetje 		sumpages += (list->size >> PAGESHIFT);
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	*topp = top;
3950Sstevel@tonic-gate 	*sumpagesp = sumpages;
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate /*
3990Sstevel@tonic-gate  * Copy a memory list.  Used in startup() to copy boot's
4000Sstevel@tonic-gate  * memory lists to the kernel.
4010Sstevel@tonic-gate  */
4020Sstevel@tonic-gate void
copy_memlist(prom_memlist_t * src,size_t nelems,struct memlist ** dstp)4030Sstevel@tonic-gate copy_memlist(
4045648Ssetje 	prom_memlist_t	*src,
4050Sstevel@tonic-gate 	size_t		nelems,
4060Sstevel@tonic-gate 	struct memlist	**dstp)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	struct memlist *dst, *prev;
4090Sstevel@tonic-gate 	size_t	i;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	dst = *dstp;
4120Sstevel@tonic-gate 	prev = dst;
4130Sstevel@tonic-gate 
4145648Ssetje 	for (i = 0; i < nelems; src++, i++) {
415*11474SJonathan.Adams@Sun.COM 		dst->ml_address = src->addr;
416*11474SJonathan.Adams@Sun.COM 		dst->ml_size = src->size;
417*11474SJonathan.Adams@Sun.COM 		dst->ml_next = 0;
4180Sstevel@tonic-gate 		if (prev == dst) {
419*11474SJonathan.Adams@Sun.COM 			dst->ml_prev = 0;
4200Sstevel@tonic-gate 			dst++;
4210Sstevel@tonic-gate 		} else {
422*11474SJonathan.Adams@Sun.COM 			dst->ml_prev = prev;
423*11474SJonathan.Adams@Sun.COM 			prev->ml_next = dst;
4240Sstevel@tonic-gate 			dst++;
4250Sstevel@tonic-gate 			prev++;
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	*dstp = dst;
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4325648Ssetje 
4330Sstevel@tonic-gate static struct bootmem_props {
4345648Ssetje 	prom_memlist_t	*ptr;
4350Sstevel@tonic-gate 	size_t		nelems;		/* actual number of elements */
4365648Ssetje 	size_t		maxsize;	/* max buffer */
4375648Ssetje } bootmem_props[3];
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate #define	PHYSINSTALLED	0
4400Sstevel@tonic-gate #define	PHYSAVAIL	1
4410Sstevel@tonic-gate #define	VIRTAVAIL	2
4420Sstevel@tonic-gate 
4435648Ssetje /*
4445648Ssetje  * Comapct contiguous memory list elements
4455648Ssetje  */
4465648Ssetje static void
compact_promlist(struct bootmem_props * bpp)4475648Ssetje compact_promlist(struct bootmem_props *bpp)
4480Sstevel@tonic-gate {
4495648Ssetje 	int i = 0, j;
4505648Ssetje 	struct prom_memlist *pmp = bpp->ptr;
4510Sstevel@tonic-gate 
4525648Ssetje 	for (;;) {
4535648Ssetje 		if (pmp[i].addr + pmp[i].size == pmp[i+1].addr) {
4545648Ssetje 			pmp[i].size += pmp[i+1].size;
4555648Ssetje 			bpp->nelems--;
4565648Ssetje 			for (j = i + 1; j < bpp->nelems; j++)
4575648Ssetje 				pmp[j] = pmp[j+1];
4585648Ssetje 			pmp[j].addr = 0;
4595648Ssetje 		} else
4605648Ssetje 			i++;
4615648Ssetje 		if (i == bpp->nelems)
4625648Ssetje 			break;
4635648Ssetje 	}
4645648Ssetje }
4655648Ssetje 
4665648Ssetje /*
4675648Ssetje  *  Sort prom memory lists into ascending order
4685648Ssetje  */
4695648Ssetje static void
sort_promlist(struct bootmem_props * bpp)4705648Ssetje sort_promlist(struct bootmem_props *bpp)
4715648Ssetje {
4725648Ssetje 	int i, j, min;
4735648Ssetje 	struct prom_memlist *pmp = bpp->ptr;
4745648Ssetje 	struct prom_memlist temp;
4755648Ssetje 
4765648Ssetje 	for (i = 0; i < bpp->nelems; i++) {
4775648Ssetje 		min = i;
4785648Ssetje 
4795648Ssetje 		for (j = i+1; j < bpp->nelems; j++)  {
4805648Ssetje 			if (pmp[j].addr < pmp[min].addr)
4815648Ssetje 				min = j;
4820Sstevel@tonic-gate 		}
4830Sstevel@tonic-gate 
4845648Ssetje 		if (i != min)  {
4855648Ssetje 			/* Swap pmp[i] and pmp[min] */
4865648Ssetje 			temp = pmp[min];
4875648Ssetje 			pmp[min] = pmp[i];
4885648Ssetje 			pmp[i] = temp;
4890Sstevel@tonic-gate 		}
4900Sstevel@tonic-gate 	}
4915648Ssetje }
4925648Ssetje 
4935648Ssetje static int max_bootlist_sz;
4945648Ssetje 
4955648Ssetje void
init_boot_memlists(void)4965648Ssetje init_boot_memlists(void)
4975648Ssetje {
4985648Ssetje 	size_t	size, len;
4995648Ssetje 	char *start;
5005648Ssetje 	struct bootmem_props *tmp;
5015648Ssetje 
5025648Ssetje 	/*
5035648Ssetje 	 * These lists can get fragmented as the prom allocates
5045648Ssetje 	 * memory, so generously round up.
5055648Ssetje 	 */
5065648Ssetje 	size = prom_phys_installed_len() + prom_phys_avail_len() +
5075648Ssetje 	    prom_virt_avail_len();
5085648Ssetje 	size *= 4;
5095648Ssetje 	size = roundup(size, PAGESIZE);
5105648Ssetje 	start = prom_alloc(0, size, BO_NO_ALIGN);
5115648Ssetje 
5125648Ssetje 	/*
5135648Ssetje 	 * Get physinstalled
5145648Ssetje 	 */
5155648Ssetje 	tmp = &bootmem_props[PHYSINSTALLED];
5165648Ssetje 	len = prom_phys_installed_len();
5175648Ssetje 	if (len == 0)
5185648Ssetje 		panic("no \"reg\" in /memory");
5195648Ssetje 	tmp->nelems = len / sizeof (struct prom_memlist);
5205648Ssetje 	tmp->maxsize = len;
5215648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
5225648Ssetje 	start += len;
5235648Ssetje 	size -= len;
5245648Ssetje 	(void) prom_phys_installed((caddr_t)tmp->ptr);
5255648Ssetje 	sort_promlist(tmp);
5265648Ssetje 	compact_promlist(tmp);
5275648Ssetje 
5285648Ssetje 	/*
5295648Ssetje 	 * Start out giving each half of available space
5305648Ssetje 	 */
5315648Ssetje 	max_bootlist_sz = size;
5325648Ssetje 	len = size / 2;
5335648Ssetje 	tmp = &bootmem_props[PHYSAVAIL];
5345648Ssetje 	tmp->maxsize = len;
5355648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
5365648Ssetje 	start += len;
5375648Ssetje 
5385648Ssetje 	tmp = &bootmem_props[VIRTAVAIL];
5395648Ssetje 	tmp->maxsize = len;
5405648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
5415648Ssetje }
5425648Ssetje 
5435648Ssetje 
5445648Ssetje void
copy_boot_memlists(prom_memlist_t ** physinstalled,size_t * physinstalled_len,prom_memlist_t ** physavail,size_t * physavail_len,prom_memlist_t ** virtavail,size_t * virtavail_len)5455648Ssetje copy_boot_memlists(
5465648Ssetje     prom_memlist_t **physinstalled, size_t *physinstalled_len,
5475648Ssetje     prom_memlist_t **physavail, size_t *physavail_len,
5485648Ssetje     prom_memlist_t **virtavail, size_t *virtavail_len)
5495648Ssetje {
5505648Ssetje 	size_t	plen, vlen, move = 0;
5515648Ssetje 	struct bootmem_props *il, *pl, *vl;
5525648Ssetje 
5535648Ssetje 	plen = prom_phys_avail_len();
5545648Ssetje 	if (plen == 0)
5555648Ssetje 		panic("no \"available\" in /memory");
5565648Ssetje 	vlen = prom_virt_avail_len();
5575648Ssetje 	if (vlen == 0)
5585648Ssetje 		panic("no \"available\" in /virtual-memory");
5595648Ssetje 	if (plen + vlen > max_bootlist_sz)
5605648Ssetje 		panic("ran out of prom_memlist space");
5615648Ssetje 
5625648Ssetje 	pl = &bootmem_props[PHYSAVAIL];
5635648Ssetje 	vl = &bootmem_props[VIRTAVAIL];
5645648Ssetje 
5655648Ssetje 	/*
5665648Ssetje 	 * re-adjust ptrs if needed
5675648Ssetje 	 */
5685648Ssetje 	if (plen > pl->maxsize) {
5695648Ssetje 		/* move virt avail up */
5705648Ssetje 		move = plen - pl->maxsize;
5715648Ssetje 		pl->maxsize = plen;
5725648Ssetje 		vl->ptr += move / sizeof (struct prom_memlist);
5735648Ssetje 		vl->maxsize -= move;
5745648Ssetje 	} else if (vlen > vl->maxsize) {
5755648Ssetje 		/* move virt avail down */
5765648Ssetje 		move = vlen - vl->maxsize;
5775648Ssetje 		vl->maxsize = vlen;
5785648Ssetje 		vl->ptr -= move / sizeof (struct prom_memlist);
5795648Ssetje 		pl->maxsize -= move;
5805648Ssetje 	}
5815648Ssetje 
5825648Ssetje 	pl->nelems = plen / sizeof (struct prom_memlist);
5835648Ssetje 	vl->nelems = vlen / sizeof (struct prom_memlist);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/* now we can retrieve the properties */
5865648Ssetje 	(void) prom_phys_avail((caddr_t)pl->ptr);
5875648Ssetje 	(void) prom_virt_avail((caddr_t)vl->ptr);
5885648Ssetje 
5895648Ssetje 	/* .. and sort them */
5905648Ssetje 	sort_promlist(pl);
5915648Ssetje 	sort_promlist(vl);
5920Sstevel@tonic-gate 
5935648Ssetje 	il = &bootmem_props[PHYSINSTALLED];
5945648Ssetje 	*physinstalled = il->ptr;
5955648Ssetje 	*physinstalled_len = il->nelems;
5960Sstevel@tonic-gate 
5975648Ssetje 	*physavail = pl->ptr;
5985648Ssetje 	*physavail_len = pl->nelems;
5995648Ssetje 
6005648Ssetje 	*virtavail = vl->ptr;
6015648Ssetje 	*virtavail_len = vl->nelems;
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate /*
6060Sstevel@tonic-gate  * Find the page number of the highest installed physical
6070Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
6080Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
6090Sstevel@tonic-gate  * contiguous).
6100Sstevel@tonic-gate  */
6110Sstevel@tonic-gate void
installed_top_size(struct memlist * list,pfn_t * topp,pgcnt_t * sumpagesp)6120Sstevel@tonic-gate installed_top_size(
6130Sstevel@tonic-gate 	struct memlist *list,	/* pointer to start of installed list */
6140Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
6150Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate 	pfn_t top = 0;
6180Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
6190Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
6200Sstevel@tonic-gate 
621*11474SJonathan.Adams@Sun.COM 	for (; list; list = list->ml_next) {
622*11474SJonathan.Adams@Sun.COM 		highp = (list->ml_address + list->ml_size - 1) >> PAGESHIFT;
6230Sstevel@tonic-gate 		if (top < highp)
6240Sstevel@tonic-gate 			top = highp;
625*11474SJonathan.Adams@Sun.COM 		sumpages += (uint_t)(list->ml_size >> PAGESHIFT);
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	*topp = top;
6290Sstevel@tonic-gate 	*sumpagesp = sumpages;
6300Sstevel@tonic-gate }
631