xref: /titanic_44/usr/src/uts/sparc/os/bootops.c (revision ca622e3ab18bb72e81149987556769fb415fb5da)
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
5986fd29aSsetje  * Common Development and Distribution License (the "License").
6986fd29aSsetje  * 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*ca622e3aSsvemuri  * 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 /*
297c478bd9Sstevel@tonic-gate  * Definitions of interfaces that provide services from the secondary
307c478bd9Sstevel@tonic-gate  * boot program to its clients (primarily Solaris, krtld, kmdb and their
317c478bd9Sstevel@tonic-gate  * successors.) This interface replaces the bootops (BOP) implementation
327c478bd9Sstevel@tonic-gate  * as the interface to be called by boot clients.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
37986fd29aSsetje #include <sys/systm.h>
387c478bd9Sstevel@tonic-gate #include <sys/reboot.h>
397c478bd9Sstevel@tonic-gate #include <sys/param.h>
407c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
417c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
42986fd29aSsetje #include <sys/promimpl.h>
43986fd29aSsetje #include <sys/prom_plat.h>
447c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
457c478bd9Sstevel@tonic-gate #include <sys/bootstat.h>
46986fd29aSsetje #include <sys/kobj_impl.h>
477c478bd9Sstevel@tonic-gate 
48986fd29aSsetje struct bootops *bootops;
49986fd29aSsetje struct bootops kbootops;
50986fd29aSsetje 
51986fd29aSsetje pnode_t chosennode;
52986fd29aSsetje 
53986fd29aSsetje #define	FAKE_ROOT	(pnode_t)1
54986fd29aSsetje 
55986fd29aSsetje struct fakeprop {
56986fd29aSsetje 	char	*bootname;
57986fd29aSsetje 	pnode_t	promnode;
58986fd29aSsetje 	char	*promname;
59986fd29aSsetje } fakeprops[] = {
60986fd29aSsetje 	{ "mfg-name", FAKE_ROOT, "name" },
61986fd29aSsetje 	{ NULL, 0, NULL }
62986fd29aSsetje };
63986fd29aSsetje 
64986fd29aSsetje static void
65986fd29aSsetje fakelook_init(void)
667c478bd9Sstevel@tonic-gate {
67986fd29aSsetje 	struct fakeprop *fpp = fakeprops;
68986fd29aSsetje 
69986fd29aSsetje 	while (fpp->bootname != NULL) {
70986fd29aSsetje 		switch (fpp->promnode) {
71986fd29aSsetje 		case FAKE_ROOT:
72986fd29aSsetje 			fpp->promnode = prom_rootnode();
73986fd29aSsetje 			break;
74986fd29aSsetje 		}
75986fd29aSsetje 		fpp++;
76986fd29aSsetje 	}
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
79986fd29aSsetje static struct fakeprop *
80986fd29aSsetje fakelook(const char *prop)
81986fd29aSsetje {
82986fd29aSsetje 	struct fakeprop *fpp = fakeprops;
83986fd29aSsetje 
84986fd29aSsetje 	while (fpp->bootname != NULL) {
85986fd29aSsetje 		if (strcmp(prop, fpp->bootname) == 0)
86986fd29aSsetje 			return (fpp);
87986fd29aSsetje 		fpp++;
88986fd29aSsetje 	}
89986fd29aSsetje 	return (NULL);
90986fd29aSsetje }
91986fd29aSsetje 
92986fd29aSsetje ihandle_t bfs_ih = OBP_BADNODE;
93986fd29aSsetje ihandle_t afs_ih = OBP_BADNODE;
94986fd29aSsetje 
95986fd29aSsetje void
96986fd29aSsetje bop_init(void)
97986fd29aSsetje {
98986fd29aSsetje 	chosennode = prom_chosennode();
99986fd29aSsetje 
100986fd29aSsetje 	fakelook_init();
101986fd29aSsetje 
102986fd29aSsetje 	/* fake bootops - it needs to point to non-NULL */
103986fd29aSsetje 	bootops = &kbootops;
104986fd29aSsetje }
105986fd29aSsetje 
106986fd29aSsetje #define	MAXPROMFD	16
107986fd29aSsetje 
108986fd29aSsetje static ihandle_t prom_ihs[MAXPROMFD];
109986fd29aSsetje int filter_etc = 1;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Implementation of the "open" boot service.
1137c478bd9Sstevel@tonic-gate  */
114986fd29aSsetje /*ARGSUSED*/
1157c478bd9Sstevel@tonic-gate int
116986fd29aSsetje bop_open(const char *name, int flags)
1177c478bd9Sstevel@tonic-gate {
118986fd29aSsetje 	int fd = -1, layered;
119986fd29aSsetje 	ihandle_t ih;
1207c478bd9Sstevel@tonic-gate 
121986fd29aSsetje 	/*
122986fd29aSsetje 	 * Only look underneath archive for /etc files
123986fd29aSsetje 	 */
124986fd29aSsetje 	layered = filter_etc ?
125986fd29aSsetje 	    strncmp(name, "/etc", sizeof ("/etc") - 1) == 0 : 1;
1267c478bd9Sstevel@tonic-gate 
127986fd29aSsetje 	if (afs_ih != OBP_BADNODE) {
128986fd29aSsetje 		ih = afs_ih;
129986fd29aSsetje 		fd = prom_fopen(ih, (char *)name);
130986fd29aSsetje 		if (fd == -1 && !layered)
131986fd29aSsetje 			return (BOOT_SVC_FAIL);
132986fd29aSsetje 	}
133986fd29aSsetje 	if (fd == -1 && bfs_ih != OBP_BADNODE) {
134986fd29aSsetje 		ih = bfs_ih;
135986fd29aSsetje 		fd = prom_fopen(ih, (char *)name);
136986fd29aSsetje 	}
137986fd29aSsetje 	if (fd == -1)
138986fd29aSsetje 		return (BOOT_SVC_FAIL);
139986fd29aSsetje 	ASSERT(fd < MAXPROMFD);
140986fd29aSsetje 	ASSERT(prom_ihs[fd] == 0);
141986fd29aSsetje 	prom_ihs[fd] = ih;
142986fd29aSsetje 	return (fd);
143986fd29aSsetje }
144986fd29aSsetje 
145986fd29aSsetje static void
146986fd29aSsetje spinner(void)
147986fd29aSsetje {
148986fd29aSsetje 	static int pos;
149986fd29aSsetje 	static char ind[] = "|/-\\";	/* that's entertainment? */
150986fd29aSsetje 	static int blks_read;
151986fd29aSsetje 
152986fd29aSsetje 	if ((blks_read++ & 0x3) == 0)
153986fd29aSsetje 		prom_printf("%c\b", ind[pos++ & 3]);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * Implementation of the "read" boot service.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate int
160986fd29aSsetje bop_read(int fd, caddr_t buf, size_t size)
1617c478bd9Sstevel@tonic-gate {
162986fd29aSsetje 	ASSERT(prom_ihs[fd] != 0);
163986fd29aSsetje 	spinner();
164986fd29aSsetje 	return (prom_fread(prom_ihs[fd], fd, buf, size));
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Implementation of the "seek" boot service.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate int
171986fd29aSsetje bop_seek(int fd, off_t off)
1727c478bd9Sstevel@tonic-gate {
173986fd29aSsetje 	ASSERT(prom_ihs[fd] != 0);
174986fd29aSsetje 	return (prom_fseek(prom_ihs[fd], fd, off));
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * Implementation of the "close" boot service.
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate int
181986fd29aSsetje bop_close(int fd)
1827c478bd9Sstevel@tonic-gate {
183986fd29aSsetje 	ASSERT(prom_ihs[fd] != 0);
184986fd29aSsetje 	prom_fclose(prom_ihs[fd], fd);
185986fd29aSsetje 	prom_ihs[fd] = 0;
186986fd29aSsetje 	return (0);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
190986fd29aSsetje  * Simple temp memory allocator
1917c478bd9Sstevel@tonic-gate  *
192986fd29aSsetje  * >PAGESIZE allocations are gotten directly from prom at bighand
193986fd29aSsetje  * smaller ones are satisfied from littlehand, which does a
194986fd29aSsetje  *  1 page bighand allocation when it runs out of memory
195986fd29aSsetje  */
196986fd29aSsetje static	caddr_t bighand = (caddr_t)BOOTTMPBASE;
197986fd29aSsetje static	caddr_t littlehand = (caddr_t)BOOTTMPBASE;
198986fd29aSsetje 
199986fd29aSsetje #define	NTMPALLOC	128
200986fd29aSsetje 
201986fd29aSsetje static	caddr_t temp_base[NTMPALLOC];
202986fd29aSsetje static	size_t	temp_size[NTMPALLOC];
203986fd29aSsetje static	int temp_indx;
204986fd29aSsetje 
205986fd29aSsetje #if defined(C_OBP)
206986fd29aSsetje void	cobp_free_mem(caddr_t, size_t);
207986fd29aSsetje #endif	/* C_OBP */
208986fd29aSsetje 
209986fd29aSsetje 
210986fd29aSsetje /*
211986fd29aSsetje  * temporary memory storage until bop_tmp_freeall is called
212986fd29aSsetje  * (after the kernel heap is initialized)
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate caddr_t
215986fd29aSsetje bop_temp_alloc(size_t size, int align)
2167c478bd9Sstevel@tonic-gate {
217986fd29aSsetje 	caddr_t ret;
2187c478bd9Sstevel@tonic-gate 
219986fd29aSsetje 	/*
220986fd29aSsetje 	 * OBP allocs 10MB to boot, which is where virthint = 0
221986fd29aSsetje 	 * memory was allocated from.  Without boot, we allocate
222986fd29aSsetje 	 * from BOOTTMPBASE and free when we're ready to take
223986fd29aSsetje 	 * the machine from OBP
224986fd29aSsetje 	 */
225986fd29aSsetje 	if (size < PAGESIZE) {
226986fd29aSsetje 		size_t left =
227986fd29aSsetje 		    ALIGN(littlehand, PAGESIZE) - (uintptr_t)littlehand;
2287c478bd9Sstevel@tonic-gate 
229986fd29aSsetje 		size = roundup(size, MAX(align, 8));
230986fd29aSsetje 		if (size <= left) {
231986fd29aSsetje 			ret = littlehand;
232986fd29aSsetje 			littlehand += size;
233986fd29aSsetje 			return (ret);
234986fd29aSsetje 		}
235986fd29aSsetje 		littlehand = bighand + size;
236986fd29aSsetje 	}
237986fd29aSsetje 	size = roundup(size, PAGESIZE);
238986fd29aSsetje 	ret = prom_alloc(bighand, size, align);
239986fd29aSsetje 	if (ret == NULL)
240986fd29aSsetje 		prom_panic("boot temp overflow");
241986fd29aSsetje 	bighand += size;
242986fd29aSsetje 
243986fd29aSsetje 	/* log it for bop_fini() */
244986fd29aSsetje 	temp_base[temp_indx] = ret;
245986fd29aSsetje 	temp_size[temp_indx] = size;
246986fd29aSsetje 	if (++temp_indx == NTMPALLOC)
247986fd29aSsetje 		prom_panic("out of bop temp space");
248986fd29aSsetje 
249986fd29aSsetje 	return (ret);
250986fd29aSsetje }
251986fd29aSsetje 
252986fd29aSsetje void
253986fd29aSsetje bop_temp_freeall(void)
254986fd29aSsetje {
255986fd29aSsetje 	int i;
256986fd29aSsetje 
257986fd29aSsetje 	/*
258986fd29aSsetje 	 * We have to call prom_free() with the same args
259986fd29aSsetje 	 * as we used in prom_alloc()
260986fd29aSsetje 	 */
261986fd29aSsetje 	for (i = 0; i < NTMPALLOC; i++) {
262986fd29aSsetje 		if (temp_base[i] == NULL)
263986fd29aSsetje 			break;
264986fd29aSsetje #if !defined(C_OBP)
265986fd29aSsetje 		prom_free(temp_base[i], temp_size[i]);
266986fd29aSsetje #else	/* !C_OBP */
267986fd29aSsetje 		cobp_free_mem(temp_base[i], temp_size[i]);
268986fd29aSsetje #endif	/* !C_OBP */
269986fd29aSsetje 	}
270986fd29aSsetje }
271986fd29aSsetje 
272986fd29aSsetje 
273986fd29aSsetje /*
274986fd29aSsetje  * Implementation of the "alloc" boot service.
275986fd29aSsetje  */
276986fd29aSsetje caddr_t
277986fd29aSsetje bop_alloc(caddr_t virthint, size_t size, int align)
278986fd29aSsetje {
279986fd29aSsetje 	if (virthint == NULL)
280986fd29aSsetje 		return (bop_temp_alloc(size, align));
281986fd29aSsetje 	return (prom_alloc(virthint, size, align));
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
284*ca622e3aSsvemuri 
285*ca622e3aSsvemuri /*
286*ca622e3aSsvemuri  * Similar to bop_alloc functionality except that
287*ca622e3aSsvemuri  * it will try to breakup into PAGESIZE chunk allocations
288*ca622e3aSsvemuri  * if the original single chunk request failed.
289*ca622e3aSsvemuri  * This routine does not guarantee physical contig
290*ca622e3aSsvemuri  * allocation.
291*ca622e3aSsvemuri  */
292*ca622e3aSsvemuri caddr_t
293*ca622e3aSsvemuri bop_alloc_chunk(caddr_t virthint, size_t size, int align)
294*ca622e3aSsvemuri {
295*ca622e3aSsvemuri 	caddr_t ret;
296*ca622e3aSsvemuri 	size_t chunksz;
297*ca622e3aSsvemuri 
298*ca622e3aSsvemuri 	if (virthint == NULL)
299*ca622e3aSsvemuri 		return (bop_temp_alloc(size, align));
300*ca622e3aSsvemuri 
301*ca622e3aSsvemuri 	if ((ret = prom_alloc(virthint, size, align)))
302*ca622e3aSsvemuri 		return (ret);
303*ca622e3aSsvemuri 
304*ca622e3aSsvemuri 	/*
305*ca622e3aSsvemuri 	 * Normal request to prom_alloc has failed.
306*ca622e3aSsvemuri 	 * We will attempt to satisfy the request by allocating
307*ca622e3aSsvemuri 	 * smaller chunks resulting in allocation that
308*ca622e3aSsvemuri 	 * will be virtually contiguous but potentially
309*ca622e3aSsvemuri 	 * not physically contiguous. There are additional
310*ca622e3aSsvemuri 	 * requirements before we want to do this:
311*ca622e3aSsvemuri 	 * 1. virthirt must be PAGESIZE aligned.
312*ca622e3aSsvemuri 	 * 2. align must not be greater than PAGESIZE
313*ca622e3aSsvemuri 	 * 3. size request must be at least PAGESIZE
314*ca622e3aSsvemuri 	 * Otherwise, we will revert back to the original
315*ca622e3aSsvemuri 	 * bop_alloc behavior i.e. return failure.
316*ca622e3aSsvemuri 	 */
317*ca622e3aSsvemuri 	if (P2PHASE_TYPED(virthint, PAGESIZE, size_t) != 0 ||
318*ca622e3aSsvemuri 	    align > PAGESIZE || size < PAGESIZE)
319*ca622e3aSsvemuri 		return (ret);
320*ca622e3aSsvemuri 
321*ca622e3aSsvemuri 	/*
322*ca622e3aSsvemuri 	 * Now we will break up the allocation
323*ca622e3aSsvemuri 	 * request in smaller chunks that are
324*ca622e3aSsvemuri 	 * always PAGESIZE aligned.
325*ca622e3aSsvemuri 	 */
326*ca622e3aSsvemuri 	ret = virthint;
327*ca622e3aSsvemuri 	chunksz = P2ALIGN((size >> 1), PAGESIZE);
328*ca622e3aSsvemuri 	chunksz = MAX(chunksz, PAGESIZE);
329*ca622e3aSsvemuri 
330*ca622e3aSsvemuri 	while (size) {
331*ca622e3aSsvemuri 		do {
332*ca622e3aSsvemuri 			/*LINTED E_FUNC_SET_NOT_USED*/
333*ca622e3aSsvemuri 			caddr_t res;
334*ca622e3aSsvemuri 			if ((res = prom_alloc(virthint, chunksz,
335*ca622e3aSsvemuri 			    PAGESIZE))) {
336*ca622e3aSsvemuri 				ASSERT(virthint == res);
337*ca622e3aSsvemuri 				break;
338*ca622e3aSsvemuri 			}
339*ca622e3aSsvemuri 
340*ca622e3aSsvemuri 			chunksz >>= 1;
341*ca622e3aSsvemuri 			chunksz = P2ALIGN(chunksz, PAGESIZE);
342*ca622e3aSsvemuri 		} while (chunksz >= PAGESIZE);
343*ca622e3aSsvemuri 
344*ca622e3aSsvemuri 		if (chunksz < PAGESIZE)
345*ca622e3aSsvemuri 			/* Can't really happen.. */
346*ca622e3aSsvemuri 			prom_panic("bop_alloc_chunk failed");
347*ca622e3aSsvemuri 
348*ca622e3aSsvemuri 		virthint += chunksz;
349*ca622e3aSsvemuri 		size -= chunksz;
350*ca622e3aSsvemuri 		if (size < chunksz)
351*ca622e3aSsvemuri 			chunksz = size;
352*ca622e3aSsvemuri 	}
353*ca622e3aSsvemuri 	return (ret);
354*ca622e3aSsvemuri }
355*ca622e3aSsvemuri 
356*ca622e3aSsvemuri 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * Implementation of the "alloc_virt" boot service
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate caddr_t
361986fd29aSsetje bop_alloc_virt(caddr_t virt, size_t size)
3627c478bd9Sstevel@tonic-gate {
363986fd29aSsetje 	return (prom_claim_virt(size, virt));
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * Implementation of the "free" boot service.
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3707c478bd9Sstevel@tonic-gate void
371986fd29aSsetje bop_free(caddr_t virt, size_t size)
3727c478bd9Sstevel@tonic-gate {
373986fd29aSsetje 	prom_free(virt, size);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * Implementation of the "getproplen" boot service.
3807c478bd9Sstevel@tonic-gate  */
3817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3827c478bd9Sstevel@tonic-gate int
383986fd29aSsetje bop_getproplen(const char *name)
3847c478bd9Sstevel@tonic-gate {
385986fd29aSsetje 	struct fakeprop *fpp;
386986fd29aSsetje 	pnode_t node;
387986fd29aSsetje 	char *prop;
3887c478bd9Sstevel@tonic-gate 
389986fd29aSsetje 	fpp = fakelook(name);
390986fd29aSsetje 	if (fpp != NULL) {
391986fd29aSsetje 		node = fpp->promnode;
392986fd29aSsetje 		prop = fpp->promname;
393986fd29aSsetje 	} else {
394986fd29aSsetje 		node = chosennode;
395986fd29aSsetje 		prop = (char *)name;
396986fd29aSsetje 	}
397986fd29aSsetje 	return (prom_getproplen(node, prop));
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Implementation of the "getprop" boot service.
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4047c478bd9Sstevel@tonic-gate int
405986fd29aSsetje bop_getprop(const char *name, void *value)
4067c478bd9Sstevel@tonic-gate {
407986fd29aSsetje 	struct fakeprop *fpp;
408986fd29aSsetje 	pnode_t node;
409986fd29aSsetje 	char *prop;
4107c478bd9Sstevel@tonic-gate 
411986fd29aSsetje 	fpp = fakelook(name);
412986fd29aSsetje 	if (fpp != NULL) {
413986fd29aSsetje 		node = fpp->promnode;
414986fd29aSsetje 		prop = fpp->promname;
415986fd29aSsetje 	} else {
416986fd29aSsetje 		node = chosennode;
417986fd29aSsetje 		prop = (char *)name;
418986fd29aSsetje 	}
419986fd29aSsetje 	return (prom_getprop(node, prop, value));
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
423986fd29aSsetje  * Implementation of the "print" boot service.
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4267c478bd9Sstevel@tonic-gate void
427986fd29aSsetje bop_printf(void *ops, const char *fmt, ...)
4287c478bd9Sstevel@tonic-gate {
429986fd29aSsetje 	va_list adx;
4307c478bd9Sstevel@tonic-gate 
431986fd29aSsetje 	va_start(adx, fmt);
432986fd29aSsetje 	prom_vprintf(fmt, adx);
433986fd29aSsetje 	va_end(adx);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate /*
437986fd29aSsetje  * Special routine for kmdb
4387c478bd9Sstevel@tonic-gate  */
4397c478bd9Sstevel@tonic-gate void
440986fd29aSsetje bop_putsarg(const char *fmt, char *arg)
4417c478bd9Sstevel@tonic-gate {
442986fd29aSsetje 	prom_printf(fmt, arg);
443986fd29aSsetje }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*
446986fd29aSsetje  * panic for krtld only
4477c478bd9Sstevel@tonic-gate  */
448986fd29aSsetje void
449986fd29aSsetje bop_panic(const char *s)
450986fd29aSsetje {
451986fd29aSsetje 	prom_panic((char *)s);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Implementation of the "mount" boot service.
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  */
4587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4597c478bd9Sstevel@tonic-gate int
460986fd29aSsetje bop_mountroot(void)
4617c478bd9Sstevel@tonic-gate {
462986fd29aSsetje 	(void) prom_getprop(chosennode, "bootfs", (caddr_t)&bfs_ih);
463986fd29aSsetje 	(void) prom_getprop(chosennode, "archfs", (caddr_t)&afs_ih);
464986fd29aSsetje 	return ((bfs_ih == -1 && afs_ih == -1) ? BOOT_SVC_FAIL : BOOT_SVC_OK);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate  * Implementation of the "unmountroot" boot service.
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4717c478bd9Sstevel@tonic-gate int
472986fd29aSsetje bop_unmountroot(void)
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 
475986fd29aSsetje 	if (bfs_ih != OBP_BADNODE) {
476986fd29aSsetje 		(void) prom_close(bfs_ih);
477986fd29aSsetje 		bfs_ih = OBP_BADNODE;
4787c478bd9Sstevel@tonic-gate 	}
479986fd29aSsetje 	if (afs_ih != OBP_BADNODE) {
480986fd29aSsetje 		(void) prom_close(afs_ih);
481986fd29aSsetje 		afs_ih = OBP_BADNODE;
482986fd29aSsetje 	}
483986fd29aSsetje 	return (BOOT_SVC_OK);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate /*
4877c478bd9Sstevel@tonic-gate  * Implementation of the "fstat" boot service.
4887c478bd9Sstevel@tonic-gate  */
4897c478bd9Sstevel@tonic-gate int
490986fd29aSsetje bop_fstat(int fd, struct bootstat *st)
4917c478bd9Sstevel@tonic-gate {
492986fd29aSsetje 	ASSERT(prom_ihs[fd] != 0);
493986fd29aSsetje 	return (prom_fsize(prom_ihs[fd], fd, (size_t *)&st->st_size));
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
496986fd29aSsetje int
497986fd29aSsetje boot_compinfo(int fd, struct compinfo *cb)
498986fd29aSsetje {
499986fd29aSsetje 	ASSERT(prom_ihs[fd] != 0);
500986fd29aSsetje 	return (prom_compinfo(prom_ihs[fd], fd,
501986fd29aSsetje 	    &cb->iscmp, &cb->fsize, &cb->blksize));
502986fd29aSsetje }
503986fd29aSsetje 
504986fd29aSsetje void
505986fd29aSsetje bop_free_archive(void)
506986fd29aSsetje {
507986fd29aSsetje 	char archive[OBP_MAXPATHLEN];
508986fd29aSsetje 	pnode_t arph;
509986fd29aSsetje 	uint32_t arbase, arsize, alloc_size;
510986fd29aSsetje 
511986fd29aSsetje 	/*
512986fd29aSsetje 	 * If the ramdisk will eventually be root, or we weren't
513986fd29aSsetje 	 * booted via the archive, then nothing to do here
514986fd29aSsetje 	 */
515986fd29aSsetje 	if (root_is_ramdisk == B_TRUE ||
516986fd29aSsetje 	    prom_getprop(chosennode, "bootarchive", archive) == -1)
517986fd29aSsetje 		return;
518986fd29aSsetje 	arph = prom_finddevice(archive);
519986fd29aSsetje 	if (arph == -1 ||
520986fd29aSsetje 	    prom_getprop(arph, OBP_ALLOCSIZE, (caddr_t)&alloc_size) == -1 ||
521986fd29aSsetje 	    prom_getprop(arph, OBP_SIZE, (caddr_t)&arsize) == -1 ||
522986fd29aSsetje 	    prom_getprop(arph, OBP_ADDRESS, (caddr_t)&arbase) == -1)
523986fd29aSsetje 		prom_panic("can't free boot archive");
524986fd29aSsetje 
525986fd29aSsetje #if !defined(C_OBP)
526986fd29aSsetje 	if (alloc_size == 0)
527986fd29aSsetje 		prom_free((caddr_t)(uintptr_t)arbase, arsize);
528986fd29aSsetje 	else {
529986fd29aSsetje 		uint32_t arend = arbase + arsize;
530986fd29aSsetje 
531986fd29aSsetje 		while (arbase < arend) {
532986fd29aSsetje 			prom_free((caddr_t)(uintptr_t)arbase,
533986fd29aSsetje 			    MIN(alloc_size, arend - arbase));
534986fd29aSsetje 			arbase += alloc_size;
535986fd29aSsetje 		}
536986fd29aSsetje 	}
537986fd29aSsetje #else	/* !C_OBP */
538986fd29aSsetje 	cobp_free_mem((caddr_t)(uintptr_t)arbase, arsize);
539986fd29aSsetje #endif	/* !C_OBP */
540986fd29aSsetje }
541986fd29aSsetje 
542986fd29aSsetje #if defined(C_OBP)
543986fd29aSsetje /*
544986fd29aSsetje  * Blech.  The C proms have a bug when freeing areas that cross
545986fd29aSsetje  * page sizes, so we have to break up the free into sections
546986fd29aSsetje  * bounded by the various pagesizes.
547986fd29aSsetje  */
548986fd29aSsetje void
549986fd29aSsetje cobp_free_mem(caddr_t base, size_t size)
550986fd29aSsetje {
551986fd29aSsetje 	int i;
552986fd29aSsetje 	size_t len, pgsz;
553986fd29aSsetje 
554986fd29aSsetje 	/*
555986fd29aSsetje 	 * Large pages only used when size > 512k
556986fd29aSsetje 	 */
557986fd29aSsetje 	if (size < MMU_PAGESIZE512K ||
558986fd29aSsetje 	    ((uintptr_t)base & MMU_PAGEOFFSET512K) != 0) {
559986fd29aSsetje 		prom_free(base, size);
560986fd29aSsetje 		return;
561986fd29aSsetje 	}
562986fd29aSsetje 	for (i = 3; i >= 0; i--) {
563986fd29aSsetje 		pgsz = page_get_pagesize(i);
564986fd29aSsetje 		if (size < pgsz)
565986fd29aSsetje 			continue;
566986fd29aSsetje 		len = size & ~(pgsz - 1);
567986fd29aSsetje 		prom_free(base, len);
568986fd29aSsetje 		base += len;
569986fd29aSsetje 		size -= len;
570986fd29aSsetje 	}
571986fd29aSsetje }
572986fd29aSsetje #endif	/* C_OBP */
573986fd29aSsetje 
574986fd29aSsetje 
5757c478bd9Sstevel@tonic-gate /*
5767c478bd9Sstevel@tonic-gate  * Implementation of the "enter_mon" boot service.
5777c478bd9Sstevel@tonic-gate  */
5787c478bd9Sstevel@tonic-gate void
579986fd29aSsetje bop_enter_mon(void)
5807c478bd9Sstevel@tonic-gate {
581986fd29aSsetje 	prom_enter_mon();
582986fd29aSsetje }
5837c478bd9Sstevel@tonic-gate 
584986fd29aSsetje /*
585986fd29aSsetje  * free elf info allocated by booter
586986fd29aSsetje  */
587986fd29aSsetje void
588986fd29aSsetje bop_free_elf(void)
589986fd29aSsetje {
590986fd29aSsetje 	uint32_t eadr;
591986fd29aSsetje 	uint32_t esize;
592986fd29aSsetje 	extern Addr dynseg;
593986fd29aSsetje 	extern size_t dynsize;
594986fd29aSsetje 
595986fd29aSsetje 	if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1 ||
596986fd29aSsetje 	    bop_getprop("elfheader-length", (caddr_t)&esize) == -1)
597986fd29aSsetje 		prom_panic("missing elfheader");
598986fd29aSsetje 	prom_free((caddr_t)(uintptr_t)eadr, roundup(esize, PAGESIZE));
599986fd29aSsetje 
600986fd29aSsetje 	prom_free((caddr_t)(uintptr_t)dynseg, roundup(dynsize, PAGESIZE));
601986fd29aSsetje }
602986fd29aSsetje 
603986fd29aSsetje 
604986fd29aSsetje /* Simple message to indicate that the bootops pointer has been zeroed */
605986fd29aSsetje #ifdef DEBUG
606986fd29aSsetje int bootops_gone_on = 0;
607986fd29aSsetje #define	BOOTOPS_GONE() \
608986fd29aSsetje 	if (bootops_gone_on) \
609986fd29aSsetje 		prom_printf("The bootops vec is zeroed now!\n");
610986fd29aSsetje #else
611986fd29aSsetje #define	BOOTOPS_GONE()
612986fd29aSsetje #endif	/* DEBUG */
613986fd29aSsetje 
614986fd29aSsetje void
615986fd29aSsetje bop_fini(void)
616986fd29aSsetje {
617986fd29aSsetje 	bop_free_archive();
618986fd29aSsetje 	(void) bop_unmountroot();
619986fd29aSsetje 	bop_free_elf();
620986fd29aSsetje 	bop_temp_freeall();
621986fd29aSsetje 
622986fd29aSsetje 	bootops = (struct bootops *)NULL;
623986fd29aSsetje 	BOOTOPS_GONE();
6247c478bd9Sstevel@tonic-gate }
625