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 /* 225084Sjohnlev * 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> 89*5648Ssetje #include <sys/prom_plat.h> 900Sstevel@tonic-gate 910Sstevel@tonic-gate u_longlong_t spec_hole_start = 0x80000000000ull; 920Sstevel@tonic-gate u_longlong_t spec_hole_end = 0xfffff80000000000ull; 930Sstevel@tonic-gate 945084Sjohnlev pgcnt_t 955084Sjohnlev num_phys_pages() 965084Sjohnlev { 975084Sjohnlev pgcnt_t npages = 0; 985084Sjohnlev struct memlist *mp; 995084Sjohnlev 1005084Sjohnlev for (mp = phys_install; mp != NULL; mp = mp->next) 1015084Sjohnlev npages += mp->size >> PAGESHIFT; 1025084Sjohnlev 1035084Sjohnlev return (npages); 1045084Sjohnlev } 1055084Sjohnlev 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate pgcnt_t 108*5648Ssetje size_virtalloc(prom_memlist_t *avail, size_t nelems) 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate u_longlong_t start, end; 1120Sstevel@tonic-gate pgcnt_t allocpages = 0; 1130Sstevel@tonic-gate uint_t hole_allocated = 0; 1140Sstevel@tonic-gate uint_t i; 1150Sstevel@tonic-gate 116*5648Ssetje for (i = 0; i < nelems - 1; i++) { 1170Sstevel@tonic-gate 118*5648Ssetje start = avail[i].addr + avail[i].size; 119*5648Ssetje end = avail[i + 1].addr; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Notes: 1230Sstevel@tonic-gate * 1240Sstevel@tonic-gate * (1) OBP on platforms with US I/II pre-allocates the hole 1250Sstevel@tonic-gate * represented by [spec_hole_start, spec_hole_end); 1260Sstevel@tonic-gate * pre-allocation is done to make this range unavailable 1270Sstevel@tonic-gate * for any allocation. 1280Sstevel@tonic-gate * 1290Sstevel@tonic-gate * (2) OBP on starcat always pre-allocates the hole similar to 1300Sstevel@tonic-gate * platforms with US I/II. 1310Sstevel@tonic-gate * 1320Sstevel@tonic-gate * (3) OBP on serengeti does _not_ pre-allocate the hole. 1330Sstevel@tonic-gate * 1340Sstevel@tonic-gate * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_ 1350Sstevel@tonic-gate * fill up or pre-allocate an additional 4GB on both sides 1360Sstevel@tonic-gate * of the hole. 1370Sstevel@tonic-gate * 1380Sstevel@tonic-gate * (5) kernel virtual range [spec_hole_start, spec_hole_end) 1390Sstevel@tonic-gate * is _not_ used on any platform including those with 1400Sstevel@tonic-gate * UltraSPARC III where there is no hole. 1410Sstevel@tonic-gate * 1420Sstevel@tonic-gate * Algorithm: 1430Sstevel@tonic-gate * 1440Sstevel@tonic-gate * Check if range [spec_hole_start, spec_hole_end) is 1450Sstevel@tonic-gate * pre-allocated by OBP; if so, subtract that range from 1460Sstevel@tonic-gate * allocpages. 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate if (end >= spec_hole_end && start <= spec_hole_start) 1490Sstevel@tonic-gate hole_allocated = 1; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate allocpages += btopr(end - start); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate if (hole_allocated) 1550Sstevel@tonic-gate allocpages -= btop(spec_hole_end - spec_hole_start); 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate return (allocpages); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1610Sstevel@tonic-gate * Returns the max contiguous physical memory present in the 1620Sstevel@tonic-gate * memlist "physavail". 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate uint64_t 1650Sstevel@tonic-gate get_max_phys_size( 1660Sstevel@tonic-gate struct memlist *physavail) 1670Sstevel@tonic-gate { 1680Sstevel@tonic-gate uint64_t max_size = 0; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate for (; physavail; physavail = physavail->next) { 1710Sstevel@tonic-gate if (physavail->size > max_size) 1720Sstevel@tonic-gate max_size = physavail->size; 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate return (max_size); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate struct vnode prom_ppages; 1810Sstevel@tonic-gate 182*5648Ssetje static void 183*5648Ssetje more_pages(uint64_t base, uint64_t len) 1840Sstevel@tonic-gate { 185*5648Ssetje void kphysm_add(); 186*5648Ssetje 187*5648Ssetje kphysm_add(base, len, 1); 188*5648Ssetje } 189*5648Ssetje 190*5648Ssetje static void 191*5648Ssetje less_pages(uint64_t base, uint64_t len) 192*5648Ssetje { 193*5648Ssetje uint64_t pa, end = base + len; 1940Sstevel@tonic-gate extern int kcage_on; 1950Sstevel@tonic-gate 196*5648Ssetje for (pa = base; pa < end; pa += PAGESIZE) { 1970Sstevel@tonic-gate pfn_t pfnum; 1980Sstevel@tonic-gate page_t *pp; 1990Sstevel@tonic-gate 200*5648Ssetje pfnum = (pfn_t)(pa >> PAGESHIFT); 201*5648Ssetje if ((pp = page_numtopp_nolock(pfnum)) == NULL) 202*5648Ssetje cmn_err(CE_PANIC, "missing pfnum %lx", pfnum); 203*5648Ssetje 204*5648Ssetje /* 205*5648Ssetje * must break up any large pages that may have 206*5648Ssetje * constituent pages being utilized for 207*5648Ssetje * prom_alloc()'s. page_reclaim() can't handle 208*5648Ssetje * large pages. 209*5648Ssetje */ 210*5648Ssetje if (pp->p_szc != 0) 211*5648Ssetje page_boot_demote(pp); 212*5648Ssetje 213*5648Ssetje if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) { 214*5648Ssetje /* 215*5648Ssetje * Ahhh yes, a prom page, 216*5648Ssetje * suck it off the freelist, 217*5648Ssetje * lock it, and hashin on prom_pages vp. 218*5648Ssetje */ 219*5648Ssetje if (page_trylock(pp, SE_EXCL) == 0) 220*5648Ssetje cmn_err(CE_PANIC, "prom page locked"); 221*5648Ssetje 222*5648Ssetje (void) page_reclaim(pp, NULL); 223*5648Ssetje /* 224*5648Ssetje * vnode offsets on the prom_ppages vnode 225*5648Ssetje * are page numbers (gack) for >32 bit 226*5648Ssetje * physical memory machines. 227*5648Ssetje */ 228*5648Ssetje (void) page_hashin(pp, &prom_ppages, 229*5648Ssetje (offset_t)pfnum, NULL); 230*5648Ssetje 231*5648Ssetje if (kcage_on) { 232*5648Ssetje ASSERT(pp->p_szc == 0); 233*5648Ssetje PP_SETNORELOC(pp); 234*5648Ssetje } 235*5648Ssetje (void) page_pp_lock(pp, 0, 1); 236*5648Ssetje } 237*5648Ssetje } 238*5648Ssetje } 239*5648Ssetje 240*5648Ssetje void 241*5648Ssetje diff_memlists(struct memlist *proto, struct memlist *diff, void (*func)()) 242*5648Ssetje { 243*5648Ssetje uint64_t p_base, p_end, d_base, d_end; 244*5648Ssetje 245*5648Ssetje while (proto != NULL) { 246*5648Ssetje /* 247*5648Ssetje * find diff item which may overlap with proto item 248*5648Ssetje * if none, apply func to all of proto item 249*5648Ssetje */ 250*5648Ssetje while (diff != NULL && 251*5648Ssetje proto->address >= diff->address + diff->size) 252*5648Ssetje diff = diff->next; 253*5648Ssetje if (diff == NULL) { 254*5648Ssetje (*func)(proto->address, proto->size); 255*5648Ssetje proto = proto->next; 256*5648Ssetje continue; 257*5648Ssetje } 258*5648Ssetje if (proto->address == diff->address && 259*5648Ssetje proto->size == diff->size) { 260*5648Ssetje proto = proto->next; 261*5648Ssetje diff = diff->next; 262*5648Ssetje continue; 263*5648Ssetje } 264*5648Ssetje 265*5648Ssetje p_base = proto->address; 266*5648Ssetje p_end = p_base + proto->size; 267*5648Ssetje d_base = diff->address; 268*5648Ssetje d_end = d_base + diff->size; 269*5648Ssetje /* 270*5648Ssetje * here p_base < d_end 271*5648Ssetje * there are 5 cases 272*5648Ssetje */ 273*5648Ssetje 274*5648Ssetje /* 275*5648Ssetje * d_end 276*5648Ssetje * d_base 277*5648Ssetje * p_end 278*5648Ssetje * p_base 279*5648Ssetje * 280*5648Ssetje * apply func to all of proto item 281*5648Ssetje */ 282*5648Ssetje if (p_end <= d_base) { 283*5648Ssetje (*func)(p_base, proto->size); 284*5648Ssetje proto = proto->next; 2850Sstevel@tonic-gate continue; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* 289*5648Ssetje * ... 290*5648Ssetje * d_base 291*5648Ssetje * p_base 292*5648Ssetje * 293*5648Ssetje * normalize by applying func from p_base to d_base 2940Sstevel@tonic-gate */ 295*5648Ssetje if (p_base < d_base) 296*5648Ssetje (*func)(p_base, d_base - p_base); 2970Sstevel@tonic-gate 298*5648Ssetje if (p_end <= d_end) { 2990Sstevel@tonic-gate /* 300*5648Ssetje * d_end 301*5648Ssetje * p_end 302*5648Ssetje * d_base 303*5648Ssetje * p_base 304*5648Ssetje * 305*5648Ssetje * -or- 306*5648Ssetje * 307*5648Ssetje * d_end 308*5648Ssetje * p_end 309*5648Ssetje * p_base 310*5648Ssetje * d_base 311*5648Ssetje * 312*5648Ssetje * any non-overlapping ranges applied above, 313*5648Ssetje * so just continue 3140Sstevel@tonic-gate */ 315*5648Ssetje proto = proto->next; 316*5648Ssetje continue; 317*5648Ssetje } 3180Sstevel@tonic-gate 319*5648Ssetje /* 320*5648Ssetje * p_end 321*5648Ssetje * d_end 322*5648Ssetje * d_base 323*5648Ssetje * p_base 324*5648Ssetje * 325*5648Ssetje * -or- 326*5648Ssetje * 327*5648Ssetje * p_end 328*5648Ssetje * d_end 329*5648Ssetje * p_base 330*5648Ssetje * d_base 331*5648Ssetje * 332*5648Ssetje * Find overlapping d_base..d_end ranges, and apply func 333*5648Ssetje * where no overlap occurs. Stop when d_base is above 334*5648Ssetje * p_end 335*5648Ssetje */ 336*5648Ssetje for (p_base = d_end, diff = diff->next; diff != NULL; 337*5648Ssetje p_base = d_end, diff = diff->next) { 338*5648Ssetje d_base = diff->address; 339*5648Ssetje d_end = d_base + diff->size; 340*5648Ssetje if (p_end <= d_base) { 341*5648Ssetje (*func)(p_base, p_end - p_base); 342*5648Ssetje break; 343*5648Ssetje } else 344*5648Ssetje (*func)(p_base, d_base - p_base); 3450Sstevel@tonic-gate } 346*5648Ssetje if (diff == NULL) 347*5648Ssetje (*func)(p_base, p_end - p_base); 348*5648Ssetje proto = proto->next; 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 352*5648Ssetje void 353*5648Ssetje sync_memlists(struct memlist *orig, struct memlist *new) 354*5648Ssetje { 355*5648Ssetje 356*5648Ssetje /* 357*5648Ssetje * Find pages allocated via prom by looking for 358*5648Ssetje * pages on orig, but no on new. 359*5648Ssetje */ 360*5648Ssetje diff_memlists(orig, new, less_pages); 361*5648Ssetje 362*5648Ssetje /* 363*5648Ssetje * Find pages free'd via prom by looking for 364*5648Ssetje * pages on new, but not on orig. 365*5648Ssetje */ 366*5648Ssetje diff_memlists(new, orig, more_pages); 367*5648Ssetje } 368*5648Ssetje 369*5648Ssetje 3700Sstevel@tonic-gate /* 3710Sstevel@tonic-gate * Find the page number of the highest installed physical 3720Sstevel@tonic-gate * page and the number of pages installed (one cannot be 3730Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 3740Sstevel@tonic-gate * contiguous). 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate void 3770Sstevel@tonic-gate installed_top_size_memlist_array( 378*5648Ssetje prom_memlist_t *list, /* base of array */ 3790Sstevel@tonic-gate size_t nelems, /* number of elements */ 3800Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 3810Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate pfn_t top = 0; 3840Sstevel@tonic-gate pgcnt_t sumpages = 0; 3850Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 3860Sstevel@tonic-gate size_t i; 3870Sstevel@tonic-gate 388*5648Ssetje for (i = 0; i < nelems; list++, i++) { 389*5648Ssetje highp = (list->addr + list->size - 1) >> PAGESHIFT; 3900Sstevel@tonic-gate if (top < highp) 3910Sstevel@tonic-gate top = highp; 392*5648Ssetje sumpages += (list->size >> PAGESHIFT); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate *topp = top; 3960Sstevel@tonic-gate *sumpagesp = sumpages; 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Copy a memory list. Used in startup() to copy boot's 4010Sstevel@tonic-gate * memory lists to the kernel. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate void 4040Sstevel@tonic-gate copy_memlist( 405*5648Ssetje prom_memlist_t *src, 4060Sstevel@tonic-gate size_t nelems, 4070Sstevel@tonic-gate struct memlist **dstp) 4080Sstevel@tonic-gate { 4090Sstevel@tonic-gate struct memlist *dst, *prev; 4100Sstevel@tonic-gate size_t i; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate dst = *dstp; 4130Sstevel@tonic-gate prev = dst; 4140Sstevel@tonic-gate 415*5648Ssetje for (i = 0; i < nelems; src++, i++) { 416*5648Ssetje dst->address = src->addr; 417*5648Ssetje dst->size = src->size; 4180Sstevel@tonic-gate dst->next = 0; 4190Sstevel@tonic-gate if (prev == dst) { 4200Sstevel@tonic-gate dst->prev = 0; 4210Sstevel@tonic-gate dst++; 4220Sstevel@tonic-gate } else { 4230Sstevel@tonic-gate dst->prev = prev; 4240Sstevel@tonic-gate prev->next = dst; 4250Sstevel@tonic-gate dst++; 4260Sstevel@tonic-gate prev++; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate *dstp = dst; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 433*5648Ssetje 4340Sstevel@tonic-gate static struct bootmem_props { 435*5648Ssetje prom_memlist_t *ptr; 4360Sstevel@tonic-gate size_t nelems; /* actual number of elements */ 437*5648Ssetje size_t maxsize; /* max buffer */ 438*5648Ssetje } bootmem_props[3]; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate #define PHYSINSTALLED 0 4410Sstevel@tonic-gate #define PHYSAVAIL 1 4420Sstevel@tonic-gate #define VIRTAVAIL 2 4430Sstevel@tonic-gate 444*5648Ssetje /* 445*5648Ssetje * Comapct contiguous memory list elements 446*5648Ssetje */ 447*5648Ssetje static void 448*5648Ssetje compact_promlist(struct bootmem_props *bpp) 4490Sstevel@tonic-gate { 450*5648Ssetje int i = 0, j; 451*5648Ssetje struct prom_memlist *pmp = bpp->ptr; 4520Sstevel@tonic-gate 453*5648Ssetje for (;;) { 454*5648Ssetje if (pmp[i].addr + pmp[i].size == pmp[i+1].addr) { 455*5648Ssetje pmp[i].size += pmp[i+1].size; 456*5648Ssetje bpp->nelems--; 457*5648Ssetje for (j = i + 1; j < bpp->nelems; j++) 458*5648Ssetje pmp[j] = pmp[j+1]; 459*5648Ssetje pmp[j].addr = 0; 460*5648Ssetje } else 461*5648Ssetje i++; 462*5648Ssetje if (i == bpp->nelems) 463*5648Ssetje break; 464*5648Ssetje } 465*5648Ssetje } 466*5648Ssetje 467*5648Ssetje /* 468*5648Ssetje * Sort prom memory lists into ascending order 469*5648Ssetje */ 470*5648Ssetje static void 471*5648Ssetje sort_promlist(struct bootmem_props *bpp) 472*5648Ssetje { 473*5648Ssetje int i, j, min; 474*5648Ssetje struct prom_memlist *pmp = bpp->ptr; 475*5648Ssetje struct prom_memlist temp; 476*5648Ssetje 477*5648Ssetje for (i = 0; i < bpp->nelems; i++) { 478*5648Ssetje min = i; 479*5648Ssetje 480*5648Ssetje for (j = i+1; j < bpp->nelems; j++) { 481*5648Ssetje if (pmp[j].addr < pmp[min].addr) 482*5648Ssetje min = j; 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 485*5648Ssetje if (i != min) { 486*5648Ssetje /* Swap pmp[i] and pmp[min] */ 487*5648Ssetje temp = pmp[min]; 488*5648Ssetje pmp[min] = pmp[i]; 489*5648Ssetje pmp[i] = temp; 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate } 492*5648Ssetje } 493*5648Ssetje 494*5648Ssetje static int max_bootlist_sz; 495*5648Ssetje 496*5648Ssetje void 497*5648Ssetje init_boot_memlists(void) 498*5648Ssetje { 499*5648Ssetje size_t size, len; 500*5648Ssetje char *start; 501*5648Ssetje struct bootmem_props *tmp; 502*5648Ssetje 503*5648Ssetje /* 504*5648Ssetje * These lists can get fragmented as the prom allocates 505*5648Ssetje * memory, so generously round up. 506*5648Ssetje */ 507*5648Ssetje size = prom_phys_installed_len() + prom_phys_avail_len() + 508*5648Ssetje prom_virt_avail_len(); 509*5648Ssetje size *= 4; 510*5648Ssetje size = roundup(size, PAGESIZE); 511*5648Ssetje start = prom_alloc(0, size, BO_NO_ALIGN); 512*5648Ssetje 513*5648Ssetje /* 514*5648Ssetje * Get physinstalled 515*5648Ssetje */ 516*5648Ssetje tmp = &bootmem_props[PHYSINSTALLED]; 517*5648Ssetje len = prom_phys_installed_len(); 518*5648Ssetje if (len == 0) 519*5648Ssetje panic("no \"reg\" in /memory"); 520*5648Ssetje tmp->nelems = len / sizeof (struct prom_memlist); 521*5648Ssetje tmp->maxsize = len; 522*5648Ssetje tmp->ptr = (prom_memlist_t *)start; 523*5648Ssetje start += len; 524*5648Ssetje size -= len; 525*5648Ssetje (void) prom_phys_installed((caddr_t)tmp->ptr); 526*5648Ssetje sort_promlist(tmp); 527*5648Ssetje compact_promlist(tmp); 528*5648Ssetje 529*5648Ssetje /* 530*5648Ssetje * Start out giving each half of available space 531*5648Ssetje */ 532*5648Ssetje max_bootlist_sz = size; 533*5648Ssetje len = size / 2; 534*5648Ssetje tmp = &bootmem_props[PHYSAVAIL]; 535*5648Ssetje tmp->maxsize = len; 536*5648Ssetje tmp->ptr = (prom_memlist_t *)start; 537*5648Ssetje start += len; 538*5648Ssetje 539*5648Ssetje tmp = &bootmem_props[VIRTAVAIL]; 540*5648Ssetje tmp->maxsize = len; 541*5648Ssetje tmp->ptr = (prom_memlist_t *)start; 542*5648Ssetje } 543*5648Ssetje 544*5648Ssetje 545*5648Ssetje void 546*5648Ssetje copy_boot_memlists( 547*5648Ssetje prom_memlist_t **physinstalled, size_t *physinstalled_len, 548*5648Ssetje prom_memlist_t **physavail, size_t *physavail_len, 549*5648Ssetje prom_memlist_t **virtavail, size_t *virtavail_len) 550*5648Ssetje { 551*5648Ssetje size_t plen, vlen, move = 0; 552*5648Ssetje struct bootmem_props *il, *pl, *vl; 553*5648Ssetje 554*5648Ssetje plen = prom_phys_avail_len(); 555*5648Ssetje if (plen == 0) 556*5648Ssetje panic("no \"available\" in /memory"); 557*5648Ssetje vlen = prom_virt_avail_len(); 558*5648Ssetje if (vlen == 0) 559*5648Ssetje panic("no \"available\" in /virtual-memory"); 560*5648Ssetje if (plen + vlen > max_bootlist_sz) 561*5648Ssetje panic("ran out of prom_memlist space"); 562*5648Ssetje 563*5648Ssetje pl = &bootmem_props[PHYSAVAIL]; 564*5648Ssetje vl = &bootmem_props[VIRTAVAIL]; 565*5648Ssetje 566*5648Ssetje /* 567*5648Ssetje * re-adjust ptrs if needed 568*5648Ssetje */ 569*5648Ssetje if (plen > pl->maxsize) { 570*5648Ssetje /* move virt avail up */ 571*5648Ssetje move = plen - pl->maxsize; 572*5648Ssetje pl->maxsize = plen; 573*5648Ssetje vl->ptr += move / sizeof (struct prom_memlist); 574*5648Ssetje vl->maxsize -= move; 575*5648Ssetje } else if (vlen > vl->maxsize) { 576*5648Ssetje /* move virt avail down */ 577*5648Ssetje move = vlen - vl->maxsize; 578*5648Ssetje vl->maxsize = vlen; 579*5648Ssetje vl->ptr -= move / sizeof (struct prom_memlist); 580*5648Ssetje pl->maxsize -= move; 581*5648Ssetje } 582*5648Ssetje 583*5648Ssetje pl->nelems = plen / sizeof (struct prom_memlist); 584*5648Ssetje vl->nelems = vlen / sizeof (struct prom_memlist); 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate /* now we can retrieve the properties */ 587*5648Ssetje (void) prom_phys_avail((caddr_t)pl->ptr); 588*5648Ssetje (void) prom_virt_avail((caddr_t)vl->ptr); 589*5648Ssetje 590*5648Ssetje /* .. and sort them */ 591*5648Ssetje sort_promlist(pl); 592*5648Ssetje sort_promlist(vl); 5930Sstevel@tonic-gate 594*5648Ssetje il = &bootmem_props[PHYSINSTALLED]; 595*5648Ssetje *physinstalled = il->ptr; 596*5648Ssetje *physinstalled_len = il->nelems; 5970Sstevel@tonic-gate 598*5648Ssetje *physavail = pl->ptr; 599*5648Ssetje *physavail_len = pl->nelems; 600*5648Ssetje 601*5648Ssetje *virtavail = vl->ptr; 602*5648Ssetje *virtavail_len = vl->nelems; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate /* 6070Sstevel@tonic-gate * Find the page number of the highest installed physical 6080Sstevel@tonic-gate * page and the number of pages installed (one cannot be 6090Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 6100Sstevel@tonic-gate * contiguous). 6110Sstevel@tonic-gate */ 6120Sstevel@tonic-gate void 6130Sstevel@tonic-gate installed_top_size( 6140Sstevel@tonic-gate struct memlist *list, /* pointer to start of installed list */ 6150Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 6160Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 6170Sstevel@tonic-gate { 6180Sstevel@tonic-gate pfn_t top = 0; 6190Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 6200Sstevel@tonic-gate pgcnt_t sumpages = 0; 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate for (; list; list = list->next) { 6230Sstevel@tonic-gate highp = (list->address + list->size - 1) >> PAGESHIFT; 6240Sstevel@tonic-gate if (top < highp) 6250Sstevel@tonic-gate top = highp; 6260Sstevel@tonic-gate sumpages += (uint_t)(list->size >> PAGESHIFT); 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate *topp = top; 6300Sstevel@tonic-gate *sumpagesp = sumpages; 6310Sstevel@tonic-gate } 632