xref: /onnv-gate/usr/src/uts/sparc/os/bootops.c (revision 9956:1705cb23ec4b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55648Ssetje  * Common Development and Distribution License (the "License").
65648Ssetje  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9956SWilliam.Roche@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Definitions of interfaces that provide services from the secondary
280Sstevel@tonic-gate  * boot program to its clients (primarily Solaris, krtld, kmdb and their
290Sstevel@tonic-gate  * successors.) This interface replaces the bootops (BOP) implementation
300Sstevel@tonic-gate  * as the interface to be called by boot clients.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <sys/types.h>
355648Ssetje #include <sys/systm.h>
360Sstevel@tonic-gate #include <sys/reboot.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <sys/varargs.h>
390Sstevel@tonic-gate #include <sys/obpdefs.h>
405648Ssetje #include <sys/promimpl.h>
415648Ssetje #include <sys/prom_plat.h>
420Sstevel@tonic-gate #include <sys/bootconf.h>
430Sstevel@tonic-gate #include <sys/bootstat.h>
445648Ssetje #include <sys/kobj_impl.h>
450Sstevel@tonic-gate 
465648Ssetje struct bootops *bootops;
475648Ssetje struct bootops kbootops;
485648Ssetje 
495648Ssetje pnode_t chosennode;
50*9956SWilliam.Roche@Sun.COM /*
51*9956SWilliam.Roche@Sun.COM  * Flag to disable the use of real ramdisks (in the OBP - on Sparc) when
52*9956SWilliam.Roche@Sun.COM  * the associated memory is no longer available.
53*9956SWilliam.Roche@Sun.COM  */
54*9956SWilliam.Roche@Sun.COM int bootops_obp_ramdisk_disabled = 0;
555648Ssetje 
565648Ssetje #define	FAKE_ROOT	(pnode_t)1
575648Ssetje 
585648Ssetje struct fakeprop {
595648Ssetje 	char	*bootname;
605648Ssetje 	pnode_t	promnode;
615648Ssetje 	char	*promname;
625648Ssetje } fakeprops[] = {
635648Ssetje 	{ "mfg-name", FAKE_ROOT, "name" },
645648Ssetje 	{ NULL, 0, NULL }
655648Ssetje };
665648Ssetje 
675648Ssetje static void
fakelook_init(void)685648Ssetje fakelook_init(void)
690Sstevel@tonic-gate {
705648Ssetje 	struct fakeprop *fpp = fakeprops;
715648Ssetje 
725648Ssetje 	while (fpp->bootname != NULL) {
735648Ssetje 		switch (fpp->promnode) {
745648Ssetje 		case FAKE_ROOT:
755648Ssetje 			fpp->promnode = prom_rootnode();
765648Ssetje 			break;
775648Ssetje 		}
785648Ssetje 		fpp++;
795648Ssetje 	}
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
825648Ssetje static struct fakeprop *
fakelook(const char * prop)835648Ssetje fakelook(const char *prop)
845648Ssetje {
855648Ssetje 	struct fakeprop *fpp = fakeprops;
865648Ssetje 
875648Ssetje 	while (fpp->bootname != NULL) {
885648Ssetje 		if (strcmp(prop, fpp->bootname) == 0)
895648Ssetje 			return (fpp);
905648Ssetje 		fpp++;
915648Ssetje 	}
925648Ssetje 	return (NULL);
935648Ssetje }
945648Ssetje 
955648Ssetje ihandle_t bfs_ih = OBP_BADNODE;
965648Ssetje ihandle_t afs_ih = OBP_BADNODE;
975648Ssetje 
985648Ssetje void
bop_init(void)995648Ssetje bop_init(void)
1005648Ssetje {
1015648Ssetje 	chosennode = prom_chosennode();
1025648Ssetje 
1035648Ssetje 	fakelook_init();
1045648Ssetje 
1055648Ssetje 	/* fake bootops - it needs to point to non-NULL */
1065648Ssetje 	bootops = &kbootops;
1075648Ssetje }
1085648Ssetje 
1095648Ssetje #define	MAXPROMFD	16
1105648Ssetje 
1115648Ssetje static ihandle_t prom_ihs[MAXPROMFD];
1125648Ssetje int filter_etc = 1;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate  * Implementation of the "open" boot service.
1160Sstevel@tonic-gate  */
1175648Ssetje /*ARGSUSED*/
1180Sstevel@tonic-gate int
bop_open(const char * name,int flags)1195648Ssetje bop_open(const char *name, int flags)
1200Sstevel@tonic-gate {
1215648Ssetje 	int fd = -1, layered;
1225648Ssetje 	ihandle_t ih;
1235648Ssetje 
1245648Ssetje 	/*
1255648Ssetje 	 * Only look underneath archive for /etc files
1265648Ssetje 	 */
1275648Ssetje 	layered = filter_etc ?
1285648Ssetje 	    strncmp(name, "/etc", sizeof ("/etc") - 1) == 0 : 1;
1290Sstevel@tonic-gate 
1305648Ssetje 	if (afs_ih != OBP_BADNODE) {
1315648Ssetje 		ih = afs_ih;
1325648Ssetje 		fd = prom_fopen(ih, (char *)name);
1335648Ssetje 		if (fd == -1 && !layered)
1345648Ssetje 			return (BOOT_SVC_FAIL);
1355648Ssetje 	}
1365648Ssetje 	if (fd == -1 && bfs_ih != OBP_BADNODE) {
1375648Ssetje 		ih = bfs_ih;
1385648Ssetje 		fd = prom_fopen(ih, (char *)name);
1395648Ssetje 	}
1405648Ssetje 	if (fd == -1)
1415648Ssetje 		return (BOOT_SVC_FAIL);
1425648Ssetje 	ASSERT(fd < MAXPROMFD);
1435648Ssetje 	ASSERT(prom_ihs[fd] == 0);
1445648Ssetje 	prom_ihs[fd] = ih;
1455648Ssetje 	return (fd);
1465648Ssetje }
1470Sstevel@tonic-gate 
1485648Ssetje static void
spinner(void)1495648Ssetje spinner(void)
1505648Ssetje {
1515648Ssetje 	static int pos;
1525648Ssetje 	static char ind[] = "|/-\\";	/* that's entertainment? */
1535648Ssetje 	static int blks_read;
1545648Ssetje 
1555648Ssetje 	if ((blks_read++ & 0x3) == 0)
1565648Ssetje 		prom_printf("%c\b", ind[pos++ & 3]);
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * Implementation of the "read" boot service.
1610Sstevel@tonic-gate  */
1620Sstevel@tonic-gate int
bop_read(int fd,caddr_t buf,size_t size)1635648Ssetje bop_read(int fd, caddr_t buf, size_t size)
1640Sstevel@tonic-gate {
1655648Ssetje 	ASSERT(prom_ihs[fd] != 0);
1665648Ssetje 	spinner();
1675648Ssetje 	return (prom_fread(prom_ihs[fd], fd, buf, size));
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * Implementation of the "seek" boot service.
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate int
bop_seek(int fd,off_t off)1745648Ssetje bop_seek(int fd, off_t off)
1750Sstevel@tonic-gate {
1765648Ssetje 	ASSERT(prom_ihs[fd] != 0);
1775648Ssetje 	return (prom_fseek(prom_ihs[fd], fd, off));
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * Implementation of the "close" boot service.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate int
bop_close(int fd)1845648Ssetje bop_close(int fd)
1850Sstevel@tonic-gate {
1865648Ssetje 	ASSERT(prom_ihs[fd] != 0);
1875648Ssetje 	prom_fclose(prom_ihs[fd], fd);
1885648Ssetje 	prom_ihs[fd] = 0;
1895648Ssetje 	return (0);
1905648Ssetje }
1915648Ssetje 
1925648Ssetje /*
1935648Ssetje  * Simple temp memory allocator
1945648Ssetje  *
1955648Ssetje  * >PAGESIZE allocations are gotten directly from prom at bighand
1965648Ssetje  * smaller ones are satisfied from littlehand, which does a
1975648Ssetje  *  1 page bighand allocation when it runs out of memory
1985648Ssetje  */
1995648Ssetje static	caddr_t bighand = (caddr_t)BOOTTMPBASE;
2005648Ssetje static	caddr_t littlehand = (caddr_t)BOOTTMPBASE;
2015648Ssetje 
2025648Ssetje #define	NTMPALLOC	128
2035648Ssetje 
2045648Ssetje static	caddr_t temp_base[NTMPALLOC];
2055648Ssetje static	size_t	temp_size[NTMPALLOC];
2065648Ssetje static	int temp_indx;
2075648Ssetje 
2085648Ssetje #if defined(C_OBP)
2095648Ssetje void	cobp_free_mem(caddr_t, size_t);
2105648Ssetje #endif	/* C_OBP */
2115648Ssetje 
2125648Ssetje 
2135648Ssetje /*
2145648Ssetje  * temporary memory storage until bop_tmp_freeall is called
2155648Ssetje  * (after the kernel heap is initialized)
2165648Ssetje  */
2175648Ssetje caddr_t
bop_temp_alloc(size_t size,int align)2185648Ssetje bop_temp_alloc(size_t size, int align)
2195648Ssetje {
2205648Ssetje 	caddr_t ret;
2210Sstevel@tonic-gate 
2225648Ssetje 	/*
2235648Ssetje 	 * OBP allocs 10MB to boot, which is where virthint = 0
2245648Ssetje 	 * memory was allocated from.  Without boot, we allocate
2255648Ssetje 	 * from BOOTTMPBASE and free when we're ready to take
2265648Ssetje 	 * the machine from OBP
2275648Ssetje 	 */
2285648Ssetje 	if (size < PAGESIZE) {
2295648Ssetje 		size_t left =
2305648Ssetje 		    ALIGN(littlehand, PAGESIZE) - (uintptr_t)littlehand;
2315648Ssetje 
2325648Ssetje 		size = roundup(size, MAX(align, 8));
2335648Ssetje 		if (size <= left) {
2345648Ssetje 			ret = littlehand;
2355648Ssetje 			littlehand += size;
2365648Ssetje 			return (ret);
2375648Ssetje 		}
2385648Ssetje 		littlehand = bighand + size;
2395648Ssetje 	}
2405648Ssetje 	size = roundup(size, PAGESIZE);
2415648Ssetje 	ret = prom_alloc(bighand, size, align);
2425648Ssetje 	if (ret == NULL)
2435648Ssetje 		prom_panic("boot temp overflow");
2445648Ssetje 	bighand += size;
2450Sstevel@tonic-gate 
2465648Ssetje 	/* log it for bop_fini() */
2475648Ssetje 	temp_base[temp_indx] = ret;
2485648Ssetje 	temp_size[temp_indx] = size;
2495648Ssetje 	if (++temp_indx == NTMPALLOC)
2505648Ssetje 		prom_panic("out of bop temp space");
2515648Ssetje 
2525648Ssetje 	return (ret);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2555648Ssetje void
bop_temp_freeall(void)2565648Ssetje bop_temp_freeall(void)
2575648Ssetje {
2585648Ssetje 	int i;
2595648Ssetje 
2605648Ssetje 	/*
2615648Ssetje 	 * We have to call prom_free() with the same args
2625648Ssetje 	 * as we used in prom_alloc()
2635648Ssetje 	 */
2645648Ssetje 	for (i = 0; i < NTMPALLOC; i++) {
2655648Ssetje 		if (temp_base[i] == NULL)
2665648Ssetje 			break;
2675648Ssetje #if !defined(C_OBP)
2685648Ssetje 		prom_free(temp_base[i], temp_size[i]);
2695648Ssetje #else	/* !C_OBP */
2705648Ssetje 		cobp_free_mem(temp_base[i], temp_size[i]);
2715648Ssetje #endif	/* !C_OBP */
2725648Ssetje 	}
2735648Ssetje }
2745648Ssetje 
2755648Ssetje 
2760Sstevel@tonic-gate /*
2770Sstevel@tonic-gate  * Implementation of the "alloc" boot service.
2780Sstevel@tonic-gate  */
2790Sstevel@tonic-gate caddr_t
bop_alloc(caddr_t virthint,size_t size,int align)2805648Ssetje bop_alloc(caddr_t virthint, size_t size, int align)
2810Sstevel@tonic-gate {
2825648Ssetje 	if (virthint == NULL)
2835648Ssetje 		return (bop_temp_alloc(size, align));
2845648Ssetje 	return (prom_alloc(virthint, size, align));
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2877218Ssvemuri 
2887218Ssvemuri /*
2897218Ssvemuri  * Similar to bop_alloc functionality except that
2907218Ssvemuri  * it will try to breakup into PAGESIZE chunk allocations
2917218Ssvemuri  * if the original single chunk request failed.
2927218Ssvemuri  * This routine does not guarantee physical contig
2937218Ssvemuri  * allocation.
2947218Ssvemuri  */
2957218Ssvemuri caddr_t
bop_alloc_chunk(caddr_t virthint,size_t size,int align)2967218Ssvemuri bop_alloc_chunk(caddr_t virthint, size_t size, int align)
2977218Ssvemuri {
2987218Ssvemuri 	caddr_t ret;
2997218Ssvemuri 	size_t chunksz;
3007218Ssvemuri 
3017218Ssvemuri 	if (virthint == NULL)
3027218Ssvemuri 		return (bop_temp_alloc(size, align));
3037218Ssvemuri 
3047218Ssvemuri 	if ((ret = prom_alloc(virthint, size, align)))
3057218Ssvemuri 		return (ret);
3067218Ssvemuri 
3077218Ssvemuri 	/*
3087218Ssvemuri 	 * Normal request to prom_alloc has failed.
3097218Ssvemuri 	 * We will attempt to satisfy the request by allocating
3107218Ssvemuri 	 * smaller chunks resulting in allocation that
3117218Ssvemuri 	 * will be virtually contiguous but potentially
3127218Ssvemuri 	 * not physically contiguous. There are additional
3137218Ssvemuri 	 * requirements before we want to do this:
3147218Ssvemuri 	 * 1. virthirt must be PAGESIZE aligned.
3157218Ssvemuri 	 * 2. align must not be greater than PAGESIZE
3167218Ssvemuri 	 * 3. size request must be at least PAGESIZE
3177218Ssvemuri 	 * Otherwise, we will revert back to the original
3187218Ssvemuri 	 * bop_alloc behavior i.e. return failure.
3197218Ssvemuri 	 */
3207218Ssvemuri 	if (P2PHASE_TYPED(virthint, PAGESIZE, size_t) != 0 ||
3217218Ssvemuri 	    align > PAGESIZE || size < PAGESIZE)
3227218Ssvemuri 		return (ret);
3237218Ssvemuri 
3247218Ssvemuri 	/*
3257218Ssvemuri 	 * Now we will break up the allocation
3267218Ssvemuri 	 * request in smaller chunks that are
3277218Ssvemuri 	 * always PAGESIZE aligned.
3287218Ssvemuri 	 */
3297218Ssvemuri 	ret = virthint;
3307218Ssvemuri 	chunksz = P2ALIGN((size >> 1), PAGESIZE);
3317218Ssvemuri 	chunksz = MAX(chunksz, PAGESIZE);
3327218Ssvemuri 
3337218Ssvemuri 	while (size) {
3347218Ssvemuri 		do {
3357218Ssvemuri 			/*LINTED E_FUNC_SET_NOT_USED*/
3367218Ssvemuri 			caddr_t res;
3377218Ssvemuri 			if ((res = prom_alloc(virthint, chunksz,
3387218Ssvemuri 			    PAGESIZE))) {
3397218Ssvemuri 				ASSERT(virthint == res);
3407218Ssvemuri 				break;
3417218Ssvemuri 			}
3427218Ssvemuri 
3437218Ssvemuri 			chunksz >>= 1;
3447218Ssvemuri 			chunksz = P2ALIGN(chunksz, PAGESIZE);
3457218Ssvemuri 		} while (chunksz >= PAGESIZE);
3467218Ssvemuri 
3477218Ssvemuri 		if (chunksz < PAGESIZE)
3487218Ssvemuri 			/* Can't really happen.. */
3497218Ssvemuri 			prom_panic("bop_alloc_chunk failed");
3507218Ssvemuri 
3517218Ssvemuri 		virthint += chunksz;
3527218Ssvemuri 		size -= chunksz;
3537218Ssvemuri 		if (size < chunksz)
3547218Ssvemuri 			chunksz = size;
3557218Ssvemuri 	}
3567218Ssvemuri 	return (ret);
3577218Ssvemuri }
3587218Ssvemuri 
3597218Ssvemuri 
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate  * Implementation of the "alloc_virt" boot service
3620Sstevel@tonic-gate  */
3630Sstevel@tonic-gate caddr_t
bop_alloc_virt(caddr_t virt,size_t size)3645648Ssetje bop_alloc_virt(caddr_t virt, size_t size)
3650Sstevel@tonic-gate {
3665648Ssetje 	return (prom_claim_virt(size, virt));
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate /*
3700Sstevel@tonic-gate  * Implementation of the "free" boot service.
3710Sstevel@tonic-gate  */
3720Sstevel@tonic-gate /*ARGSUSED*/
3730Sstevel@tonic-gate void
bop_free(caddr_t virt,size_t size)3745648Ssetje bop_free(caddr_t virt, size_t size)
3750Sstevel@tonic-gate {
3765648Ssetje 	prom_free(virt, size);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate  * Implementation of the "getproplen" boot service.
3830Sstevel@tonic-gate  */
3840Sstevel@tonic-gate /*ARGSUSED*/
3850Sstevel@tonic-gate int
bop_getproplen(const char * name)3865648Ssetje bop_getproplen(const char *name)
3870Sstevel@tonic-gate {
3885648Ssetje 	struct fakeprop *fpp;
3895648Ssetje 	pnode_t node;
3905648Ssetje 	char *prop;
3910Sstevel@tonic-gate 
3925648Ssetje 	fpp = fakelook(name);
3935648Ssetje 	if (fpp != NULL) {
3945648Ssetje 		node = fpp->promnode;
3955648Ssetje 		prop = fpp->promname;
3965648Ssetje 	} else {
3975648Ssetje 		node = chosennode;
3985648Ssetje 		prop = (char *)name;
3995648Ssetje 	}
4005648Ssetje 	return (prom_getproplen(node, prop));
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate /*
4040Sstevel@tonic-gate  * Implementation of the "getprop" boot service.
4050Sstevel@tonic-gate  */
4060Sstevel@tonic-gate /*ARGSUSED*/
4070Sstevel@tonic-gate int
bop_getprop(const char * name,void * value)4085648Ssetje bop_getprop(const char *name, void *value)
4090Sstevel@tonic-gate {
4105648Ssetje 	struct fakeprop *fpp;
4115648Ssetje 	pnode_t node;
4125648Ssetje 	char *prop;
4130Sstevel@tonic-gate 
4145648Ssetje 	fpp = fakelook(name);
4155648Ssetje 	if (fpp != NULL) {
4165648Ssetje 		node = fpp->promnode;
4175648Ssetje 		prop = fpp->promname;
4185648Ssetje 	} else {
4195648Ssetje 		node = chosennode;
4205648Ssetje 		prop = (char *)name;
4215648Ssetje 	}
4225648Ssetje 	return (prom_getprop(node, prop, value));
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate /*
4265648Ssetje  * Implementation of the "print" boot service.
4270Sstevel@tonic-gate  */
4280Sstevel@tonic-gate /*ARGSUSED*/
4290Sstevel@tonic-gate void
bop_printf(void * ops,const char * fmt,...)4305648Ssetje bop_printf(void *ops, const char *fmt, ...)
4310Sstevel@tonic-gate {
4325648Ssetje 	va_list adx;
4330Sstevel@tonic-gate 
4345648Ssetje 	va_start(adx, fmt);
4355648Ssetje 	prom_vprintf(fmt, adx);
4365648Ssetje 	va_end(adx);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate /*
4405648Ssetje  * Special routine for kmdb
4410Sstevel@tonic-gate  */
4420Sstevel@tonic-gate void
bop_putsarg(const char * fmt,char * arg)4435648Ssetje bop_putsarg(const char *fmt, char *arg)
4440Sstevel@tonic-gate {
4455648Ssetje 	prom_printf(fmt, arg);
4465648Ssetje }
4470Sstevel@tonic-gate 
4485648Ssetje /*
4495648Ssetje  * panic for krtld only
4505648Ssetje  */
4515648Ssetje void
bop_panic(const char * s)4525648Ssetje bop_panic(const char *s)
4535648Ssetje {
4545648Ssetje 	prom_panic((char *)s);
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate /*
4580Sstevel@tonic-gate  * Implementation of the "mount" boot service.
4590Sstevel@tonic-gate  *
4600Sstevel@tonic-gate  */
4610Sstevel@tonic-gate /*ARGSUSED*/
4620Sstevel@tonic-gate int
bop_mountroot(void)4635648Ssetje bop_mountroot(void)
4640Sstevel@tonic-gate {
4655648Ssetje 	(void) prom_getprop(chosennode, "bootfs", (caddr_t)&bfs_ih);
4665648Ssetje 	(void) prom_getprop(chosennode, "archfs", (caddr_t)&afs_ih);
4675648Ssetje 	return ((bfs_ih == -1 && afs_ih == -1) ? BOOT_SVC_FAIL : BOOT_SVC_OK);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * Implementation of the "unmountroot" boot service.
4720Sstevel@tonic-gate  */
4730Sstevel@tonic-gate /*ARGSUSED*/
4740Sstevel@tonic-gate int
bop_unmountroot(void)4755648Ssetje bop_unmountroot(void)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 
4785648Ssetje 	if (bfs_ih != OBP_BADNODE) {
4795648Ssetje 		(void) prom_close(bfs_ih);
4805648Ssetje 		bfs_ih = OBP_BADNODE;
4815648Ssetje 	}
4825648Ssetje 	if (afs_ih != OBP_BADNODE) {
4835648Ssetje 		(void) prom_close(afs_ih);
4845648Ssetje 		afs_ih = OBP_BADNODE;
4855648Ssetje 	}
4865648Ssetje 	return (BOOT_SVC_OK);
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate /*
4900Sstevel@tonic-gate  * Implementation of the "fstat" boot service.
4910Sstevel@tonic-gate  */
4920Sstevel@tonic-gate int
bop_fstat(int fd,struct bootstat * st)4935648Ssetje bop_fstat(int fd, struct bootstat *st)
4945648Ssetje {
4955648Ssetje 	ASSERT(prom_ihs[fd] != 0);
4965648Ssetje 	return (prom_fsize(prom_ihs[fd], fd, (size_t *)&st->st_size));
4975648Ssetje }
4985648Ssetje 
4995648Ssetje int
boot_compinfo(int fd,struct compinfo * cb)5005648Ssetje boot_compinfo(int fd, struct compinfo *cb)
5015648Ssetje {
5025648Ssetje 	ASSERT(prom_ihs[fd] != 0);
5035648Ssetje 	return (prom_compinfo(prom_ihs[fd], fd,
5045648Ssetje 	    &cb->iscmp, &cb->fsize, &cb->blksize));
5055648Ssetje }
5065648Ssetje 
5075648Ssetje void
bop_free_archive(void)5085648Ssetje bop_free_archive(void)
5090Sstevel@tonic-gate {
5105648Ssetje 	char archive[OBP_MAXPATHLEN];
5115648Ssetje 	pnode_t arph;
5125648Ssetje 	uint32_t arbase, arsize, alloc_size;
5135648Ssetje 
5145648Ssetje 	/*
5155648Ssetje 	 * If the ramdisk will eventually be root, or we weren't
5165648Ssetje 	 * booted via the archive, then nothing to do here
5175648Ssetje 	 */
5185648Ssetje 	if (root_is_ramdisk == B_TRUE ||
5195648Ssetje 	    prom_getprop(chosennode, "bootarchive", archive) == -1)
5205648Ssetje 		return;
5215648Ssetje 	arph = prom_finddevice(archive);
5225648Ssetje 	if (arph == -1 ||
5235648Ssetje 	    prom_getprop(arph, OBP_ALLOCSIZE, (caddr_t)&alloc_size) == -1 ||
5245648Ssetje 	    prom_getprop(arph, OBP_SIZE, (caddr_t)&arsize) == -1 ||
5255648Ssetje 	    prom_getprop(arph, OBP_ADDRESS, (caddr_t)&arbase) == -1)
5265648Ssetje 		prom_panic("can't free boot archive");
5275648Ssetje 
528*9956SWilliam.Roche@Sun.COM 	bootops_obp_ramdisk_disabled = 1;
529*9956SWilliam.Roche@Sun.COM 
5305648Ssetje #if !defined(C_OBP)
5315648Ssetje 	if (alloc_size == 0)
5325648Ssetje 		prom_free((caddr_t)(uintptr_t)arbase, arsize);
5335648Ssetje 	else {
5345648Ssetje 		uint32_t arend = arbase + arsize;
5350Sstevel@tonic-gate 
5365648Ssetje 		while (arbase < arend) {
5375648Ssetje 			prom_free((caddr_t)(uintptr_t)arbase,
5385648Ssetje 			    MIN(alloc_size, arend - arbase));
5395648Ssetje 			arbase += alloc_size;
5405648Ssetje 		}
5415648Ssetje 	}
5425648Ssetje #else	/* !C_OBP */
5435648Ssetje 	cobp_free_mem((caddr_t)(uintptr_t)arbase, arsize);
5445648Ssetje #endif	/* !C_OBP */
5455648Ssetje }
5465648Ssetje 
5475648Ssetje #if defined(C_OBP)
5485648Ssetje /*
5495648Ssetje  * Blech.  The C proms have a bug when freeing areas that cross
5505648Ssetje  * page sizes, so we have to break up the free into sections
5515648Ssetje  * bounded by the various pagesizes.
5525648Ssetje  */
5535648Ssetje void
cobp_free_mem(caddr_t base,size_t size)5545648Ssetje cobp_free_mem(caddr_t base, size_t size)
5555648Ssetje {
5565648Ssetje 	int i;
5575648Ssetje 	size_t len, pgsz;
5585648Ssetje 
5595648Ssetje 	/*
5605648Ssetje 	 * Large pages only used when size > 512k
5615648Ssetje 	 */
5625648Ssetje 	if (size < MMU_PAGESIZE512K ||
5635648Ssetje 	    ((uintptr_t)base & MMU_PAGEOFFSET512K) != 0) {
5645648Ssetje 		prom_free(base, size);
5655648Ssetje 		return;
5665648Ssetje 	}
5675648Ssetje 	for (i = 3; i >= 0; i--) {
5685648Ssetje 		pgsz = page_get_pagesize(i);
5695648Ssetje 		if (size < pgsz)
5705648Ssetje 			continue;
5715648Ssetje 		len = size & ~(pgsz - 1);
5725648Ssetje 		prom_free(base, len);
5735648Ssetje 		base += len;
5745648Ssetje 		size -= len;
5755648Ssetje 	}
5765648Ssetje }
5775648Ssetje #endif	/* C_OBP */
5785648Ssetje 
5795648Ssetje 
5805648Ssetje /*
5815648Ssetje  * Implementation of the "enter_mon" boot service.
5825648Ssetje  */
5835648Ssetje void
bop_enter_mon(void)5845648Ssetje bop_enter_mon(void)
5855648Ssetje {
5865648Ssetje 	prom_enter_mon();
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate /*
5905648Ssetje  * free elf info allocated by booter
5910Sstevel@tonic-gate  */
5920Sstevel@tonic-gate void
bop_free_elf(void)5935648Ssetje bop_free_elf(void)
5940Sstevel@tonic-gate {
5955648Ssetje 	uint32_t eadr;
5965648Ssetje 	uint32_t esize;
5975648Ssetje 	extern Addr dynseg;
5985648Ssetje 	extern size_t dynsize;
5995648Ssetje 
6005648Ssetje 	if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1 ||
6015648Ssetje 	    bop_getprop("elfheader-length", (caddr_t)&esize) == -1)
6025648Ssetje 		prom_panic("missing elfheader");
6035648Ssetje 	prom_free((caddr_t)(uintptr_t)eadr, roundup(esize, PAGESIZE));
6045648Ssetje 
6055648Ssetje 	prom_free((caddr_t)(uintptr_t)dynseg, roundup(dynsize, PAGESIZE));
6065648Ssetje }
6075648Ssetje 
6080Sstevel@tonic-gate 
6095648Ssetje /* Simple message to indicate that the bootops pointer has been zeroed */
6105648Ssetje #ifdef DEBUG
6115648Ssetje int bootops_gone_on = 0;
6125648Ssetje #define	BOOTOPS_GONE() \
6135648Ssetje 	if (bootops_gone_on) \
6145648Ssetje 		prom_printf("The bootops vec is zeroed now!\n");
6155648Ssetje #else
6165648Ssetje #define	BOOTOPS_GONE()
6175648Ssetje #endif	/* DEBUG */
6185648Ssetje 
6195648Ssetje void
bop_fini(void)6205648Ssetje bop_fini(void)
6215648Ssetje {
6225648Ssetje 	bop_free_archive();
6235648Ssetje 	(void) bop_unmountroot();
6245648Ssetje 	bop_free_elf();
6255648Ssetje 	bop_temp_freeall();
6265648Ssetje 
6275648Ssetje 	bootops = (struct bootops *)NULL;
6285648Ssetje 	BOOTOPS_GONE();
6290Sstevel@tonic-gate }
630