xref: /netbsd/sys/arch/sparc/sparc/promlib.c (revision 09eb5c43)
1 /*	$NetBSD: promlib.c,v 1.52 2022/01/22 11:49:16 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
34  * from the rest of the kernel.
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: promlib.c,v 1.52 2022/01/22 11:49:16 thorpej Exp $");
39 
40 #if defined(_KERNEL_OPT)
41 #include "opt_sparc_arch.h"
42 #endif
43 
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/device.h>
47 
48 #ifdef _STANDALONE
49 #include <lib/libsa/stand.h>
50 #define malloc(s,t,f)	alloc(s)
51 #else
52 #include <sys/device_calls.h>
53 #include <sys/systm.h>
54 #include <sys/malloc.h>
55 #endif /* _STANDALONE */
56 
57 #include <machine/oldmon.h>
58 #include <machine/promlib.h>
59 #include <machine/ctlreg.h>
60 
61 #include <sparc/sparc/asm.h>
62 #include <sparc/sparc/cache.h>
63 
64 #include <lib/libkern/libkern.h>
65 
66 #define obpvec ((struct promvec *)romp)
67 
68 static void	notimplemented(void);
69 static void	obp_v0_fortheval(const char *);
70 static void	obp_set_callback(void (*)(void));
71 static int	obp_v0_read(int, void *, int);
72 static int	obp_v0_write(int, const void *, int);
73 static int	obp_v2_getchar(void);
74 static int	obp_v2_peekchar(void);
75 static void	obp_v2_putchar(int);
76 static void	obp_v2_putstr(const char *, int);
77 static int	obp_v2_seek(int, u_quad_t);
78 static char	*parse_bootfile(char *);
79 static char	*parse_bootargs(char *);
80 static const char *obp_v0_getbootpath(void);
81 static const char *obp_v0_getbootfile(void);
82 static const char *obp_v0_getbootargs(void);
83 static const char *obp_v2_getbootpath(void);
84 static const char *obp_v2_getbootfile(void);
85 static const char *obp_v2_getbootargs(void);
86 static int	obp_v2_finddevice(const char *);
87 static int	obp_ticks(void);
88 
89 static int	findchosen(void);
90 static const char *opf_getbootpath(void);
91 static const char *opf_getbootfile(void);
92 static const char *opf_getbootargs(void);
93 static int	opf_finddevice(const char *);
94 static int	opf_instance_to_package(int);
95 static char	*opf_nextprop(int, const char *);
96 static void	opf_interpret_simple(const char *);
97 
98 #ifndef _STANDALONE
99 static devhandle_t
null_prom_to_devhandle(int node __unused)100 null_prom_to_devhandle(int node __unused)
101 {
102 	return devhandle_invalid();
103 }
104 
105 static int
null_devhandle_to_prom(devhandle_t devhandle __unused)106 null_devhandle_to_prom(devhandle_t devhandle __unused)
107 {
108 	return 0;
109 }
110 #endif /* ! _STANDALONE */
111 
112 /*
113  * PROM entry points.
114  * Note: only PROM functions we use ar represented here; add as required.
115  */
116 struct promops promops = {
117 	-1,				/* version */
118 	-1,				/* revision */
119 	-1,				/* stdin handle */
120 	-1,				/* stdout handle */
121 	NULL,				/* bootargs */
122 
123 	(void *)notimplemented,		/* bootpath */
124 	(void *)notimplemented,		/* bootargs */
125 	(void *)notimplemented,		/* bootfile */
126 
127 	(void *)notimplemented,		/* getchar */
128 	(void *)notimplemented,		/* peekchar */
129 	(void *)notimplemented,		/* putchar */
130 	(void *)notimplemented,		/* putstr */
131 	(void *)notimplemented,		/* open */
132 	(void *)notimplemented,		/* close */
133 	(void *)notimplemented,		/* read */
134 	(void *)notimplemented,		/* write */
135 	(void *)notimplemented,		/* seek */
136 
137 	(void *)notimplemented,		/* instance_to_package */
138 
139 	(void *)notimplemented,		/* halt */
140 	(void *)notimplemented,		/* boot */
141 	(void *)notimplemented,		/* call */
142 	(void *)notimplemented,		/* interpret */
143 	(void *)notimplemented,		/* callback */
144 	(void *)notimplemented,		/* ticks */
145 	NULL,				/* ticker data */
146 
147 	(void *)notimplemented,		/* setcontext */
148 	(void *)notimplemented,		/* cpustart */
149 	(void *)notimplemented,		/* cpustop */
150 	(void *)notimplemented,		/* cpuidle */
151 	(void *)notimplemented,		/* cpuresume */
152 
153 	(void *)notimplemented,		/* firstchild */
154 	(void *)notimplemented,		/* nextsibling */
155 
156 	(void *)notimplemented,		/* getproplen */
157 	(void *)notimplemented,		/* getprop */
158 	(void *)notimplemented,		/* setprop */
159 	(void *)notimplemented,		/* nextprop */
160 	(void *)notimplemented,		/* finddevice */
161 
162 	/*
163 	 * These should never be called in the STANDALONE environment,
164 	 * but when we're in the kernel environment, it's not really
165 	 * invalid to do so.
166 	 */
167 #ifdef STANDALONE
168 	(void *)notimplemented,		/* node_to_devhandle */
169 	(void *)notimplemented,		/* devhandle_to_node */
170 #else
171 	(void *)null_prom_to_devhandle,	/* node_to_devhandle */
172 	(void *)null_devhandle_to_prom,	/* devhandle_to_node */
173 #endif /* STANDALONE */
174 };
175 
176 static void
notimplemented(void)177 notimplemented(void)
178 {
179 	char str[64];
180 	int n;
181 
182 	n = snprintf(str, sizeof(str),
183 	    "Operation not implemented on ROM version %d\r\n",
184 	    promops.po_version);
185 
186 	/*
187 	 * Use PROM vector directly, in case we're called before prom_init().
188 	 */
189 #if defined(SUN4)
190 	if (CPU_ISSUN4) {
191 		struct om_vector *sun4pvec = (struct om_vector *)PROM_BASE;
192 		(*sun4pvec->fbWriteStr)(str, n);
193 	} else
194 #endif
195 	if (obpvec->pv_magic == OBP_MAGIC) {
196 		if (obpvec->pv_romvec_vers < 2) {
197 			(*obpvec->pv_putstr)(str, n);
198 		} else {
199 			int fd = *obpvec->pv_v2bootargs.v2_fd1;
200 			(*obpvec->pv_v2devops.v2_write)(fd, str, n);
201 		}
202 	} else {	/* assume OFW */
203 		static int stdout_node;
204 		if (stdout_node == 0) {
205 			int chosen = findchosen();
206 			OF_getprop(chosen, "stdout", &stdout_node, sizeof(int));
207 		}
208 		OF_write(stdout_node, str, n);
209 	}
210 }
211 
212 #ifndef _STANDALONE
213 /*
214  * OBP device handle support.  We subsume v0-v3 into a single implementation
215  * and use promops to handle differences.
216  *
217  * On 32-bit SPARC, the OpenFirmware variant also gets redirected here.
218  * See prom_init_opf().
219  */
220 
221 static device_call_t
obp_devhandle_lookup_device_call(devhandle_t handle,const char * name,devhandle_t * call_handlep)222 obp_devhandle_lookup_device_call(devhandle_t handle, const char *name,
223     devhandle_t *call_handlep)
224 {
225 	__link_set_decl(obp_device_calls, struct device_call_descriptor);
226 	struct device_call_descriptor * const *desc;
227 
228 	__link_set_foreach(desc, obp_device_calls) {
229 		if (strcmp((*desc)->name, name) == 0) {
230 			return (*desc)->call;
231 		}
232 	}
233 	return NULL;
234 }
235 
236 static const struct devhandle_impl obp_devhandle_impl = {
237 	.type = DEVHANDLE_TYPE_OPENBOOT,
238 	.lookup_device_call = obp_devhandle_lookup_device_call,
239 };
240 
241 static devhandle_t
devhandle_from_obp(devhandle_t super_handle,int node)242 devhandle_from_obp(devhandle_t super_handle, int node)
243 {
244 	devhandle_type_t super_type = devhandle_type(super_handle);
245 	devhandle_t handle = { 0 };
246 
247 	if (super_type == DEVHANDLE_TYPE_OPENBOOT) {
248 		handle.impl = super_handle.impl;
249 	} else {
250 		KASSERT(super_type == DEVHANDLE_TYPE_INVALID);
251 		handle.impl = &obp_devhandle_impl;
252 	}
253 	handle.integer = node;
254 
255 	return handle;
256 }
257 
258 static int
devhandle_to_obp(devhandle_t const handle)259 devhandle_to_obp(devhandle_t const handle)
260 {
261 	KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_OPENBOOT);
262 
263 	return handle.integer;
264 }
265 
266 static int
obp_device_enumerate_children(device_t dev,devhandle_t call_handle,void * v)267 obp_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v)
268 {
269 	struct device_enumerate_children_args *args = v;
270 	int node = devhandle_to_obp(call_handle);
271 
272 	for (node = prom_firstchild(node); node != 0;
273 	     node = prom_nextsibling(node)) {
274 		if (!args->callback(dev, devhandle_from_obp(call_handle, node),
275 				    args->callback_arg)) {
276 			break;
277 		}
278 	}
279 
280 	return 0;
281 }
OBP_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,obp_device_enumerate_children)282 OBP_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,
283 			 obp_device_enumerate_children)
284 #endif /* ! _STANDALONE */
285 
286 /*
287  * prom_getprop() reads the named property data from a given node.
288  * A buffer for the data may be passed in `*bufp'; if NULL, a
289  * buffer is allocated. The argument `size' specifies the data
290  * element size of the property data. This function checks that
291  * the actual property data length is an integral multiple of
292  * the element size.  The number of data elements read into the
293  * buffer is returned into the integer pointed at by `nitem'.
294  */
295 
296 int
297 prom_getprop(int node, const char *name, size_t	size, int *nitem, void *bufp)
298 {
299 	void	*buf;
300 	int	len;
301 
302 	len = prom_getproplen(node, name);
303 	if (len <= 0)
304 		return (ENOENT);
305 
306 	if ((len % size) != 0)
307 		return (EINVAL);
308 
309 	buf = *(void **)bufp;
310 	if (buf == NULL) {
311 		/* No storage provided, so we allocate some */
312 		buf = malloc(len, M_DEVBUF, M_NOWAIT);
313 		if (buf == NULL)
314 			return (ENOMEM);
315 	} else {
316 		if (size * (*nitem) < len)
317 			return (ENOMEM);
318 	}
319 
320 	_prom_getprop(node, name, buf, len);
321 	*(void **)bufp = buf;
322 	*nitem = len / size;
323 	return (0);
324 }
325 
326 /*
327  * Return a string property.  There is a (small) limit on the length;
328  * the string is fetched into a static buffer which is overwritten on
329  * subsequent calls.
330  */
331 char *
prom_getpropstring(int node,const char * name)332 prom_getpropstring(int node, const char *name)
333 {
334 	static char stringbuf[32];
335 
336 	return (prom_getpropstringA(node, name, stringbuf, sizeof stringbuf));
337 }
338 
339 /*
340  * Alternative prom_getpropstring(), where caller provides the buffer
341  */
342 char *
prom_getpropstringA(int node,const char * name,char * buf,size_t bufsize)343 prom_getpropstringA(int node, const char *name, char *buf, size_t bufsize)
344 {
345 	int len = bufsize - 1;
346 
347 	if (prom_getprop(node, name, 1, &len, &buf) != 0)
348 		len = 0;
349 
350 	buf[len] = '\0';	/* usually unnecessary */
351 	return (buf);
352 }
353 
354 /*
355  * Fetch an integer (or pointer) property.
356  * The return value is the property, or the default if there was none.
357  */
358 int
prom_getpropint(int node,const char * name,int deflt)359 prom_getpropint(int node, const char *name, int deflt)
360 {
361 	int intbuf, *ip = &intbuf;
362 	int len = 1;
363 
364 	if (prom_getprop(node, name, sizeof(int), &len, &ip) != 0)
365 		return (deflt);
366 
367 	return (*ip);
368 }
369 
370 /*
371  * Fetch an unsigned 64-bit integer (or pointer) property.
372  * The return value is the property, or the default if there was none.
373  */
374 uint64_t
prom_getpropuint64(int node,const char * name,uint64_t deflt)375 prom_getpropuint64(int node, const char *name, uint64_t deflt)
376 {
377 	uint64_t uint64buf, *uint64p = &uint64buf;
378 	int len = 2;
379 
380 	if (prom_getprop(node, name, sizeof(uint64_t), &len, &uint64p) != 0)
381 		return deflt;
382 
383 	return uint64buf;
384 }
385 
386 /*
387  * Node Name Matching per IEEE 1275, section 4.3.6.
388  */
389 static int
prom_matchname(int node,const char * name)390 prom_matchname(int node, const char *name)
391 {
392 	char buf[32], *cp;
393 
394 	prom_getpropstringA(node, "name", buf, sizeof buf);
395 	if (strcmp(buf, name) == 0)
396 		/* Exact match */
397 		return (1);
398 
399 	/* If name has a comma, an exact match is required */
400 	if (strchr(name, ','))
401 		return (0);
402 
403 	/*
404 	 * Otherwise, if the node's name contains a comma, we can match
405 	 * against the trailing string defined by the first comma.
406 	 */
407 	if ((cp = strchr(buf, ',')) != NULL) {
408 		if (strcmp(cp + 1, name) == 0)
409 			return (1);
410 	}
411 
412 	return (0);
413 }
414 
415 /*
416  * Translate device path to node
417  */
418 int
prom_opennode(const char * path)419 prom_opennode(const char *path)
420 {
421 	int fd;
422 
423 	if (prom_version() < 2) {
424 		printf("WARNING: opennode not valid on PROM version %d\n",
425 			promops.po_version);
426 		return (0);
427 	}
428 	fd = prom_open(path);
429 	if (fd == 0)
430 		return (0);
431 
432 	return (prom_instance_to_package(fd));
433 }
434 
435 int
prom_findroot(void)436 prom_findroot(void)
437 {
438 	static int rootnode;
439 	int node;
440 
441 	if ((node = rootnode) == 0 && (node = prom_nextsibling(0)) == 0)
442 		panic("no PROM root device");
443 	rootnode = node;
444 	return (node);
445 }
446 
447 /*
448  * Given a `first child' node number, locate the node with the given name.
449  * Return the node number, or 0 if not found.
450  */
451 int
prom_findnode(int first,const char * name)452 prom_findnode(int first, const char *name)
453 {
454 	int node;
455 
456 	for (node = first; node != 0; node = prom_nextsibling(node)) {
457 		if (prom_matchname(node, name))
458 			return (node);
459 	}
460 	return (0);
461 }
462 
463 /*
464  * Determine whether a node has the given property.
465  */
466 int
prom_node_has_property(int node,const char * prop)467 prom_node_has_property(int node, const char *prop)
468 {
469 
470 	return (prom_getproplen(node, prop) != -1);
471 }
472 
473 /*
474  * prom_search() recursively searches a PROM subtree for a given node name
475  * See IEEE 1275 `Search for matching child node', section 4.3.3.
476  */
477 int
prom_search(int node,const char * name)478 prom_search(int node, const char *name)
479 {
480 
481 	if (node == 0)
482 		node = prom_findroot();
483 
484 	if (prom_matchname(node, name))
485 		return (node);
486 
487 	for (node = prom_firstchild(node); node != 0;
488 	     node = prom_nextsibling(node)) {
489 		int cnode;
490 		if ((cnode = prom_search(node, name)) != 0)
491 			return (cnode);
492 	}
493 
494 	return (0);
495 }
496 
497 /*
498  * Find the named device in the PROM device tree.
499  * XXX - currently we discard any qualifiers attached to device component names
500  */
501 int
obp_v2_finddevice(const char * path)502 obp_v2_finddevice(const char *path)
503 {
504 	int node;
505 	char component[64];
506 	char c, *cp;
507 	const char *startp, *endp;
508 #define IS_SEP(c)	((c) == '/' || (c) == '@' || (c) == ':')
509 
510 	if (path == NULL)
511 		return (-1);
512 
513 	node = prom_findroot();
514 
515 	for (startp = path; *startp != '\0'; ) {
516 		/*
517 		 * Identify next component in path
518 		 */
519 		while (*startp == '/')
520 			startp++;
521 
522 		endp = startp;
523 		while ((c = *endp) != '\0' && !IS_SEP(c))
524 			endp++;
525 
526 		/* Copy component */
527 		for (cp = component; startp != endp;) {
528 			/* Check component bounds */
529 			if (cp > component + sizeof component - 1)
530 				return (-1);
531 			*cp++ = *startp++;
532 		}
533 
534 		/* Zero terminate this component */
535 		*cp = '\0';
536 
537 		/* Advance `startp' over any non-slash separators */
538 		while ((c = *startp) != '\0' && c != '/')
539 			startp++;
540 
541 		node = prom_findnode(prom_firstchild(node), component);
542 		if (node == 0)
543 			return (-1);
544 	}
545 
546 	return (node);
547 }
548 
549 
550 /*
551  * Get the global "options" node Id.
552  */
prom_getoptionsnode(void)553 int prom_getoptionsnode(void)
554 {
555 static	int optionsnode;
556 
557 	if (optionsnode == 0) {
558 		optionsnode = prom_findnode(prom_firstchild(prom_findroot()),
559 					    "options");
560 	}
561 	return optionsnode;
562 }
563 
564 /*
565  * Return a property string value from the global "options" node.
566  */
prom_getoption(const char * name,char * buf,int buflen)567 int prom_getoption(const char *name, char *buf, int buflen)
568 {
569 	int node = prom_getoptionsnode();
570 	int error, len;
571 
572 	if (buflen == 0)
573 		return (EINVAL);
574 
575 	if (node == 0)
576 		return (ENOENT);
577 
578 	len = buflen - 1;
579 	if ((error = prom_getprop(node, name, 1, &len, &buf)) != 0)
580 		return error;
581 
582 	buf[len] = '\0';
583 	return (0);
584 }
585 
586 void
prom_halt(void)587 prom_halt(void)
588 {
589 
590 	prom_setcallback(NULL);
591 	_prom_halt();
592 	panic("PROM exit failed");
593 }
594 
595 void
prom_boot(char * str)596 prom_boot(char *str)
597 {
598 
599 	prom_setcallback(NULL);
600 	_prom_boot(str);
601 	panic("PROM boot failed");
602 }
603 
604 
605 /*
606  * print debug info to prom.
607  * This is not safe, but then what do you expect?
608  */
609 void
prom_printf(const char * fmt,...)610 prom_printf(const char *fmt, ...)
611 {
612 static	char buf[256];
613 	int i, len;
614 	va_list ap;
615 
616 	va_start(ap, fmt);
617 	len = vsnprintf(buf, sizeof(buf), fmt, ap);
618 	va_end(ap);
619 
620 #if _obp_not_cooked_
621 	(*promops.po_write)(promops.po_stdout, buf, len);
622 #endif
623 
624 	for (i = 0; i < len; i++) {
625 		int c = buf[i];
626 		if (c == '\n')
627 			(*promops.po_putchar)('\r');
628 		(*promops.po_putchar)(c);
629 	}
630 }
631 
632 
633 /*
634  * Pass a string to the FORTH PROM to be interpreted.
635  * (Note: may fail silently)
636  */
637 static void
obp_v0_fortheval(const char * s)638 obp_v0_fortheval(const char *s)
639 {
640 
641 	obpvec->pv_fortheval.v0_eval(strlen(s), s);
642 }
643 
644 int
obp_v0_read(int fd,void * buf,int len)645 obp_v0_read(int fd, void *buf, int len)
646 {
647 	if (fd != prom_stdin())
648 		prom_printf("obp_v0_read: unimplemented read from %d\n", fd);
649 	return (-1);
650 }
651 
652 int
obp_v0_write(int fd,const void * buf,int len)653 obp_v0_write(int fd, const void *buf, int len)
654 {
655 	if (fd != prom_stdout())
656 		prom_printf("obp_v0_write: unimplemented write on %d\n", fd);
657 	(*obpvec->pv_putstr)(buf, len);
658 	return (-1);
659 }
660 
661 inline void
obp_v2_putchar(int c)662 obp_v2_putchar(int c)
663 {
664 	char c0;
665 
666 	c0 = (c & 0x7f);
667 	(*promops.po_write)(promops.po_stdout, &c0, 1);
668 }
669 
670 #if 0
671 void
672 obp_v2_putchar_cooked(int c)
673 {
674 
675 	if (c == '\n')
676 		obp_v2_putchar('\r');
677 	obp_v2_putchar(c);
678 }
679 #endif
680 
681 int
obp_v2_getchar(void)682 obp_v2_getchar(void)
683 {
684 	char c;
685 	int n;
686 
687 	while ((n = (*promops.po_read)(promops.po_stdin, &c, 1)) != 1)
688 		/*void*/;
689 	if (c == '\r')
690 		c = '\n';
691 	return (c);
692 }
693 
694 int
obp_v2_peekchar(void)695 obp_v2_peekchar(void)
696 {
697 	char c;
698 	int n;
699 
700 	n = (*promops.po_read)(promops.po_stdin, &c, 1);
701 	if (n < 0)
702 		return (-1);
703 
704 	if (c == '\r')
705 		c = '\n';
706 	return (c);
707 }
708 
709 int
obp_v2_seek(int handle,u_quad_t offset)710 obp_v2_seek(int handle, u_quad_t offset)
711 {
712 	uint32_t hi, lo;
713 
714 	lo = offset & ((uint32_t)-1);
715 	hi = (offset >> 32) & ((uint32_t)-1);
716 	(*obpvec->pv_v2devops.v2_seek)(handle, hi, lo);
717 	return (0);
718 }
719 
720 /*
721  * On SS1s (and also IPCs, SLCs), `promvec->pv_v0bootargs->ba_argv[1]'
722  * contains the flags that were given after the boot command.  On SS2s
723  * (and ELCs, IPXs, etc. and any sun4m class machine), `pv_v0bootargs'
724  * is NULL but `*promvec->pv_v2bootargs.v2_bootargs' points to
725  * "netbsd -s" or whatever.
726  */
727 const char *
obp_v0_getbootpath(void)728 obp_v0_getbootpath(void)
729 {
730 	struct v0bootargs *ba = promops.po_bootcookie;
731 	return (ba->ba_argv[0]);
732 }
733 
734 const char *
obp_v0_getbootargs(void)735 obp_v0_getbootargs(void)
736 {
737 	struct v0bootargs *ba = promops.po_bootcookie;
738 	return (ba->ba_argv[1]);
739 }
740 
741 const char *
obp_v0_getbootfile(void)742 obp_v0_getbootfile(void)
743 {
744 	struct v0bootargs *ba = promops.po_bootcookie;
745 	return (ba->ba_kernel);
746 }
747 
748 char *
parse_bootargs(char * args)749 parse_bootargs(char *args)
750 {
751 	char *cp;
752 
753 	for (cp = args; *cp != '\0'; cp++) {
754 		if (*cp == '-') {
755 			int c;
756 			/*
757 			 * Looks like options start here, but check this
758 			 * `-' is not part of the kernel name.
759 			 */
760 			if (cp == args)
761 				break;
762 			if ((c = *(cp-1)) == ' ' || c == '\t')
763 				break;
764 		}
765 	}
766 	return (cp);
767 }
768 
769 const char *
obp_v2_getbootpath(void)770 obp_v2_getbootpath(void)
771 {
772 	struct v2bootargs *ba = promops.po_bootcookie;
773 	return (*ba->v2_bootpath);
774 }
775 
776 const char *
obp_v2_getbootargs(void)777 obp_v2_getbootargs(void)
778 {
779 	struct v2bootargs *ba = promops.po_bootcookie;
780 
781 	return (parse_bootargs(*ba->v2_bootargs));
782 }
783 
784 /*
785  * Static storage shared by prom_getbootfile(), prom_getbootargs() and
786  * prom_getbootpath().
787  * Overwritten on each call!
788  */
789 static	char storage[128];
790 
791 char *
parse_bootfile(char * args)792 parse_bootfile(char *args)
793 {
794 	char *cp, *dp;
795 
796 	cp = args;
797 	dp = storage;
798 	while (*cp != 0 && *cp != ' ' && *cp != '\t') {
799 		if (dp >= storage + sizeof(storage) - 1) {
800 			prom_printf("v2_bootargs too long\n");
801 			return (NULL);
802 		}
803 		if (*cp == '-') {
804 			int c;
805 			/*
806 			 * If this `-' is most likely the start of boot
807 			 * options, we're done.
808 			 */
809 			if (cp == args)
810 				break;
811 			if ((c = *(cp-1)) == ' ' || c == '\t')
812 				break;
813 		}
814 		*dp++ = *cp++;
815 	}
816 	*dp = '\0';
817 	return (storage);
818 }
819 
820 const char *
obp_v2_getbootfile(void)821 obp_v2_getbootfile(void)
822 {
823 	struct v2bootargs *ba = promops.po_bootcookie;
824 	char *kernel = parse_bootfile(*ba->v2_bootargs);
825 	char buf[4+1];
826 	const char *prop;
827 
828 	if (kernel[0] != '\0')
829 		return kernel;
830 
831 	/*
832 	 * The PROM does not insert the `boot-file' variable if any argument
833 	 * was given to the `boot' command (e.g `boot -s'). If we determine
834 	 * in parse_bootfile() above, that boot args contain only switches
835 	 * then get the `boot-file' value (if any) ourselves.
836 	 * If the `diag-switch?' PROM variable is set to true, we use
837 	 * `diag-file' instead.
838 	 */
839 	prop = (prom_getoption("diag-switch?", buf, sizeof buf) != 0 ||
840 		strcmp(buf, "true") != 0)
841 		? "diag-file"
842 		: "boot-file";
843 
844 	if (prom_getoption(prop, storage, sizeof storage) != 0)
845 		return (NULL);
846 
847 	return (storage);
848 }
849 
850 void
obp_v2_putstr(const char * str,int len)851 obp_v2_putstr(const char *str, int len)
852 {
853 	prom_write(prom_stdout(), str, len);
854 }
855 
856 void
obp_set_callback(void (* f)(void))857 obp_set_callback(void (*f)(void))
858 {
859 	*obpvec->pv_synchook = f;
860 }
861 
862 int
obp_ticks(void)863 obp_ticks(void)
864 {
865 
866 	return (*((int *)promops.po_tickdata));
867 }
868 
869 static int
findchosen(void)870 findchosen(void)
871 {
872 static	int chosennode;
873 	int node;
874 
875 	if ((node = chosennode) == 0 && (node = OF_finddevice("/chosen")) == -1)
876 		panic("no CHOSEN node");
877 
878 	chosennode = node;
879 	return (node);
880 }
881 
882 static int
opf_finddevice(const char * name)883 opf_finddevice(const char *name)
884 {
885 	int phandle = OF_finddevice(name);
886 	if (phandle == -1)
887 		return (0);
888 	else
889 		return (phandle);
890 }
891 
892 static int
opf_instance_to_package(int ihandle)893 opf_instance_to_package(int ihandle)
894 {
895 	int phandle = OF_instance_to_package(ihandle);
896 	if (phandle == -1)
897 		return (0);
898 	else
899 		return (phandle);
900 }
901 
902 
903 static const char *
opf_getbootpath(void)904 opf_getbootpath(void)
905 {
906 	int node = findchosen();
907 	char *buf = storage;
908 	int blen = sizeof storage;
909 
910 	if (prom_getprop(node, "bootpath", 1, &blen, &buf) != 0)
911 		return ("");
912 
913 	return (buf);
914 }
915 
916 static const char *
opf_getbootargs(void)917 opf_getbootargs(void)
918 {
919 	int node = findchosen();
920 	char *buf = storage;
921 	int blen = sizeof storage;
922 
923 	if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0)
924 		return ("");
925 
926 	return (parse_bootargs(buf));
927 }
928 
929 static const char *
opf_getbootfile(void)930 opf_getbootfile(void)
931 {
932 	int node = findchosen();
933 	char *buf = storage;
934 	int blen = sizeof storage;
935 
936 	if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0)
937 		return ("");
938 
939 	return (parse_bootfile(buf));
940 }
941 
942 static char *
opf_nextprop(int node,const char * prop)943 opf_nextprop(int node, const char *prop)
944 {
945 #define OF_NEXTPROP_BUF_SIZE 32	/* specified by the standard */
946 	static char buf[OF_NEXTPROP_BUF_SIZE];
947 	OF_nextprop(node, prop, buf);
948 	return (buf);
949 }
950 
951 void
opf_interpret_simple(const char * s)952 opf_interpret_simple(const char *s)
953 {
954 	(void)OF_interpret(s, 0, 0);
955 }
956 
957 /*
958  * Retrieve physical memory information from the PROM.
959  * If ap is NULL, return the required length of the array.
960  */
961 int
prom_makememarr(struct memarr * ap,int xmax,int which)962 prom_makememarr(struct memarr *ap, int xmax, int which)
963 {
964 	struct v0mlist *mp;
965 	int node, n;
966 	const char *prop;
967 
968 	if (which != MEMARR_AVAILPHYS && which != MEMARR_TOTALPHYS)
969 		panic("makememarr");
970 
971 	/*
972 	 * `struct memarr' is in V2 memory property format.
973 	 * On previous ROM versions we must convert.
974 	 */
975 	switch (prom_version()) {
976 		struct promvec *promvec;
977 		struct om_vector *oldpvec;
978 	case PROM_OLDMON:
979 		oldpvec = (struct om_vector *)PROM_BASE;
980 		n = 1;
981 		if (ap != NULL) {
982 			ap[0].zero = 0;
983 			ap[0].addr = 0;
984 			ap[0].len = (which == MEMARR_AVAILPHYS)
985 				? *oldpvec->memoryAvail
986 				: *oldpvec->memorySize;
987 		}
988 		break;
989 
990 	case PROM_OBP_V0:
991 		/*
992 		 * Version 0 PROMs use a linked list to describe these
993 		 * guys.
994 		 */
995 		promvec = romp;
996 		mp = (which == MEMARR_AVAILPHYS)
997 			? *promvec->pv_v0mem.v0_physavail
998 			: *promvec->pv_v0mem.v0_phystot;
999 		for (n = 0; mp != NULL; mp = mp->next, n++) {
1000 			if (ap == NULL)
1001 				continue;
1002 			if (n >= xmax) {
1003 				printf("makememarr: WARNING: lost some memory\n");
1004 				break;
1005 			}
1006 			ap->zero = 0;
1007 			ap->addr = (u_long)mp->addr;
1008 			ap->len = mp->nbytes;
1009 			ap++;
1010 		}
1011 		break;
1012 
1013 	default:
1014 		printf("makememarr: hope version %d PROM is like version 2\n",
1015 			prom_version());
1016 		/* FALLTHROUGH */
1017 
1018         case PROM_OBP_V3:
1019 	case PROM_OBP_V2:
1020 		/*
1021 		 * Version 2 PROMs use a property array to describe them.
1022 		 */
1023 
1024 		/* Consider emulating `OF_finddevice' */
1025 		node = findnode(firstchild(findroot()), "memory");
1026 		goto case_common;
1027 
1028 	case PROM_OPENFIRM:
1029 		node = OF_finddevice("/memory");
1030 		if (node == -1)
1031 			node = 0;
1032 
1033 	case_common:
1034 		if (node == 0)
1035 			panic("makememarr: cannot find \"memory\" node");
1036 
1037 		prop = (which == MEMARR_AVAILPHYS) ? "available" : "reg";
1038 		if (ap == NULL) {
1039 			n = prom_getproplen(node, prop);
1040 		} else {
1041 			n = xmax;
1042 			if (prom_getprop(node, prop, sizeof(struct memarr),
1043 					&n, &ap) != 0)
1044 				panic("makememarr: cannot get property");
1045 		}
1046 		break;
1047 	}
1048 
1049 	if (n <= 0)
1050 		panic("makememarr: no memory found");
1051 	/*
1052 	 * Success!  (Hooray)
1053 	 */
1054 	return (n);
1055 }
1056 
1057 static struct idprom idprom;
1058 #ifdef _STANDALONE
1059 long hostid;
1060 #endif
1061 
1062 struct idprom *
prom_getidprom(void)1063 prom_getidprom(void)
1064 {
1065 	int node, len;
1066 	u_long h;
1067 	u_char *dst;
1068 
1069 	if (idprom.idp_format != 0)
1070 		/* Already got it */
1071 		return (&idprom);
1072 
1073 	dst = (u_char *)&idprom;
1074 	len = sizeof(struct idprom);
1075 
1076 	switch (prom_version()) {
1077 	case PROM_OLDMON:
1078 #ifdef AC_IDPROM
1079 		{
1080 			u_char *src = (u_char *)AC_IDPROM;
1081 			do {
1082 				*dst++ = lduba(src++, ASI_CONTROL);
1083 			} while (--len > 0);
1084 		}
1085 #endif
1086 		break;
1087 
1088 	/*
1089 	 * Fetch the `idprom' property at the root node.
1090 	 */
1091 	case PROM_OBP_V0:
1092 	case PROM_OBP_V2:
1093 	case PROM_OPENFIRM:
1094 	case PROM_OBP_V3:
1095 		node = prom_findroot();
1096 		if (prom_getprop(node, "idprom", 1, &len, &dst) != 0) {
1097 			printf("`idprom' property cannot be read: "
1098 				"cannot get ethernet address");
1099 		}
1100 		break;
1101 	}
1102 
1103 	/* Establish hostid */
1104 	h =  (u_int)idprom.idp_machtype << 24;
1105 	h |= idprom.idp_serialnum[0] << 16;
1106 	h |= idprom.idp_serialnum[1] << 8;
1107 	h |= idprom.idp_serialnum[2];
1108 	hostid = h;
1109 
1110 	return (&idprom);
1111 }
1112 
prom_getether(int node,u_char * cp)1113 void prom_getether(int node, u_char *cp)
1114 {
1115 	struct idprom *idp;
1116 
1117 	if (prom_get_node_ether(node, cp))
1118 		return;
1119 
1120 	/* Fall back on the machine's global ethernet address */
1121 	idp = prom_getidprom();
1122 	memcpy(cp, idp->idp_etheraddr, 6);
1123 }
1124 
1125 bool
prom_get_node_ether(int node,u_char * cp)1126 prom_get_node_ether(int node, u_char *cp)
1127 {
1128 	char buf[6+1], *bp;
1129 	int nitem;
1130 
1131 	if (node == 0)
1132 		return false;
1133 
1134 	/*
1135 	 * First, try the node's "mac-address" property.
1136 	 * This property is set by the adapter's firmware if the
1137 	 * device has already been opened for traffic, e.g. for
1138 	 * net booting.  Its value might be `0-terminated', probably
1139 	 * because the Forth ROMs uses `xdrstring' instead of `xdrbytes'
1140 	 * to construct the property.
1141 	 */
1142 	nitem = 6+1;
1143 	bp = buf;
1144 	if (prom_getprop(node, "mac-address", 1, &nitem, &bp) == 0 &&
1145 	    nitem >= 6) {
1146 		memcpy(cp, bp, 6);
1147 		return true;
1148 	}
1149 
1150 	/*
1151 	 * Next, check the global "local-mac-address?" switch to see
1152 	 * if we should try to extract the node's "local-mac-address"
1153 	 * property.
1154 	 */
1155 	if (prom_getoption("local-mac-address?", buf, sizeof buf) != 0 ||
1156 	    strcmp(buf, "true") != 0)
1157 		return false;
1158 
1159 	/* Retrieve the node's "local-mac-address" property, if any */
1160 	nitem = 6;
1161 	if (prom_getprop(node, "local-mac-address", 1, &nitem, &cp) == 0 &&
1162 	    nitem == 6)
1163 		return true;
1164 
1165 	return false;
1166 }
1167 
1168 /*
1169  * The integer property "get-unum" on the root device is the address
1170  * of a callable function in the PROM that takes a physical address
1171  * (in lo/hipart format) and returns a string identifying the chip
1172  * location of the corresponding memory cell.
1173  */
1174 const char *
prom_pa_location(u_int phys_lo,u_int phys_hi)1175 prom_pa_location(u_int phys_lo, u_int phys_hi)
1176 {
1177 	static char *(*unum)(u_int, u_int);
1178 	char *str;
1179 	const char *unk = "<Unknown>";
1180 
1181 	switch (prom_version()) {
1182 	case PROM_OLDMON:
1183 	case PROM_OPENFIRM:
1184 		/* to do */
1185 	default:
1186 		break;
1187 	case PROM_OBP_V0:
1188 	case PROM_OBP_V2:
1189 	case PROM_OBP_V3:
1190 		if (unum == NULL)
1191 			unum = (char *(*)(u_int,u_int))(u_long)
1192 				prom_getpropint(prom_findroot(), "get-unum", 0);
1193 
1194 		if (unum == NULL || (str = unum(phys_lo, phys_hi)) == NULL)
1195 			break;
1196 
1197 		return (str);
1198 	}
1199 
1200 	return (unk);
1201 }
1202 
1203 static void prom_init_oldmon(void);
1204 static void prom_init_obp(void);
1205 static void prom_init_opf(void);
1206 
1207 static inline void
prom_init_oldmon(void)1208 prom_init_oldmon(void)
1209 {
1210 	struct om_vector *oldpvec = (struct om_vector *)PROM_BASE;
1211 
1212 	promops.po_version = PROM_OLDMON;
1213 	promops.po_revision = oldpvec->monId[0];	/*XXX*/
1214 
1215 	promops.po_stdin = *oldpvec->inSource;
1216 	promops.po_stdout = *oldpvec->outSink;
1217 
1218 	promops.po_bootcookie = *oldpvec->bootParam; /* deref 1 lvl */
1219 	promops.po_bootpath = obp_v0_getbootpath;
1220 	promops.po_bootfile = obp_v0_getbootfile;
1221 	promops.po_bootargs = obp_v0_getbootargs;
1222 
1223 	promops.po_putchar = oldpvec->putChar;
1224 	promops.po_getchar = oldpvec->getChar;
1225 	promops.po_peekchar = oldpvec->mayGet;
1226 	promops.po_putstr = oldpvec->fbWriteStr;
1227 	promops.po_reboot = oldpvec->reBoot;
1228 	promops.po_abort = oldpvec->abortEntry;
1229 	promops.po_halt = oldpvec->exitToMon;
1230 	promops.po_ticks = obp_ticks;
1231 	promops.po_tickdata = oldpvec->nmiClock;
1232 	promops.po_setcallback = (void *)sparc_noop;
1233 	promops.po_setcontext = oldpvec->setcxsegmap;
1234 
1235 #ifdef SUN4
1236 #ifndef _STANDALONE
1237 	if (oldpvec->romvecVersion >= 2) {
1238 		*oldpvec->vector_cmd = oldmon_w_cmd;
1239 	}
1240 #endif
1241 #endif
1242 }
1243 
1244 static inline void
prom_init_obp(void)1245 prom_init_obp(void)
1246 {
1247 	struct nodeops *no;
1248 
1249 	/*
1250 	 * OBP v0, v2 & v3
1251 	 */
1252 	switch (obpvec->pv_romvec_vers) {
1253 	case 0:
1254 		promops.po_version = PROM_OBP_V0;
1255 		break;
1256 	case 2:
1257 		promops.po_version = PROM_OBP_V2;
1258 		break;
1259 	case 3:
1260 		promops.po_version = PROM_OBP_V3;
1261 		break;
1262 	default:
1263 		obpvec->pv_halt();	/* What else? */
1264 	}
1265 
1266 	promops.po_revision = obpvec->pv_printrev;
1267 
1268 	promops.po_halt = obpvec->pv_halt;
1269 	promops.po_reboot = obpvec->pv_reboot;
1270 	promops.po_abort = obpvec->pv_abort;
1271 	promops.po_setcontext = obpvec->pv_setctxt;
1272 	promops.po_setcallback = obp_set_callback;
1273 	promops.po_ticks = obp_ticks;
1274 	promops.po_tickdata = obpvec->pv_ticks;
1275 
1276 	/*
1277 	 * Remove indirection through `pv_nodeops' while we're here.
1278 	 * Hopefully, the PROM has no need to change this pointer on the fly..
1279 	 */
1280 	no = obpvec->pv_nodeops;
1281 	promops.po_firstchild = no->no_child;
1282 	promops.po_nextsibling = no->no_nextnode;
1283 	promops.po_getproplen = no->no_proplen;
1284 	/* XXX - silently discard getprop's `len' argument */
1285 	promops.po_getprop = (void *)no->no_getprop;
1286 	promops.po_setprop = no->no_setprop;
1287 	promops.po_nextprop = no->no_nextprop;
1288 
1289 #ifndef _STANDALONE
1290 	promops.po_node_to_devhandle = devhandle_from_obp;
1291 	promops.po_devhandle_to_node = devhandle_to_obp;
1292 #endif /* _STANDALONE */
1293 
1294 	/*
1295 	 * Next, deal with prom vector differences between versions.
1296 	 */
1297 	switch (promops.po_version) {
1298 	case PROM_OBP_V0:
1299 		promops.po_stdin = *obpvec->pv_stdin;
1300 		promops.po_stdout = *obpvec->pv_stdout;
1301 		promops.po_bootcookie = *obpvec->pv_v0bootargs; /* deref 1 lvl */
1302 		promops.po_bootpath = obp_v0_getbootpath;
1303 		promops.po_bootfile = obp_v0_getbootfile;
1304 		promops.po_bootargs = obp_v0_getbootargs;
1305 		promops.po_putchar = obpvec->pv_putchar;
1306 		promops.po_getchar = obpvec->pv_getchar;
1307 		promops.po_peekchar = obpvec->pv_nbgetchar;
1308 		promops.po_putstr = obpvec->pv_putstr;
1309 		promops.po_open = obpvec->pv_v0devops.v0_open;
1310 		promops.po_close = (void *)obpvec->pv_v0devops.v0_close;
1311 		promops.po_read = obp_v0_read;
1312 		promops.po_write = obp_v0_write;
1313 		promops.po_interpret = obp_v0_fortheval;
1314 		break;
1315 	case PROM_OBP_V3:
1316 		promops.po_cpustart = obpvec->pv_v3cpustart;
1317 		promops.po_cpustop = obpvec->pv_v3cpustop;
1318 		promops.po_cpuidle = obpvec->pv_v3cpuidle;
1319 		promops.po_cpuresume = obpvec->pv_v3cpuresume;
1320 		/*FALLTHROUGH*/
1321 	case PROM_OBP_V2:
1322 		/* Deref stdio handles one level */
1323 		promops.po_stdin = *obpvec->pv_v2bootargs.v2_fd0;
1324 		promops.po_stdout = *obpvec->pv_v2bootargs.v2_fd1;
1325 
1326 		promops.po_bootcookie = &obpvec->pv_v2bootargs;
1327 		promops.po_bootpath = obp_v2_getbootpath;
1328 		promops.po_bootfile = obp_v2_getbootfile;
1329 		promops.po_bootargs = obp_v2_getbootargs;
1330 
1331 		promops.po_interpret = obpvec->pv_fortheval.v2_eval;
1332 
1333 		promops.po_putchar = obp_v2_putchar;
1334 		promops.po_getchar = obp_v2_getchar;
1335 		promops.po_peekchar = obp_v2_peekchar;
1336 		promops.po_putstr = obp_v2_putstr;
1337 		promops.po_open = obpvec->pv_v2devops.v2_open;
1338 		promops.po_close = (void *)obpvec->pv_v2devops.v2_close;
1339 		promops.po_read = obpvec->pv_v2devops.v2_read;
1340 		promops.po_write = obpvec->pv_v2devops.v2_write;
1341 		promops.po_seek = obp_v2_seek;
1342 		promops.po_instance_to_package = obpvec->pv_v2devops.v2_fd_phandle;
1343 		promops.po_finddevice = obp_v2_finddevice;
1344 
1345 #ifndef _STANDALONE
1346 		prom_printf("OBP version %d, revision %d.%d (plugin rev %x)\n",
1347 			obpvec->pv_romvec_vers,
1348 			obpvec->pv_printrev >> 16, obpvec->pv_printrev & 0xffff,
1349 			obpvec->pv_plugin_vers);
1350 #endif
1351 		break;
1352 	}
1353 }
1354 
1355 static inline void
prom_init_opf(void)1356 prom_init_opf(void)
1357 {
1358 	int node;
1359 
1360 	promops.po_version = PROM_OPENFIRM;
1361 
1362 	/*
1363 	 * OpenFirmware ops are mostly straightforward.
1364 	 */
1365 	promops.po_halt = OF_exit;
1366 	promops.po_reboot = OF_boot;
1367 	promops.po_abort = OF_enter;
1368 	promops.po_interpret = opf_interpret_simple;
1369 	promops.po_setcallback = (void *)OF_set_callback;
1370 	promops.po_ticks = OF_milliseconds;
1371 
1372 	promops.po_bootpath = opf_getbootpath;
1373 	promops.po_bootfile = opf_getbootfile;
1374 	promops.po_bootargs = opf_getbootargs;
1375 
1376 	promops.po_firstchild = OF_child;
1377 	promops.po_nextsibling = OF_peer;
1378 	promops.po_getproplen = OF_getproplen;
1379 	promops.po_getprop = OF_getprop;
1380 	promops.po_nextprop = opf_nextprop;
1381 	promops.po_setprop = OF_setprop;
1382 
1383 	/* We can re-use OBP v2 emulation */
1384 	promops.po_putchar = obp_v2_putchar;
1385 	promops.po_getchar = obp_v2_getchar;
1386 	promops.po_peekchar = obp_v2_peekchar;
1387 	promops.po_putstr = obp_v2_putstr;
1388 
1389 	promops.po_open = OF_open;
1390 	promops.po_close = OF_close;
1391 	promops.po_read = OF_read;
1392 	promops.po_write = OF_write;
1393 	promops.po_seek = OF_seek;
1394 	promops.po_instance_to_package = opf_instance_to_package;
1395 	promops.po_finddevice = opf_finddevice;
1396 
1397 #ifndef _STANDALONE
1398 #ifdef __sparc64__
1399 	promops.po_node_to_devhandle = devhandle_from_of;
1400 	promops.po_devhandle_to_node = devhandle_to_of;
1401 #else
1402 	/*
1403 	 * For 32-bit SPARC, pretend this is OpenBoot for now.
1404 	 * The differences will be hidden behind the promops
1405 	 * anyway.  We do this because this platform doesn't
1406 	 * pull in all of the OpenFirmware support code that
1407 	 * 64-bit SPARC does.
1408 	 */
1409 	promops.po_node_to_devhandle = devhandle_from_obp;
1410 	promops.po_devhandle_to_node = devhandle_to_obp;
1411 #endif /* __sparc64__ */
1412 #endif /* _STANDALONE */
1413 
1414 	/* Retrieve and cache stdio handles */
1415 	node = findchosen();
1416 	OF_getprop(node, "stdin", &promops.po_stdin, sizeof(int));
1417 	OF_getprop(node, "stdout", &promops.po_stdout, sizeof(int));
1418 
1419 	OF_init();
1420 }
1421 
1422 /*
1423  * Initialize our PROM operations vector.
1424  */
1425 void
prom_init(void)1426 prom_init(void)
1427 {
1428 #ifdef _STANDALONE
1429 	int node;
1430 	char *cp;
1431 #endif
1432 
1433 	if (CPU_ISSUN4) {
1434 		prom_init_oldmon();
1435 	} else if (obpvec->pv_magic == OBP_MAGIC) {
1436 		prom_init_obp();
1437 	} else {
1438 		/*
1439 		 * Assume this is an Openfirm machine.
1440 		 */
1441 		prom_init_opf();
1442 	}
1443 
1444 #ifdef _STANDALONE
1445 	/*
1446 	 * Find out what type of machine we're running on.
1447 	 *
1448 	 * This process is actually started in srt0.S, which has discovered
1449 	 * the minimal set of machine specific parameters for the 1st-level
1450 	 * boot program (bootxx) to run. The page size has already been set
1451 	 * and the CPU type is either CPU_SUN4, CPU_SUN4C or CPU_SUN4M.
1452 	 */
1453 
1454 	if (cputyp == CPU_SUN4 || cputyp == CPU_SUN4M)
1455 		return;
1456 
1457 	/*
1458 	 * We have SUN4C, SUN4M or SUN4D.
1459 	 * Use the PROM `compatible' property to determine which.
1460 	 * Absence of the `compatible' property means `sun4c'.
1461 	 */
1462 
1463 	node = prom_findroot();
1464 	cp = prom_getpropstring(node, "compatible");
1465 	if (*cp == '\0' || strcmp(cp, "sun4c") == 0)
1466 		cputyp = CPU_SUN4C;
1467 	else if (strcmp(cp, "sun4m") == 0)
1468 		cputyp = CPU_SUN4M;
1469 	else if (strcmp(cp, "sun4d") == 0)
1470 		cputyp = CPU_SUN4D;
1471 	else
1472 		printf("Unknown CPU type (compatible=`%s')\n", cp);
1473 #endif /* _STANDALONE */
1474 }
1475