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*11185SSean.McEnroe@Sun.COM * Copyright 2009 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 945084Sjohnlev num_phys_pages() 955084Sjohnlev { 965084Sjohnlev pgcnt_t npages = 0; 975084Sjohnlev struct memlist *mp; 985084Sjohnlev 995084Sjohnlev for (mp = phys_install; mp != NULL; mp = mp->next) 1005084Sjohnlev npages += mp->size >> PAGESHIFT; 1015084Sjohnlev 1025084Sjohnlev return (npages); 1035084Sjohnlev } 1045084Sjohnlev 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate pgcnt_t 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 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 1690Sstevel@tonic-gate for (; physavail; physavail = physavail->next) { 1700Sstevel@tonic-gate if (physavail->size > max_size) 1710Sstevel@tonic-gate max_size = physavail->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 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 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 */ 224*11185SSean.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 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 && 2505648Ssetje proto->address >= diff->address + diff->size) 2515648Ssetje diff = diff->next; 2525648Ssetje if (diff == NULL) { 2535648Ssetje (*func)(proto->address, proto->size); 2545648Ssetje proto = proto->next; 2555648Ssetje continue; 2565648Ssetje } 2575648Ssetje if (proto->address == diff->address && 2585648Ssetje proto->size == diff->size) { 2595648Ssetje proto = proto->next; 2605648Ssetje diff = diff->next; 2615648Ssetje continue; 2625648Ssetje } 2635648Ssetje 2645648Ssetje p_base = proto->address; 2655648Ssetje p_end = p_base + proto->size; 2665648Ssetje d_base = diff->address; 2675648Ssetje d_end = d_base + diff->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) { 2825648Ssetje (*func)(p_base, proto->size); 2835648Ssetje proto = proto->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 */ 3145648Ssetje proto = proto->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 */ 3355648Ssetje for (p_base = d_end, diff = diff->next; diff != NULL; 3365648Ssetje p_base = d_end, diff = diff->next) { 3375648Ssetje d_base = diff->address; 3385648Ssetje d_end = d_base + diff->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); 3475648Ssetje proto = proto->next; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3515648Ssetje void 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 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 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++) { 4155648Ssetje dst->address = src->addr; 4165648Ssetje dst->size = src->size; 4170Sstevel@tonic-gate dst->next = 0; 4180Sstevel@tonic-gate if (prev == dst) { 4190Sstevel@tonic-gate dst->prev = 0; 4200Sstevel@tonic-gate dst++; 4210Sstevel@tonic-gate } else { 4220Sstevel@tonic-gate dst->prev = prev; 4230Sstevel@tonic-gate prev->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 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 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 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 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 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 6210Sstevel@tonic-gate for (; list; list = list->next) { 6220Sstevel@tonic-gate highp = (list->address + list->size - 1) >> PAGESHIFT; 6230Sstevel@tonic-gate if (top < highp) 6240Sstevel@tonic-gate top = highp; 6250Sstevel@tonic-gate sumpages += (uint_t)(list->size >> PAGESHIFT); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate *topp = top; 6290Sstevel@tonic-gate *sumpagesp = sumpages; 6300Sstevel@tonic-gate } 631