xref: /onnv-gate/usr/src/uts/sun4/os/memlist.c (revision 5648)
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 /*
225084Sjohnlev  * Copyright 2007 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>
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #include <sys/exec.h>
760Sstevel@tonic-gate #include <sys/acct.h>
770Sstevel@tonic-gate #include <sys/modctl.h>
780Sstevel@tonic-gate #include <sys/tuneable.h>
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #include <c2/audit.h>
810Sstevel@tonic-gate 
820Sstevel@tonic-gate #include <sys/trap.h>
830Sstevel@tonic-gate #include <sys/sunddi.h>
840Sstevel@tonic-gate #include <sys/bootconf.h>
850Sstevel@tonic-gate #include <sys/memlist.h>
860Sstevel@tonic-gate #include <sys/memlist_plat.h>
870Sstevel@tonic-gate #include <sys/systeminfo.h>
880Sstevel@tonic-gate #include <sys/promif.h>
89*5648Ssetje #include <sys/prom_plat.h>
900Sstevel@tonic-gate 
910Sstevel@tonic-gate u_longlong_t	spec_hole_start = 0x80000000000ull;
920Sstevel@tonic-gate u_longlong_t	spec_hole_end = 0xfffff80000000000ull;
930Sstevel@tonic-gate 
945084Sjohnlev pgcnt_t
955084Sjohnlev num_phys_pages()
965084Sjohnlev {
975084Sjohnlev 	pgcnt_t npages = 0;
985084Sjohnlev 	struct memlist *mp;
995084Sjohnlev 
1005084Sjohnlev 	for (mp = phys_install; mp != NULL; mp = mp->next)
1015084Sjohnlev 		npages += mp->size >> PAGESHIFT;
1025084Sjohnlev 
1035084Sjohnlev 	return (npages);
1045084Sjohnlev }
1055084Sjohnlev 
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate pgcnt_t
108*5648Ssetje size_virtalloc(prom_memlist_t *avail, size_t nelems)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	u_longlong_t	start, end;
1120Sstevel@tonic-gate 	pgcnt_t		allocpages = 0;
1130Sstevel@tonic-gate 	uint_t		hole_allocated = 0;
1140Sstevel@tonic-gate 	uint_t		i;
1150Sstevel@tonic-gate 
116*5648Ssetje 	for (i = 0; i < nelems - 1; i++) {
1170Sstevel@tonic-gate 
118*5648Ssetje 		start = avail[i].addr + avail[i].size;
119*5648Ssetje 		end = avail[i + 1].addr;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 		/*
1220Sstevel@tonic-gate 		 * Notes:
1230Sstevel@tonic-gate 		 *
1240Sstevel@tonic-gate 		 * (1) OBP on platforms with US I/II pre-allocates the hole
1250Sstevel@tonic-gate 		 * represented by [spec_hole_start, spec_hole_end);
1260Sstevel@tonic-gate 		 * pre-allocation is done to make this range unavailable
1270Sstevel@tonic-gate 		 * for any allocation.
1280Sstevel@tonic-gate 		 *
1290Sstevel@tonic-gate 		 * (2) OBP on starcat always pre-allocates the hole similar to
1300Sstevel@tonic-gate 		 * platforms with US I/II.
1310Sstevel@tonic-gate 		 *
1320Sstevel@tonic-gate 		 * (3) OBP on serengeti does _not_ pre-allocate the hole.
1330Sstevel@tonic-gate 		 *
1340Sstevel@tonic-gate 		 * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_
1350Sstevel@tonic-gate 		 * fill up or pre-allocate an additional 4GB on both sides
1360Sstevel@tonic-gate 		 * of the hole.
1370Sstevel@tonic-gate 		 *
1380Sstevel@tonic-gate 		 * (5) kernel virtual range [spec_hole_start, spec_hole_end)
1390Sstevel@tonic-gate 		 * is _not_ used on any platform including those with
1400Sstevel@tonic-gate 		 * UltraSPARC III where there is no hole.
1410Sstevel@tonic-gate 		 *
1420Sstevel@tonic-gate 		 * Algorithm:
1430Sstevel@tonic-gate 		 *
1440Sstevel@tonic-gate 		 * Check if range [spec_hole_start, spec_hole_end) is
1450Sstevel@tonic-gate 		 * pre-allocated by OBP; if so, subtract that range from
1460Sstevel@tonic-gate 		 * allocpages.
1470Sstevel@tonic-gate 		 */
1480Sstevel@tonic-gate 		if (end >= spec_hole_end && start <= spec_hole_start)
1490Sstevel@tonic-gate 			hole_allocated = 1;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 		allocpages += btopr(end - start);
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	if (hole_allocated)
1550Sstevel@tonic-gate 		allocpages -= btop(spec_hole_end - spec_hole_start);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	return (allocpages);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate  * Returns the max contiguous physical memory present in the
1620Sstevel@tonic-gate  * memlist "physavail".
1630Sstevel@tonic-gate  */
1640Sstevel@tonic-gate uint64_t
1650Sstevel@tonic-gate get_max_phys_size(
1660Sstevel@tonic-gate 	struct memlist	*physavail)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	uint64_t	max_size = 0;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	for (; physavail; physavail = physavail->next) {
1710Sstevel@tonic-gate 		if (physavail->size > max_size)
1720Sstevel@tonic-gate 			max_size = physavail->size;
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	return (max_size);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate struct vnode prom_ppages;
1810Sstevel@tonic-gate 
182*5648Ssetje static void
183*5648Ssetje more_pages(uint64_t base, uint64_t len)
1840Sstevel@tonic-gate {
185*5648Ssetje 	void kphysm_add();
186*5648Ssetje 
187*5648Ssetje 	kphysm_add(base, len, 1);
188*5648Ssetje }
189*5648Ssetje 
190*5648Ssetje static void
191*5648Ssetje less_pages(uint64_t base, uint64_t len)
192*5648Ssetje {
193*5648Ssetje 	uint64_t pa, end = base + len;
1940Sstevel@tonic-gate 	extern int kcage_on;
1950Sstevel@tonic-gate 
196*5648Ssetje 	for (pa = base; pa < end; pa += PAGESIZE) {
1970Sstevel@tonic-gate 		pfn_t pfnum;
1980Sstevel@tonic-gate 		page_t *pp;
1990Sstevel@tonic-gate 
200*5648Ssetje 		pfnum = (pfn_t)(pa >> PAGESHIFT);
201*5648Ssetje 		if ((pp = page_numtopp_nolock(pfnum)) == NULL)
202*5648Ssetje 			cmn_err(CE_PANIC, "missing pfnum %lx", pfnum);
203*5648Ssetje 
204*5648Ssetje 		/*
205*5648Ssetje 		 * must break up any large pages that may have
206*5648Ssetje 		 * constituent pages being utilized for
207*5648Ssetje 		 * prom_alloc()'s. page_reclaim() can't handle
208*5648Ssetje 		 * large pages.
209*5648Ssetje 		 */
210*5648Ssetje 		if (pp->p_szc != 0)
211*5648Ssetje 			page_boot_demote(pp);
212*5648Ssetje 
213*5648Ssetje 		if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) {
214*5648Ssetje 			/*
215*5648Ssetje 			 * Ahhh yes, a prom page,
216*5648Ssetje 			 * suck it off the freelist,
217*5648Ssetje 			 * lock it, and hashin on prom_pages vp.
218*5648Ssetje 			 */
219*5648Ssetje 			if (page_trylock(pp, SE_EXCL) == 0)
220*5648Ssetje 				cmn_err(CE_PANIC, "prom page locked");
221*5648Ssetje 
222*5648Ssetje 			(void) page_reclaim(pp, NULL);
223*5648Ssetje 			/*
224*5648Ssetje 			 * vnode offsets on the prom_ppages vnode
225*5648Ssetje 			 * are page numbers (gack) for >32 bit
226*5648Ssetje 			 * physical memory machines.
227*5648Ssetje 			 */
228*5648Ssetje 			(void) page_hashin(pp, &prom_ppages,
229*5648Ssetje 			    (offset_t)pfnum, NULL);
230*5648Ssetje 
231*5648Ssetje 			if (kcage_on) {
232*5648Ssetje 				ASSERT(pp->p_szc == 0);
233*5648Ssetje 				PP_SETNORELOC(pp);
234*5648Ssetje 			}
235*5648Ssetje 			(void) page_pp_lock(pp, 0, 1);
236*5648Ssetje 		}
237*5648Ssetje 	}
238*5648Ssetje }
239*5648Ssetje 
240*5648Ssetje void
241*5648Ssetje diff_memlists(struct memlist *proto, struct memlist *diff, void (*func)())
242*5648Ssetje {
243*5648Ssetje 	uint64_t p_base, p_end, d_base, d_end;
244*5648Ssetje 
245*5648Ssetje 	while (proto != NULL) {
246*5648Ssetje 		/*
247*5648Ssetje 		 * find diff item which may overlap with proto item
248*5648Ssetje 		 * if none, apply func to all of proto item
249*5648Ssetje 		 */
250*5648Ssetje 		while (diff != NULL &&
251*5648Ssetje 		    proto->address >= diff->address + diff->size)
252*5648Ssetje 			diff = diff->next;
253*5648Ssetje 		if (diff == NULL) {
254*5648Ssetje 			(*func)(proto->address, proto->size);
255*5648Ssetje 			proto = proto->next;
256*5648Ssetje 			continue;
257*5648Ssetje 		}
258*5648Ssetje 		if (proto->address == diff->address &&
259*5648Ssetje 		    proto->size == diff->size) {
260*5648Ssetje 			proto = proto->next;
261*5648Ssetje 			diff = diff->next;
262*5648Ssetje 			continue;
263*5648Ssetje 		}
264*5648Ssetje 
265*5648Ssetje 		p_base = proto->address;
266*5648Ssetje 		p_end = p_base + proto->size;
267*5648Ssetje 		d_base = diff->address;
268*5648Ssetje 		d_end = d_base + diff->size;
269*5648Ssetje 		/*
270*5648Ssetje 		 * here p_base < d_end
271*5648Ssetje 		 * there are 5 cases
272*5648Ssetje 		 */
273*5648Ssetje 
274*5648Ssetje 		/*
275*5648Ssetje 		 *	d_end
276*5648Ssetje 		 *	d_base
277*5648Ssetje 		 *  p_end
278*5648Ssetje 		 *  p_base
279*5648Ssetje 		 *
280*5648Ssetje 		 * apply func to all of proto item
281*5648Ssetje 		 */
282*5648Ssetje 		if (p_end <= d_base) {
283*5648Ssetje 			(*func)(p_base, proto->size);
284*5648Ssetje 			proto = proto->next;
2850Sstevel@tonic-gate 			continue;
2860Sstevel@tonic-gate 		}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		/*
289*5648Ssetje 		 * ...
290*5648Ssetje 		 *	d_base
291*5648Ssetje 		 *  p_base
292*5648Ssetje 		 *
293*5648Ssetje 		 * normalize by applying func from p_base to d_base
2940Sstevel@tonic-gate 		 */
295*5648Ssetje 		if (p_base < d_base)
296*5648Ssetje 			(*func)(p_base, d_base - p_base);
2970Sstevel@tonic-gate 
298*5648Ssetje 		if (p_end <= d_end) {
2990Sstevel@tonic-gate 			/*
300*5648Ssetje 			 *	d_end
301*5648Ssetje 			 *  p_end
302*5648Ssetje 			 *	d_base
303*5648Ssetje 			 *  p_base
304*5648Ssetje 			 *
305*5648Ssetje 			 *	-or-
306*5648Ssetje 			 *
307*5648Ssetje 			 *	d_end
308*5648Ssetje 			 *  p_end
309*5648Ssetje 			 *  p_base
310*5648Ssetje 			 *	d_base
311*5648Ssetje 			 *
312*5648Ssetje 			 * any non-overlapping ranges applied above,
313*5648Ssetje 			 * so just continue
3140Sstevel@tonic-gate 			 */
315*5648Ssetje 			proto = proto->next;
316*5648Ssetje 			continue;
317*5648Ssetje 		}
3180Sstevel@tonic-gate 
319*5648Ssetje 		/*
320*5648Ssetje 		 *  p_end
321*5648Ssetje 		 *	d_end
322*5648Ssetje 		 *	d_base
323*5648Ssetje 		 *  p_base
324*5648Ssetje 		 *
325*5648Ssetje 		 *	-or-
326*5648Ssetje 		 *
327*5648Ssetje 		 *  p_end
328*5648Ssetje 		 *	d_end
329*5648Ssetje 		 *  p_base
330*5648Ssetje 		 *	d_base
331*5648Ssetje 		 *
332*5648Ssetje 		 * Find overlapping d_base..d_end ranges, and apply func
333*5648Ssetje 		 * where no overlap occurs.  Stop when d_base is above
334*5648Ssetje 		 * p_end
335*5648Ssetje 		 */
336*5648Ssetje 		for (p_base = d_end, diff = diff->next; diff != NULL;
337*5648Ssetje 		    p_base = d_end, diff = diff->next) {
338*5648Ssetje 			d_base = diff->address;
339*5648Ssetje 			d_end = d_base + diff->size;
340*5648Ssetje 			if (p_end <= d_base) {
341*5648Ssetje 				(*func)(p_base, p_end - p_base);
342*5648Ssetje 				break;
343*5648Ssetje 			} else
344*5648Ssetje 				(*func)(p_base, d_base - p_base);
3450Sstevel@tonic-gate 		}
346*5648Ssetje 		if (diff == NULL)
347*5648Ssetje 			(*func)(p_base, p_end - p_base);
348*5648Ssetje 		proto = proto->next;
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
352*5648Ssetje void
353*5648Ssetje sync_memlists(struct memlist *orig, struct memlist *new)
354*5648Ssetje {
355*5648Ssetje 
356*5648Ssetje 	/*
357*5648Ssetje 	 * Find pages allocated via prom by looking for
358*5648Ssetje 	 * pages on orig, but no on new.
359*5648Ssetje 	 */
360*5648Ssetje 	diff_memlists(orig, new, less_pages);
361*5648Ssetje 
362*5648Ssetje 	/*
363*5648Ssetje 	 * Find pages free'd via prom by looking for
364*5648Ssetje 	 * pages on new, but not on orig.
365*5648Ssetje 	 */
366*5648Ssetje 	diff_memlists(new, orig, more_pages);
367*5648Ssetje }
368*5648Ssetje 
369*5648Ssetje 
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate  * Find the page number of the highest installed physical
3720Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
3730Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
3740Sstevel@tonic-gate  * contiguous).
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate void
3770Sstevel@tonic-gate installed_top_size_memlist_array(
378*5648Ssetje 	prom_memlist_t *list,	/* base of array */
3790Sstevel@tonic-gate 	size_t	nelems,		/* number of elements */
3800Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
3810Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	pfn_t top = 0;
3840Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
3850Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
3860Sstevel@tonic-gate 	size_t i;
3870Sstevel@tonic-gate 
388*5648Ssetje 	for (i = 0; i < nelems; list++, i++) {
389*5648Ssetje 		highp = (list->addr + list->size - 1) >> PAGESHIFT;
3900Sstevel@tonic-gate 		if (top < highp)
3910Sstevel@tonic-gate 			top = highp;
392*5648Ssetje 		sumpages += (list->size >> PAGESHIFT);
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	*topp = top;
3960Sstevel@tonic-gate 	*sumpagesp = sumpages;
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate /*
4000Sstevel@tonic-gate  * Copy a memory list.  Used in startup() to copy boot's
4010Sstevel@tonic-gate  * memory lists to the kernel.
4020Sstevel@tonic-gate  */
4030Sstevel@tonic-gate void
4040Sstevel@tonic-gate copy_memlist(
405*5648Ssetje 	prom_memlist_t	*src,
4060Sstevel@tonic-gate 	size_t		nelems,
4070Sstevel@tonic-gate 	struct memlist	**dstp)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate 	struct memlist *dst, *prev;
4100Sstevel@tonic-gate 	size_t	i;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	dst = *dstp;
4130Sstevel@tonic-gate 	prev = dst;
4140Sstevel@tonic-gate 
415*5648Ssetje 	for (i = 0; i < nelems; src++, i++) {
416*5648Ssetje 		dst->address = src->addr;
417*5648Ssetje 		dst->size = src->size;
4180Sstevel@tonic-gate 		dst->next = 0;
4190Sstevel@tonic-gate 		if (prev == dst) {
4200Sstevel@tonic-gate 			dst->prev = 0;
4210Sstevel@tonic-gate 			dst++;
4220Sstevel@tonic-gate 		} else {
4230Sstevel@tonic-gate 			dst->prev = prev;
4240Sstevel@tonic-gate 			prev->next = dst;
4250Sstevel@tonic-gate 			dst++;
4260Sstevel@tonic-gate 			prev++;
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	*dstp = dst;
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
433*5648Ssetje 
4340Sstevel@tonic-gate static struct bootmem_props {
435*5648Ssetje 	prom_memlist_t	*ptr;
4360Sstevel@tonic-gate 	size_t		nelems;		/* actual number of elements */
437*5648Ssetje 	size_t		maxsize;	/* max buffer */
438*5648Ssetje } bootmem_props[3];
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate #define	PHYSINSTALLED	0
4410Sstevel@tonic-gate #define	PHYSAVAIL	1
4420Sstevel@tonic-gate #define	VIRTAVAIL	2
4430Sstevel@tonic-gate 
444*5648Ssetje /*
445*5648Ssetje  * Comapct contiguous memory list elements
446*5648Ssetje  */
447*5648Ssetje static void
448*5648Ssetje compact_promlist(struct bootmem_props *bpp)
4490Sstevel@tonic-gate {
450*5648Ssetje 	int i = 0, j;
451*5648Ssetje 	struct prom_memlist *pmp = bpp->ptr;
4520Sstevel@tonic-gate 
453*5648Ssetje 	for (;;) {
454*5648Ssetje 		if (pmp[i].addr + pmp[i].size == pmp[i+1].addr) {
455*5648Ssetje 			pmp[i].size += pmp[i+1].size;
456*5648Ssetje 			bpp->nelems--;
457*5648Ssetje 			for (j = i + 1; j < bpp->nelems; j++)
458*5648Ssetje 				pmp[j] = pmp[j+1];
459*5648Ssetje 			pmp[j].addr = 0;
460*5648Ssetje 		} else
461*5648Ssetje 			i++;
462*5648Ssetje 		if (i == bpp->nelems)
463*5648Ssetje 			break;
464*5648Ssetje 	}
465*5648Ssetje }
466*5648Ssetje 
467*5648Ssetje /*
468*5648Ssetje  *  Sort prom memory lists into ascending order
469*5648Ssetje  */
470*5648Ssetje static void
471*5648Ssetje sort_promlist(struct bootmem_props *bpp)
472*5648Ssetje {
473*5648Ssetje 	int i, j, min;
474*5648Ssetje 	struct prom_memlist *pmp = bpp->ptr;
475*5648Ssetje 	struct prom_memlist temp;
476*5648Ssetje 
477*5648Ssetje 	for (i = 0; i < bpp->nelems; i++) {
478*5648Ssetje 		min = i;
479*5648Ssetje 
480*5648Ssetje 		for (j = i+1; j < bpp->nelems; j++)  {
481*5648Ssetje 			if (pmp[j].addr < pmp[min].addr)
482*5648Ssetje 				min = j;
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 
485*5648Ssetje 		if (i != min)  {
486*5648Ssetje 			/* Swap pmp[i] and pmp[min] */
487*5648Ssetje 			temp = pmp[min];
488*5648Ssetje 			pmp[min] = pmp[i];
489*5648Ssetje 			pmp[i] = temp;
4900Sstevel@tonic-gate 		}
4910Sstevel@tonic-gate 	}
492*5648Ssetje }
493*5648Ssetje 
494*5648Ssetje static int max_bootlist_sz;
495*5648Ssetje 
496*5648Ssetje void
497*5648Ssetje init_boot_memlists(void)
498*5648Ssetje {
499*5648Ssetje 	size_t	size, len;
500*5648Ssetje 	char *start;
501*5648Ssetje 	struct bootmem_props *tmp;
502*5648Ssetje 
503*5648Ssetje 	/*
504*5648Ssetje 	 * These lists can get fragmented as the prom allocates
505*5648Ssetje 	 * memory, so generously round up.
506*5648Ssetje 	 */
507*5648Ssetje 	size = prom_phys_installed_len() + prom_phys_avail_len() +
508*5648Ssetje 	    prom_virt_avail_len();
509*5648Ssetje 	size *= 4;
510*5648Ssetje 	size = roundup(size, PAGESIZE);
511*5648Ssetje 	start = prom_alloc(0, size, BO_NO_ALIGN);
512*5648Ssetje 
513*5648Ssetje 	/*
514*5648Ssetje 	 * Get physinstalled
515*5648Ssetje 	 */
516*5648Ssetje 	tmp = &bootmem_props[PHYSINSTALLED];
517*5648Ssetje 	len = prom_phys_installed_len();
518*5648Ssetje 	if (len == 0)
519*5648Ssetje 		panic("no \"reg\" in /memory");
520*5648Ssetje 	tmp->nelems = len / sizeof (struct prom_memlist);
521*5648Ssetje 	tmp->maxsize = len;
522*5648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
523*5648Ssetje 	start += len;
524*5648Ssetje 	size -= len;
525*5648Ssetje 	(void) prom_phys_installed((caddr_t)tmp->ptr);
526*5648Ssetje 	sort_promlist(tmp);
527*5648Ssetje 	compact_promlist(tmp);
528*5648Ssetje 
529*5648Ssetje 	/*
530*5648Ssetje 	 * Start out giving each half of available space
531*5648Ssetje 	 */
532*5648Ssetje 	max_bootlist_sz = size;
533*5648Ssetje 	len = size / 2;
534*5648Ssetje 	tmp = &bootmem_props[PHYSAVAIL];
535*5648Ssetje 	tmp->maxsize = len;
536*5648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
537*5648Ssetje 	start += len;
538*5648Ssetje 
539*5648Ssetje 	tmp = &bootmem_props[VIRTAVAIL];
540*5648Ssetje 	tmp->maxsize = len;
541*5648Ssetje 	tmp->ptr = (prom_memlist_t *)start;
542*5648Ssetje }
543*5648Ssetje 
544*5648Ssetje 
545*5648Ssetje void
546*5648Ssetje copy_boot_memlists(
547*5648Ssetje     prom_memlist_t **physinstalled, size_t *physinstalled_len,
548*5648Ssetje     prom_memlist_t **physavail, size_t *physavail_len,
549*5648Ssetje     prom_memlist_t **virtavail, size_t *virtavail_len)
550*5648Ssetje {
551*5648Ssetje 	size_t	plen, vlen, move = 0;
552*5648Ssetje 	struct bootmem_props *il, *pl, *vl;
553*5648Ssetje 
554*5648Ssetje 	plen = prom_phys_avail_len();
555*5648Ssetje 	if (plen == 0)
556*5648Ssetje 		panic("no \"available\" in /memory");
557*5648Ssetje 	vlen = prom_virt_avail_len();
558*5648Ssetje 	if (vlen == 0)
559*5648Ssetje 		panic("no \"available\" in /virtual-memory");
560*5648Ssetje 	if (plen + vlen > max_bootlist_sz)
561*5648Ssetje 		panic("ran out of prom_memlist space");
562*5648Ssetje 
563*5648Ssetje 	pl = &bootmem_props[PHYSAVAIL];
564*5648Ssetje 	vl = &bootmem_props[VIRTAVAIL];
565*5648Ssetje 
566*5648Ssetje 	/*
567*5648Ssetje 	 * re-adjust ptrs if needed
568*5648Ssetje 	 */
569*5648Ssetje 	if (plen > pl->maxsize) {
570*5648Ssetje 		/* move virt avail up */
571*5648Ssetje 		move = plen - pl->maxsize;
572*5648Ssetje 		pl->maxsize = plen;
573*5648Ssetje 		vl->ptr += move / sizeof (struct prom_memlist);
574*5648Ssetje 		vl->maxsize -= move;
575*5648Ssetje 	} else if (vlen > vl->maxsize) {
576*5648Ssetje 		/* move virt avail down */
577*5648Ssetje 		move = vlen - vl->maxsize;
578*5648Ssetje 		vl->maxsize = vlen;
579*5648Ssetje 		vl->ptr -= move / sizeof (struct prom_memlist);
580*5648Ssetje 		pl->maxsize -= move;
581*5648Ssetje 	}
582*5648Ssetje 
583*5648Ssetje 	pl->nelems = plen / sizeof (struct prom_memlist);
584*5648Ssetje 	vl->nelems = vlen / sizeof (struct prom_memlist);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/* now we can retrieve the properties */
587*5648Ssetje 	(void) prom_phys_avail((caddr_t)pl->ptr);
588*5648Ssetje 	(void) prom_virt_avail((caddr_t)vl->ptr);
589*5648Ssetje 
590*5648Ssetje 	/* .. and sort them */
591*5648Ssetje 	sort_promlist(pl);
592*5648Ssetje 	sort_promlist(vl);
5930Sstevel@tonic-gate 
594*5648Ssetje 	il = &bootmem_props[PHYSINSTALLED];
595*5648Ssetje 	*physinstalled = il->ptr;
596*5648Ssetje 	*physinstalled_len = il->nelems;
5970Sstevel@tonic-gate 
598*5648Ssetje 	*physavail = pl->ptr;
599*5648Ssetje 	*physavail_len = pl->nelems;
600*5648Ssetje 
601*5648Ssetje 	*virtavail = vl->ptr;
602*5648Ssetje 	*virtavail_len = vl->nelems;
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate  * Find the page number of the highest installed physical
6080Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
6090Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
6100Sstevel@tonic-gate  * contiguous).
6110Sstevel@tonic-gate  */
6120Sstevel@tonic-gate void
6130Sstevel@tonic-gate installed_top_size(
6140Sstevel@tonic-gate 	struct memlist *list,	/* pointer to start of installed list */
6150Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
6160Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
6170Sstevel@tonic-gate {
6180Sstevel@tonic-gate 	pfn_t top = 0;
6190Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
6200Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	for (; list; list = list->next) {
6230Sstevel@tonic-gate 		highp = (list->address + list->size - 1) >> PAGESHIFT;
6240Sstevel@tonic-gate 		if (top < highp)
6250Sstevel@tonic-gate 			top = highp;
6260Sstevel@tonic-gate 		sumpages += (uint_t)(list->size >> PAGESHIFT);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	*topp = top;
6300Sstevel@tonic-gate 	*sumpagesp = sumpages;
6310Sstevel@tonic-gate }
632