10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*5084Sjohnlev * Common Development and Distribution License (the "License"). 6*5084Sjohnlev * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5084Sjohnlev * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/param.h> 300Sstevel@tonic-gate #include <sys/sysmacros.h> 310Sstevel@tonic-gate #include <sys/signal.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/user.h> 340Sstevel@tonic-gate #include <sys/mman.h> 350Sstevel@tonic-gate #include <sys/class.h> 360Sstevel@tonic-gate #include <sys/proc.h> 370Sstevel@tonic-gate #include <sys/procfs.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/cred.h> 400Sstevel@tonic-gate #include <sys/archsystm.h> 410Sstevel@tonic-gate #include <sys/machsystm.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include <sys/reboot.h> 440Sstevel@tonic-gate #include <sys/uadmin.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include <sys/vfs.h> 470Sstevel@tonic-gate #include <sys/vnode.h> 480Sstevel@tonic-gate #include <sys/session.h> 490Sstevel@tonic-gate #include <sys/ucontext.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <sys/dnlc.h> 520Sstevel@tonic-gate #include <sys/var.h> 530Sstevel@tonic-gate #include <sys/cmn_err.h> 540Sstevel@tonic-gate #include <sys/debug.h> 550Sstevel@tonic-gate #include <sys/thread.h> 560Sstevel@tonic-gate #include <sys/vtrace.h> 570Sstevel@tonic-gate #include <sys/consdev.h> 580Sstevel@tonic-gate #include <sys/frame.h> 590Sstevel@tonic-gate #include <sys/stack.h> 600Sstevel@tonic-gate #include <sys/swap.h> 610Sstevel@tonic-gate #include <sys/vmparam.h> 620Sstevel@tonic-gate #include <sys/cpuvar.h> 630Sstevel@tonic-gate 640Sstevel@tonic-gate #include <sys/privregs.h> 650Sstevel@tonic-gate 660Sstevel@tonic-gate #include <vm/hat.h> 670Sstevel@tonic-gate #include <vm/anon.h> 680Sstevel@tonic-gate #include <vm/as.h> 690Sstevel@tonic-gate #include <vm/page.h> 700Sstevel@tonic-gate #include <vm/seg.h> 710Sstevel@tonic-gate #include <vm/seg_kmem.h> 720Sstevel@tonic-gate #include <vm/seg_map.h> 730Sstevel@tonic-gate #include <vm/seg_vn.h> 740Sstevel@tonic-gate 750Sstevel@tonic-gate #include <sys/exec.h> 760Sstevel@tonic-gate #include <sys/acct.h> 770Sstevel@tonic-gate #include <sys/modctl.h> 780Sstevel@tonic-gate #include <sys/tuneable.h> 790Sstevel@tonic-gate 800Sstevel@tonic-gate #include <c2/audit.h> 810Sstevel@tonic-gate 820Sstevel@tonic-gate #include <sys/trap.h> 830Sstevel@tonic-gate #include <sys/sunddi.h> 840Sstevel@tonic-gate #include <sys/bootconf.h> 850Sstevel@tonic-gate #include <sys/memlist.h> 860Sstevel@tonic-gate #include <sys/memlist_plat.h> 870Sstevel@tonic-gate #include <sys/systeminfo.h> 880Sstevel@tonic-gate #include <sys/promif.h> 890Sstevel@tonic-gate 900Sstevel@tonic-gate u_longlong_t spec_hole_start = 0x80000000000ull; 910Sstevel@tonic-gate u_longlong_t spec_hole_end = 0xfffff80000000000ull; 920Sstevel@tonic-gate 93*5084Sjohnlev pgcnt_t 94*5084Sjohnlev num_phys_pages() 95*5084Sjohnlev { 96*5084Sjohnlev pgcnt_t npages = 0; 97*5084Sjohnlev struct memlist *mp; 98*5084Sjohnlev 99*5084Sjohnlev for (mp = phys_install; mp != NULL; mp = mp->next) 100*5084Sjohnlev npages += mp->size >> PAGESHIFT; 101*5084Sjohnlev 102*5084Sjohnlev return (npages); 103*5084Sjohnlev } 104*5084Sjohnlev 1050Sstevel@tonic-gate /* 1060Sstevel@tonic-gate * Count the number of available pages and the number of 1070Sstevel@tonic-gate * chunks in the list of available memory. 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate void 1100Sstevel@tonic-gate size_physavail( 1110Sstevel@tonic-gate u_longlong_t *physavail, 1120Sstevel@tonic-gate size_t nelems, 1130Sstevel@tonic-gate pgcnt_t *npages, 1140Sstevel@tonic-gate int *memblocks) 1150Sstevel@tonic-gate { 1160Sstevel@tonic-gate size_t i; 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate *npages = 0; 1190Sstevel@tonic-gate *memblocks = 0; 1200Sstevel@tonic-gate for (i = 0; i < nelems; i += 2) { 1210Sstevel@tonic-gate *npages += (pgcnt_t)(physavail[i+1] >> PAGESHIFT); 1220Sstevel@tonic-gate (*memblocks)++; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate pgcnt_t 1270Sstevel@tonic-gate size_virtalloc(u_longlong_t *avail, size_t nelems) 1280Sstevel@tonic-gate { 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate u_longlong_t start, end; 1310Sstevel@tonic-gate pgcnt_t allocpages = 0; 1320Sstevel@tonic-gate uint_t hole_allocated = 0; 1330Sstevel@tonic-gate uint_t i; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate for (i = 0; i < (nelems - 2); i += 2) { 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate start = avail[i] + avail[i + 1]; 1380Sstevel@tonic-gate end = avail[i + 2]; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /* 1410Sstevel@tonic-gate * Notes: 1420Sstevel@tonic-gate * 1430Sstevel@tonic-gate * (1) OBP on platforms with US I/II pre-allocates the hole 1440Sstevel@tonic-gate * represented by [spec_hole_start, spec_hole_end); 1450Sstevel@tonic-gate * pre-allocation is done to make this range unavailable 1460Sstevel@tonic-gate * for any allocation. 1470Sstevel@tonic-gate * 1480Sstevel@tonic-gate * (2) OBP on starcat always pre-allocates the hole similar to 1490Sstevel@tonic-gate * platforms with US I/II. 1500Sstevel@tonic-gate * 1510Sstevel@tonic-gate * (3) OBP on serengeti does _not_ pre-allocate the hole. 1520Sstevel@tonic-gate * 1530Sstevel@tonic-gate * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_ 1540Sstevel@tonic-gate * fill up or pre-allocate an additional 4GB on both sides 1550Sstevel@tonic-gate * of the hole. 1560Sstevel@tonic-gate * 1570Sstevel@tonic-gate * (5) kernel virtual range [spec_hole_start, spec_hole_end) 1580Sstevel@tonic-gate * is _not_ used on any platform including those with 1590Sstevel@tonic-gate * UltraSPARC III where there is no hole. 1600Sstevel@tonic-gate * 1610Sstevel@tonic-gate * Algorithm: 1620Sstevel@tonic-gate * 1630Sstevel@tonic-gate * Check if range [spec_hole_start, spec_hole_end) is 1640Sstevel@tonic-gate * pre-allocated by OBP; if so, subtract that range from 1650Sstevel@tonic-gate * allocpages. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate if (end >= spec_hole_end && start <= spec_hole_start) 1680Sstevel@tonic-gate hole_allocated = 1; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate allocpages += btopr(end - start); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (hole_allocated) 1740Sstevel@tonic-gate allocpages -= btop(spec_hole_end - spec_hole_start); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate return (allocpages); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * Returns the max contiguous physical memory present in the 1810Sstevel@tonic-gate * memlist "physavail". 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate uint64_t 1840Sstevel@tonic-gate get_max_phys_size( 1850Sstevel@tonic-gate struct memlist *physavail) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate uint64_t max_size = 0; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate for (; physavail; physavail = physavail->next) { 1900Sstevel@tonic-gate if (physavail->size > max_size) 1910Sstevel@tonic-gate max_size = physavail->size; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate return (max_size); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * Copy boot's physavail list deducting memory at "start" 2000Sstevel@tonic-gate * for "size" bytes. 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate int 2030Sstevel@tonic-gate copy_physavail( 2040Sstevel@tonic-gate u_longlong_t *src, 2050Sstevel@tonic-gate size_t nelems, 2060Sstevel@tonic-gate struct memlist **dstp, 2070Sstevel@tonic-gate uint_t start, 2080Sstevel@tonic-gate uint_t size) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate struct memlist *dst, *prev; 2110Sstevel@tonic-gate uint_t end1; 2120Sstevel@tonic-gate int deducted = 0; 2130Sstevel@tonic-gate size_t i; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate dst = *dstp; 2160Sstevel@tonic-gate prev = dst; 2170Sstevel@tonic-gate end1 = start + size; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate for (i = 0; i < nelems; i += 2) { 2200Sstevel@tonic-gate uint64_t addr, lsize, end2; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate addr = src[i]; 2230Sstevel@tonic-gate lsize = src[i+1]; 2240Sstevel@tonic-gate end2 = addr + lsize; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if ((size != 0) && start >= addr && end1 <= end2) { 2270Sstevel@tonic-gate /* deducted range in this chunk */ 2280Sstevel@tonic-gate deducted = 1; 2290Sstevel@tonic-gate if (start == addr) { 2300Sstevel@tonic-gate /* abuts start of chunk */ 2310Sstevel@tonic-gate if (end1 == end2) 2320Sstevel@tonic-gate /* is equal to the chunk */ 2330Sstevel@tonic-gate continue; 2340Sstevel@tonic-gate dst->address = end1; 2350Sstevel@tonic-gate dst->size = lsize - size; 2360Sstevel@tonic-gate } else if (end1 == end2) { 2370Sstevel@tonic-gate /* abuts end of chunk */ 2380Sstevel@tonic-gate dst->address = addr; 2390Sstevel@tonic-gate dst->size = lsize - size; 2400Sstevel@tonic-gate } else { 2410Sstevel@tonic-gate /* in the middle of the chunk */ 2420Sstevel@tonic-gate dst->address = addr; 2430Sstevel@tonic-gate dst->size = start - addr; 2440Sstevel@tonic-gate dst->next = 0; 2450Sstevel@tonic-gate if (prev == dst) { 2460Sstevel@tonic-gate dst->prev = 0; 2470Sstevel@tonic-gate dst++; 2480Sstevel@tonic-gate } else { 2490Sstevel@tonic-gate dst->prev = prev; 2500Sstevel@tonic-gate prev->next = dst; 2510Sstevel@tonic-gate dst++; 2520Sstevel@tonic-gate prev++; 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate dst->address = end1; 2550Sstevel@tonic-gate dst->size = end2 - end1; 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate dst->next = 0; 2580Sstevel@tonic-gate if (prev == dst) { 2590Sstevel@tonic-gate dst->prev = 0; 2600Sstevel@tonic-gate dst++; 2610Sstevel@tonic-gate } else { 2620Sstevel@tonic-gate dst->prev = prev; 2630Sstevel@tonic-gate prev->next = dst; 2640Sstevel@tonic-gate dst++; 2650Sstevel@tonic-gate prev++; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate } else { 2680Sstevel@tonic-gate dst->address = src[i]; 2690Sstevel@tonic-gate dst->size = src[i+1]; 2700Sstevel@tonic-gate dst->next = 0; 2710Sstevel@tonic-gate if (prev == dst) { 2720Sstevel@tonic-gate dst->prev = 0; 2730Sstevel@tonic-gate dst++; 2740Sstevel@tonic-gate } else { 2750Sstevel@tonic-gate dst->prev = prev; 2760Sstevel@tonic-gate prev->next = dst; 2770Sstevel@tonic-gate dst++; 2780Sstevel@tonic-gate prev++; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate *dstp = dst; 2840Sstevel@tonic-gate return (deducted); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate struct vnode prom_ppages; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * Find the pages allocated by the prom by diffing the original 2910Sstevel@tonic-gate * phys_avail list and the current list. In the difference, the 2920Sstevel@tonic-gate * pages not locked belong to the PROM. (The kernel has already locked 2930Sstevel@tonic-gate * and removed all the pages it has allocated from the freelist, this 2940Sstevel@tonic-gate * routine removes the remaining "free" pages that really belong to the 2950Sstevel@tonic-gate * PROM and hashs them in on the 'prom_pages' vnode.) 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate void 2980Sstevel@tonic-gate fix_prom_pages(struct memlist *orig, struct memlist *new) 2990Sstevel@tonic-gate { 3000Sstevel@tonic-gate struct memlist *list, *nlist; 3010Sstevel@tonic-gate extern int kcage_on; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate nlist = new; 3040Sstevel@tonic-gate for (list = orig; list; list = list->next) { 3050Sstevel@tonic-gate uint64_t pa, end; 3060Sstevel@tonic-gate pfn_t pfnum; 3070Sstevel@tonic-gate page_t *pp; 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate if (list->address == nlist->address && 3100Sstevel@tonic-gate list->size == nlist->size) { 3110Sstevel@tonic-gate nlist = nlist->next ? nlist->next : nlist; 3120Sstevel@tonic-gate continue; 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* 3160Sstevel@tonic-gate * Loop through the old list looking to 3170Sstevel@tonic-gate * see if each page is still in the new one. 3180Sstevel@tonic-gate * If a page is not in the new list then we 3190Sstevel@tonic-gate * check to see if it locked permanently. 3200Sstevel@tonic-gate * If so, the kernel allocated and owns it. 3210Sstevel@tonic-gate * If not, then the prom must own it. We 3220Sstevel@tonic-gate * remove any pages found to owned by the prom 3230Sstevel@tonic-gate * from the freelist. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate end = list->address + list->size; 3260Sstevel@tonic-gate for (pa = list->address; pa < end; pa += PAGESIZE) { 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate if (address_in_memlist(new, pa, PAGESIZE)) 3290Sstevel@tonic-gate continue; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate pfnum = (pfn_t)(pa >> PAGESHIFT); 3320Sstevel@tonic-gate if ((pp = page_numtopp_nolock(pfnum)) == NULL) 3330Sstevel@tonic-gate cmn_err(CE_PANIC, "missing pfnum %lx", pfnum); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * must break up any large pages that may have 3370Sstevel@tonic-gate * constituent pages being utilized for 3380Sstevel@tonic-gate * BOP_ALLOC()'s. page_reclaim() can't handle 3390Sstevel@tonic-gate * large pages. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate if (pp->p_szc != 0) 3420Sstevel@tonic-gate page_boot_demote(pp); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) { 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * Ahhh yes, a prom page, 3470Sstevel@tonic-gate * suck it off the freelist, 3480Sstevel@tonic-gate * lock it, and hashin on prom_pages vp. 3490Sstevel@tonic-gate */ 3500Sstevel@tonic-gate if (page_trylock(pp, SE_EXCL) == 0) 3510Sstevel@tonic-gate cmn_err(CE_PANIC, "prom page locked"); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate (void) page_reclaim(pp, NULL); 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * XXX vnode offsets on the prom_ppages vnode 3560Sstevel@tonic-gate * are page numbers (gack) for >32 bit 3570Sstevel@tonic-gate * physical memory machines. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate (void) page_hashin(pp, &prom_ppages, 360*5084Sjohnlev (offset_t)pfnum, NULL); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (kcage_on) { 3630Sstevel@tonic-gate ASSERT(pp->p_szc == 0); 3640Sstevel@tonic-gate PP_SETNORELOC(pp); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate (void) page_pp_lock(pp, 0, 1); 3670Sstevel@tonic-gate page_downgrade(pp); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate nlist = nlist->next ? nlist->next : nlist; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* 3750Sstevel@tonic-gate * Find the page number of the highest installed physical 3760Sstevel@tonic-gate * page and the number of pages installed (one cannot be 3770Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 3780Sstevel@tonic-gate * contiguous). 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate void 3810Sstevel@tonic-gate installed_top_size_memlist_array( 3820Sstevel@tonic-gate u_longlong_t *list, /* base of array */ 3830Sstevel@tonic-gate size_t nelems, /* number of elements */ 3840Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 3850Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 3860Sstevel@tonic-gate { 3870Sstevel@tonic-gate pfn_t top = 0; 3880Sstevel@tonic-gate pgcnt_t sumpages = 0; 3890Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 3900Sstevel@tonic-gate size_t i; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate for (i = 0; i < nelems; i += 2) { 3930Sstevel@tonic-gate highp = (list[i] + list[i+1] - 1) >> PAGESHIFT; 3940Sstevel@tonic-gate if (top < highp) 3950Sstevel@tonic-gate top = highp; 3960Sstevel@tonic-gate sumpages += (list[i+1] >> PAGESHIFT); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate *topp = top; 4000Sstevel@tonic-gate *sumpagesp = sumpages; 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Copy a memory list. Used in startup() to copy boot's 4050Sstevel@tonic-gate * memory lists to the kernel. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate void 4080Sstevel@tonic-gate copy_memlist( 4090Sstevel@tonic-gate u_longlong_t *src, 4100Sstevel@tonic-gate size_t nelems, 4110Sstevel@tonic-gate struct memlist **dstp) 4120Sstevel@tonic-gate { 4130Sstevel@tonic-gate struct memlist *dst, *prev; 4140Sstevel@tonic-gate size_t i; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate dst = *dstp; 4170Sstevel@tonic-gate prev = dst; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate for (i = 0; i < nelems; i += 2) { 4200Sstevel@tonic-gate dst->address = src[i]; 4210Sstevel@tonic-gate dst->size = src[i+1]; 4220Sstevel@tonic-gate dst->next = 0; 4230Sstevel@tonic-gate if (prev == dst) { 4240Sstevel@tonic-gate dst->prev = 0; 4250Sstevel@tonic-gate dst++; 4260Sstevel@tonic-gate } else { 4270Sstevel@tonic-gate dst->prev = prev; 4280Sstevel@tonic-gate prev->next = dst; 4290Sstevel@tonic-gate dst++; 4300Sstevel@tonic-gate prev++; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate *dstp = dst; 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate static struct bootmem_props { 4380Sstevel@tonic-gate char *name; 4390Sstevel@tonic-gate u_longlong_t *ptr; 4400Sstevel@tonic-gate size_t nelems; /* actual number of elements */ 4410Sstevel@tonic-gate size_t bufsize; /* length of allocated buffer */ 4420Sstevel@tonic-gate } bootmem_props[] = { 4430Sstevel@tonic-gate { "phys-installed", NULL, 0, 0 }, 4440Sstevel@tonic-gate { "phys-avail", NULL, 0, 0 }, 4450Sstevel@tonic-gate { "virt-avail", NULL, 0, 0 }, 4460Sstevel@tonic-gate { NULL, NULL, 0, 0 } 4470Sstevel@tonic-gate }; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate #define PHYSINSTALLED 0 4500Sstevel@tonic-gate #define PHYSAVAIL 1 4510Sstevel@tonic-gate #define VIRTAVAIL 2 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate void 4540Sstevel@tonic-gate copy_boot_memlists(u_longlong_t **physinstalled, size_t *physinstalled_len, 4550Sstevel@tonic-gate u_longlong_t **physavail, size_t *physavail_len, 4560Sstevel@tonic-gate u_longlong_t **virtavail, size_t *virtavail_len) 4570Sstevel@tonic-gate { 4580Sstevel@tonic-gate int align = BO_ALIGN_L3; 4590Sstevel@tonic-gate size_t len; 4600Sstevel@tonic-gate struct bootmem_props *tmp = bootmem_props; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate tryagain: 4630Sstevel@tonic-gate for (tmp = bootmem_props; tmp->name != NULL; tmp++) { 4640Sstevel@tonic-gate len = BOP_GETPROPLEN(bootops, tmp->name); 4650Sstevel@tonic-gate if (len == 0) { 4660Sstevel@tonic-gate panic("cannot get length of \"%s\" property", 4670Sstevel@tonic-gate tmp->name); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate tmp->nelems = len / sizeof (u_longlong_t); 4700Sstevel@tonic-gate len = roundup(len, PAGESIZE); 4710Sstevel@tonic-gate if (len <= tmp->bufsize) 4720Sstevel@tonic-gate continue; 4730Sstevel@tonic-gate /* need to allocate more */ 4740Sstevel@tonic-gate if (tmp->ptr) { 4750Sstevel@tonic-gate BOP_FREE(bootops, (caddr_t)tmp->ptr, tmp->bufsize); 4760Sstevel@tonic-gate tmp->ptr = NULL; 4770Sstevel@tonic-gate tmp->bufsize = 0; 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate tmp->bufsize = len; 4800Sstevel@tonic-gate tmp->ptr = (void *)BOP_ALLOC(bootops, 0, tmp->bufsize, align); 4810Sstevel@tonic-gate if (tmp->ptr == NULL) 482567Sdmick panic("cannot allocate %lu bytes for \"%s\" property", 4830Sstevel@tonic-gate tmp->bufsize, tmp->name); 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * take the most current snapshot we can by calling mem-update 4880Sstevel@tonic-gate */ 4890Sstevel@tonic-gate if (BOP_GETPROPLEN(bootops, "memory-update") == 0) 4900Sstevel@tonic-gate (void) BOP_GETPROP(bootops, "memory-update", NULL); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* did the sizes change? */ 4930Sstevel@tonic-gate for (tmp = bootmem_props; tmp->name != NULL; tmp++) { 4940Sstevel@tonic-gate len = BOP_GETPROPLEN(bootops, tmp->name); 4950Sstevel@tonic-gate tmp->nelems = len / sizeof (u_longlong_t); 4960Sstevel@tonic-gate len = roundup(len, PAGESIZE); 4970Sstevel@tonic-gate if (len > tmp->bufsize) { 4980Sstevel@tonic-gate /* ick. Free them all and try again */ 4990Sstevel@tonic-gate for (tmp = bootmem_props; tmp->name != NULL; tmp++) { 5000Sstevel@tonic-gate BOP_FREE(bootops, (caddr_t)tmp->ptr, 5010Sstevel@tonic-gate tmp->bufsize); 5020Sstevel@tonic-gate tmp->ptr = NULL; 5030Sstevel@tonic-gate tmp->bufsize = 0; 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate goto tryagain; 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* now we can retrieve the properties */ 5100Sstevel@tonic-gate for (tmp = bootmem_props; tmp->name != NULL; tmp++) { 5110Sstevel@tonic-gate if (BOP_GETPROP(bootops, tmp->name, tmp->ptr) == -1) { 5120Sstevel@tonic-gate panic("cannot retrieve \"%s\" property", 5130Sstevel@tonic-gate tmp->name); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate *physinstalled = bootmem_props[PHYSINSTALLED].ptr; 5170Sstevel@tonic-gate *physinstalled_len = bootmem_props[PHYSINSTALLED].nelems; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate *physavail = bootmem_props[PHYSAVAIL].ptr; 5200Sstevel@tonic-gate *physavail_len = bootmem_props[PHYSAVAIL].nelems; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate *virtavail = bootmem_props[VIRTAVAIL].ptr; 5230Sstevel@tonic-gate *virtavail_len = bootmem_props[VIRTAVAIL].nelems; 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* 5280Sstevel@tonic-gate * Find the page number of the highest installed physical 5290Sstevel@tonic-gate * page and the number of pages installed (one cannot be 5300Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 5310Sstevel@tonic-gate * contiguous). 5320Sstevel@tonic-gate */ 5330Sstevel@tonic-gate void 5340Sstevel@tonic-gate installed_top_size( 5350Sstevel@tonic-gate struct memlist *list, /* pointer to start of installed list */ 5360Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 5370Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 5380Sstevel@tonic-gate { 5390Sstevel@tonic-gate pfn_t top = 0; 5400Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 5410Sstevel@tonic-gate pgcnt_t sumpages = 0; 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate for (; list; list = list->next) { 5440Sstevel@tonic-gate highp = (list->address + list->size - 1) >> PAGESHIFT; 5450Sstevel@tonic-gate if (top < highp) 5460Sstevel@tonic-gate top = highp; 5470Sstevel@tonic-gate sumpages += (uint_t)(list->size >> PAGESHIFT); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate *topp = top; 5510Sstevel@tonic-gate *sumpagesp = sumpages; 5520Sstevel@tonic-gate } 553