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*7142Skchow * Copyright 2008 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> 74*7142Skchow #include <vm/vm_dep.h> 750Sstevel@tonic-gate 760Sstevel@tonic-gate #include <sys/exec.h> 770Sstevel@tonic-gate #include <sys/acct.h> 780Sstevel@tonic-gate #include <sys/modctl.h> 790Sstevel@tonic-gate #include <sys/tuneable.h> 800Sstevel@tonic-gate 810Sstevel@tonic-gate #include <c2/audit.h> 820Sstevel@tonic-gate 830Sstevel@tonic-gate #include <sys/trap.h> 840Sstevel@tonic-gate #include <sys/sunddi.h> 850Sstevel@tonic-gate #include <sys/bootconf.h> 860Sstevel@tonic-gate #include <sys/memlist.h> 870Sstevel@tonic-gate #include <sys/memlist_plat.h> 880Sstevel@tonic-gate #include <sys/systeminfo.h> 890Sstevel@tonic-gate #include <sys/promif.h> 905648Ssetje #include <sys/prom_plat.h> 910Sstevel@tonic-gate 920Sstevel@tonic-gate u_longlong_t spec_hole_start = 0x80000000000ull; 930Sstevel@tonic-gate u_longlong_t spec_hole_end = 0xfffff80000000000ull; 940Sstevel@tonic-gate 955084Sjohnlev pgcnt_t 965084Sjohnlev num_phys_pages() 975084Sjohnlev { 985084Sjohnlev pgcnt_t npages = 0; 995084Sjohnlev struct memlist *mp; 1005084Sjohnlev 1015084Sjohnlev for (mp = phys_install; mp != NULL; mp = mp->next) 1025084Sjohnlev npages += mp->size >> PAGESHIFT; 1035084Sjohnlev 1045084Sjohnlev return (npages); 1055084Sjohnlev } 1065084Sjohnlev 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate pgcnt_t 1095648Ssetje size_virtalloc(prom_memlist_t *avail, size_t nelems) 1100Sstevel@tonic-gate { 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate u_longlong_t start, end; 1130Sstevel@tonic-gate pgcnt_t allocpages = 0; 1140Sstevel@tonic-gate uint_t hole_allocated = 0; 1150Sstevel@tonic-gate uint_t i; 1160Sstevel@tonic-gate 1175648Ssetje for (i = 0; i < nelems - 1; i++) { 1180Sstevel@tonic-gate 1195648Ssetje start = avail[i].addr + avail[i].size; 1205648Ssetje end = avail[i + 1].addr; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate /* 1230Sstevel@tonic-gate * Notes: 1240Sstevel@tonic-gate * 1250Sstevel@tonic-gate * (1) OBP on platforms with US I/II pre-allocates the hole 1260Sstevel@tonic-gate * represented by [spec_hole_start, spec_hole_end); 1270Sstevel@tonic-gate * pre-allocation is done to make this range unavailable 1280Sstevel@tonic-gate * for any allocation. 1290Sstevel@tonic-gate * 1300Sstevel@tonic-gate * (2) OBP on starcat always pre-allocates the hole similar to 1310Sstevel@tonic-gate * platforms with US I/II. 1320Sstevel@tonic-gate * 1330Sstevel@tonic-gate * (3) OBP on serengeti does _not_ pre-allocate the hole. 1340Sstevel@tonic-gate * 1350Sstevel@tonic-gate * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_ 1360Sstevel@tonic-gate * fill up or pre-allocate an additional 4GB on both sides 1370Sstevel@tonic-gate * of the hole. 1380Sstevel@tonic-gate * 1390Sstevel@tonic-gate * (5) kernel virtual range [spec_hole_start, spec_hole_end) 1400Sstevel@tonic-gate * is _not_ used on any platform including those with 1410Sstevel@tonic-gate * UltraSPARC III where there is no hole. 1420Sstevel@tonic-gate * 1430Sstevel@tonic-gate * Algorithm: 1440Sstevel@tonic-gate * 1450Sstevel@tonic-gate * Check if range [spec_hole_start, spec_hole_end) is 1460Sstevel@tonic-gate * pre-allocated by OBP; if so, subtract that range from 1470Sstevel@tonic-gate * allocpages. 1480Sstevel@tonic-gate */ 1490Sstevel@tonic-gate if (end >= spec_hole_end && start <= spec_hole_start) 1500Sstevel@tonic-gate hole_allocated = 1; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate allocpages += btopr(end - start); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate if (hole_allocated) 1560Sstevel@tonic-gate allocpages -= btop(spec_hole_end - spec_hole_start); 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate return (allocpages); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Returns the max contiguous physical memory present in the 1630Sstevel@tonic-gate * memlist "physavail". 1640Sstevel@tonic-gate */ 1650Sstevel@tonic-gate uint64_t 1660Sstevel@tonic-gate get_max_phys_size( 1670Sstevel@tonic-gate struct memlist *physavail) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate uint64_t max_size = 0; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate for (; physavail; physavail = physavail->next) { 1720Sstevel@tonic-gate if (physavail->size > max_size) 1730Sstevel@tonic-gate max_size = physavail->size; 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate return (max_size); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate struct vnode prom_ppages; 1820Sstevel@tonic-gate 1835648Ssetje static void 1845648Ssetje more_pages(uint64_t base, uint64_t len) 1850Sstevel@tonic-gate { 1865648Ssetje void kphysm_add(); 1875648Ssetje 1885648Ssetje kphysm_add(base, len, 1); 1895648Ssetje } 1905648Ssetje 1915648Ssetje static void 1925648Ssetje less_pages(uint64_t base, uint64_t len) 1935648Ssetje { 1945648Ssetje uint64_t pa, end = base + len; 1950Sstevel@tonic-gate extern int kcage_on; 1960Sstevel@tonic-gate 1975648Ssetje for (pa = base; pa < end; pa += PAGESIZE) { 1980Sstevel@tonic-gate pfn_t pfnum; 1990Sstevel@tonic-gate page_t *pp; 2000Sstevel@tonic-gate 2015648Ssetje pfnum = (pfn_t)(pa >> PAGESHIFT); 2025648Ssetje if ((pp = page_numtopp_nolock(pfnum)) == NULL) 2035648Ssetje cmn_err(CE_PANIC, "missing pfnum %lx", pfnum); 2045648Ssetje 2055648Ssetje /* 2065648Ssetje * must break up any large pages that may have 2075648Ssetje * constituent pages being utilized for 2085648Ssetje * prom_alloc()'s. page_reclaim() can't handle 2095648Ssetje * large pages. 2105648Ssetje */ 2115648Ssetje if (pp->p_szc != 0) 2125648Ssetje page_boot_demote(pp); 2135648Ssetje 2145648Ssetje if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) { 2155648Ssetje /* 2165648Ssetje * Ahhh yes, a prom page, 2175648Ssetje * suck it off the freelist, 2185648Ssetje * lock it, and hashin on prom_pages vp. 2195648Ssetje */ 2205648Ssetje if (page_trylock(pp, SE_EXCL) == 0) 2215648Ssetje cmn_err(CE_PANIC, "prom page locked"); 2225648Ssetje 2235648Ssetje (void) page_reclaim(pp, NULL); 2245648Ssetje /* 2255648Ssetje * vnode offsets on the prom_ppages vnode 2265648Ssetje * are page numbers (gack) for >32 bit 2275648Ssetje * physical memory machines. 2285648Ssetje */ 2295648Ssetje (void) page_hashin(pp, &prom_ppages, 2305648Ssetje (offset_t)pfnum, NULL); 2315648Ssetje 2325648Ssetje if (kcage_on) { 2335648Ssetje ASSERT(pp->p_szc == 0); 234*7142Skchow if (PP_ISNORELOC(pp) == 0) { 235*7142Skchow PP_SETNORELOC(pp); 236*7142Skchow PLCNT_XFER_NORELOC(pp); 237*7142Skchow } 2385648Ssetje } 2395648Ssetje (void) page_pp_lock(pp, 0, 1); 2405648Ssetje } 2415648Ssetje } 2425648Ssetje } 2435648Ssetje 2445648Ssetje void 2455648Ssetje diff_memlists(struct memlist *proto, struct memlist *diff, void (*func)()) 2465648Ssetje { 2475648Ssetje uint64_t p_base, p_end, d_base, d_end; 2485648Ssetje 2495648Ssetje while (proto != NULL) { 2505648Ssetje /* 2515648Ssetje * find diff item which may overlap with proto item 2525648Ssetje * if none, apply func to all of proto item 2535648Ssetje */ 2545648Ssetje while (diff != NULL && 2555648Ssetje proto->address >= diff->address + diff->size) 2565648Ssetje diff = diff->next; 2575648Ssetje if (diff == NULL) { 2585648Ssetje (*func)(proto->address, proto->size); 2595648Ssetje proto = proto->next; 2605648Ssetje continue; 2615648Ssetje } 2625648Ssetje if (proto->address == diff->address && 2635648Ssetje proto->size == diff->size) { 2645648Ssetje proto = proto->next; 2655648Ssetje diff = diff->next; 2665648Ssetje continue; 2675648Ssetje } 2685648Ssetje 2695648Ssetje p_base = proto->address; 2705648Ssetje p_end = p_base + proto->size; 2715648Ssetje d_base = diff->address; 2725648Ssetje d_end = d_base + diff->size; 2735648Ssetje /* 2745648Ssetje * here p_base < d_end 2755648Ssetje * there are 5 cases 2765648Ssetje */ 2775648Ssetje 2785648Ssetje /* 2795648Ssetje * d_end 2805648Ssetje * d_base 2815648Ssetje * p_end 2825648Ssetje * p_base 2835648Ssetje * 2845648Ssetje * apply func to all of proto item 2855648Ssetje */ 2865648Ssetje if (p_end <= d_base) { 2875648Ssetje (*func)(p_base, proto->size); 2885648Ssetje proto = proto->next; 2890Sstevel@tonic-gate continue; 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate /* 2935648Ssetje * ... 2945648Ssetje * d_base 2955648Ssetje * p_base 2965648Ssetje * 2975648Ssetje * normalize by applying func from p_base to d_base 2980Sstevel@tonic-gate */ 2995648Ssetje if (p_base < d_base) 3005648Ssetje (*func)(p_base, d_base - p_base); 3010Sstevel@tonic-gate 3025648Ssetje if (p_end <= d_end) { 3030Sstevel@tonic-gate /* 3045648Ssetje * d_end 3055648Ssetje * p_end 3065648Ssetje * d_base 3075648Ssetje * p_base 3085648Ssetje * 3095648Ssetje * -or- 3105648Ssetje * 3115648Ssetje * d_end 3125648Ssetje * p_end 3135648Ssetje * p_base 3145648Ssetje * d_base 3155648Ssetje * 3165648Ssetje * any non-overlapping ranges applied above, 3175648Ssetje * so just continue 3180Sstevel@tonic-gate */ 3195648Ssetje proto = proto->next; 3205648Ssetje continue; 3215648Ssetje } 3220Sstevel@tonic-gate 3235648Ssetje /* 3245648Ssetje * p_end 3255648Ssetje * d_end 3265648Ssetje * d_base 3275648Ssetje * p_base 3285648Ssetje * 3295648Ssetje * -or- 3305648Ssetje * 3315648Ssetje * p_end 3325648Ssetje * d_end 3335648Ssetje * p_base 3345648Ssetje * d_base 3355648Ssetje * 3365648Ssetje * Find overlapping d_base..d_end ranges, and apply func 3375648Ssetje * where no overlap occurs. Stop when d_base is above 3385648Ssetje * p_end 3395648Ssetje */ 3405648Ssetje for (p_base = d_end, diff = diff->next; diff != NULL; 3415648Ssetje p_base = d_end, diff = diff->next) { 3425648Ssetje d_base = diff->address; 3435648Ssetje d_end = d_base + diff->size; 3445648Ssetje if (p_end <= d_base) { 3455648Ssetje (*func)(p_base, p_end - p_base); 3465648Ssetje break; 3475648Ssetje } else 3485648Ssetje (*func)(p_base, d_base - p_base); 3490Sstevel@tonic-gate } 3505648Ssetje if (diff == NULL) 3515648Ssetje (*func)(p_base, p_end - p_base); 3525648Ssetje proto = proto->next; 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate 3565648Ssetje void 3575648Ssetje sync_memlists(struct memlist *orig, struct memlist *new) 3585648Ssetje { 3595648Ssetje 3605648Ssetje /* 3615648Ssetje * Find pages allocated via prom by looking for 3625648Ssetje * pages on orig, but no on new. 3635648Ssetje */ 3645648Ssetje diff_memlists(orig, new, less_pages); 3655648Ssetje 3665648Ssetje /* 3675648Ssetje * Find pages free'd via prom by looking for 3685648Ssetje * pages on new, but not on orig. 3695648Ssetje */ 3705648Ssetje diff_memlists(new, orig, more_pages); 3715648Ssetje } 3725648Ssetje 3735648Ssetje 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( 3825648Ssetje prom_memlist_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 3925648Ssetje for (i = 0; i < nelems; list++, i++) { 3935648Ssetje highp = (list->addr + list->size - 1) >> PAGESHIFT; 3940Sstevel@tonic-gate if (top < highp) 3950Sstevel@tonic-gate top = highp; 3965648Ssetje sumpages += (list->size >> 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( 4095648Ssetje prom_memlist_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 4195648Ssetje for (i = 0; i < nelems; src++, i++) { 4205648Ssetje dst->address = src->addr; 4215648Ssetje dst->size = src->size; 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 4375648Ssetje 4380Sstevel@tonic-gate static struct bootmem_props { 4395648Ssetje prom_memlist_t *ptr; 4400Sstevel@tonic-gate size_t nelems; /* actual number of elements */ 4415648Ssetje size_t maxsize; /* max buffer */ 4425648Ssetje } bootmem_props[3]; 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate #define PHYSINSTALLED 0 4450Sstevel@tonic-gate #define PHYSAVAIL 1 4460Sstevel@tonic-gate #define VIRTAVAIL 2 4470Sstevel@tonic-gate 4485648Ssetje /* 4495648Ssetje * Comapct contiguous memory list elements 4505648Ssetje */ 4515648Ssetje static void 4525648Ssetje compact_promlist(struct bootmem_props *bpp) 4530Sstevel@tonic-gate { 4545648Ssetje int i = 0, j; 4555648Ssetje struct prom_memlist *pmp = bpp->ptr; 4560Sstevel@tonic-gate 4575648Ssetje for (;;) { 4585648Ssetje if (pmp[i].addr + pmp[i].size == pmp[i+1].addr) { 4595648Ssetje pmp[i].size += pmp[i+1].size; 4605648Ssetje bpp->nelems--; 4615648Ssetje for (j = i + 1; j < bpp->nelems; j++) 4625648Ssetje pmp[j] = pmp[j+1]; 4635648Ssetje pmp[j].addr = 0; 4645648Ssetje } else 4655648Ssetje i++; 4665648Ssetje if (i == bpp->nelems) 4675648Ssetje break; 4685648Ssetje } 4695648Ssetje } 4705648Ssetje 4715648Ssetje /* 4725648Ssetje * Sort prom memory lists into ascending order 4735648Ssetje */ 4745648Ssetje static void 4755648Ssetje sort_promlist(struct bootmem_props *bpp) 4765648Ssetje { 4775648Ssetje int i, j, min; 4785648Ssetje struct prom_memlist *pmp = bpp->ptr; 4795648Ssetje struct prom_memlist temp; 4805648Ssetje 4815648Ssetje for (i = 0; i < bpp->nelems; i++) { 4825648Ssetje min = i; 4835648Ssetje 4845648Ssetje for (j = i+1; j < bpp->nelems; j++) { 4855648Ssetje if (pmp[j].addr < pmp[min].addr) 4865648Ssetje min = j; 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4895648Ssetje if (i != min) { 4905648Ssetje /* Swap pmp[i] and pmp[min] */ 4915648Ssetje temp = pmp[min]; 4925648Ssetje pmp[min] = pmp[i]; 4935648Ssetje pmp[i] = temp; 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate } 4965648Ssetje } 4975648Ssetje 4985648Ssetje static int max_bootlist_sz; 4995648Ssetje 5005648Ssetje void 5015648Ssetje init_boot_memlists(void) 5025648Ssetje { 5035648Ssetje size_t size, len; 5045648Ssetje char *start; 5055648Ssetje struct bootmem_props *tmp; 5065648Ssetje 5075648Ssetje /* 5085648Ssetje * These lists can get fragmented as the prom allocates 5095648Ssetje * memory, so generously round up. 5105648Ssetje */ 5115648Ssetje size = prom_phys_installed_len() + prom_phys_avail_len() + 5125648Ssetje prom_virt_avail_len(); 5135648Ssetje size *= 4; 5145648Ssetje size = roundup(size, PAGESIZE); 5155648Ssetje start = prom_alloc(0, size, BO_NO_ALIGN); 5165648Ssetje 5175648Ssetje /* 5185648Ssetje * Get physinstalled 5195648Ssetje */ 5205648Ssetje tmp = &bootmem_props[PHYSINSTALLED]; 5215648Ssetje len = prom_phys_installed_len(); 5225648Ssetje if (len == 0) 5235648Ssetje panic("no \"reg\" in /memory"); 5245648Ssetje tmp->nelems = len / sizeof (struct prom_memlist); 5255648Ssetje tmp->maxsize = len; 5265648Ssetje tmp->ptr = (prom_memlist_t *)start; 5275648Ssetje start += len; 5285648Ssetje size -= len; 5295648Ssetje (void) prom_phys_installed((caddr_t)tmp->ptr); 5305648Ssetje sort_promlist(tmp); 5315648Ssetje compact_promlist(tmp); 5325648Ssetje 5335648Ssetje /* 5345648Ssetje * Start out giving each half of available space 5355648Ssetje */ 5365648Ssetje max_bootlist_sz = size; 5375648Ssetje len = size / 2; 5385648Ssetje tmp = &bootmem_props[PHYSAVAIL]; 5395648Ssetje tmp->maxsize = len; 5405648Ssetje tmp->ptr = (prom_memlist_t *)start; 5415648Ssetje start += len; 5425648Ssetje 5435648Ssetje tmp = &bootmem_props[VIRTAVAIL]; 5445648Ssetje tmp->maxsize = len; 5455648Ssetje tmp->ptr = (prom_memlist_t *)start; 5465648Ssetje } 5475648Ssetje 5485648Ssetje 5495648Ssetje void 5505648Ssetje copy_boot_memlists( 5515648Ssetje prom_memlist_t **physinstalled, size_t *physinstalled_len, 5525648Ssetje prom_memlist_t **physavail, size_t *physavail_len, 5535648Ssetje prom_memlist_t **virtavail, size_t *virtavail_len) 5545648Ssetje { 5555648Ssetje size_t plen, vlen, move = 0; 5565648Ssetje struct bootmem_props *il, *pl, *vl; 5575648Ssetje 5585648Ssetje plen = prom_phys_avail_len(); 5595648Ssetje if (plen == 0) 5605648Ssetje panic("no \"available\" in /memory"); 5615648Ssetje vlen = prom_virt_avail_len(); 5625648Ssetje if (vlen == 0) 5635648Ssetje panic("no \"available\" in /virtual-memory"); 5645648Ssetje if (plen + vlen > max_bootlist_sz) 5655648Ssetje panic("ran out of prom_memlist space"); 5665648Ssetje 5675648Ssetje pl = &bootmem_props[PHYSAVAIL]; 5685648Ssetje vl = &bootmem_props[VIRTAVAIL]; 5695648Ssetje 5705648Ssetje /* 5715648Ssetje * re-adjust ptrs if needed 5725648Ssetje */ 5735648Ssetje if (plen > pl->maxsize) { 5745648Ssetje /* move virt avail up */ 5755648Ssetje move = plen - pl->maxsize; 5765648Ssetje pl->maxsize = plen; 5775648Ssetje vl->ptr += move / sizeof (struct prom_memlist); 5785648Ssetje vl->maxsize -= move; 5795648Ssetje } else if (vlen > vl->maxsize) { 5805648Ssetje /* move virt avail down */ 5815648Ssetje move = vlen - vl->maxsize; 5825648Ssetje vl->maxsize = vlen; 5835648Ssetje vl->ptr -= move / sizeof (struct prom_memlist); 5845648Ssetje pl->maxsize -= move; 5855648Ssetje } 5865648Ssetje 5875648Ssetje pl->nelems = plen / sizeof (struct prom_memlist); 5885648Ssetje vl->nelems = vlen / sizeof (struct prom_memlist); 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* now we can retrieve the properties */ 5915648Ssetje (void) prom_phys_avail((caddr_t)pl->ptr); 5925648Ssetje (void) prom_virt_avail((caddr_t)vl->ptr); 5935648Ssetje 5945648Ssetje /* .. and sort them */ 5955648Ssetje sort_promlist(pl); 5965648Ssetje sort_promlist(vl); 5970Sstevel@tonic-gate 5985648Ssetje il = &bootmem_props[PHYSINSTALLED]; 5995648Ssetje *physinstalled = il->ptr; 6005648Ssetje *physinstalled_len = il->nelems; 6010Sstevel@tonic-gate 6025648Ssetje *physavail = pl->ptr; 6035648Ssetje *physavail_len = pl->nelems; 6045648Ssetje 6055648Ssetje *virtavail = vl->ptr; 6065648Ssetje *virtavail_len = vl->nelems; 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * Find the page number of the highest installed physical 6120Sstevel@tonic-gate * page and the number of pages installed (one cannot be 6130Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 6140Sstevel@tonic-gate * contiguous). 6150Sstevel@tonic-gate */ 6160Sstevel@tonic-gate void 6170Sstevel@tonic-gate installed_top_size( 6180Sstevel@tonic-gate struct memlist *list, /* pointer to start of installed list */ 6190Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 6200Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 6210Sstevel@tonic-gate { 6220Sstevel@tonic-gate pfn_t top = 0; 6230Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 6240Sstevel@tonic-gate pgcnt_t sumpages = 0; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate for (; list; list = list->next) { 6270Sstevel@tonic-gate highp = (list->address + list->size - 1) >> PAGESHIFT; 6280Sstevel@tonic-gate if (top < highp) 6290Sstevel@tonic-gate top = highp; 6300Sstevel@tonic-gate sumpages += (uint_t)(list->size >> PAGESHIFT); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate *topp = top; 6340Sstevel@tonic-gate *sumpagesp = sumpages; 6350Sstevel@tonic-gate } 636