xref: /onnv-gate/usr/src/uts/sparc/os/bootops.c (revision 7218:1d7c704d89d1)
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*7218Ssvemuri  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Definitions of interfaces that provide services from the secondary
300Sstevel@tonic-gate  * boot program to its clients (primarily Solaris, krtld, kmdb and their
310Sstevel@tonic-gate  * successors.) This interface replaces the bootops (BOP) implementation
320Sstevel@tonic-gate  * as the interface to be called by boot clients.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <sys/types.h>
375648Ssetje #include <sys/systm.h>
380Sstevel@tonic-gate #include <sys/reboot.h>
390Sstevel@tonic-gate #include <sys/param.h>
400Sstevel@tonic-gate #include <sys/varargs.h>
410Sstevel@tonic-gate #include <sys/obpdefs.h>
425648Ssetje #include <sys/promimpl.h>
435648Ssetje #include <sys/prom_plat.h>
440Sstevel@tonic-gate #include <sys/bootconf.h>
450Sstevel@tonic-gate #include <sys/bootstat.h>
465648Ssetje #include <sys/kobj_impl.h>
470Sstevel@tonic-gate 
485648Ssetje struct bootops *bootops;
495648Ssetje struct bootops kbootops;
505648Ssetje 
515648Ssetje pnode_t chosennode;
525648Ssetje 
535648Ssetje #define	FAKE_ROOT	(pnode_t)1
545648Ssetje 
555648Ssetje struct fakeprop {
565648Ssetje 	char	*bootname;
575648Ssetje 	pnode_t	promnode;
585648Ssetje 	char	*promname;
595648Ssetje } fakeprops[] = {
605648Ssetje 	{ "mfg-name", FAKE_ROOT, "name" },
615648Ssetje 	{ NULL, 0, NULL }
625648Ssetje };
635648Ssetje 
645648Ssetje static void
655648Ssetje fakelook_init(void)
660Sstevel@tonic-gate {
675648Ssetje 	struct fakeprop *fpp = fakeprops;
685648Ssetje 
695648Ssetje 	while (fpp->bootname != NULL) {
705648Ssetje 		switch (fpp->promnode) {
715648Ssetje 		case FAKE_ROOT:
725648Ssetje 			fpp->promnode = prom_rootnode();
735648Ssetje 			break;
745648Ssetje 		}
755648Ssetje 		fpp++;
765648Ssetje 	}
770Sstevel@tonic-gate }
780Sstevel@tonic-gate 
795648Ssetje static struct fakeprop *
805648Ssetje fakelook(const char *prop)
815648Ssetje {
825648Ssetje 	struct fakeprop *fpp = fakeprops;
835648Ssetje 
845648Ssetje 	while (fpp->bootname != NULL) {
855648Ssetje 		if (strcmp(prop, fpp->bootname) == 0)
865648Ssetje 			return (fpp);
875648Ssetje 		fpp++;
885648Ssetje 	}
895648Ssetje 	return (NULL);
905648Ssetje }
915648Ssetje 
925648Ssetje ihandle_t bfs_ih = OBP_BADNODE;
935648Ssetje ihandle_t afs_ih = OBP_BADNODE;
945648Ssetje 
955648Ssetje void
965648Ssetje bop_init(void)
975648Ssetje {
985648Ssetje 	chosennode = prom_chosennode();
995648Ssetje 
1005648Ssetje 	fakelook_init();
1015648Ssetje 
1025648Ssetje 	/* fake bootops - it needs to point to non-NULL */
1035648Ssetje 	bootops = &kbootops;
1045648Ssetje }
1055648Ssetje 
1065648Ssetje #define	MAXPROMFD	16
1075648Ssetje 
1085648Ssetje static ihandle_t prom_ihs[MAXPROMFD];
1095648Ssetje int filter_etc = 1;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * Implementation of the "open" boot service.
1130Sstevel@tonic-gate  */
1145648Ssetje /*ARGSUSED*/
1150Sstevel@tonic-gate int
1165648Ssetje bop_open(const char *name, int flags)
1170Sstevel@tonic-gate {
1185648Ssetje 	int fd = -1, layered;
1195648Ssetje 	ihandle_t ih;
1205648Ssetje 
1215648Ssetje 	/*
1225648Ssetje 	 * Only look underneath archive for /etc files
1235648Ssetje 	 */
1245648Ssetje 	layered = filter_etc ?
1255648Ssetje 	    strncmp(name, "/etc", sizeof ("/etc") - 1) == 0 : 1;
1260Sstevel@tonic-gate 
1275648Ssetje 	if (afs_ih != OBP_BADNODE) {
1285648Ssetje 		ih = afs_ih;
1295648Ssetje 		fd = prom_fopen(ih, (char *)name);
1305648Ssetje 		if (fd == -1 && !layered)
1315648Ssetje 			return (BOOT_SVC_FAIL);
1325648Ssetje 	}
1335648Ssetje 	if (fd == -1 && bfs_ih != OBP_BADNODE) {
1345648Ssetje 		ih = bfs_ih;
1355648Ssetje 		fd = prom_fopen(ih, (char *)name);
1365648Ssetje 	}
1375648Ssetje 	if (fd == -1)
1385648Ssetje 		return (BOOT_SVC_FAIL);
1395648Ssetje 	ASSERT(fd < MAXPROMFD);
1405648Ssetje 	ASSERT(prom_ihs[fd] == 0);
1415648Ssetje 	prom_ihs[fd] = ih;
1425648Ssetje 	return (fd);
1435648Ssetje }
1440Sstevel@tonic-gate 
1455648Ssetje static void
1465648Ssetje spinner(void)
1475648Ssetje {
1485648Ssetje 	static int pos;
1495648Ssetje 	static char ind[] = "|/-\\";	/* that's entertainment? */
1505648Ssetje 	static int blks_read;
1515648Ssetje 
1525648Ssetje 	if ((blks_read++ & 0x3) == 0)
1535648Ssetje 		prom_printf("%c\b", ind[pos++ & 3]);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * Implementation of the "read" boot service.
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate int
1605648Ssetje bop_read(int fd, caddr_t buf, size_t size)
1610Sstevel@tonic-gate {
1625648Ssetje 	ASSERT(prom_ihs[fd] != 0);
1635648Ssetje 	spinner();
1645648Ssetje 	return (prom_fread(prom_ihs[fd], fd, buf, size));
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate  * Implementation of the "seek" boot service.
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate int
1715648Ssetje bop_seek(int fd, off_t off)
1720Sstevel@tonic-gate {
1735648Ssetje 	ASSERT(prom_ihs[fd] != 0);
1745648Ssetje 	return (prom_fseek(prom_ihs[fd], fd, off));
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * Implementation of the "close" boot service.
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate int
1815648Ssetje bop_close(int fd)
1820Sstevel@tonic-gate {
1835648Ssetje 	ASSERT(prom_ihs[fd] != 0);
1845648Ssetje 	prom_fclose(prom_ihs[fd], fd);
1855648Ssetje 	prom_ihs[fd] = 0;
1865648Ssetje 	return (0);
1875648Ssetje }
1885648Ssetje 
1895648Ssetje /*
1905648Ssetje  * Simple temp memory allocator
1915648Ssetje  *
1925648Ssetje  * >PAGESIZE allocations are gotten directly from prom at bighand
1935648Ssetje  * smaller ones are satisfied from littlehand, which does a
1945648Ssetje  *  1 page bighand allocation when it runs out of memory
1955648Ssetje  */
1965648Ssetje static	caddr_t bighand = (caddr_t)BOOTTMPBASE;
1975648Ssetje static	caddr_t littlehand = (caddr_t)BOOTTMPBASE;
1985648Ssetje 
1995648Ssetje #define	NTMPALLOC	128
2005648Ssetje 
2015648Ssetje static	caddr_t temp_base[NTMPALLOC];
2025648Ssetje static	size_t	temp_size[NTMPALLOC];
2035648Ssetje static	int temp_indx;
2045648Ssetje 
2055648Ssetje #if defined(C_OBP)
2065648Ssetje void	cobp_free_mem(caddr_t, size_t);
2075648Ssetje #endif	/* C_OBP */
2085648Ssetje 
2095648Ssetje 
2105648Ssetje /*
2115648Ssetje  * temporary memory storage until bop_tmp_freeall is called
2125648Ssetje  * (after the kernel heap is initialized)
2135648Ssetje  */
2145648Ssetje caddr_t
2155648Ssetje bop_temp_alloc(size_t size, int align)
2165648Ssetje {
2175648Ssetje 	caddr_t ret;
2180Sstevel@tonic-gate 
2195648Ssetje 	/*
2205648Ssetje 	 * OBP allocs 10MB to boot, which is where virthint = 0
2215648Ssetje 	 * memory was allocated from.  Without boot, we allocate
2225648Ssetje 	 * from BOOTTMPBASE and free when we're ready to take
2235648Ssetje 	 * the machine from OBP
2245648Ssetje 	 */
2255648Ssetje 	if (size < PAGESIZE) {
2265648Ssetje 		size_t left =
2275648Ssetje 		    ALIGN(littlehand, PAGESIZE) - (uintptr_t)littlehand;
2285648Ssetje 
2295648Ssetje 		size = roundup(size, MAX(align, 8));
2305648Ssetje 		if (size <= left) {
2315648Ssetje 			ret = littlehand;
2325648Ssetje 			littlehand += size;
2335648Ssetje 			return (ret);
2345648Ssetje 		}
2355648Ssetje 		littlehand = bighand + size;
2365648Ssetje 	}
2375648Ssetje 	size = roundup(size, PAGESIZE);
2385648Ssetje 	ret = prom_alloc(bighand, size, align);
2395648Ssetje 	if (ret == NULL)
2405648Ssetje 		prom_panic("boot temp overflow");
2415648Ssetje 	bighand += size;
2420Sstevel@tonic-gate 
2435648Ssetje 	/* log it for bop_fini() */
2445648Ssetje 	temp_base[temp_indx] = ret;
2455648Ssetje 	temp_size[temp_indx] = size;
2465648Ssetje 	if (++temp_indx == NTMPALLOC)
2475648Ssetje 		prom_panic("out of bop temp space");
2485648Ssetje 
2495648Ssetje 	return (ret);
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate 
2525648Ssetje void
2535648Ssetje bop_temp_freeall(void)
2545648Ssetje {
2555648Ssetje 	int i;
2565648Ssetje 
2575648Ssetje 	/*
2585648Ssetje 	 * We have to call prom_free() with the same args
2595648Ssetje 	 * as we used in prom_alloc()
2605648Ssetje 	 */
2615648Ssetje 	for (i = 0; i < NTMPALLOC; i++) {
2625648Ssetje 		if (temp_base[i] == NULL)
2635648Ssetje 			break;
2645648Ssetje #if !defined(C_OBP)
2655648Ssetje 		prom_free(temp_base[i], temp_size[i]);
2665648Ssetje #else	/* !C_OBP */
2675648Ssetje 		cobp_free_mem(temp_base[i], temp_size[i]);
2685648Ssetje #endif	/* !C_OBP */
2695648Ssetje 	}
2705648Ssetje }
2715648Ssetje 
2725648Ssetje 
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate  * Implementation of the "alloc" boot service.
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate caddr_t
2775648Ssetje bop_alloc(caddr_t virthint, size_t size, int align)
2780Sstevel@tonic-gate {
2795648Ssetje 	if (virthint == NULL)
2805648Ssetje 		return (bop_temp_alloc(size, align));
2815648Ssetje 	return (prom_alloc(virthint, size, align));
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
284*7218Ssvemuri 
285*7218Ssvemuri /*
286*7218Ssvemuri  * Similar to bop_alloc functionality except that
287*7218Ssvemuri  * it will try to breakup into PAGESIZE chunk allocations
288*7218Ssvemuri  * if the original single chunk request failed.
289*7218Ssvemuri  * This routine does not guarantee physical contig
290*7218Ssvemuri  * allocation.
291*7218Ssvemuri  */
292*7218Ssvemuri caddr_t
293*7218Ssvemuri bop_alloc_chunk(caddr_t virthint, size_t size, int align)
294*7218Ssvemuri {
295*7218Ssvemuri 	caddr_t ret;
296*7218Ssvemuri 	size_t chunksz;
297*7218Ssvemuri 
298*7218Ssvemuri 	if (virthint == NULL)
299*7218Ssvemuri 		return (bop_temp_alloc(size, align));
300*7218Ssvemuri 
301*7218Ssvemuri 	if ((ret = prom_alloc(virthint, size, align)))
302*7218Ssvemuri 		return (ret);
303*7218Ssvemuri 
304*7218Ssvemuri 	/*
305*7218Ssvemuri 	 * Normal request to prom_alloc has failed.
306*7218Ssvemuri 	 * We will attempt to satisfy the request by allocating
307*7218Ssvemuri 	 * smaller chunks resulting in allocation that
308*7218Ssvemuri 	 * will be virtually contiguous but potentially
309*7218Ssvemuri 	 * not physically contiguous. There are additional
310*7218Ssvemuri 	 * requirements before we want to do this:
311*7218Ssvemuri 	 * 1. virthirt must be PAGESIZE aligned.
312*7218Ssvemuri 	 * 2. align must not be greater than PAGESIZE
313*7218Ssvemuri 	 * 3. size request must be at least PAGESIZE
314*7218Ssvemuri 	 * Otherwise, we will revert back to the original
315*7218Ssvemuri 	 * bop_alloc behavior i.e. return failure.
316*7218Ssvemuri 	 */
317*7218Ssvemuri 	if (P2PHASE_TYPED(virthint, PAGESIZE, size_t) != 0 ||
318*7218Ssvemuri 	    align > PAGESIZE || size < PAGESIZE)
319*7218Ssvemuri 		return (ret);
320*7218Ssvemuri 
321*7218Ssvemuri 	/*
322*7218Ssvemuri 	 * Now we will break up the allocation
323*7218Ssvemuri 	 * request in smaller chunks that are
324*7218Ssvemuri 	 * always PAGESIZE aligned.
325*7218Ssvemuri 	 */
326*7218Ssvemuri 	ret = virthint;
327*7218Ssvemuri 	chunksz = P2ALIGN((size >> 1), PAGESIZE);
328*7218Ssvemuri 	chunksz = MAX(chunksz, PAGESIZE);
329*7218Ssvemuri 
330*7218Ssvemuri 	while (size) {
331*7218Ssvemuri 		do {
332*7218Ssvemuri 			/*LINTED E_FUNC_SET_NOT_USED*/
333*7218Ssvemuri 			caddr_t res;
334*7218Ssvemuri 			if ((res = prom_alloc(virthint, chunksz,
335*7218Ssvemuri 			    PAGESIZE))) {
336*7218Ssvemuri 				ASSERT(virthint == res);
337*7218Ssvemuri 				break;
338*7218Ssvemuri 			}
339*7218Ssvemuri 
340*7218Ssvemuri 			chunksz >>= 1;
341*7218Ssvemuri 			chunksz = P2ALIGN(chunksz, PAGESIZE);
342*7218Ssvemuri 		} while (chunksz >= PAGESIZE);
343*7218Ssvemuri 
344*7218Ssvemuri 		if (chunksz < PAGESIZE)
345*7218Ssvemuri 			/* Can't really happen.. */
346*7218Ssvemuri 			prom_panic("bop_alloc_chunk failed");
347*7218Ssvemuri 
348*7218Ssvemuri 		virthint += chunksz;
349*7218Ssvemuri 		size -= chunksz;
350*7218Ssvemuri 		if (size < chunksz)
351*7218Ssvemuri 			chunksz = size;
352*7218Ssvemuri 	}
353*7218Ssvemuri 	return (ret);
354*7218Ssvemuri }
355*7218Ssvemuri 
356*7218Ssvemuri 
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate  * Implementation of the "alloc_virt" boot service
3590Sstevel@tonic-gate  */
3600Sstevel@tonic-gate caddr_t
3615648Ssetje bop_alloc_virt(caddr_t virt, size_t size)
3620Sstevel@tonic-gate {
3635648Ssetje 	return (prom_claim_virt(size, virt));
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate /*
3670Sstevel@tonic-gate  * Implementation of the "free" boot service.
3680Sstevel@tonic-gate  */
3690Sstevel@tonic-gate /*ARGSUSED*/
3700Sstevel@tonic-gate void
3715648Ssetje bop_free(caddr_t virt, size_t size)
3720Sstevel@tonic-gate {
3735648Ssetje 	prom_free(virt, size);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate  * Implementation of the "getproplen" boot service.
3800Sstevel@tonic-gate  */
3810Sstevel@tonic-gate /*ARGSUSED*/
3820Sstevel@tonic-gate int
3835648Ssetje bop_getproplen(const char *name)
3840Sstevel@tonic-gate {
3855648Ssetje 	struct fakeprop *fpp;
3865648Ssetje 	pnode_t node;
3875648Ssetje 	char *prop;
3880Sstevel@tonic-gate 
3895648Ssetje 	fpp = fakelook(name);
3905648Ssetje 	if (fpp != NULL) {
3915648Ssetje 		node = fpp->promnode;
3925648Ssetje 		prop = fpp->promname;
3935648Ssetje 	} else {
3945648Ssetje 		node = chosennode;
3955648Ssetje 		prop = (char *)name;
3965648Ssetje 	}
3975648Ssetje 	return (prom_getproplen(node, prop));
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate  * Implementation of the "getprop" boot service.
4020Sstevel@tonic-gate  */
4030Sstevel@tonic-gate /*ARGSUSED*/
4040Sstevel@tonic-gate int
4055648Ssetje bop_getprop(const char *name, void *value)
4060Sstevel@tonic-gate {
4075648Ssetje 	struct fakeprop *fpp;
4085648Ssetje 	pnode_t node;
4095648Ssetje 	char *prop;
4100Sstevel@tonic-gate 
4115648Ssetje 	fpp = fakelook(name);
4125648Ssetje 	if (fpp != NULL) {
4135648Ssetje 		node = fpp->promnode;
4145648Ssetje 		prop = fpp->promname;
4155648Ssetje 	} else {
4165648Ssetje 		node = chosennode;
4175648Ssetje 		prop = (char *)name;
4185648Ssetje 	}
4195648Ssetje 	return (prom_getprop(node, prop, value));
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*
4235648Ssetje  * Implementation of the "print" boot service.
4240Sstevel@tonic-gate  */
4250Sstevel@tonic-gate /*ARGSUSED*/
4260Sstevel@tonic-gate void
4275648Ssetje bop_printf(void *ops, const char *fmt, ...)
4280Sstevel@tonic-gate {
4295648Ssetje 	va_list adx;
4300Sstevel@tonic-gate 
4315648Ssetje 	va_start(adx, fmt);
4325648Ssetje 	prom_vprintf(fmt, adx);
4335648Ssetje 	va_end(adx);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate /*
4375648Ssetje  * Special routine for kmdb
4380Sstevel@tonic-gate  */
4390Sstevel@tonic-gate void
4405648Ssetje bop_putsarg(const char *fmt, char *arg)
4410Sstevel@tonic-gate {
4425648Ssetje 	prom_printf(fmt, arg);
4435648Ssetje }
4440Sstevel@tonic-gate 
4455648Ssetje /*
4465648Ssetje  * panic for krtld only
4475648Ssetje  */
4485648Ssetje void
4495648Ssetje bop_panic(const char *s)
4505648Ssetje {
4515648Ssetje 	prom_panic((char *)s);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate  * Implementation of the "mount" boot service.
4560Sstevel@tonic-gate  *
4570Sstevel@tonic-gate  */
4580Sstevel@tonic-gate /*ARGSUSED*/
4590Sstevel@tonic-gate int
4605648Ssetje bop_mountroot(void)
4610Sstevel@tonic-gate {
4625648Ssetje 	(void) prom_getprop(chosennode, "bootfs", (caddr_t)&bfs_ih);
4635648Ssetje 	(void) prom_getprop(chosennode, "archfs", (caddr_t)&afs_ih);
4645648Ssetje 	return ((bfs_ih == -1 && afs_ih == -1) ? BOOT_SVC_FAIL : BOOT_SVC_OK);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate  * Implementation of the "unmountroot" boot service.
4690Sstevel@tonic-gate  */
4700Sstevel@tonic-gate /*ARGSUSED*/
4710Sstevel@tonic-gate int
4725648Ssetje bop_unmountroot(void)
4730Sstevel@tonic-gate {
4740Sstevel@tonic-gate 
4755648Ssetje 	if (bfs_ih != OBP_BADNODE) {
4765648Ssetje 		(void) prom_close(bfs_ih);
4775648Ssetje 		bfs_ih = OBP_BADNODE;
4785648Ssetje 	}
4795648Ssetje 	if (afs_ih != OBP_BADNODE) {
4805648Ssetje 		(void) prom_close(afs_ih);
4815648Ssetje 		afs_ih = OBP_BADNODE;
4825648Ssetje 	}
4835648Ssetje 	return (BOOT_SVC_OK);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate /*
4870Sstevel@tonic-gate  * Implementation of the "fstat" boot service.
4880Sstevel@tonic-gate  */
4890Sstevel@tonic-gate int
4905648Ssetje bop_fstat(int fd, struct bootstat *st)
4915648Ssetje {
4925648Ssetje 	ASSERT(prom_ihs[fd] != 0);
4935648Ssetje 	return (prom_fsize(prom_ihs[fd], fd, (size_t *)&st->st_size));
4945648Ssetje }
4955648Ssetje 
4965648Ssetje int
4975648Ssetje boot_compinfo(int fd, struct compinfo *cb)
4985648Ssetje {
4995648Ssetje 	ASSERT(prom_ihs[fd] != 0);
5005648Ssetje 	return (prom_compinfo(prom_ihs[fd], fd,
5015648Ssetje 	    &cb->iscmp, &cb->fsize, &cb->blksize));
5025648Ssetje }
5035648Ssetje 
5045648Ssetje void
5055648Ssetje bop_free_archive(void)
5060Sstevel@tonic-gate {
5075648Ssetje 	char archive[OBP_MAXPATHLEN];
5085648Ssetje 	pnode_t arph;
5095648Ssetje 	uint32_t arbase, arsize, alloc_size;
5105648Ssetje 
5115648Ssetje 	/*
5125648Ssetje 	 * If the ramdisk will eventually be root, or we weren't
5135648Ssetje 	 * booted via the archive, then nothing to do here
5145648Ssetje 	 */
5155648Ssetje 	if (root_is_ramdisk == B_TRUE ||
5165648Ssetje 	    prom_getprop(chosennode, "bootarchive", archive) == -1)
5175648Ssetje 		return;
5185648Ssetje 	arph = prom_finddevice(archive);
5195648Ssetje 	if (arph == -1 ||
5205648Ssetje 	    prom_getprop(arph, OBP_ALLOCSIZE, (caddr_t)&alloc_size) == -1 ||
5215648Ssetje 	    prom_getprop(arph, OBP_SIZE, (caddr_t)&arsize) == -1 ||
5225648Ssetje 	    prom_getprop(arph, OBP_ADDRESS, (caddr_t)&arbase) == -1)
5235648Ssetje 		prom_panic("can't free boot archive");
5245648Ssetje 
5255648Ssetje #if !defined(C_OBP)
5265648Ssetje 	if (alloc_size == 0)
5275648Ssetje 		prom_free((caddr_t)(uintptr_t)arbase, arsize);
5285648Ssetje 	else {
5295648Ssetje 		uint32_t arend = arbase + arsize;
5300Sstevel@tonic-gate 
5315648Ssetje 		while (arbase < arend) {
5325648Ssetje 			prom_free((caddr_t)(uintptr_t)arbase,
5335648Ssetje 			    MIN(alloc_size, arend - arbase));
5345648Ssetje 			arbase += alloc_size;
5355648Ssetje 		}
5365648Ssetje 	}
5375648Ssetje #else	/* !C_OBP */
5385648Ssetje 	cobp_free_mem((caddr_t)(uintptr_t)arbase, arsize);
5395648Ssetje #endif	/* !C_OBP */
5405648Ssetje }
5415648Ssetje 
5425648Ssetje #if defined(C_OBP)
5435648Ssetje /*
5445648Ssetje  * Blech.  The C proms have a bug when freeing areas that cross
5455648Ssetje  * page sizes, so we have to break up the free into sections
5465648Ssetje  * bounded by the various pagesizes.
5475648Ssetje  */
5485648Ssetje void
5495648Ssetje cobp_free_mem(caddr_t base, size_t size)
5505648Ssetje {
5515648Ssetje 	int i;
5525648Ssetje 	size_t len, pgsz;
5535648Ssetje 
5545648Ssetje 	/*
5555648Ssetje 	 * Large pages only used when size > 512k
5565648Ssetje 	 */
5575648Ssetje 	if (size < MMU_PAGESIZE512K ||
5585648Ssetje 	    ((uintptr_t)base & MMU_PAGEOFFSET512K) != 0) {
5595648Ssetje 		prom_free(base, size);
5605648Ssetje 		return;
5615648Ssetje 	}
5625648Ssetje 	for (i = 3; i >= 0; i--) {
5635648Ssetje 		pgsz = page_get_pagesize(i);
5645648Ssetje 		if (size < pgsz)
5655648Ssetje 			continue;
5665648Ssetje 		len = size & ~(pgsz - 1);
5675648Ssetje 		prom_free(base, len);
5685648Ssetje 		base += len;
5695648Ssetje 		size -= len;
5705648Ssetje 	}
5715648Ssetje }
5725648Ssetje #endif	/* C_OBP */
5735648Ssetje 
5745648Ssetje 
5755648Ssetje /*
5765648Ssetje  * Implementation of the "enter_mon" boot service.
5775648Ssetje  */
5785648Ssetje void
5795648Ssetje bop_enter_mon(void)
5805648Ssetje {
5815648Ssetje 	prom_enter_mon();
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate /*
5855648Ssetje  * free elf info allocated by booter
5860Sstevel@tonic-gate  */
5870Sstevel@tonic-gate void
5885648Ssetje bop_free_elf(void)
5890Sstevel@tonic-gate {
5905648Ssetje 	uint32_t eadr;
5915648Ssetje 	uint32_t esize;
5925648Ssetje 	extern Addr dynseg;
5935648Ssetje 	extern size_t dynsize;
5945648Ssetje 
5955648Ssetje 	if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1 ||
5965648Ssetje 	    bop_getprop("elfheader-length", (caddr_t)&esize) == -1)
5975648Ssetje 		prom_panic("missing elfheader");
5985648Ssetje 	prom_free((caddr_t)(uintptr_t)eadr, roundup(esize, PAGESIZE));
5995648Ssetje 
6005648Ssetje 	prom_free((caddr_t)(uintptr_t)dynseg, roundup(dynsize, PAGESIZE));
6015648Ssetje }
6025648Ssetje 
6030Sstevel@tonic-gate 
6045648Ssetje /* Simple message to indicate that the bootops pointer has been zeroed */
6055648Ssetje #ifdef DEBUG
6065648Ssetje int bootops_gone_on = 0;
6075648Ssetje #define	BOOTOPS_GONE() \
6085648Ssetje 	if (bootops_gone_on) \
6095648Ssetje 		prom_printf("The bootops vec is zeroed now!\n");
6105648Ssetje #else
6115648Ssetje #define	BOOTOPS_GONE()
6125648Ssetje #endif	/* DEBUG */
6135648Ssetje 
6145648Ssetje void
6155648Ssetje bop_fini(void)
6165648Ssetje {
6175648Ssetje 	bop_free_archive();
6185648Ssetje 	(void) bop_unmountroot();
6195648Ssetje 	bop_free_elf();
6205648Ssetje 	bop_temp_freeall();
6215648Ssetje 
6225648Ssetje 	bootops = (struct bootops *)NULL;
6235648Ssetje 	BOOTOPS_GONE();
6240Sstevel@tonic-gate }
625