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 5*903a11ebSrh87107 * Common Development and Distribution License (the "License"). 6*903a11ebSrh87107 * 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*903a11ebSrh87107 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/cpr.h> 307c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 317c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h> 327c478bd9Sstevel@tonic-gate #include "cprboot.h" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* 367c478bd9Sstevel@tonic-gate * max space for a copy of physavail data 377c478bd9Sstevel@tonic-gate * prop size is usually 80 to 128 bytes 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate #define PA_BUFSIZE 1024 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #define CB_SETBIT 1 427c478bd9Sstevel@tonic-gate #define CB_ISSET 2 437c478bd9Sstevel@tonic-gate #define CB_ISCLR 3 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * globals 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate int cb_nbitmaps; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * file scope 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate static arange_t *cb_physavail; 547c478bd9Sstevel@tonic-gate static char pabuf[PA_BUFSIZE]; 557c478bd9Sstevel@tonic-gate static caddr_t high_virt; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static cbd_t cb_bmda[CPR_MAX_BMDESC]; 587c478bd9Sstevel@tonic-gate static int tracking_init; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static int 627c478bd9Sstevel@tonic-gate cb_bitop(pfn_t ppn, int op) 637c478bd9Sstevel@tonic-gate { 647c478bd9Sstevel@tonic-gate int rel, rval = 0; 657c478bd9Sstevel@tonic-gate char *bitmap; 667c478bd9Sstevel@tonic-gate cbd_t *dp; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate for (dp = cb_bmda; dp->cbd_size; dp++) { 697c478bd9Sstevel@tonic-gate if (PPN_IN_RANGE(ppn, dp)) { 707c478bd9Sstevel@tonic-gate bitmap = (char *)dp->cbd_reg_bitmap; 717c478bd9Sstevel@tonic-gate rel = ppn - dp->cbd_spfn; 727c478bd9Sstevel@tonic-gate if (op == CB_SETBIT) 737c478bd9Sstevel@tonic-gate setbit(bitmap, rel); 747c478bd9Sstevel@tonic-gate else if (op == CB_ISSET) 757c478bd9Sstevel@tonic-gate rval = isset(bitmap, rel); 767c478bd9Sstevel@tonic-gate else if (op == CB_ISCLR) 777c478bd9Sstevel@tonic-gate rval = isclr(bitmap, rel); 787c478bd9Sstevel@tonic-gate break; 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate return (rval); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * count pages that are isolated from the kernel 887c478bd9Sstevel@tonic-gate * within each available range 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate static void 917c478bd9Sstevel@tonic-gate count_free_pages(void) 927c478bd9Sstevel@tonic-gate { 937c478bd9Sstevel@tonic-gate arange_t *arp; 947c478bd9Sstevel@tonic-gate pfn_t bitno; 957c478bd9Sstevel@tonic-gate int cnt; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate for (arp = cb_physavail; arp->high; arp++) { 987c478bd9Sstevel@tonic-gate cnt = 0; 997c478bd9Sstevel@tonic-gate for (bitno = arp->low; bitno <= arp->high; bitno++) { 1007c478bd9Sstevel@tonic-gate if (cb_bitop(bitno, CB_ISCLR)) 1017c478bd9Sstevel@tonic-gate cnt++; 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate arp->nfree = cnt; 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * scan the physavail list for a page 1107c478bd9Sstevel@tonic-gate * that doesn't clash with the kernel 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate static pfn_t 1137c478bd9Sstevel@tonic-gate search_phav_pages(void) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate static arange_t *arp; 1167c478bd9Sstevel@tonic-gate static pfn_t bitno; 1177c478bd9Sstevel@tonic-gate int rescan; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate if (arp == NULL) { 1207c478bd9Sstevel@tonic-gate count_free_pages(); 1217c478bd9Sstevel@tonic-gate arp = cb_physavail; 1227c478bd9Sstevel@tonic-gate bitno = arp->low; 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * begin scanning from the previous position and if the scan 1277c478bd9Sstevel@tonic-gate * reaches the end of the list, scan a second time from the top; 1287c478bd9Sstevel@tonic-gate * nfree is checked to eliminate scanning overhead when most 1297c478bd9Sstevel@tonic-gate * of the available space gets used up. when a page is found, 1307c478bd9Sstevel@tonic-gate * set a bit so the page wont be found by another scan. 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate for (rescan = 0; rescan < 2; rescan++) { 1337c478bd9Sstevel@tonic-gate for (; arp->high; bitno = (++arp)->low) { 1347c478bd9Sstevel@tonic-gate if (arp->nfree == 0) 1357c478bd9Sstevel@tonic-gate continue; 1367c478bd9Sstevel@tonic-gate for (; bitno <= arp->high; bitno++) { 1377c478bd9Sstevel@tonic-gate if (cb_bitop(bitno, CB_ISCLR)) { 1387c478bd9Sstevel@tonic-gate (void) cb_bitop(bitno, CB_SETBIT); 1397c478bd9Sstevel@tonic-gate arp->nfree--; 1407c478bd9Sstevel@tonic-gate return (bitno++); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate arp = cb_physavail; 1457c478bd9Sstevel@tonic-gate bitno = arp->low; 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate return (PFN_INVALID); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * scan statefile buffer pages for reusable tmp space 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate static pfn_t 1567c478bd9Sstevel@tonic-gate search_buf_pages(void) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate size_t coff, src_base; 1597c478bd9Sstevel@tonic-gate static size_t lboff; 1607c478bd9Sstevel@tonic-gate pfn_t ppn; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate if (tracking_init == 0) 1637c478bd9Sstevel@tonic-gate return (PFN_INVALID); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1667c478bd9Sstevel@tonic-gate * when scanning the list of statefile buffer ppns, we know that 1677c478bd9Sstevel@tonic-gate * all pages from lboff to the page boundary of buf_offset have 1687c478bd9Sstevel@tonic-gate * already been restored; when the associated page bit is clear, 1697c478bd9Sstevel@tonic-gate * that page is isolated from the kernel and we can reuse it for 1707c478bd9Sstevel@tonic-gate * tmp space; otherwise, when SF_DIFF_PPN indicates a page had 1717c478bd9Sstevel@tonic-gate * been moved, we know the page bit was previously clear and 1727c478bd9Sstevel@tonic-gate * later set, and we can reuse the new page. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate src_base = sfile.buf_offset & MMU_PAGEMASK; 1757c478bd9Sstevel@tonic-gate while (lboff < src_base) { 1767c478bd9Sstevel@tonic-gate coff = lboff; 1777c478bd9Sstevel@tonic-gate lboff += MMU_PAGESIZE; 1787c478bd9Sstevel@tonic-gate ppn = SF_ORIG_PPN(coff); 1797c478bd9Sstevel@tonic-gate if (cb_bitop(ppn, CB_ISCLR)) { 1807c478bd9Sstevel@tonic-gate (void) cb_bitop(ppn, CB_SETBIT); 1817c478bd9Sstevel@tonic-gate SF_STAT_INC(recycle); 1827c478bd9Sstevel@tonic-gate return (ppn); 1837c478bd9Sstevel@tonic-gate } else if (SF_DIFF_PPN(coff)) { 1847c478bd9Sstevel@tonic-gate SF_STAT_INC(recycle); 1857c478bd9Sstevel@tonic-gate return (SF_BUF_PPN(coff)); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate return (PFN_INVALID); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * scan physavail and statefile buffer page lists 1957c478bd9Sstevel@tonic-gate * for a page that doesn't clash with the kernel 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate pfn_t 1987c478bd9Sstevel@tonic-gate find_apage(void) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate pfn_t ppn; 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate ppn = search_phav_pages(); 2037c478bd9Sstevel@tonic-gate if (ppn != PFN_INVALID) 2047c478bd9Sstevel@tonic-gate return (ppn); 2057c478bd9Sstevel@tonic-gate ppn = search_buf_pages(); 2067c478bd9Sstevel@tonic-gate if (ppn != PFN_INVALID) 2077c478bd9Sstevel@tonic-gate return (ppn); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate prom_printf("\n%s: ran out of available/free pages!\n%s\n", 2107c478bd9Sstevel@tonic-gate prog, rsvp); 2117c478bd9Sstevel@tonic-gate cb_exit_to_mon(); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2147c478bd9Sstevel@tonic-gate return (PFN_INVALID); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * reserve virt range, find available phys pages, 2207c478bd9Sstevel@tonic-gate * and map-in each phys starting at vaddr 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate static caddr_t 2237c478bd9Sstevel@tonic-gate map_free_phys(caddr_t vaddr, size_t size, char *name) 2247c478bd9Sstevel@tonic-gate { 2257c478bd9Sstevel@tonic-gate int pages, ppn, err; 2267c478bd9Sstevel@tonic-gate physaddr_t phys; 2277c478bd9Sstevel@tonic-gate caddr_t virt; 2287c478bd9Sstevel@tonic-gate char *str; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate str = "map_free_phys"; 2317c478bd9Sstevel@tonic-gate virt = prom_claim_virt(size, vaddr); 23253391bafSeota CB_VPRINTF(("\n%s: claim vaddr 0x%p, size 0x%lx, ret 0x%p\n", 233*903a11ebSrh87107 str, (void *)vaddr, size, (void *)virt)); 2347c478bd9Sstevel@tonic-gate if (virt != vaddr) { 2357c478bd9Sstevel@tonic-gate prom_printf("\n%s: cant reserve (0x%p - 0x%p) for \"%s\"\n", 236*903a11ebSrh87107 str, (void *)vaddr, (void *)(vaddr + size), name); 2377c478bd9Sstevel@tonic-gate return (virt); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate for (pages = mmu_btop(size); pages--; virt += MMU_PAGESIZE) { 2417c478bd9Sstevel@tonic-gate /* 2427c478bd9Sstevel@tonic-gate * map virt page to free phys 2437c478bd9Sstevel@tonic-gate */ 2447c478bd9Sstevel@tonic-gate ppn = find_apage(); 2457c478bd9Sstevel@tonic-gate phys = PN_TO_ADDR(ppn); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate err = prom_map_phys(-1, MMU_PAGESIZE, virt, phys); 2487c478bd9Sstevel@tonic-gate if (err || verbose) { 24953391bafSeota prom_printf(" map virt 0x%p, phys 0x%llx, " 250*903a11ebSrh87107 "ppn 0x%x, ret %d\n", (void *)virt, phys, ppn, err); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate if (err) 2537c478bd9Sstevel@tonic-gate return ((caddr_t)ERR); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate return (vaddr); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * check bitmap desc and relocate bitmap data 2627c478bd9Sstevel@tonic-gate * to pages isolated from the kernel 2637c478bd9Sstevel@tonic-gate * 2647c478bd9Sstevel@tonic-gate * sets globals: 2657c478bd9Sstevel@tonic-gate * high_virt 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate int 2687c478bd9Sstevel@tonic-gate cb_set_bitmap(void) 2697c478bd9Sstevel@tonic-gate { 2707c478bd9Sstevel@tonic-gate size_t bmda_size, all_bitmap_size, alloc_size; 2717c478bd9Sstevel@tonic-gate caddr_t newvirt, src, dst, base; 2727c478bd9Sstevel@tonic-gate cbd_t *dp; 2737c478bd9Sstevel@tonic-gate char *str; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate str = "cb_set_bitmap"; 2767c478bd9Sstevel@tonic-gate CB_VPRINTF((ent_fmt, str, entry)); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * max is checked in the cpr module; 2807c478bd9Sstevel@tonic-gate * this condition should never occur 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate if (cb_nbitmaps > (CPR_MAX_BMDESC - 1)) { 2837c478bd9Sstevel@tonic-gate prom_printf("%s: too many bitmap descriptors %d, max %d\n", 2847c478bd9Sstevel@tonic-gate str, cb_nbitmaps, (CPR_MAX_BMDESC - 1)); 2857c478bd9Sstevel@tonic-gate return (ERR); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * copy bitmap descriptors to aligned space, check magic numbers, 2907c478bd9Sstevel@tonic-gate * and set the total size of all bitmaps 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate bmda_size = cb_nbitmaps * sizeof (cbd_t); 2937c478bd9Sstevel@tonic-gate src = SF_DATA(); 2947c478bd9Sstevel@tonic-gate bcopy(src, cb_bmda, bmda_size); 2957c478bd9Sstevel@tonic-gate base = src + bmda_size; 2967c478bd9Sstevel@tonic-gate all_bitmap_size = 0; 2977c478bd9Sstevel@tonic-gate for (dp = cb_bmda; dp < &cb_bmda[cb_nbitmaps]; dp++) { 2987c478bd9Sstevel@tonic-gate if (dp->cbd_magic != CPR_BITMAP_MAGIC) { 2997c478bd9Sstevel@tonic-gate prom_printf("%s: bad magic 0x%x, expect 0x%x\n", 3007c478bd9Sstevel@tonic-gate str, dp->cbd_magic, CPR_BITMAP_MAGIC); 3017c478bd9Sstevel@tonic-gate return (ERR); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate all_bitmap_size += dp->cbd_size; 3047c478bd9Sstevel@tonic-gate dp->cbd_reg_bitmap = (cpr_ptr)base; 3057c478bd9Sstevel@tonic-gate base += dp->cbd_size; 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * reserve new space for bitmaps 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate alloc_size = PAGE_ROUNDUP(all_bitmap_size); 3127c478bd9Sstevel@tonic-gate if (verbose || CPR_DBG(7)) { 3137c478bd9Sstevel@tonic-gate prom_printf("%s: nbitmaps %d, bmda_size 0x%lx\n", 31453391bafSeota str, cb_nbitmaps, bmda_size); 3157c478bd9Sstevel@tonic-gate prom_printf("%s: all_bitmap_size 0x%lx, alloc_size 0x%lx\n", 3167c478bd9Sstevel@tonic-gate str, all_bitmap_size, alloc_size); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate high_virt = (caddr_t)CB_HIGH_VIRT; 3197c478bd9Sstevel@tonic-gate newvirt = map_free_phys(high_virt, alloc_size, "bitmaps"); 3207c478bd9Sstevel@tonic-gate if (newvirt != high_virt) 3217c478bd9Sstevel@tonic-gate return (ERR); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * copy the bitmaps, clear any unused space trailing them, 3257c478bd9Sstevel@tonic-gate * and set references into the new space 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate base = src + bmda_size; 3287c478bd9Sstevel@tonic-gate dst = newvirt; 3297c478bd9Sstevel@tonic-gate bcopy(base, dst, all_bitmap_size); 3307c478bd9Sstevel@tonic-gate if (alloc_size > all_bitmap_size) 3317c478bd9Sstevel@tonic-gate bzero(dst + all_bitmap_size, alloc_size - all_bitmap_size); 3327c478bd9Sstevel@tonic-gate for (dp = cb_bmda; dp->cbd_size; dp++) { 3337c478bd9Sstevel@tonic-gate dp->cbd_reg_bitmap = (cpr_ptr)dst; 3347c478bd9Sstevel@tonic-gate dst += dp->cbd_size; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* advance past all the bitmap data */ 3387c478bd9Sstevel@tonic-gate SF_ADV(bmda_size + all_bitmap_size); 3397c478bd9Sstevel@tonic-gate high_virt += alloc_size; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate return (0); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * create a new stack for cprboot; 3477c478bd9Sstevel@tonic-gate * this stack is used to avoid clashes with kernel pages and 3487c478bd9Sstevel@tonic-gate * to avoid exceptions while remapping cprboot virt pages 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate int 3517c478bd9Sstevel@tonic-gate cb_get_newstack(void) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate caddr_t newstack; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate CB_VENTRY(cb_get_newstack); 3567c478bd9Sstevel@tonic-gate newstack = map_free_phys((caddr_t)CB_STACK_VIRT, 3577c478bd9Sstevel@tonic-gate CB_STACK_SIZE, "new stack"); 3587c478bd9Sstevel@tonic-gate if (newstack != (caddr_t)CB_STACK_VIRT) 3597c478bd9Sstevel@tonic-gate return (ERR); 3607c478bd9Sstevel@tonic-gate return (0); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * since kernel phys pages span most of the installed memory range, 3667c478bd9Sstevel@tonic-gate * some statefile buffer pages will likely clash with the kernel 3677c478bd9Sstevel@tonic-gate * and need to be moved before kernel pages are restored; a list 3687c478bd9Sstevel@tonic-gate * of buf phys page numbers is created here and later updated as 3697c478bd9Sstevel@tonic-gate * buf pages are moved 3707c478bd9Sstevel@tonic-gate * 3717c478bd9Sstevel@tonic-gate * sets globals: 3727c478bd9Sstevel@tonic-gate * sfile.buf_map 3737c478bd9Sstevel@tonic-gate * tracking_init 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate int 3767c478bd9Sstevel@tonic-gate cb_tracking_setup(void) 3777c478bd9Sstevel@tonic-gate { 3787c478bd9Sstevel@tonic-gate pfn_t ppn, lppn; 3797c478bd9Sstevel@tonic-gate uint_t *imap; 3807c478bd9Sstevel@tonic-gate caddr_t newvirt; 3817c478bd9Sstevel@tonic-gate size_t size; 3827c478bd9Sstevel@tonic-gate int pages; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate CB_VENTRY(cb_tracking_setup); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate pages = mmu_btop(sfile.size); 3877c478bd9Sstevel@tonic-gate size = PAGE_ROUNDUP(pages * sizeof (*imap)); 3887c478bd9Sstevel@tonic-gate newvirt = map_free_phys(high_virt, size, "buf tracking"); 3897c478bd9Sstevel@tonic-gate if (newvirt != high_virt) 3907c478bd9Sstevel@tonic-gate return (ERR); 3917c478bd9Sstevel@tonic-gate sfile.buf_map = (uint_t *)newvirt; 3927c478bd9Sstevel@tonic-gate high_virt += size; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * create identity map of sfile.buf phys pages 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate imap = sfile.buf_map; 3987c478bd9Sstevel@tonic-gate lppn = sfile.low_ppn + pages; 3997c478bd9Sstevel@tonic-gate for (ppn = sfile.low_ppn; ppn < lppn; ppn++, imap++) 4007c478bd9Sstevel@tonic-gate *imap = (uint_t)ppn; 4017c478bd9Sstevel@tonic-gate tracking_init = 1; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate return (0); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * get "available" prop from /memory node 4097c478bd9Sstevel@tonic-gate * 4107c478bd9Sstevel@tonic-gate * sets globals: 4117c478bd9Sstevel@tonic-gate * cb_physavail 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate int 4147c478bd9Sstevel@tonic-gate cb_get_physavail(void) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate int len, glen, scnt, need, space; 4177c478bd9Sstevel@tonic-gate char *str, *pdev, *mem_prop; 418fa9e4066Sahrens pnode_t mem_node; 4197c478bd9Sstevel@tonic-gate physaddr_t phys; 4207c478bd9Sstevel@tonic-gate pgcnt_t pages; 4217c478bd9Sstevel@tonic-gate arange_t *arp; 4227c478bd9Sstevel@tonic-gate pphav_t *pap; 4237c478bd9Sstevel@tonic-gate size_t size; 4247c478bd9Sstevel@tonic-gate pfn_t ppn; 4257c478bd9Sstevel@tonic-gate int err; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate str = "cb_get_physavail"; 4287c478bd9Sstevel@tonic-gate CB_VPRINTF((ent_fmt, str, entry)); 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* 4317c478bd9Sstevel@tonic-gate * first move cprboot pages off the physavail list 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate size = PAGE_ROUNDUP((uintptr_t)_end) - (uintptr_t)_start; 4347c478bd9Sstevel@tonic-gate ppn = cpr_vatopfn((caddr_t)_start); 4357c478bd9Sstevel@tonic-gate phys = PN_TO_ADDR(ppn); 4367c478bd9Sstevel@tonic-gate err = prom_claim_phys(size, phys); 4377c478bd9Sstevel@tonic-gate CB_VPRINTF((" text/data claim (0x%lx - 0x%lx) = %d\n", 4387c478bd9Sstevel@tonic-gate ppn, ppn + mmu_btop(size) - 1, err)); 4397c478bd9Sstevel@tonic-gate if (err) 4407c478bd9Sstevel@tonic-gate return (ERR); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate pdev = "/memory"; 4437c478bd9Sstevel@tonic-gate mem_node = prom_finddevice(pdev); 4447c478bd9Sstevel@tonic-gate if (mem_node == OBP_BADNODE) { 4457c478bd9Sstevel@tonic-gate prom_printf("%s: cant find \"%s\" node\n", str, pdev); 4467c478bd9Sstevel@tonic-gate return (ERR); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate mem_prop = "available"; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * prop data is treated as a struct array; 4527c478bd9Sstevel@tonic-gate * verify pabuf has enough room for the array 4537c478bd9Sstevel@tonic-gate * in the original and converted forms 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate len = prom_getproplen(mem_node, mem_prop); 4567c478bd9Sstevel@tonic-gate scnt = len / sizeof (*pap); 4577c478bd9Sstevel@tonic-gate need = len + (sizeof (*arp) * (scnt + 1)); 4587c478bd9Sstevel@tonic-gate space = sizeof (pabuf); 4597c478bd9Sstevel@tonic-gate CB_VPRINTF((" %s node 0x%x, len %d\n", pdev, mem_node, len)); 4607c478bd9Sstevel@tonic-gate if (len == -1 || need > space) { 4617c478bd9Sstevel@tonic-gate prom_printf("\n%s: bad \"%s\" length %d, min %d, max %d\n", 4627c478bd9Sstevel@tonic-gate str, mem_prop, len, need, space); 4637c478bd9Sstevel@tonic-gate return (ERR); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * read-in prop data and clear trailing space 4687c478bd9Sstevel@tonic-gate */ 4697c478bd9Sstevel@tonic-gate glen = prom_getprop(mem_node, mem_prop, pabuf); 4707c478bd9Sstevel@tonic-gate if (glen != len) { 47153391bafSeota prom_printf("\n%s: 0x%x,%s: expected len %d, got %d\n", 4727c478bd9Sstevel@tonic-gate str, mem_node, mem_prop, len, glen); 4737c478bd9Sstevel@tonic-gate return (ERR); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate bzero(&pabuf[len], space - len); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * convert the physavail list in place 4797c478bd9Sstevel@tonic-gate * from (phys_base, phys_size) to (low_ppn, high_ppn) 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate if (verbose) 4827c478bd9Sstevel@tonic-gate prom_printf("\nphysavail list:\n"); 4837c478bd9Sstevel@tonic-gate cb_physavail = (arange_t *)pabuf; 4847c478bd9Sstevel@tonic-gate arp = cb_physavail + scnt - 1; 4857c478bd9Sstevel@tonic-gate pap = (pphav_t *)cb_physavail + scnt - 1; 4867c478bd9Sstevel@tonic-gate for (; scnt--; pap--, arp--) { 4877c478bd9Sstevel@tonic-gate pages = mmu_btop(pap->size); 4887c478bd9Sstevel@tonic-gate arp->low = ADDR_TO_PN(pap->base); 4897c478bd9Sstevel@tonic-gate arp->high = arp->low + pages - 1; 4907c478bd9Sstevel@tonic-gate if (verbose) { 49153391bafSeota prom_printf(" %d: (0x%lx - 0x%lx),\tpages %ld\n", 4927c478bd9Sstevel@tonic-gate (int)(arp - cb_physavail), 4937c478bd9Sstevel@tonic-gate arp->low, arp->high, (arp->high - arp->low + 1)); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate return (0); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * search for an available phys page, 5037c478bd9Sstevel@tonic-gate * copy the old phys page to the new one 5047c478bd9Sstevel@tonic-gate * and remap the virt page to the new phys 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate static int 5077c478bd9Sstevel@tonic-gate move_page(caddr_t vaddr, pfn_t oldppn) 5087c478bd9Sstevel@tonic-gate { 5097c478bd9Sstevel@tonic-gate physaddr_t oldphys, newphys; 5107c478bd9Sstevel@tonic-gate pfn_t newppn; 5117c478bd9Sstevel@tonic-gate int err; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate newppn = find_apage(); 5147c478bd9Sstevel@tonic-gate newphys = PN_TO_ADDR(newppn); 5157c478bd9Sstevel@tonic-gate oldphys = PN_TO_ADDR(oldppn); 51653391bafSeota CB_VPRINTF((" remap vaddr 0x%p, old 0x%lx/0x%llx," 51753391bafSeota " new 0x%lx/0x%llx\n", 518*903a11ebSrh87107 (void *)vaddr, oldppn, oldphys, newppn, newphys)); 5197c478bd9Sstevel@tonic-gate phys_xcopy(oldphys, newphys, MMU_PAGESIZE); 5207c478bd9Sstevel@tonic-gate err = prom_remap(MMU_PAGESIZE, vaddr, newphys); 5217c478bd9Sstevel@tonic-gate if (err) 5227c478bd9Sstevel@tonic-gate prom_printf("\nmove_page: remap error\n"); 5237c478bd9Sstevel@tonic-gate return (err); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate /* 5287c478bd9Sstevel@tonic-gate * physically relocate any text/data pages that clash 5297c478bd9Sstevel@tonic-gate * with the kernel; since we're already running on 5307c478bd9Sstevel@tonic-gate * a new stack, the original stack area is skipped 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate int 5337c478bd9Sstevel@tonic-gate cb_relocate(void) 5347c478bd9Sstevel@tonic-gate { 5357c478bd9Sstevel@tonic-gate int is_ostk, is_clash, clash_cnt, ok_cnt; 5367c478bd9Sstevel@tonic-gate char *str, *desc, *skip_fmt; 5377c478bd9Sstevel@tonic-gate caddr_t ostk_low, ostk_high; 5387c478bd9Sstevel@tonic-gate caddr_t virt, saddr, eaddr; 5397c478bd9Sstevel@tonic-gate pfn_t ppn; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate str = "cb_relocate"; 5427c478bd9Sstevel@tonic-gate CB_VPRINTF((ent_fmt, str, entry)); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate ostk_low = (caddr_t)&estack - CB_STACK_SIZE; 5457c478bd9Sstevel@tonic-gate ostk_high = (caddr_t)&estack - MMU_PAGESIZE; 5467c478bd9Sstevel@tonic-gate saddr = (caddr_t)_start; 5477c478bd9Sstevel@tonic-gate eaddr = (caddr_t)PAGE_ROUNDUP((uintptr_t)_end); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate install_remap(); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate skip_fmt = " skip vaddr 0x%p, clash=%d, %s\n"; 5527c478bd9Sstevel@tonic-gate clash_cnt = ok_cnt = 0; 5537c478bd9Sstevel@tonic-gate ppn = cpr_vatopfn(saddr); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate for (virt = saddr; virt < eaddr; virt += MMU_PAGESIZE, ppn++) { 5567c478bd9Sstevel@tonic-gate is_clash = (cb_bitop(ppn, CB_ISSET) != 0); 5577c478bd9Sstevel@tonic-gate if (is_clash) 5587c478bd9Sstevel@tonic-gate clash_cnt++; 5597c478bd9Sstevel@tonic-gate else 5607c478bd9Sstevel@tonic-gate ok_cnt++; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate is_ostk = (virt >= ostk_low && virt <= ostk_high); 5637c478bd9Sstevel@tonic-gate if (is_ostk) 5647c478bd9Sstevel@tonic-gate desc = "orig stack"; 5657c478bd9Sstevel@tonic-gate else 5667c478bd9Sstevel@tonic-gate desc = "text/data"; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * page logic: 5707c478bd9Sstevel@tonic-gate * 5717c478bd9Sstevel@tonic-gate * if (original stack page) 5727c478bd9Sstevel@tonic-gate * clash doesn't matter, just skip the page 5737c478bd9Sstevel@tonic-gate * else (not original stack page) 5747c478bd9Sstevel@tonic-gate * if (no clash) 5757c478bd9Sstevel@tonic-gate * setbit to avoid later alloc and overwrite 5767c478bd9Sstevel@tonic-gate * else (clash) 5777c478bd9Sstevel@tonic-gate * relocate phys page 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate if (is_ostk) { 5807c478bd9Sstevel@tonic-gate CB_VPRINTF((skip_fmt, virt, is_clash, desc)); 5817c478bd9Sstevel@tonic-gate } else if (is_clash == 0) { 5827c478bd9Sstevel@tonic-gate CB_VPRINTF((skip_fmt, virt, is_clash, desc)); 5837c478bd9Sstevel@tonic-gate (void) cb_bitop(ppn, CB_SETBIT); 5847c478bd9Sstevel@tonic-gate } else if (move_page(virt, ppn)) 5857c478bd9Sstevel@tonic-gate return (ERR); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate CB_VPRINTF(("%s: total %d, clash %d, ok %d\n", 5887c478bd9Sstevel@tonic-gate str, clash_cnt + ok_cnt, clash_cnt, ok_cnt)); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * free original stack area for reuse 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate ppn = cpr_vatopfn(ostk_low); 5947c478bd9Sstevel@tonic-gate prom_free_phys(CB_STACK_SIZE, PN_TO_ADDR(ppn)); 5957c478bd9Sstevel@tonic-gate CB_VPRINTF(("%s: free old stack (0x%lx - 0x%lx)\n", 5967c478bd9Sstevel@tonic-gate str, ppn, ppn + mmu_btop(CB_STACK_SIZE) - 1)); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate return (0); 5997c478bd9Sstevel@tonic-gate } 600