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*903a11ebSrh  * Common Development and Distribution License (the "License").
6*903a11ebSrh  * 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*903a11ebSrh  * 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*903a11ebSrh 	    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*903a11ebSrh 		    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*903a11ebSrh 			    "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*903a11ebSrh 	    (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