xref: /onnv-gate/usr/src/uts/sun4/os/memlist.c (revision 5084)
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
5*5084Sjohnlev  * Common Development and Distribution License (the "License").
6*5084Sjohnlev  * 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*5084Sjohnlev  * 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>
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 
93*5084Sjohnlev pgcnt_t
94*5084Sjohnlev num_phys_pages()
95*5084Sjohnlev {
96*5084Sjohnlev 	pgcnt_t npages = 0;
97*5084Sjohnlev 	struct memlist *mp;
98*5084Sjohnlev 
99*5084Sjohnlev 	for (mp = phys_install; mp != NULL; mp = mp->next)
100*5084Sjohnlev 		npages += mp->size >> PAGESHIFT;
101*5084Sjohnlev 
102*5084Sjohnlev 	return (npages);
103*5084Sjohnlev }
104*5084Sjohnlev 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * Count the number of available pages and the number of
1070Sstevel@tonic-gate  * chunks in the list of available memory.
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate void
1100Sstevel@tonic-gate size_physavail(
1110Sstevel@tonic-gate 	u_longlong_t	*physavail,
1120Sstevel@tonic-gate 	size_t		nelems,
1130Sstevel@tonic-gate 	pgcnt_t		*npages,
1140Sstevel@tonic-gate 	int		*memblocks)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	size_t	i;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	*npages = 0;
1190Sstevel@tonic-gate 	*memblocks = 0;
1200Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
1210Sstevel@tonic-gate 		*npages += (pgcnt_t)(physavail[i+1] >> PAGESHIFT);
1220Sstevel@tonic-gate 		(*memblocks)++;
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate pgcnt_t
1270Sstevel@tonic-gate size_virtalloc(u_longlong_t *avail, size_t nelems)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	u_longlong_t	start, end;
1310Sstevel@tonic-gate 	pgcnt_t		allocpages = 0;
1320Sstevel@tonic-gate 	uint_t		hole_allocated = 0;
1330Sstevel@tonic-gate 	uint_t		i;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	for (i = 0; i < (nelems - 2); i += 2) {
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 		start = avail[i] + avail[i + 1];
1380Sstevel@tonic-gate 		end = avail[i + 2];
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		/*
1410Sstevel@tonic-gate 		 * Notes:
1420Sstevel@tonic-gate 		 *
1430Sstevel@tonic-gate 		 * (1) OBP on platforms with US I/II pre-allocates the hole
1440Sstevel@tonic-gate 		 * represented by [spec_hole_start, spec_hole_end);
1450Sstevel@tonic-gate 		 * pre-allocation is done to make this range unavailable
1460Sstevel@tonic-gate 		 * for any allocation.
1470Sstevel@tonic-gate 		 *
1480Sstevel@tonic-gate 		 * (2) OBP on starcat always pre-allocates the hole similar to
1490Sstevel@tonic-gate 		 * platforms with US I/II.
1500Sstevel@tonic-gate 		 *
1510Sstevel@tonic-gate 		 * (3) OBP on serengeti does _not_ pre-allocate the hole.
1520Sstevel@tonic-gate 		 *
1530Sstevel@tonic-gate 		 * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_
1540Sstevel@tonic-gate 		 * fill up or pre-allocate an additional 4GB on both sides
1550Sstevel@tonic-gate 		 * of the hole.
1560Sstevel@tonic-gate 		 *
1570Sstevel@tonic-gate 		 * (5) kernel virtual range [spec_hole_start, spec_hole_end)
1580Sstevel@tonic-gate 		 * is _not_ used on any platform including those with
1590Sstevel@tonic-gate 		 * UltraSPARC III where there is no hole.
1600Sstevel@tonic-gate 		 *
1610Sstevel@tonic-gate 		 * Algorithm:
1620Sstevel@tonic-gate 		 *
1630Sstevel@tonic-gate 		 * Check if range [spec_hole_start, spec_hole_end) is
1640Sstevel@tonic-gate 		 * pre-allocated by OBP; if so, subtract that range from
1650Sstevel@tonic-gate 		 * allocpages.
1660Sstevel@tonic-gate 		 */
1670Sstevel@tonic-gate 		if (end >= spec_hole_end && start <= spec_hole_start)
1680Sstevel@tonic-gate 			hole_allocated = 1;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 		allocpages += btopr(end - start);
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if (hole_allocated)
1740Sstevel@tonic-gate 		allocpages -= btop(spec_hole_end - spec_hole_start);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (allocpages);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * Returns the max contiguous physical memory present in the
1810Sstevel@tonic-gate  * memlist "physavail".
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate uint64_t
1840Sstevel@tonic-gate get_max_phys_size(
1850Sstevel@tonic-gate 	struct memlist	*physavail)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	uint64_t	max_size = 0;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	for (; physavail; physavail = physavail->next) {
1900Sstevel@tonic-gate 		if (physavail->size > max_size)
1910Sstevel@tonic-gate 			max_size = physavail->size;
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	return (max_size);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate  * Copy boot's physavail list deducting memory at "start"
2000Sstevel@tonic-gate  * for "size" bytes.
2010Sstevel@tonic-gate  */
2020Sstevel@tonic-gate int
2030Sstevel@tonic-gate copy_physavail(
2040Sstevel@tonic-gate 	u_longlong_t	*src,
2050Sstevel@tonic-gate 	size_t		nelems,
2060Sstevel@tonic-gate 	struct memlist	**dstp,
2070Sstevel@tonic-gate 	uint_t		start,
2080Sstevel@tonic-gate 	uint_t		size)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	struct memlist *dst, *prev;
2110Sstevel@tonic-gate 	uint_t end1;
2120Sstevel@tonic-gate 	int deducted = 0;
2130Sstevel@tonic-gate 	size_t	i;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	dst = *dstp;
2160Sstevel@tonic-gate 	prev = dst;
2170Sstevel@tonic-gate 	end1 = start + size;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
2200Sstevel@tonic-gate 		uint64_t addr, lsize, end2;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		addr = src[i];
2230Sstevel@tonic-gate 		lsize = src[i+1];
2240Sstevel@tonic-gate 		end2 = addr + lsize;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		if ((size != 0) && start >= addr && end1 <= end2) {
2270Sstevel@tonic-gate 			/* deducted range in this chunk */
2280Sstevel@tonic-gate 			deducted = 1;
2290Sstevel@tonic-gate 			if (start == addr) {
2300Sstevel@tonic-gate 				/* abuts start of chunk */
2310Sstevel@tonic-gate 				if (end1 == end2)
2320Sstevel@tonic-gate 					/* is equal to the chunk */
2330Sstevel@tonic-gate 					continue;
2340Sstevel@tonic-gate 				dst->address = end1;
2350Sstevel@tonic-gate 				dst->size = lsize - size;
2360Sstevel@tonic-gate 			} else if (end1 == end2) {
2370Sstevel@tonic-gate 				/* abuts end of chunk */
2380Sstevel@tonic-gate 				dst->address = addr;
2390Sstevel@tonic-gate 				dst->size = lsize - size;
2400Sstevel@tonic-gate 			} else {
2410Sstevel@tonic-gate 				/* in the middle of the chunk */
2420Sstevel@tonic-gate 				dst->address = addr;
2430Sstevel@tonic-gate 				dst->size = start - addr;
2440Sstevel@tonic-gate 				dst->next = 0;
2450Sstevel@tonic-gate 				if (prev == dst) {
2460Sstevel@tonic-gate 					dst->prev = 0;
2470Sstevel@tonic-gate 					dst++;
2480Sstevel@tonic-gate 				} else {
2490Sstevel@tonic-gate 					dst->prev = prev;
2500Sstevel@tonic-gate 					prev->next = dst;
2510Sstevel@tonic-gate 					dst++;
2520Sstevel@tonic-gate 					prev++;
2530Sstevel@tonic-gate 				}
2540Sstevel@tonic-gate 				dst->address = end1;
2550Sstevel@tonic-gate 				dst->size = end2 - end1;
2560Sstevel@tonic-gate 			}
2570Sstevel@tonic-gate 			dst->next = 0;
2580Sstevel@tonic-gate 			if (prev == dst) {
2590Sstevel@tonic-gate 				dst->prev = 0;
2600Sstevel@tonic-gate 				dst++;
2610Sstevel@tonic-gate 			} else {
2620Sstevel@tonic-gate 				dst->prev = prev;
2630Sstevel@tonic-gate 				prev->next = dst;
2640Sstevel@tonic-gate 				dst++;
2650Sstevel@tonic-gate 				prev++;
2660Sstevel@tonic-gate 			}
2670Sstevel@tonic-gate 		} else {
2680Sstevel@tonic-gate 			dst->address = src[i];
2690Sstevel@tonic-gate 			dst->size = src[i+1];
2700Sstevel@tonic-gate 			dst->next = 0;
2710Sstevel@tonic-gate 			if (prev == dst) {
2720Sstevel@tonic-gate 				dst->prev = 0;
2730Sstevel@tonic-gate 				dst++;
2740Sstevel@tonic-gate 			} else {
2750Sstevel@tonic-gate 				dst->prev = prev;
2760Sstevel@tonic-gate 				prev->next = dst;
2770Sstevel@tonic-gate 				dst++;
2780Sstevel@tonic-gate 				prev++;
2790Sstevel@tonic-gate 			}
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	*dstp = dst;
2840Sstevel@tonic-gate 	return (deducted);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate struct vnode prom_ppages;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate  * Find the pages allocated by the prom by diffing the original
2910Sstevel@tonic-gate  * phys_avail list and the current list.  In the difference, the
2920Sstevel@tonic-gate  * pages not locked belong to the PROM.  (The kernel has already locked
2930Sstevel@tonic-gate  * and removed all the pages it has allocated from the freelist, this
2940Sstevel@tonic-gate  * routine removes the remaining "free" pages that really belong to the
2950Sstevel@tonic-gate  * PROM and hashs them in on the 'prom_pages' vnode.)
2960Sstevel@tonic-gate  */
2970Sstevel@tonic-gate void
2980Sstevel@tonic-gate fix_prom_pages(struct memlist *orig, struct memlist *new)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	struct memlist *list, *nlist;
3010Sstevel@tonic-gate 	extern int kcage_on;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	nlist = new;
3040Sstevel@tonic-gate 	for (list = orig; list; list = list->next) {
3050Sstevel@tonic-gate 		uint64_t pa, end;
3060Sstevel@tonic-gate 		pfn_t pfnum;
3070Sstevel@tonic-gate 		page_t *pp;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 		if (list->address == nlist->address &&
3100Sstevel@tonic-gate 		    list->size == nlist->size) {
3110Sstevel@tonic-gate 			nlist = nlist->next ? nlist->next : nlist;
3120Sstevel@tonic-gate 			continue;
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		/*
3160Sstevel@tonic-gate 		 * Loop through the old list looking to
3170Sstevel@tonic-gate 		 * see if each page is still in the new one.
3180Sstevel@tonic-gate 		 * If a page is not in the new list then we
3190Sstevel@tonic-gate 		 * check to see if it locked permanently.
3200Sstevel@tonic-gate 		 * If so, the kernel allocated and owns it.
3210Sstevel@tonic-gate 		 * If not, then the prom must own it. We
3220Sstevel@tonic-gate 		 * remove any pages found to owned by the prom
3230Sstevel@tonic-gate 		 * from the freelist.
3240Sstevel@tonic-gate 		 */
3250Sstevel@tonic-gate 		end = list->address + list->size;
3260Sstevel@tonic-gate 		for (pa = list->address; pa < end; pa += PAGESIZE) {
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 			if (address_in_memlist(new, pa, PAGESIZE))
3290Sstevel@tonic-gate 				continue;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 			pfnum = (pfn_t)(pa >> PAGESHIFT);
3320Sstevel@tonic-gate 			if ((pp = page_numtopp_nolock(pfnum)) == NULL)
3330Sstevel@tonic-gate 				cmn_err(CE_PANIC, "missing pfnum %lx", pfnum);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 			/*
3360Sstevel@tonic-gate 			 * must break up any large pages that may have
3370Sstevel@tonic-gate 			 * constituent pages being utilized for
3380Sstevel@tonic-gate 			 * BOP_ALLOC()'s. page_reclaim() can't handle
3390Sstevel@tonic-gate 			 * large pages.
3400Sstevel@tonic-gate 			 */
3410Sstevel@tonic-gate 			if (pp->p_szc != 0)
3420Sstevel@tonic-gate 				page_boot_demote(pp);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 			if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) {
3450Sstevel@tonic-gate 				/*
3460Sstevel@tonic-gate 				 * Ahhh yes, a prom page,
3470Sstevel@tonic-gate 				 * suck it off the freelist,
3480Sstevel@tonic-gate 				 * lock it, and hashin on prom_pages vp.
3490Sstevel@tonic-gate 				 */
3500Sstevel@tonic-gate 				if (page_trylock(pp, SE_EXCL) == 0)
3510Sstevel@tonic-gate 					cmn_err(CE_PANIC, "prom page locked");
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 				(void) page_reclaim(pp, NULL);
3540Sstevel@tonic-gate 				/*
3550Sstevel@tonic-gate 				 * XXX	vnode offsets on the prom_ppages vnode
3560Sstevel@tonic-gate 				 *	are page numbers (gack) for >32 bit
3570Sstevel@tonic-gate 				 *	physical memory machines.
3580Sstevel@tonic-gate 				 */
3590Sstevel@tonic-gate 				(void) page_hashin(pp, &prom_ppages,
360*5084Sjohnlev 				    (offset_t)pfnum, NULL);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 				if (kcage_on) {
3630Sstevel@tonic-gate 					ASSERT(pp->p_szc == 0);
3640Sstevel@tonic-gate 					PP_SETNORELOC(pp);
3650Sstevel@tonic-gate 				}
3660Sstevel@tonic-gate 				(void) page_pp_lock(pp, 0, 1);
3670Sstevel@tonic-gate 				page_downgrade(pp);
3680Sstevel@tonic-gate 			}
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 		nlist = nlist->next ? nlist->next : nlist;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
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(
3820Sstevel@tonic-gate 	u_longlong_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 
3920Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
3930Sstevel@tonic-gate 		highp = (list[i] + list[i+1] - 1) >> PAGESHIFT;
3940Sstevel@tonic-gate 		if (top < highp)
3950Sstevel@tonic-gate 			top = highp;
3960Sstevel@tonic-gate 		sumpages += (list[i+1] >> 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(
4090Sstevel@tonic-gate 	u_longlong_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 
4190Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
4200Sstevel@tonic-gate 		dst->address = src[i];
4210Sstevel@tonic-gate 		dst->size = src[i+1];
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 
4370Sstevel@tonic-gate static struct bootmem_props {
4380Sstevel@tonic-gate 	char		*name;
4390Sstevel@tonic-gate 	u_longlong_t	*ptr;
4400Sstevel@tonic-gate 	size_t		nelems;		/* actual number of elements */
4410Sstevel@tonic-gate 	size_t		bufsize;	/* length of allocated buffer */
4420Sstevel@tonic-gate } bootmem_props[] = {
4430Sstevel@tonic-gate 	{ "phys-installed", NULL, 0, 0 },
4440Sstevel@tonic-gate 	{ "phys-avail", NULL, 0, 0 },
4450Sstevel@tonic-gate 	{ "virt-avail", NULL, 0, 0 },
4460Sstevel@tonic-gate 	{ NULL, NULL, 0, 0 }
4470Sstevel@tonic-gate };
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate #define	PHYSINSTALLED	0
4500Sstevel@tonic-gate #define	PHYSAVAIL	1
4510Sstevel@tonic-gate #define	VIRTAVAIL	2
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate void
4540Sstevel@tonic-gate copy_boot_memlists(u_longlong_t **physinstalled, size_t *physinstalled_len,
4550Sstevel@tonic-gate     u_longlong_t **physavail, size_t *physavail_len,
4560Sstevel@tonic-gate     u_longlong_t **virtavail, size_t *virtavail_len)
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate 	int	align = BO_ALIGN_L3;
4590Sstevel@tonic-gate 	size_t	len;
4600Sstevel@tonic-gate 	struct bootmem_props *tmp = bootmem_props;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate tryagain:
4630Sstevel@tonic-gate 	for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
4640Sstevel@tonic-gate 		len = BOP_GETPROPLEN(bootops, tmp->name);
4650Sstevel@tonic-gate 		if (len == 0) {
4660Sstevel@tonic-gate 			panic("cannot get length of \"%s\" property",
4670Sstevel@tonic-gate 			    tmp->name);
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 		tmp->nelems = len / sizeof (u_longlong_t);
4700Sstevel@tonic-gate 		len = roundup(len, PAGESIZE);
4710Sstevel@tonic-gate 		if (len <= tmp->bufsize)
4720Sstevel@tonic-gate 			continue;
4730Sstevel@tonic-gate 		/* need to allocate more */
4740Sstevel@tonic-gate 		if (tmp->ptr) {
4750Sstevel@tonic-gate 			BOP_FREE(bootops, (caddr_t)tmp->ptr, tmp->bufsize);
4760Sstevel@tonic-gate 			tmp->ptr = NULL;
4770Sstevel@tonic-gate 			tmp->bufsize = 0;
4780Sstevel@tonic-gate 		}
4790Sstevel@tonic-gate 		tmp->bufsize = len;
4800Sstevel@tonic-gate 		tmp->ptr = (void *)BOP_ALLOC(bootops, 0, tmp->bufsize, align);
4810Sstevel@tonic-gate 		if (tmp->ptr == NULL)
482567Sdmick 			panic("cannot allocate %lu bytes for \"%s\" property",
4830Sstevel@tonic-gate 			    tmp->bufsize, tmp->name);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 	/*
4870Sstevel@tonic-gate 	 * take the most current snapshot we can by calling mem-update
4880Sstevel@tonic-gate 	 */
4890Sstevel@tonic-gate 	if (BOP_GETPROPLEN(bootops, "memory-update") == 0)
4900Sstevel@tonic-gate 		(void) BOP_GETPROP(bootops, "memory-update", NULL);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/* did the sizes change? */
4930Sstevel@tonic-gate 	for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
4940Sstevel@tonic-gate 		len = BOP_GETPROPLEN(bootops, tmp->name);
4950Sstevel@tonic-gate 		tmp->nelems = len / sizeof (u_longlong_t);
4960Sstevel@tonic-gate 		len = roundup(len, PAGESIZE);
4970Sstevel@tonic-gate 		if (len > tmp->bufsize) {
4980Sstevel@tonic-gate 			/* ick. Free them all and try again */
4990Sstevel@tonic-gate 			for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
5000Sstevel@tonic-gate 				BOP_FREE(bootops, (caddr_t)tmp->ptr,
5010Sstevel@tonic-gate 				    tmp->bufsize);
5020Sstevel@tonic-gate 				tmp->ptr = NULL;
5030Sstevel@tonic-gate 				tmp->bufsize = 0;
5040Sstevel@tonic-gate 			}
5050Sstevel@tonic-gate 			goto tryagain;
5060Sstevel@tonic-gate 		}
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/* now we can retrieve the properties */
5100Sstevel@tonic-gate 	for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
5110Sstevel@tonic-gate 		if (BOP_GETPROP(bootops, tmp->name, tmp->ptr) == -1) {
5120Sstevel@tonic-gate 			panic("cannot retrieve \"%s\" property",
5130Sstevel@tonic-gate 			    tmp->name);
5140Sstevel@tonic-gate 		}
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 	*physinstalled = bootmem_props[PHYSINSTALLED].ptr;
5170Sstevel@tonic-gate 	*physinstalled_len = bootmem_props[PHYSINSTALLED].nelems;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	*physavail = bootmem_props[PHYSAVAIL].ptr;
5200Sstevel@tonic-gate 	*physavail_len = bootmem_props[PHYSAVAIL].nelems;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	*virtavail = bootmem_props[VIRTAVAIL].ptr;
5230Sstevel@tonic-gate 	*virtavail_len = bootmem_props[VIRTAVAIL].nelems;
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate  * Find the page number of the highest installed physical
5290Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
5300Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
5310Sstevel@tonic-gate  * contiguous).
5320Sstevel@tonic-gate  */
5330Sstevel@tonic-gate void
5340Sstevel@tonic-gate installed_top_size(
5350Sstevel@tonic-gate 	struct memlist *list,	/* pointer to start of installed list */
5360Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
5370Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate 	pfn_t top = 0;
5400Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
5410Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	for (; list; list = list->next) {
5440Sstevel@tonic-gate 		highp = (list->address + list->size - 1) >> PAGESHIFT;
5450Sstevel@tonic-gate 		if (top < highp)
5460Sstevel@tonic-gate 			top = highp;
5470Sstevel@tonic-gate 		sumpages += (uint_t)(list->size >> PAGESHIFT);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	*topp = top;
5510Sstevel@tonic-gate 	*sumpagesp = sumpages;
5520Sstevel@tonic-gate }
553