1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/param.h>
31*0Sstevel@tonic-gate #include <sys/sysmacros.h>
32*0Sstevel@tonic-gate #include <sys/signal.h>
33*0Sstevel@tonic-gate #include <sys/systm.h>
34*0Sstevel@tonic-gate #include <sys/user.h>
35*0Sstevel@tonic-gate #include <sys/mman.h>
36*0Sstevel@tonic-gate #include <sys/class.h>
37*0Sstevel@tonic-gate #include <sys/proc.h>
38*0Sstevel@tonic-gate #include <sys/procfs.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <sys/cred.h>
41*0Sstevel@tonic-gate #include <sys/archsystm.h>
42*0Sstevel@tonic-gate #include <sys/machsystm.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #include <sys/reboot.h>
45*0Sstevel@tonic-gate #include <sys/uadmin.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #include <sys/vfs.h>
48*0Sstevel@tonic-gate #include <sys/vnode.h>
49*0Sstevel@tonic-gate #include <sys/session.h>
50*0Sstevel@tonic-gate #include <sys/ucontext.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #include <sys/dnlc.h>
53*0Sstevel@tonic-gate #include <sys/var.h>
54*0Sstevel@tonic-gate #include <sys/cmn_err.h>
55*0Sstevel@tonic-gate #include <sys/debug.h>
56*0Sstevel@tonic-gate #include <sys/thread.h>
57*0Sstevel@tonic-gate #include <sys/vtrace.h>
58*0Sstevel@tonic-gate #include <sys/consdev.h>
59*0Sstevel@tonic-gate #include <sys/frame.h>
60*0Sstevel@tonic-gate #include <sys/stack.h>
61*0Sstevel@tonic-gate #include <sys/swap.h>
62*0Sstevel@tonic-gate #include <sys/vmparam.h>
63*0Sstevel@tonic-gate #include <sys/cpuvar.h>
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #include <sys/privregs.h>
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate #include <vm/hat.h>
68*0Sstevel@tonic-gate #include <vm/anon.h>
69*0Sstevel@tonic-gate #include <vm/as.h>
70*0Sstevel@tonic-gate #include <vm/page.h>
71*0Sstevel@tonic-gate #include <vm/seg.h>
72*0Sstevel@tonic-gate #include <vm/seg_kmem.h>
73*0Sstevel@tonic-gate #include <vm/seg_map.h>
74*0Sstevel@tonic-gate #include <vm/seg_vn.h>
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate #include <sys/exec.h>
77*0Sstevel@tonic-gate #include <sys/acct.h>
78*0Sstevel@tonic-gate #include <sys/modctl.h>
79*0Sstevel@tonic-gate #include <sys/tuneable.h>
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate #include <c2/audit.h>
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate #include <sys/trap.h>
84*0Sstevel@tonic-gate #include <sys/sunddi.h>
85*0Sstevel@tonic-gate #include <sys/bootconf.h>
86*0Sstevel@tonic-gate #include <sys/memlist.h>
87*0Sstevel@tonic-gate #include <sys/memlist_plat.h>
88*0Sstevel@tonic-gate #include <sys/systeminfo.h>
89*0Sstevel@tonic-gate #include <sys/promif.h>
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate u_longlong_t	spec_hole_start = 0x80000000000ull;
92*0Sstevel@tonic-gate u_longlong_t	spec_hole_end = 0xfffff80000000000ull;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate  * Count the number of available pages and the number of
96*0Sstevel@tonic-gate  * chunks in the list of available memory.
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate void
99*0Sstevel@tonic-gate size_physavail(
100*0Sstevel@tonic-gate 	u_longlong_t	*physavail,
101*0Sstevel@tonic-gate 	size_t		nelems,
102*0Sstevel@tonic-gate 	pgcnt_t		*npages,
103*0Sstevel@tonic-gate 	int		*memblocks)
104*0Sstevel@tonic-gate {
105*0Sstevel@tonic-gate 	size_t	i;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	*npages = 0;
108*0Sstevel@tonic-gate 	*memblocks = 0;
109*0Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
110*0Sstevel@tonic-gate 		*npages += (pgcnt_t)(physavail[i+1] >> PAGESHIFT);
111*0Sstevel@tonic-gate 		(*memblocks)++;
112*0Sstevel@tonic-gate 	}
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate pgcnt_t
116*0Sstevel@tonic-gate size_virtalloc(u_longlong_t *avail, size_t nelems)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	u_longlong_t	start, end;
120*0Sstevel@tonic-gate 	pgcnt_t		allocpages = 0;
121*0Sstevel@tonic-gate 	uint_t		hole_allocated = 0;
122*0Sstevel@tonic-gate 	uint_t		i;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	for (i = 0; i < (nelems - 2); i += 2) {
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 		start = avail[i] + avail[i + 1];
127*0Sstevel@tonic-gate 		end = avail[i + 2];
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 		/*
130*0Sstevel@tonic-gate 		 * Notes:
131*0Sstevel@tonic-gate 		 *
132*0Sstevel@tonic-gate 		 * (1) OBP on platforms with US I/II pre-allocates the hole
133*0Sstevel@tonic-gate 		 * represented by [spec_hole_start, spec_hole_end);
134*0Sstevel@tonic-gate 		 * pre-allocation is done to make this range unavailable
135*0Sstevel@tonic-gate 		 * for any allocation.
136*0Sstevel@tonic-gate 		 *
137*0Sstevel@tonic-gate 		 * (2) OBP on starcat always pre-allocates the hole similar to
138*0Sstevel@tonic-gate 		 * platforms with US I/II.
139*0Sstevel@tonic-gate 		 *
140*0Sstevel@tonic-gate 		 * (3) OBP on serengeti does _not_ pre-allocate the hole.
141*0Sstevel@tonic-gate 		 *
142*0Sstevel@tonic-gate 		 * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_
143*0Sstevel@tonic-gate 		 * fill up or pre-allocate an additional 4GB on both sides
144*0Sstevel@tonic-gate 		 * of the hole.
145*0Sstevel@tonic-gate 		 *
146*0Sstevel@tonic-gate 		 * (5) kernel virtual range [spec_hole_start, spec_hole_end)
147*0Sstevel@tonic-gate 		 * is _not_ used on any platform including those with
148*0Sstevel@tonic-gate 		 * UltraSPARC III where there is no hole.
149*0Sstevel@tonic-gate 		 *
150*0Sstevel@tonic-gate 		 * Algorithm:
151*0Sstevel@tonic-gate 		 *
152*0Sstevel@tonic-gate 		 * Check if range [spec_hole_start, spec_hole_end) is
153*0Sstevel@tonic-gate 		 * pre-allocated by OBP; if so, subtract that range from
154*0Sstevel@tonic-gate 		 * allocpages.
155*0Sstevel@tonic-gate 		 */
156*0Sstevel@tonic-gate 		if (end >= spec_hole_end && start <= spec_hole_start)
157*0Sstevel@tonic-gate 			hole_allocated = 1;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 		allocpages += btopr(end - start);
160*0Sstevel@tonic-gate 	}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	if (hole_allocated)
163*0Sstevel@tonic-gate 		allocpages -= btop(spec_hole_end - spec_hole_start);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	return (allocpages);
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /*
169*0Sstevel@tonic-gate  * Returns the max contiguous physical memory present in the
170*0Sstevel@tonic-gate  * memlist "physavail".
171*0Sstevel@tonic-gate  */
172*0Sstevel@tonic-gate uint64_t
173*0Sstevel@tonic-gate get_max_phys_size(
174*0Sstevel@tonic-gate 	struct memlist	*physavail)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate 	uint64_t	max_size = 0;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	for (; physavail; physavail = physavail->next) {
179*0Sstevel@tonic-gate 		if (physavail->size > max_size)
180*0Sstevel@tonic-gate 			max_size = physavail->size;
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	return (max_size);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate /*
188*0Sstevel@tonic-gate  * Copy boot's physavail list deducting memory at "start"
189*0Sstevel@tonic-gate  * for "size" bytes.
190*0Sstevel@tonic-gate  */
191*0Sstevel@tonic-gate int
192*0Sstevel@tonic-gate copy_physavail(
193*0Sstevel@tonic-gate 	u_longlong_t	*src,
194*0Sstevel@tonic-gate 	size_t		nelems,
195*0Sstevel@tonic-gate 	struct memlist	**dstp,
196*0Sstevel@tonic-gate 	uint_t		start,
197*0Sstevel@tonic-gate 	uint_t		size)
198*0Sstevel@tonic-gate {
199*0Sstevel@tonic-gate 	struct memlist *dst, *prev;
200*0Sstevel@tonic-gate 	uint_t end1;
201*0Sstevel@tonic-gate 	int deducted = 0;
202*0Sstevel@tonic-gate 	size_t	i;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	dst = *dstp;
205*0Sstevel@tonic-gate 	prev = dst;
206*0Sstevel@tonic-gate 	end1 = start + size;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
209*0Sstevel@tonic-gate 		uint64_t addr, lsize, end2;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 		addr = src[i];
212*0Sstevel@tonic-gate 		lsize = src[i+1];
213*0Sstevel@tonic-gate 		end2 = addr + lsize;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 		if ((size != 0) && start >= addr && end1 <= end2) {
216*0Sstevel@tonic-gate 			/* deducted range in this chunk */
217*0Sstevel@tonic-gate 			deducted = 1;
218*0Sstevel@tonic-gate 			if (start == addr) {
219*0Sstevel@tonic-gate 				/* abuts start of chunk */
220*0Sstevel@tonic-gate 				if (end1 == end2)
221*0Sstevel@tonic-gate 					/* is equal to the chunk */
222*0Sstevel@tonic-gate 					continue;
223*0Sstevel@tonic-gate 				dst->address = end1;
224*0Sstevel@tonic-gate 				dst->size = lsize - size;
225*0Sstevel@tonic-gate 			} else if (end1 == end2) {
226*0Sstevel@tonic-gate 				/* abuts end of chunk */
227*0Sstevel@tonic-gate 				dst->address = addr;
228*0Sstevel@tonic-gate 				dst->size = lsize - size;
229*0Sstevel@tonic-gate 			} else {
230*0Sstevel@tonic-gate 				/* in the middle of the chunk */
231*0Sstevel@tonic-gate 				dst->address = addr;
232*0Sstevel@tonic-gate 				dst->size = start - addr;
233*0Sstevel@tonic-gate 				dst->next = 0;
234*0Sstevel@tonic-gate 				if (prev == dst) {
235*0Sstevel@tonic-gate 					dst->prev = 0;
236*0Sstevel@tonic-gate 					dst++;
237*0Sstevel@tonic-gate 				} else {
238*0Sstevel@tonic-gate 					dst->prev = prev;
239*0Sstevel@tonic-gate 					prev->next = dst;
240*0Sstevel@tonic-gate 					dst++;
241*0Sstevel@tonic-gate 					prev++;
242*0Sstevel@tonic-gate 				}
243*0Sstevel@tonic-gate 				dst->address = end1;
244*0Sstevel@tonic-gate 				dst->size = end2 - end1;
245*0Sstevel@tonic-gate 			}
246*0Sstevel@tonic-gate 			dst->next = 0;
247*0Sstevel@tonic-gate 			if (prev == dst) {
248*0Sstevel@tonic-gate 				dst->prev = 0;
249*0Sstevel@tonic-gate 				dst++;
250*0Sstevel@tonic-gate 			} else {
251*0Sstevel@tonic-gate 				dst->prev = prev;
252*0Sstevel@tonic-gate 				prev->next = dst;
253*0Sstevel@tonic-gate 				dst++;
254*0Sstevel@tonic-gate 				prev++;
255*0Sstevel@tonic-gate 			}
256*0Sstevel@tonic-gate 		} else {
257*0Sstevel@tonic-gate 			dst->address = src[i];
258*0Sstevel@tonic-gate 			dst->size = src[i+1];
259*0Sstevel@tonic-gate 			dst->next = 0;
260*0Sstevel@tonic-gate 			if (prev == dst) {
261*0Sstevel@tonic-gate 				dst->prev = 0;
262*0Sstevel@tonic-gate 				dst++;
263*0Sstevel@tonic-gate 			} else {
264*0Sstevel@tonic-gate 				dst->prev = prev;
265*0Sstevel@tonic-gate 				prev->next = dst;
266*0Sstevel@tonic-gate 				dst++;
267*0Sstevel@tonic-gate 				prev++;
268*0Sstevel@tonic-gate 			}
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	*dstp = dst;
273*0Sstevel@tonic-gate 	return (deducted);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate struct vnode prom_ppages;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate /*
279*0Sstevel@tonic-gate  * Find the pages allocated by the prom by diffing the original
280*0Sstevel@tonic-gate  * phys_avail list and the current list.  In the difference, the
281*0Sstevel@tonic-gate  * pages not locked belong to the PROM.  (The kernel has already locked
282*0Sstevel@tonic-gate  * and removed all the pages it has allocated from the freelist, this
283*0Sstevel@tonic-gate  * routine removes the remaining "free" pages that really belong to the
284*0Sstevel@tonic-gate  * PROM and hashs them in on the 'prom_pages' vnode.)
285*0Sstevel@tonic-gate  */
286*0Sstevel@tonic-gate void
287*0Sstevel@tonic-gate fix_prom_pages(struct memlist *orig, struct memlist *new)
288*0Sstevel@tonic-gate {
289*0Sstevel@tonic-gate 	struct memlist *list, *nlist;
290*0Sstevel@tonic-gate 	extern int kcage_on;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	nlist = new;
293*0Sstevel@tonic-gate 	for (list = orig; list; list = list->next) {
294*0Sstevel@tonic-gate 		uint64_t pa, end;
295*0Sstevel@tonic-gate 		pfn_t pfnum;
296*0Sstevel@tonic-gate 		page_t *pp;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 		if (list->address == nlist->address &&
299*0Sstevel@tonic-gate 		    list->size == nlist->size) {
300*0Sstevel@tonic-gate 			nlist = nlist->next ? nlist->next : nlist;
301*0Sstevel@tonic-gate 			continue;
302*0Sstevel@tonic-gate 		}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 		/*
305*0Sstevel@tonic-gate 		 * Loop through the old list looking to
306*0Sstevel@tonic-gate 		 * see if each page is still in the new one.
307*0Sstevel@tonic-gate 		 * If a page is not in the new list then we
308*0Sstevel@tonic-gate 		 * check to see if it locked permanently.
309*0Sstevel@tonic-gate 		 * If so, the kernel allocated and owns it.
310*0Sstevel@tonic-gate 		 * If not, then the prom must own it. We
311*0Sstevel@tonic-gate 		 * remove any pages found to owned by the prom
312*0Sstevel@tonic-gate 		 * from the freelist.
313*0Sstevel@tonic-gate 		 */
314*0Sstevel@tonic-gate 		end = list->address + list->size;
315*0Sstevel@tonic-gate 		for (pa = list->address; pa < end; pa += PAGESIZE) {
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 			if (address_in_memlist(new, pa, PAGESIZE))
318*0Sstevel@tonic-gate 				continue;
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 			pfnum = (pfn_t)(pa >> PAGESHIFT);
321*0Sstevel@tonic-gate 			if ((pp = page_numtopp_nolock(pfnum)) == NULL)
322*0Sstevel@tonic-gate 				cmn_err(CE_PANIC, "missing pfnum %lx", pfnum);
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 			/*
325*0Sstevel@tonic-gate 			 * must break up any large pages that may have
326*0Sstevel@tonic-gate 			 * constituent pages being utilized for
327*0Sstevel@tonic-gate 			 * BOP_ALLOC()'s. page_reclaim() can't handle
328*0Sstevel@tonic-gate 			 * large pages.
329*0Sstevel@tonic-gate 			 */
330*0Sstevel@tonic-gate 			if (pp->p_szc != 0)
331*0Sstevel@tonic-gate 				page_boot_demote(pp);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 			if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) {
334*0Sstevel@tonic-gate 				/*
335*0Sstevel@tonic-gate 				 * Ahhh yes, a prom page,
336*0Sstevel@tonic-gate 				 * suck it off the freelist,
337*0Sstevel@tonic-gate 				 * lock it, and hashin on prom_pages vp.
338*0Sstevel@tonic-gate 				 */
339*0Sstevel@tonic-gate 				if (page_trylock(pp, SE_EXCL) == 0)
340*0Sstevel@tonic-gate 					cmn_err(CE_PANIC, "prom page locked");
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 				(void) page_reclaim(pp, NULL);
343*0Sstevel@tonic-gate 				/*
344*0Sstevel@tonic-gate 				 * XXX	vnode offsets on the prom_ppages vnode
345*0Sstevel@tonic-gate 				 *	are page numbers (gack) for >32 bit
346*0Sstevel@tonic-gate 				 *	physical memory machines.
347*0Sstevel@tonic-gate 				 */
348*0Sstevel@tonic-gate 				(void) page_hashin(pp, &prom_ppages,
349*0Sstevel@tonic-gate 					(offset_t)pfnum, NULL);
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 				if (kcage_on) {
352*0Sstevel@tonic-gate 					ASSERT(pp->p_szc == 0);
353*0Sstevel@tonic-gate 					PP_SETNORELOC(pp);
354*0Sstevel@tonic-gate 				}
355*0Sstevel@tonic-gate 				(void) page_pp_lock(pp, 0, 1);
356*0Sstevel@tonic-gate 				page_downgrade(pp);
357*0Sstevel@tonic-gate 			}
358*0Sstevel@tonic-gate 		}
359*0Sstevel@tonic-gate 		nlist = nlist->next ? nlist->next : nlist;
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate }
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate /*
364*0Sstevel@tonic-gate  * Find the page number of the highest installed physical
365*0Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
366*0Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
367*0Sstevel@tonic-gate  * contiguous).
368*0Sstevel@tonic-gate  */
369*0Sstevel@tonic-gate void
370*0Sstevel@tonic-gate installed_top_size_memlist_array(
371*0Sstevel@tonic-gate 	u_longlong_t *list,	/* base of array */
372*0Sstevel@tonic-gate 	size_t	nelems,		/* number of elements */
373*0Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
374*0Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
375*0Sstevel@tonic-gate {
376*0Sstevel@tonic-gate 	pfn_t top = 0;
377*0Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
378*0Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
379*0Sstevel@tonic-gate 	size_t i;
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
382*0Sstevel@tonic-gate 		highp = (list[i] + list[i+1] - 1) >> PAGESHIFT;
383*0Sstevel@tonic-gate 		if (top < highp)
384*0Sstevel@tonic-gate 			top = highp;
385*0Sstevel@tonic-gate 		sumpages += (list[i+1] >> PAGESHIFT);
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	*topp = top;
389*0Sstevel@tonic-gate 	*sumpagesp = sumpages;
390*0Sstevel@tonic-gate }
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate /*
393*0Sstevel@tonic-gate  * Copy a memory list.  Used in startup() to copy boot's
394*0Sstevel@tonic-gate  * memory lists to the kernel.
395*0Sstevel@tonic-gate  */
396*0Sstevel@tonic-gate void
397*0Sstevel@tonic-gate copy_memlist(
398*0Sstevel@tonic-gate 	u_longlong_t	*src,
399*0Sstevel@tonic-gate 	size_t		nelems,
400*0Sstevel@tonic-gate 	struct memlist	**dstp)
401*0Sstevel@tonic-gate {
402*0Sstevel@tonic-gate 	struct memlist *dst, *prev;
403*0Sstevel@tonic-gate 	size_t	i;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	dst = *dstp;
406*0Sstevel@tonic-gate 	prev = dst;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	for (i = 0; i < nelems; i += 2) {
409*0Sstevel@tonic-gate 		dst->address = src[i];
410*0Sstevel@tonic-gate 		dst->size = src[i+1];
411*0Sstevel@tonic-gate 		dst->next = 0;
412*0Sstevel@tonic-gate 		if (prev == dst) {
413*0Sstevel@tonic-gate 			dst->prev = 0;
414*0Sstevel@tonic-gate 			dst++;
415*0Sstevel@tonic-gate 		} else {
416*0Sstevel@tonic-gate 			dst->prev = prev;
417*0Sstevel@tonic-gate 			prev->next = dst;
418*0Sstevel@tonic-gate 			dst++;
419*0Sstevel@tonic-gate 			prev++;
420*0Sstevel@tonic-gate 		}
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	*dstp = dst;
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate static struct bootmem_props {
427*0Sstevel@tonic-gate 	char		*name;
428*0Sstevel@tonic-gate 	u_longlong_t	*ptr;
429*0Sstevel@tonic-gate 	size_t		nelems;		/* actual number of elements */
430*0Sstevel@tonic-gate 	size_t		bufsize;	/* length of allocated buffer */
431*0Sstevel@tonic-gate } bootmem_props[] = {
432*0Sstevel@tonic-gate 	{ "phys-installed", NULL, 0, 0 },
433*0Sstevel@tonic-gate 	{ "phys-avail", NULL, 0, 0 },
434*0Sstevel@tonic-gate 	{ "virt-avail", NULL, 0, 0 },
435*0Sstevel@tonic-gate 	{ NULL, NULL, 0, 0 }
436*0Sstevel@tonic-gate };
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate #define	PHYSINSTALLED	0
439*0Sstevel@tonic-gate #define	PHYSAVAIL	1
440*0Sstevel@tonic-gate #define	VIRTAVAIL	2
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate void
443*0Sstevel@tonic-gate copy_boot_memlists(u_longlong_t **physinstalled, size_t *physinstalled_len,
444*0Sstevel@tonic-gate     u_longlong_t **physavail, size_t *physavail_len,
445*0Sstevel@tonic-gate     u_longlong_t **virtavail, size_t *virtavail_len)
446*0Sstevel@tonic-gate {
447*0Sstevel@tonic-gate 	int	align = BO_ALIGN_L3;
448*0Sstevel@tonic-gate 	size_t	len;
449*0Sstevel@tonic-gate 	struct bootmem_props *tmp = bootmem_props;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate tryagain:
452*0Sstevel@tonic-gate 	for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
453*0Sstevel@tonic-gate 		len = BOP_GETPROPLEN(bootops, tmp->name);
454*0Sstevel@tonic-gate 		if (len == 0) {
455*0Sstevel@tonic-gate 			panic("cannot get length of \"%s\" property",
456*0Sstevel@tonic-gate 			    tmp->name);
457*0Sstevel@tonic-gate 		}
458*0Sstevel@tonic-gate 		tmp->nelems = len / sizeof (u_longlong_t);
459*0Sstevel@tonic-gate 		len = roundup(len, PAGESIZE);
460*0Sstevel@tonic-gate 		if (len <= tmp->bufsize)
461*0Sstevel@tonic-gate 			continue;
462*0Sstevel@tonic-gate 		/* need to allocate more */
463*0Sstevel@tonic-gate 		if (tmp->ptr) {
464*0Sstevel@tonic-gate 			BOP_FREE(bootops, (caddr_t)tmp->ptr, tmp->bufsize);
465*0Sstevel@tonic-gate 			tmp->ptr = NULL;
466*0Sstevel@tonic-gate 			tmp->bufsize = 0;
467*0Sstevel@tonic-gate 		}
468*0Sstevel@tonic-gate 		tmp->bufsize = len;
469*0Sstevel@tonic-gate 		tmp->ptr = (void *)BOP_ALLOC(bootops, 0, tmp->bufsize, align);
470*0Sstevel@tonic-gate 		if (tmp->ptr == NULL)
471*0Sstevel@tonic-gate 			panic("cannot allocate %d bytes for \"%s\" property",
472*0Sstevel@tonic-gate 			    tmp->bufsize, tmp->name);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 	/*
476*0Sstevel@tonic-gate 	 * take the most current snapshot we can by calling mem-update
477*0Sstevel@tonic-gate 	 */
478*0Sstevel@tonic-gate 	if (BOP_GETPROPLEN(bootops, "memory-update") == 0)
479*0Sstevel@tonic-gate 		(void) BOP_GETPROP(bootops, "memory-update", NULL);
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	/* did the sizes change? */
482*0Sstevel@tonic-gate 	for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
483*0Sstevel@tonic-gate 		len = BOP_GETPROPLEN(bootops, tmp->name);
484*0Sstevel@tonic-gate 		tmp->nelems = len / sizeof (u_longlong_t);
485*0Sstevel@tonic-gate 		len = roundup(len, PAGESIZE);
486*0Sstevel@tonic-gate 		if (len > tmp->bufsize) {
487*0Sstevel@tonic-gate 			/* ick. Free them all and try again */
488*0Sstevel@tonic-gate 			for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
489*0Sstevel@tonic-gate 				BOP_FREE(bootops, (caddr_t)tmp->ptr,
490*0Sstevel@tonic-gate 				    tmp->bufsize);
491*0Sstevel@tonic-gate 				tmp->ptr = NULL;
492*0Sstevel@tonic-gate 				tmp->bufsize = 0;
493*0Sstevel@tonic-gate 			}
494*0Sstevel@tonic-gate 			goto tryagain;
495*0Sstevel@tonic-gate 		}
496*0Sstevel@tonic-gate 	}
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	/* now we can retrieve the properties */
499*0Sstevel@tonic-gate 	for (tmp = bootmem_props; tmp->name != NULL; tmp++) {
500*0Sstevel@tonic-gate 		if (BOP_GETPROP(bootops, tmp->name, tmp->ptr) == -1) {
501*0Sstevel@tonic-gate 			panic("cannot retrieve \"%s\" property",
502*0Sstevel@tonic-gate 			    tmp->name);
503*0Sstevel@tonic-gate 		}
504*0Sstevel@tonic-gate 	}
505*0Sstevel@tonic-gate 	*physinstalled = bootmem_props[PHYSINSTALLED].ptr;
506*0Sstevel@tonic-gate 	*physinstalled_len = bootmem_props[PHYSINSTALLED].nelems;
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	*physavail = bootmem_props[PHYSAVAIL].ptr;
509*0Sstevel@tonic-gate 	*physavail_len = bootmem_props[PHYSAVAIL].nelems;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	*virtavail = bootmem_props[VIRTAVAIL].ptr;
512*0Sstevel@tonic-gate 	*virtavail_len = bootmem_props[VIRTAVAIL].nelems;
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate /*
517*0Sstevel@tonic-gate  * Find the page number of the highest installed physical
518*0Sstevel@tonic-gate  * page and the number of pages installed (one cannot be
519*0Sstevel@tonic-gate  * calculated from the other because memory isn't necessarily
520*0Sstevel@tonic-gate  * contiguous).
521*0Sstevel@tonic-gate  */
522*0Sstevel@tonic-gate void
523*0Sstevel@tonic-gate installed_top_size(
524*0Sstevel@tonic-gate 	struct memlist *list,	/* pointer to start of installed list */
525*0Sstevel@tonic-gate 	pfn_t *topp,		/* return ptr for top value */
526*0Sstevel@tonic-gate 	pgcnt_t *sumpagesp)	/* return prt for sum of installed pages */
527*0Sstevel@tonic-gate {
528*0Sstevel@tonic-gate 	pfn_t top = 0;
529*0Sstevel@tonic-gate 	pfn_t highp;		/* high page in a chunk */
530*0Sstevel@tonic-gate 	pgcnt_t sumpages = 0;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	for (; list; list = list->next) {
533*0Sstevel@tonic-gate 		highp = (list->address + list->size - 1) >> PAGESHIFT;
534*0Sstevel@tonic-gate 		if (top < highp)
535*0Sstevel@tonic-gate 			top = highp;
536*0Sstevel@tonic-gate 		sumpages += (uint_t)(list->size >> PAGESHIFT);
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	*topp = top;
540*0Sstevel@tonic-gate 	*sumpagesp = sumpages;
541*0Sstevel@tonic-gate }
542