17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*56f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/param.h> 287c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 297c478bd9Sstevel@tonic-gate #include <sys/signal.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/user.h> 327c478bd9Sstevel@tonic-gate #include <sys/mman.h> 337c478bd9Sstevel@tonic-gate #include <sys/class.h> 347c478bd9Sstevel@tonic-gate #include <sys/proc.h> 357c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 367c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 377c478bd9Sstevel@tonic-gate #include <sys/cred.h> 387c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 397c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 427c478bd9Sstevel@tonic-gate #include <sys/uadmin.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 457c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 467c478bd9Sstevel@tonic-gate #include <sys/session.h> 477c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #include <sys/dnlc.h> 507c478bd9Sstevel@tonic-gate #include <sys/var.h> 517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 527c478bd9Sstevel@tonic-gate #include <sys/debug.h> 537c478bd9Sstevel@tonic-gate #include <sys/thread.h> 547c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 557c478bd9Sstevel@tonic-gate #include <sys/consdev.h> 567c478bd9Sstevel@tonic-gate #include <sys/frame.h> 577c478bd9Sstevel@tonic-gate #include <sys/stack.h> 587c478bd9Sstevel@tonic-gate #include <sys/swap.h> 597c478bd9Sstevel@tonic-gate #include <sys/vmparam.h> 607c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #include <vm/hat.h> 657c478bd9Sstevel@tonic-gate #include <vm/anon.h> 667c478bd9Sstevel@tonic-gate #include <vm/as.h> 677c478bd9Sstevel@tonic-gate #include <vm/page.h> 687c478bd9Sstevel@tonic-gate #include <vm/seg.h> 697c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 707c478bd9Sstevel@tonic-gate #include <vm/seg_map.h> 717c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h> 7200e145c7Skchow #include <vm/vm_dep.h> 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #include <sys/exec.h> 757c478bd9Sstevel@tonic-gate #include <sys/acct.h> 767c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 777c478bd9Sstevel@tonic-gate #include <sys/tuneable.h> 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #include <c2/audit.h> 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #include <sys/trap.h> 827c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 837c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 847c478bd9Sstevel@tonic-gate #include <sys/memlist.h> 857c478bd9Sstevel@tonic-gate #include <sys/memlist_plat.h> 867c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 877c478bd9Sstevel@tonic-gate #include <sys/promif.h> 88986fd29aSsetje #include <sys/prom_plat.h> 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate u_longlong_t spec_hole_start = 0x80000000000ull; 917c478bd9Sstevel@tonic-gate u_longlong_t spec_hole_end = 0xfffff80000000000ull; 927c478bd9Sstevel@tonic-gate 93843e1988Sjohnlev pgcnt_t 94843e1988Sjohnlev num_phys_pages() 95843e1988Sjohnlev { 96843e1988Sjohnlev pgcnt_t npages = 0; 97843e1988Sjohnlev struct memlist *mp; 98843e1988Sjohnlev 99*56f33205SJonathan Adams for (mp = phys_install; mp != NULL; mp = mp->ml_next) 100*56f33205SJonathan Adams npages += mp->ml_size >> PAGESHIFT; 101843e1988Sjohnlev 102843e1988Sjohnlev return (npages); 103843e1988Sjohnlev } 104843e1988Sjohnlev 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate pgcnt_t 107986fd29aSsetje size_virtalloc(prom_memlist_t *avail, size_t nelems) 1087c478bd9Sstevel@tonic-gate { 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate u_longlong_t start, end; 1117c478bd9Sstevel@tonic-gate pgcnt_t allocpages = 0; 1127c478bd9Sstevel@tonic-gate uint_t hole_allocated = 0; 1137c478bd9Sstevel@tonic-gate uint_t i; 1147c478bd9Sstevel@tonic-gate 115986fd29aSsetje for (i = 0; i < nelems - 1; i++) { 1167c478bd9Sstevel@tonic-gate 117986fd29aSsetje start = avail[i].addr + avail[i].size; 118986fd29aSsetje end = avail[i + 1].addr; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * Notes: 1227c478bd9Sstevel@tonic-gate * 1237c478bd9Sstevel@tonic-gate * (1) OBP on platforms with US I/II pre-allocates the hole 1247c478bd9Sstevel@tonic-gate * represented by [spec_hole_start, spec_hole_end); 1257c478bd9Sstevel@tonic-gate * pre-allocation is done to make this range unavailable 1267c478bd9Sstevel@tonic-gate * for any allocation. 1277c478bd9Sstevel@tonic-gate * 1287c478bd9Sstevel@tonic-gate * (2) OBP on starcat always pre-allocates the hole similar to 1297c478bd9Sstevel@tonic-gate * platforms with US I/II. 1307c478bd9Sstevel@tonic-gate * 1317c478bd9Sstevel@tonic-gate * (3) OBP on serengeti does _not_ pre-allocate the hole. 1327c478bd9Sstevel@tonic-gate * 1337c478bd9Sstevel@tonic-gate * (4) OBP ignores Spitfire Errata #21; i.e. it does _not_ 1347c478bd9Sstevel@tonic-gate * fill up or pre-allocate an additional 4GB on both sides 1357c478bd9Sstevel@tonic-gate * of the hole. 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * (5) kernel virtual range [spec_hole_start, spec_hole_end) 1387c478bd9Sstevel@tonic-gate * is _not_ used on any platform including those with 1397c478bd9Sstevel@tonic-gate * UltraSPARC III where there is no hole. 1407c478bd9Sstevel@tonic-gate * 1417c478bd9Sstevel@tonic-gate * Algorithm: 1427c478bd9Sstevel@tonic-gate * 1437c478bd9Sstevel@tonic-gate * Check if range [spec_hole_start, spec_hole_end) is 1447c478bd9Sstevel@tonic-gate * pre-allocated by OBP; if so, subtract that range from 1457c478bd9Sstevel@tonic-gate * allocpages. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate if (end >= spec_hole_end && start <= spec_hole_start) 1487c478bd9Sstevel@tonic-gate hole_allocated = 1; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate allocpages += btopr(end - start); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate if (hole_allocated) 1547c478bd9Sstevel@tonic-gate allocpages -= btop(spec_hole_end - spec_hole_start); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate return (allocpages); 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * Returns the max contiguous physical memory present in the 1617c478bd9Sstevel@tonic-gate * memlist "physavail". 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate uint64_t 1647c478bd9Sstevel@tonic-gate get_max_phys_size( 1657c478bd9Sstevel@tonic-gate struct memlist *physavail) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate uint64_t max_size = 0; 1687c478bd9Sstevel@tonic-gate 169*56f33205SJonathan Adams for (; physavail; physavail = physavail->ml_next) { 170*56f33205SJonathan Adams if (physavail->ml_size > max_size) 171*56f33205SJonathan Adams max_size = physavail->ml_size; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate return (max_size); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate 178986fd29aSsetje static void 179986fd29aSsetje more_pages(uint64_t base, uint64_t len) 1807c478bd9Sstevel@tonic-gate { 181986fd29aSsetje void kphysm_add(); 1827c478bd9Sstevel@tonic-gate 183986fd29aSsetje kphysm_add(base, len, 1); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 186986fd29aSsetje static void 187986fd29aSsetje less_pages(uint64_t base, uint64_t len) 188986fd29aSsetje { 189986fd29aSsetje uint64_t pa, end = base + len; 190986fd29aSsetje extern int kcage_on; 1917c478bd9Sstevel@tonic-gate 192986fd29aSsetje for (pa = base; pa < end; pa += PAGESIZE) { 193986fd29aSsetje pfn_t pfnum; 194986fd29aSsetje page_t *pp; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate pfnum = (pfn_t)(pa >> PAGESHIFT); 1977c478bd9Sstevel@tonic-gate if ((pp = page_numtopp_nolock(pfnum)) == NULL) 1987c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "missing pfnum %lx", pfnum); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * must break up any large pages that may have 2027c478bd9Sstevel@tonic-gate * constituent pages being utilized for 203986fd29aSsetje * prom_alloc()'s. page_reclaim() can't handle 2047c478bd9Sstevel@tonic-gate * large pages. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate if (pp->p_szc != 0) 2077c478bd9Sstevel@tonic-gate page_boot_demote(pp); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (!PAGE_LOCKED(pp) && pp->p_lckcnt == 0) { 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Ahhh yes, a prom page, 2127c478bd9Sstevel@tonic-gate * suck it off the freelist, 2137c478bd9Sstevel@tonic-gate * lock it, and hashin on prom_pages vp. 2147c478bd9Sstevel@tonic-gate */ 2157c478bd9Sstevel@tonic-gate if (page_trylock(pp, SE_EXCL) == 0) 2167c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "prom page locked"); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate (void) page_reclaim(pp, NULL); 2197c478bd9Sstevel@tonic-gate /* 220986fd29aSsetje * vnode offsets on the prom_ppages vnode 2217c478bd9Sstevel@tonic-gate * are page numbers (gack) for >32 bit 2227c478bd9Sstevel@tonic-gate * physical memory machines. 2237c478bd9Sstevel@tonic-gate */ 224af4c679fSSean McEnroe (void) page_hashin(pp, &promvp, 2257c478bd9Sstevel@tonic-gate (offset_t)pfnum, NULL); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (kcage_on) { 2287c478bd9Sstevel@tonic-gate ASSERT(pp->p_szc == 0); 22900e145c7Skchow if (PP_ISNORELOC(pp) == 0) { 2307c478bd9Sstevel@tonic-gate PP_SETNORELOC(pp); 23100e145c7Skchow PLCNT_XFER_NORELOC(pp); 23200e145c7Skchow } 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate (void) page_pp_lock(pp, 0, 1); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate } 237986fd29aSsetje } 238986fd29aSsetje 239986fd29aSsetje void 240986fd29aSsetje diff_memlists(struct memlist *proto, struct memlist *diff, void (*func)()) 241986fd29aSsetje { 242986fd29aSsetje uint64_t p_base, p_end, d_base, d_end; 243986fd29aSsetje 244986fd29aSsetje while (proto != NULL) { 245986fd29aSsetje /* 246986fd29aSsetje * find diff item which may overlap with proto item 247986fd29aSsetje * if none, apply func to all of proto item 248986fd29aSsetje */ 249986fd29aSsetje while (diff != NULL && 250*56f33205SJonathan Adams proto->ml_address >= diff->ml_address + diff->ml_size) 251*56f33205SJonathan Adams diff = diff->ml_next; 252986fd29aSsetje if (diff == NULL) { 253*56f33205SJonathan Adams (*func)(proto->ml_address, proto->ml_size); 254*56f33205SJonathan Adams proto = proto->ml_next; 255986fd29aSsetje continue; 256986fd29aSsetje } 257*56f33205SJonathan Adams if (proto->ml_address == diff->ml_address && 258*56f33205SJonathan Adams proto->ml_size == diff->ml_size) { 259*56f33205SJonathan Adams proto = proto->ml_next; 260*56f33205SJonathan Adams diff = diff->ml_next; 261986fd29aSsetje continue; 262986fd29aSsetje } 263986fd29aSsetje 264*56f33205SJonathan Adams p_base = proto->ml_address; 265*56f33205SJonathan Adams p_end = p_base + proto->ml_size; 266*56f33205SJonathan Adams d_base = diff->ml_address; 267*56f33205SJonathan Adams d_end = d_base + diff->ml_size; 268986fd29aSsetje /* 269986fd29aSsetje * here p_base < d_end 270986fd29aSsetje * there are 5 cases 271986fd29aSsetje */ 272986fd29aSsetje 273986fd29aSsetje /* 274986fd29aSsetje * d_end 275986fd29aSsetje * d_base 276986fd29aSsetje * p_end 277986fd29aSsetje * p_base 278986fd29aSsetje * 279986fd29aSsetje * apply func to all of proto item 280986fd29aSsetje */ 281986fd29aSsetje if (p_end <= d_base) { 282*56f33205SJonathan Adams (*func)(p_base, proto->ml_size); 283*56f33205SJonathan Adams proto = proto->ml_next; 284986fd29aSsetje continue; 285986fd29aSsetje } 286986fd29aSsetje 287986fd29aSsetje /* 288986fd29aSsetje * ... 289986fd29aSsetje * d_base 290986fd29aSsetje * p_base 291986fd29aSsetje * 292986fd29aSsetje * normalize by applying func from p_base to d_base 293986fd29aSsetje */ 294986fd29aSsetje if (p_base < d_base) 295986fd29aSsetje (*func)(p_base, d_base - p_base); 296986fd29aSsetje 297986fd29aSsetje if (p_end <= d_end) { 298986fd29aSsetje /* 299986fd29aSsetje * d_end 300986fd29aSsetje * p_end 301986fd29aSsetje * d_base 302986fd29aSsetje * p_base 303986fd29aSsetje * 304986fd29aSsetje * -or- 305986fd29aSsetje * 306986fd29aSsetje * d_end 307986fd29aSsetje * p_end 308986fd29aSsetje * p_base 309986fd29aSsetje * d_base 310986fd29aSsetje * 311986fd29aSsetje * any non-overlapping ranges applied above, 312986fd29aSsetje * so just continue 313986fd29aSsetje */ 314*56f33205SJonathan Adams proto = proto->ml_next; 315986fd29aSsetje continue; 316986fd29aSsetje } 317986fd29aSsetje 318986fd29aSsetje /* 319986fd29aSsetje * p_end 320986fd29aSsetje * d_end 321986fd29aSsetje * d_base 322986fd29aSsetje * p_base 323986fd29aSsetje * 324986fd29aSsetje * -or- 325986fd29aSsetje * 326986fd29aSsetje * p_end 327986fd29aSsetje * d_end 328986fd29aSsetje * p_base 329986fd29aSsetje * d_base 330986fd29aSsetje * 331986fd29aSsetje * Find overlapping d_base..d_end ranges, and apply func 332986fd29aSsetje * where no overlap occurs. Stop when d_base is above 333986fd29aSsetje * p_end 334986fd29aSsetje */ 335*56f33205SJonathan Adams for (p_base = d_end, diff = diff->ml_next; diff != NULL; 336*56f33205SJonathan Adams p_base = d_end, diff = diff->ml_next) { 337*56f33205SJonathan Adams d_base = diff->ml_address; 338*56f33205SJonathan Adams d_end = d_base + diff->ml_size; 339986fd29aSsetje if (p_end <= d_base) { 340986fd29aSsetje (*func)(p_base, p_end - p_base); 341986fd29aSsetje break; 342986fd29aSsetje } else 343986fd29aSsetje (*func)(p_base, d_base - p_base); 344986fd29aSsetje } 345986fd29aSsetje if (diff == NULL) 346986fd29aSsetje (*func)(p_base, p_end - p_base); 347*56f33205SJonathan Adams proto = proto->ml_next; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 351986fd29aSsetje void 352986fd29aSsetje sync_memlists(struct memlist *orig, struct memlist *new) 353986fd29aSsetje { 354986fd29aSsetje 355986fd29aSsetje /* 356986fd29aSsetje * Find pages allocated via prom by looking for 357986fd29aSsetje * pages on orig, but no on new. 358986fd29aSsetje */ 359986fd29aSsetje diff_memlists(orig, new, less_pages); 360986fd29aSsetje 361986fd29aSsetje /* 362986fd29aSsetje * Find pages free'd via prom by looking for 363986fd29aSsetje * pages on new, but not on orig. 364986fd29aSsetje */ 365986fd29aSsetje diff_memlists(new, orig, more_pages); 366986fd29aSsetje } 367986fd29aSsetje 368986fd29aSsetje 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * Find the page number of the highest installed physical 3717c478bd9Sstevel@tonic-gate * page and the number of pages installed (one cannot be 3727c478bd9Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 3737c478bd9Sstevel@tonic-gate * contiguous). 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate void 3767c478bd9Sstevel@tonic-gate installed_top_size_memlist_array( 377986fd29aSsetje prom_memlist_t *list, /* base of array */ 3787c478bd9Sstevel@tonic-gate size_t nelems, /* number of elements */ 3797c478bd9Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 3807c478bd9Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 3817c478bd9Sstevel@tonic-gate { 3827c478bd9Sstevel@tonic-gate pfn_t top = 0; 3837c478bd9Sstevel@tonic-gate pgcnt_t sumpages = 0; 3847c478bd9Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 3857c478bd9Sstevel@tonic-gate size_t i; 3867c478bd9Sstevel@tonic-gate 387986fd29aSsetje for (i = 0; i < nelems; list++, i++) { 388986fd29aSsetje highp = (list->addr + list->size - 1) >> PAGESHIFT; 3897c478bd9Sstevel@tonic-gate if (top < highp) 3907c478bd9Sstevel@tonic-gate top = highp; 391986fd29aSsetje sumpages += (list->size >> PAGESHIFT); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate *topp = top; 3957c478bd9Sstevel@tonic-gate *sumpagesp = sumpages; 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * Copy a memory list. Used in startup() to copy boot's 4007c478bd9Sstevel@tonic-gate * memory lists to the kernel. 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate void 4037c478bd9Sstevel@tonic-gate copy_memlist( 404986fd29aSsetje prom_memlist_t *src, 4057c478bd9Sstevel@tonic-gate size_t nelems, 4067c478bd9Sstevel@tonic-gate struct memlist **dstp) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate struct memlist *dst, *prev; 4097c478bd9Sstevel@tonic-gate size_t i; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate dst = *dstp; 4127c478bd9Sstevel@tonic-gate prev = dst; 4137c478bd9Sstevel@tonic-gate 414986fd29aSsetje for (i = 0; i < nelems; src++, i++) { 415*56f33205SJonathan Adams dst->ml_address = src->addr; 416*56f33205SJonathan Adams dst->ml_size = src->size; 417*56f33205SJonathan Adams dst->ml_next = 0; 4187c478bd9Sstevel@tonic-gate if (prev == dst) { 419*56f33205SJonathan Adams dst->ml_prev = 0; 4207c478bd9Sstevel@tonic-gate dst++; 4217c478bd9Sstevel@tonic-gate } else { 422*56f33205SJonathan Adams dst->ml_prev = prev; 423*56f33205SJonathan Adams prev->ml_next = dst; 4247c478bd9Sstevel@tonic-gate dst++; 4257c478bd9Sstevel@tonic-gate prev++; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate *dstp = dst; 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 432986fd29aSsetje 4337c478bd9Sstevel@tonic-gate static struct bootmem_props { 434986fd29aSsetje prom_memlist_t *ptr; 4357c478bd9Sstevel@tonic-gate size_t nelems; /* actual number of elements */ 436986fd29aSsetje size_t maxsize; /* max buffer */ 437986fd29aSsetje } bootmem_props[3]; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate #define PHYSINSTALLED 0 4407c478bd9Sstevel@tonic-gate #define PHYSAVAIL 1 4417c478bd9Sstevel@tonic-gate #define VIRTAVAIL 2 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 444986fd29aSsetje * Comapct contiguous memory list elements 4457c478bd9Sstevel@tonic-gate */ 446986fd29aSsetje static void 447986fd29aSsetje compact_promlist(struct bootmem_props *bpp) 448986fd29aSsetje { 449986fd29aSsetje int i = 0, j; 450986fd29aSsetje struct prom_memlist *pmp = bpp->ptr; 4517c478bd9Sstevel@tonic-gate 452986fd29aSsetje for (;;) { 453986fd29aSsetje if (pmp[i].addr + pmp[i].size == pmp[i+1].addr) { 454986fd29aSsetje pmp[i].size += pmp[i+1].size; 455986fd29aSsetje bpp->nelems--; 456986fd29aSsetje for (j = i + 1; j < bpp->nelems; j++) 457986fd29aSsetje pmp[j] = pmp[j+1]; 458986fd29aSsetje pmp[j].addr = 0; 459986fd29aSsetje } else 460986fd29aSsetje i++; 461986fd29aSsetje if (i == bpp->nelems) 462986fd29aSsetje break; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 466986fd29aSsetje /* 467986fd29aSsetje * Sort prom memory lists into ascending order 468986fd29aSsetje */ 469986fd29aSsetje static void 470986fd29aSsetje sort_promlist(struct bootmem_props *bpp) 471986fd29aSsetje { 472986fd29aSsetje int i, j, min; 473986fd29aSsetje struct prom_memlist *pmp = bpp->ptr; 474986fd29aSsetje struct prom_memlist temp; 475986fd29aSsetje 476986fd29aSsetje for (i = 0; i < bpp->nelems; i++) { 477986fd29aSsetje min = i; 478986fd29aSsetje 479986fd29aSsetje for (j = i+1; j < bpp->nelems; j++) { 480986fd29aSsetje if (pmp[j].addr < pmp[min].addr) 481986fd29aSsetje min = j; 482986fd29aSsetje } 483986fd29aSsetje 484986fd29aSsetje if (i != min) { 485986fd29aSsetje /* Swap pmp[i] and pmp[min] */ 486986fd29aSsetje temp = pmp[min]; 487986fd29aSsetje pmp[min] = pmp[i]; 488986fd29aSsetje pmp[i] = temp; 489986fd29aSsetje } 490986fd29aSsetje } 491986fd29aSsetje } 492986fd29aSsetje 493986fd29aSsetje static int max_bootlist_sz; 494986fd29aSsetje 495986fd29aSsetje void 496986fd29aSsetje init_boot_memlists(void) 497986fd29aSsetje { 498986fd29aSsetje size_t size, len; 499986fd29aSsetje char *start; 500986fd29aSsetje struct bootmem_props *tmp; 501986fd29aSsetje 502986fd29aSsetje /* 503986fd29aSsetje * These lists can get fragmented as the prom allocates 504986fd29aSsetje * memory, so generously round up. 505986fd29aSsetje */ 506986fd29aSsetje size = prom_phys_installed_len() + prom_phys_avail_len() + 507986fd29aSsetje prom_virt_avail_len(); 508986fd29aSsetje size *= 4; 509986fd29aSsetje size = roundup(size, PAGESIZE); 510986fd29aSsetje start = prom_alloc(0, size, BO_NO_ALIGN); 511986fd29aSsetje 512986fd29aSsetje /* 513986fd29aSsetje * Get physinstalled 514986fd29aSsetje */ 515986fd29aSsetje tmp = &bootmem_props[PHYSINSTALLED]; 516986fd29aSsetje len = prom_phys_installed_len(); 517986fd29aSsetje if (len == 0) 518986fd29aSsetje panic("no \"reg\" in /memory"); 519986fd29aSsetje tmp->nelems = len / sizeof (struct prom_memlist); 520986fd29aSsetje tmp->maxsize = len; 521986fd29aSsetje tmp->ptr = (prom_memlist_t *)start; 522986fd29aSsetje start += len; 523986fd29aSsetje size -= len; 524986fd29aSsetje (void) prom_phys_installed((caddr_t)tmp->ptr); 525986fd29aSsetje sort_promlist(tmp); 526986fd29aSsetje compact_promlist(tmp); 527986fd29aSsetje 528986fd29aSsetje /* 529986fd29aSsetje * Start out giving each half of available space 530986fd29aSsetje */ 531986fd29aSsetje max_bootlist_sz = size; 532986fd29aSsetje len = size / 2; 533986fd29aSsetje tmp = &bootmem_props[PHYSAVAIL]; 534986fd29aSsetje tmp->maxsize = len; 535986fd29aSsetje tmp->ptr = (prom_memlist_t *)start; 536986fd29aSsetje start += len; 537986fd29aSsetje 538986fd29aSsetje tmp = &bootmem_props[VIRTAVAIL]; 539986fd29aSsetje tmp->maxsize = len; 540986fd29aSsetje tmp->ptr = (prom_memlist_t *)start; 541986fd29aSsetje } 542986fd29aSsetje 543986fd29aSsetje 544986fd29aSsetje void 545986fd29aSsetje copy_boot_memlists( 546986fd29aSsetje prom_memlist_t **physinstalled, size_t *physinstalled_len, 547986fd29aSsetje prom_memlist_t **physavail, size_t *physavail_len, 548986fd29aSsetje prom_memlist_t **virtavail, size_t *virtavail_len) 549986fd29aSsetje { 550986fd29aSsetje size_t plen, vlen, move = 0; 551986fd29aSsetje struct bootmem_props *il, *pl, *vl; 552986fd29aSsetje 553986fd29aSsetje plen = prom_phys_avail_len(); 554986fd29aSsetje if (plen == 0) 555986fd29aSsetje panic("no \"available\" in /memory"); 556986fd29aSsetje vlen = prom_virt_avail_len(); 557986fd29aSsetje if (vlen == 0) 558986fd29aSsetje panic("no \"available\" in /virtual-memory"); 559986fd29aSsetje if (plen + vlen > max_bootlist_sz) 560986fd29aSsetje panic("ran out of prom_memlist space"); 561986fd29aSsetje 562986fd29aSsetje pl = &bootmem_props[PHYSAVAIL]; 563986fd29aSsetje vl = &bootmem_props[VIRTAVAIL]; 564986fd29aSsetje 565986fd29aSsetje /* 566986fd29aSsetje * re-adjust ptrs if needed 567986fd29aSsetje */ 568986fd29aSsetje if (plen > pl->maxsize) { 569986fd29aSsetje /* move virt avail up */ 570986fd29aSsetje move = plen - pl->maxsize; 571986fd29aSsetje pl->maxsize = plen; 572986fd29aSsetje vl->ptr += move / sizeof (struct prom_memlist); 573986fd29aSsetje vl->maxsize -= move; 574986fd29aSsetje } else if (vlen > vl->maxsize) { 575986fd29aSsetje /* move virt avail down */ 576986fd29aSsetje move = vlen - vl->maxsize; 577986fd29aSsetje vl->maxsize = vlen; 578986fd29aSsetje vl->ptr -= move / sizeof (struct prom_memlist); 579986fd29aSsetje pl->maxsize -= move; 580986fd29aSsetje } 581986fd29aSsetje 582986fd29aSsetje pl->nelems = plen / sizeof (struct prom_memlist); 583986fd29aSsetje vl->nelems = vlen / sizeof (struct prom_memlist); 584986fd29aSsetje 5857c478bd9Sstevel@tonic-gate /* now we can retrieve the properties */ 586986fd29aSsetje (void) prom_phys_avail((caddr_t)pl->ptr); 587986fd29aSsetje (void) prom_virt_avail((caddr_t)vl->ptr); 5887c478bd9Sstevel@tonic-gate 589986fd29aSsetje /* .. and sort them */ 590986fd29aSsetje sort_promlist(pl); 591986fd29aSsetje sort_promlist(vl); 5927c478bd9Sstevel@tonic-gate 593986fd29aSsetje il = &bootmem_props[PHYSINSTALLED]; 594986fd29aSsetje *physinstalled = il->ptr; 595986fd29aSsetje *physinstalled_len = il->nelems; 596986fd29aSsetje 597986fd29aSsetje *physavail = pl->ptr; 598986fd29aSsetje *physavail_len = pl->nelems; 599986fd29aSsetje 600986fd29aSsetje *virtavail = vl->ptr; 601986fd29aSsetje *virtavail_len = vl->nelems; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * Find the page number of the highest installed physical 6077c478bd9Sstevel@tonic-gate * page and the number of pages installed (one cannot be 6087c478bd9Sstevel@tonic-gate * calculated from the other because memory isn't necessarily 6097c478bd9Sstevel@tonic-gate * contiguous). 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate void 6127c478bd9Sstevel@tonic-gate installed_top_size( 6137c478bd9Sstevel@tonic-gate struct memlist *list, /* pointer to start of installed list */ 6147c478bd9Sstevel@tonic-gate pfn_t *topp, /* return ptr for top value */ 6157c478bd9Sstevel@tonic-gate pgcnt_t *sumpagesp) /* return prt for sum of installed pages */ 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate pfn_t top = 0; 6187c478bd9Sstevel@tonic-gate pfn_t highp; /* high page in a chunk */ 6197c478bd9Sstevel@tonic-gate pgcnt_t sumpages = 0; 6207c478bd9Sstevel@tonic-gate 621*56f33205SJonathan Adams for (; list; list = list->ml_next) { 622*56f33205SJonathan Adams highp = (list->ml_address + list->ml_size - 1) >> PAGESHIFT; 6237c478bd9Sstevel@tonic-gate if (top < highp) 6247c478bd9Sstevel@tonic-gate top = highp; 625*56f33205SJonathan Adams sumpages += (uint_t)(list->ml_size >> PAGESHIFT); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate *topp = top; 6297c478bd9Sstevel@tonic-gate *sumpagesp = sumpages; 6307c478bd9Sstevel@tonic-gate } 631