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