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
cb_bitop(pfn_t ppn,int op)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
count_free_pages(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
search_phav_pages(void)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
search_buf_pages(void)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
find_apage(void)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
map_free_phys(caddr_t vaddr,size_t size,char * name)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
cb_set_bitmap(void)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
cb_get_newstack(void)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
cb_tracking_setup(void)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
cb_get_physavail(void)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
move_page(caddr_t vaddr,pfn_t oldppn)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
cb_relocate(void)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