xref: /netbsd/sys/arch/sparc/sparc/promlib.c (revision bf9ec67e)
1 /*	$NetBSD: promlib.c,v 1.13 2001/12/07 11:00:39 hannken 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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
41  * from the rest of the kernel.
42  */
43 #if defined(_KERNEL_OPT)
44 #include "opt_sparc_arch.h"
45 #endif
46 
47 #include <sys/errno.h>
48 #include <sys/param.h>
49 
50 #ifdef _STANDALONE
51 #include <lib/libsa/stand.h>
52 #define malloc(s,t,f)	alloc(s)
53 #else
54 #include <sys/systm.h>
55 #include <sys/malloc.h>
56 #endif /* _STANDALONE */
57 
58 #include <machine/stdarg.h>
59 #include <machine/oldmon.h>
60 #include <machine/bsd_openprom.h>
61 #include <machine/promlib.h>
62 #include <machine/openfirm.h>
63 
64 #define obpvec ((struct promvec *)romp)
65 
66 static void	notimplemented __P((void));
67 static void	obp_v0_fortheval __P((char *));
68 static void	obp_set_callback __P((void (*)__P((void))));
69 static int	obp_v0_read __P((int, void *, int));
70 static int	obp_v0_write __P((int, void *, int));
71 static int	obp_v2_getchar __P((void));
72 static int	obp_v2_peekchar __P((void));
73 static void	obp_v2_putchar __P((int));
74 static void	obp_v2_putstr __P((char *, int));
75 static int	obp_v2_seek __P((int, u_quad_t));
76 static char	*parse_bootfile __P((char *));
77 static char	*parse_bootargs __P((char *));
78 static char	*obp_v0_getbootpath __P((void));
79 static char	*obp_v0_getbootfile __P((void));
80 static char	*obp_v0_getbootargs __P((void));
81 static char	*obp_v2_getbootpath __P((void));
82 static char	*obp_v2_getbootfile __P((void));
83 static char	*obp_v2_getbootargs __P((void));
84 static int	obp_v2_finddevice __P((char *));
85 static int	obp_ticks __P((void));
86 
87 static int	findchosen __P((void));
88 static char	*opf_getbootpath __P((void));
89 static char	*opf_getbootfile __P((void));
90 static char	*opf_getbootargs __P((void));
91 static int	opf_finddevice __P((char *));
92 static int	opf_instance_to_package __P((int));
93 static char	*opf_nextprop __P((int, char *));
94 
95 
96 /*
97  * PROM entry points.
98  * Note: only PROM functions we use ar represented here; add as required.
99  */
100 struct promops promops = {
101 	-1,				/* version */
102 	-1,				/* revision */
103 	-1,				/* stdin handle */
104 	-1,				/* stdout handle */
105 	NULL,				/* bootargs */
106 
107 	(void *)notimplemented,		/* bootpath */
108 	(void *)notimplemented,		/* bootargs */
109 	(void *)notimplemented,		/* bootfile */
110 
111 	(void *)notimplemented,		/* getchar */
112 	(void *)notimplemented,		/* peekchar */
113 	(void *)notimplemented,		/* putchar */
114 	(void *)notimplemented,		/* putstr */
115 	(void *)notimplemented,		/* open */
116 	(void *)notimplemented,		/* close */
117 	(void *)notimplemented,		/* read */
118 	(void *)notimplemented,		/* write */
119 	(void *)notimplemented,		/* seek */
120 
121 	(void *)notimplemented,		/* instance_to_package */
122 
123 	(void *)notimplemented,		/* halt */
124 	(void *)notimplemented,		/* boot */
125 	(void *)notimplemented,		/* call */
126 	(void *)notimplemented,		/* interpret */
127 	(void *)notimplemented,		/* callback */
128 	(void *)notimplemented,		/* ticks */
129 	NULL,				/* ticker data */
130 
131 	(void *)notimplemented,		/* setcontext */
132 	(void *)notimplemented,		/* cpustart */
133 	(void *)notimplemented,		/* cpustop */
134 	(void *)notimplemented,		/* cpuidle */
135 	(void *)notimplemented,		/* cpuresume */
136 
137 	(void *)notimplemented,		/* firstchild */
138 	(void *)notimplemented,		/* nextsibling */
139 
140 	(void *)notimplemented,		/* getproplen */
141 	(void *)notimplemented,		/* getprop */
142 	(void *)notimplemented,		/* setprop */
143 	(void *)notimplemented,		/* nextprop */
144 	(void *)notimplemented		/* finddevice */
145 };
146 
147 static void
148 notimplemented()
149 {
150 	char str[64];
151 	int n;
152 
153 	n = sprintf(str, "Operation not implemented on ROM version %d\r\n",
154 		    promops.po_version);
155 
156 	/*
157 	 * Use PROM vector directly, in case we're called before prom_init().
158 	 */
159 #if defined(SUN4)
160 	if (CPU_ISSUN4) {
161 		struct om_vector *sun4pvec = (struct om_vector *)PROM_BASE;
162 		(*sun4pvec->fbWriteStr)(str, n);
163 	} else
164 #endif
165 	if (obpvec->pv_magic == OBP_MAGIC) {
166 		if (obpvec->pv_romvec_vers < 2) {
167 			(*obpvec->pv_putstr)(str, n);
168 		} else {
169 			int fd = *obpvec->pv_v2bootargs.v2_fd1;
170 			(*obpvec->pv_v2devops.v2_write)(fd, str, n);
171 		}
172 	} else {	/* assume OFW */
173 		static int stdout_node;
174 		if (stdout_node == 0) {
175 			int chosen = findchosen();
176 			OF_getprop(chosen, "stdout", &stdout_node, sizeof(int));
177 		}
178 		OF_write(stdout_node, str, n);
179 	}
180 }
181 
182 
183 /*
184  * PROM_getprop() reads the named property data from a given node.
185  * A buffer for the data may be passed in `*bufp'; if NULL, a
186  * buffer is allocated. The argument `size' specifies the data
187  * element size of the property data. This function checks that
188  * the actual property data length is an integral multiple of
189  * the element size.  The number of data elements read into the
190  * buffer is returned into the integer pointed at by `nitem'.
191  */
192 
193 int
194 PROM_getprop(node, name, size, nitem, bufp)
195 	int	node;
196 	char	*name;
197 	int	size;
198 	int	*nitem;
199 	void	**bufp;
200 {
201 	void	*buf;
202 	int	len;
203 
204 	len = PROM_getproplen(node, name);
205 	if (len <= 0)
206 		return (ENOENT);
207 
208 	if ((len % size) != 0)
209 		return (EINVAL);
210 
211 	buf = *bufp;
212 	if (buf == NULL) {
213 		/* No storage provided, so we allocate some */
214 		buf = malloc(len, M_DEVBUF, M_NOWAIT);
215 		if (buf == NULL)
216 			return (ENOMEM);
217 	} else {
218 		if (size * (*nitem) < len)
219 			return (ENOMEM);
220 	}
221 
222 	_prom_getprop(node, name, buf, len);
223 	*bufp = buf;
224 	*nitem = len / size;
225 	return (0);
226 }
227 
228 /*
229  * Return a string property.  There is a (small) limit on the length;
230  * the string is fetched into a static buffer which is overwritten on
231  * subsequent calls.
232  */
233 char *
234 PROM_getpropstring(node, name)
235 	int node;
236 	char *name;
237 {
238 	static char stringbuf[32];
239 
240 	return (PROM_getpropstringA(node, name, stringbuf, sizeof stringbuf));
241 }
242 
243 /*
244  * Alternative PROM_getpropstring(), where caller provides the buffer
245  */
246 char *
247 PROM_getpropstringA(node, name, buf, bufsize)
248 	int node;
249 	char *name;
250 	char *buf;
251 	size_t bufsize;
252 {
253 	int len = bufsize - 1;
254 
255 	if (PROM_getprop(node, name, 1, &len, (void **)&buf) != 0)
256 		len = 0;
257 
258 	buf[len] = '\0';	/* usually unnecessary */
259 	return (buf);
260 }
261 
262 /*
263  * Fetch an integer (or pointer) property.
264  * The return value is the property, or the default if there was none.
265  */
266 int
267 PROM_getpropint(node, name, deflt)
268 	int node;
269 	char *name;
270 	int deflt;
271 {
272 	int intbuf, *ip = &intbuf;
273 	int len = 1;
274 
275 	if (PROM_getprop(node, name, sizeof(int), &len, (void **)&ip) != 0)
276 		return (deflt);
277 
278 	return (*ip);
279 }
280 
281 #if 0
282 /*
283  * prom_search() recursively searches a PROM tree for a given node
284  */
285 int
286 prom_search(rootnode, name)
287 	int rootnode;
288 	const char *name;
289 {
290 	int rtnnode;
291 	int node = rootnode;
292 	char buf[32];
293 
294 #define GPSA(nm)	PROM_getpropstringA(node, nm, buf, sizeof buf)
295 	if (node == findroot() ||
296 	    !strcmp("hierarchical", GPSA("device type")))
297 		node = firstchild(node);
298 
299 	if (node == 0)
300 		panic("prom_search: null node");
301 
302 	do {
303 		if (strcmp(GPSA("name"), name) == 0)
304 			return (node);
305 
306 		if ((strcmp(GPSA("device_type"), "hierarchical") == 0 ||
307 		    strcmp(GPSA("name"), "iommu") == 0)
308 		    && (rtnnode = prom_search(node, name)) != 0)
309 			return (rtnnode);
310 
311 	} while ((node = nextsibling(node)) != NULL);
312 
313 	return (0);
314 }
315 #endif
316 
317 /*
318  * Find the named device in the PROM device tree.
319  * XXX - currently we discard any qualifiers attached to device component names
320  */
321 int
322 obp_v2_finddevice(name)
323 	char *name;
324 {
325 	int node;
326 	char component[64];
327 	char c, *startp, *endp, *cp;
328 #define IS_SEP(c)	((c) == '/' || (c) == '@' || (c) == ':')
329 
330 	if (name == NULL)
331 		return (-1);
332 
333 	node = prom_findroot();
334 
335 	for (startp = name; *startp != '\0'; ) {
336 		node = prom_firstchild(node);
337 
338 		/*
339 		 * Identify next component in pathname
340 		 */
341 		while (*startp == '/')
342 			startp++;
343 
344 		endp = startp;
345 		while ((c = *endp) != '\0' && !IS_SEP(c))
346 			endp++;
347 
348 		/* Copy component */
349 		for (cp = component; startp != endp;)
350 			*cp++ = *startp++;
351 
352 		/* Zero terminate this component */
353 		*cp = '\0';
354 
355 		/* Advance `startp' over any non-slash separators */
356 		while ((c = *startp) != '\0' && c != '/')
357 			startp++;
358 
359 		node = prom_findnode(node, component);
360 		if (node == 0)
361 			return (-1);
362 	}
363 
364 	return (node);
365 }
366 
367 
368 /*
369  * Translate device path to node
370  */
371 int
372 prom_opennode(path)
373 	char *path;
374 {
375 	int fd;
376 
377 	if (prom_version() < 2) {
378 		printf("WARNING: opennode not valid on PROM version %d\n",
379 			promops.po_version);
380 		return (0);
381 	}
382 	fd = prom_open(path);
383 	if (fd == 0)
384 		return (0);
385 
386 	return (prom_instance_to_package(fd));
387 }
388 
389 int
390 prom_findroot()
391 {
392 static	int rootnode;
393 	int node;
394 
395 	if ((node = rootnode) == 0 && (node = prom_nextsibling(0)) == 0)
396 		panic("no PROM root device");
397 	rootnode = node;
398 	return (node);
399 }
400 
401 /*
402  * Given a `first child' node number, locate the node with the given name.
403  * Return the node number, or 0 if not found.
404  */
405 int
406 prom_findnode(first, name)
407 	int first;
408 	const char *name;
409 {
410 	int node;
411 	char buf[32];
412 
413 	for (node = first; node != 0; node = prom_nextsibling(node)) {
414 		if (strcmp(PROM_getpropstringA(node, "name", buf, sizeof(buf)),
415 			   name) == 0)
416 			return (node);
417 	}
418 	return (0);
419 }
420 
421 /*
422  * Determine whether a node has the given property.
423  */
424 int
425 prom_node_has_property(node, prop)
426 	int node;
427 	const char *prop;
428 {
429 
430 	return (PROM_getproplen(node, (caddr_t)prop) != -1);
431 }
432 
433 
434 void
435 prom_halt()
436 {
437 
438 	prom_setcallback(NULL);
439 	_prom_halt();
440 	panic("PROM exit failed");
441 }
442 
443 void
444 prom_boot(str)
445 	char *str;
446 {
447 
448 	prom_setcallback(NULL);
449 	_prom_boot(str);
450 	panic("PROM boot failed");
451 }
452 
453 
454 /*
455  * print debug info to prom.
456  * This is not safe, but then what do you expect?
457  */
458 void
459 #ifdef __STDC__
460 prom_printf(const char *fmt, ...)
461 #else
462 prom_printf(fmt, va_alist)
463 	char *fmt;
464 	va_dcl
465 #endif
466 {
467 static	char buf[256];
468 	int i, len;
469 	va_list ap;
470 
471 	va_start(ap, fmt);
472 	len = vsnprintf(buf, sizeof(buf), fmt, ap);
473 	va_end(ap);
474 
475 #if _obp_not_cooked_
476 	(*promops.po_write)(promops.po_stdout, buf, len);
477 #endif
478 
479 	for (i = 0; i < len; i++) {
480 		int c = buf[i];
481 		if (c == '\n')
482 			(*promops.po_putchar)('\r');
483 		(*promops.po_putchar)(c);
484 	}
485 }
486 
487 
488 /*
489  * Pass a string to the FORTH PROM to be interpreted.
490  * (Note: may fail silently)
491  */
492 static void
493 obp_v0_fortheval(s)
494 	char *s;
495 {
496 
497 	obpvec->pv_fortheval.v0_eval(strlen(s), s);
498 }
499 
500 int
501 obp_v0_read(fd, buf, len)
502 	int fd;
503 	void *buf;
504 	int len;
505 {
506 	if (fd != prom_stdin())
507 		prom_printf("obp_v0_read: unimplemented read from %d\n", fd);
508 	return (-1);
509 }
510 
511 int
512 obp_v0_write(fd, buf, len)
513 	int fd;
514 	void *buf;
515 	int len;
516 {
517 	if (fd != prom_stdout())
518 		prom_printf("obp_v0_write: unimplemented write on %d\n", fd);
519 	(*obpvec->pv_putstr)(buf, len);
520 	return (-1);
521 }
522 
523 __inline__ void
524 obp_v2_putchar(c)
525 	int c;
526 {
527 	char c0;
528 
529 	c0 = (c & 0x7f);
530 	(*promops.po_write)(promops.po_stdout, &c0, 1);
531 }
532 
533 #if 0
534 void
535 obp_v2_putchar_cooked(c)
536 	int c;
537 {
538 
539 	if (c == '\n')
540 		obp_v2_putchar('\r');
541 	obp_v2_putchar(c);
542 }
543 #endif
544 
545 int
546 obp_v2_getchar()
547 {
548 	char c;
549 	int n;
550 
551 	while ((n = (*promops.po_read)(promops.po_stdin, &c, 1)) != 1)
552 		/*void*/;
553 	if (c == '\r')
554 		c = '\n';
555 	return (c);
556 }
557 
558 int
559 obp_v2_peekchar()
560 {
561 	char c;
562 	int n;
563 
564 	n = (*promops.po_read)(promops.po_stdin, &c, 1);
565 	if (n < 0)
566 		return (-1);
567 
568 	if (c == '\r')
569 		c = '\n';
570 	return (c);
571 }
572 
573 int
574 obp_v2_seek(handle, offset)
575 	int handle;
576 	u_quad_t offset;
577 {
578 	u_int32_t hi, lo;
579 
580 	lo = offset & ((u_int32_t)-1);
581 	hi = (offset >> 32) & ((u_int32_t)-1);
582 	(*obpvec->pv_v2devops.v2_seek)(handle, hi, lo);
583 	return (0);
584 }
585 
586 /*
587  * On SS1s (and also IPCs, SLCs), `promvec->pv_v0bootargs->ba_argv[1]'
588  * contains the flags that were given after the boot command.  On SS2s
589  * (and ELCs, IPXs, etc. and any sun4m class machine), `pv_v0bootargs'
590  * is NULL but `*promvec->pv_v2bootargs.v2_bootargs' points to
591  * "netbsd -s" or whatever.
592  */
593 char *
594 obp_v0_getbootpath()
595 {
596 	struct v0bootargs *ba = promops.po_bootcookie;
597 	return (ba->ba_argv[0]);
598 }
599 
600 char *
601 obp_v0_getbootargs()
602 {
603 	struct v0bootargs *ba = promops.po_bootcookie;
604 	return (ba->ba_argv[1]);
605 }
606 
607 char *
608 obp_v0_getbootfile()
609 {
610 	struct v0bootargs *ba = promops.po_bootcookie;
611 	return (ba->ba_kernel);
612 }
613 
614 char *
615 parse_bootargs(args)
616 	char *args;
617 {
618 	char *cp;
619 
620 	for (cp = args; *cp != '\0'; cp++) {
621 		if (*cp == '-') {
622 			int c;
623 			/*
624 			 * Looks like options start here, but check this
625 			 * `-' is not part of the kernel name.
626 			 */
627 			if (cp == args)
628 				break;
629 			if ((c = *(cp-1)) == ' ' || c == '\t')
630 				break;
631 		}
632 	}
633 	return (cp);
634 }
635 
636 char *
637 obp_v2_getbootpath()
638 {
639 	struct v2bootargs *ba = promops.po_bootcookie;
640 	return (*ba->v2_bootpath);
641 }
642 
643 char *
644 obp_v2_getbootargs()
645 {
646 	struct v2bootargs *ba = promops.po_bootcookie;
647 
648 	return (parse_bootargs(*ba->v2_bootargs));
649 }
650 
651 char *
652 parse_bootfile(args)
653 	char *args;
654 {
655 static	char storage[128];
656 	char *cp, *dp;
657 
658 	cp = args;
659 	dp = storage;
660 	while (*cp != 0 && *cp != ' ' && *cp != '\t') {
661 		if (dp >= storage + sizeof(storage) - 1) {
662 			prom_printf("v2_bootargs too long\n");
663 			return (NULL);
664 		}
665 		if (*cp == '-') {
666 			int c;
667 			/*
668 			 * If this `-' is most likely the start of boot
669 			 * options, we're done.
670 			 */
671 			if (cp == args)
672 				break;
673 			if ((c = *(cp-1)) == ' ' || c == '\t')
674 				break;
675 		}
676 		*dp++ = *cp++;
677 	}
678 	*dp = '\0';
679 	return (storage);
680 }
681 
682 char *
683 obp_v2_getbootfile()
684 {
685 	struct v2bootargs *ba = promops.po_bootcookie;
686 
687 	return (parse_bootfile(*ba->v2_bootargs));
688 }
689 
690 void
691 obp_v2_putstr(str, len)
692 	char *str;
693 	int len;
694 {
695 	prom_write(prom_stdout(), str, len);
696 }
697 
698 void
699 obp_set_callback(f)
700 	void (*f)__P((void));
701 {
702 	*obpvec->pv_synchook = f;
703 }
704 
705 int
706 obp_ticks()
707 {
708 
709 	return (*((int *)promops.po_tickdata));
710 }
711 
712 static int
713 findchosen()
714 {
715 static	int chosennode;
716 	int node;
717 
718 	if ((node = chosennode) == 0 && (node = OF_finddevice("/chosen")) == -1)
719 		panic("no CHOSEN node");
720 
721 	chosennode = node;
722 	return (node);
723 }
724 
725 static int
726 opf_finddevice(name)
727 	char *name;
728 {
729 	int phandle = OF_finddevice(name);
730 	if (phandle == -1)
731 		return (0);
732 	else
733 		return (phandle);
734 }
735 
736 static int
737 opf_instance_to_package(ihandle)
738 	int ihandle;
739 {
740 	int phandle = OF_instance_to_package(ihandle);
741 	if (phandle == -1)
742 		return (0);
743 	else
744 		return (phandle);
745 }
746 
747 
748 static char *
749 opf_getbootpath()
750 {
751 	int node = findchosen();
752 	char *buf = NULL;
753 	int blen = 0;
754 
755 	if (PROM_getprop(node, "bootpath", 1, &blen, (void **)&buf) != 0)
756 		return ("");
757 
758 	return (buf);
759 }
760 
761 static char *
762 opf_getbootargs()
763 {
764 	int node = findchosen();
765 	char *buf = NULL;
766 	int blen = 0;
767 
768 	if (PROM_getprop(node, "bootargs", 1, &blen, (void **)&buf) != 0)
769 		return ("");
770 
771 	return (parse_bootargs(buf));
772 }
773 
774 static char *
775 opf_getbootfile()
776 {
777 	int node = findchosen();
778 	char *buf = NULL;
779 	int blen = 0;
780 
781 	if (PROM_getprop(node, "bootargs", 1, &blen, (void **)&buf) != 0)
782 		return ("");
783 
784 	return (parse_bootfile(buf));
785 }
786 
787 static char *
788 opf_nextprop(node, prop)
789 	int node;
790 	char *prop;
791 {
792 #define OF_NEXTPROP_BUF_SIZE 32	/* specified by the standard */
793 	static char buf[OF_NEXTPROP_BUF_SIZE];
794 	OF_nextprop(node, prop, buf);
795 	return (buf);
796 }
797 
798 static void prom_init_oldmon __P((void));
799 static void prom_init_obp __P((void));
800 static void prom_init_opf __P((void));
801 
802 static __inline__ void
803 prom_init_oldmon()
804 {
805 	struct om_vector *oldpvec = (struct om_vector *)PROM_BASE;
806 	extern void sparc_noop __P((void));
807 
808 	promops.po_version = PROM_OLDMON;
809 	promops.po_revision = oldpvec->monId[0];	/*XXX*/
810 
811 	promops.po_stdin = *oldpvec->inSource;
812 	promops.po_stdout = *oldpvec->outSink;
813 
814 	promops.po_bootcookie = *oldpvec->bootParam; /* deref 1 lvl */
815 	promops.po_bootpath = obp_v0_getbootpath;
816 	promops.po_bootfile = obp_v0_getbootfile;
817 	promops.po_bootargs = obp_v0_getbootargs;
818 
819 	promops.po_putchar = oldpvec->putChar;
820 	promops.po_getchar = oldpvec->getChar;
821 	promops.po_peekchar = oldpvec->mayGet;
822 	promops.po_putstr = oldpvec->fbWriteStr;
823 	promops.po_reboot = oldpvec->reBoot;
824 	promops.po_abort = oldpvec->abortEntry;
825 	promops.po_halt = oldpvec->exitToMon;
826 	promops.po_ticks = obp_ticks;
827 	promops.po_tickdata = oldpvec->nmiClock;
828 	promops.po_setcallback = (void *)sparc_noop;
829 	promops.po_setcontext = oldpvec->setcxsegmap;
830 
831 #ifdef SUN4
832 #ifndef _STANDALONE
833 	if (oldpvec->romvecVersion >= 2) {
834 		extern void oldmon_w_cmd __P((u_long, char *));
835 		*oldpvec->vector_cmd = oldmon_w_cmd;
836 	}
837 #endif
838 #endif
839 }
840 
841 static __inline__ void
842 prom_init_obp()
843 {
844 	struct nodeops *no;
845 
846 	/*
847 	 * OBP v0, v2 & v3
848 	 */
849 	switch (obpvec->pv_romvec_vers) {
850 	case 0:
851 		promops.po_version = PROM_OBP_V0;
852 		break;
853 	case 2:
854 		promops.po_version = PROM_OBP_V2;
855 		break;
856 	case 3:
857 		promops.po_version = PROM_OBP_V3;
858 		break;
859 	default:
860 		obpvec->pv_halt();	/* What else? */
861 	}
862 
863 	promops.po_revision = obpvec->pv_printrev;
864 
865 	promops.po_halt = obpvec->pv_halt;
866 	promops.po_reboot = obpvec->pv_reboot;
867 	promops.po_abort = obpvec->pv_abort;
868 	promops.po_setcontext = obpvec->pv_setctxt;
869 	promops.po_setcallback = obp_set_callback;
870 	promops.po_ticks = obp_ticks;
871 	promops.po_tickdata = obpvec->pv_ticks;
872 
873 	/*
874 	 * Remove indirection through `pv_nodeops' while we're here.
875 	 * Hopefully, the PROM has no need to change this pointer on the fly..
876 	 */
877 	no = obpvec->pv_nodeops;
878 	promops.po_firstchild = no->no_child;
879 	promops.po_nextsibling = no->no_nextnode;
880 	promops.po_getproplen = no->no_proplen;
881 	/* XXX - silently discard getprop's `len' argument */
882 	promops.po_getprop = (void *)no->no_getprop;
883 	promops.po_setprop = no->no_setprop;
884 	promops.po_nextprop = no->no_nextprop;
885 
886 	/*
887 	 * Next, deal with prom vector differences between versions.
888 	 */
889 	switch (promops.po_version) {
890 	case PROM_OBP_V0:
891 		promops.po_stdin = *obpvec->pv_stdin;
892 		promops.po_stdout = *obpvec->pv_stdout;
893 		promops.po_bootcookie = *obpvec->pv_v0bootargs; /* deref 1 lvl */
894 		promops.po_bootpath = obp_v0_getbootpath;
895 		promops.po_bootfile = obp_v0_getbootfile;
896 		promops.po_bootargs = obp_v0_getbootargs;
897 		promops.po_putchar = obpvec->pv_putchar;
898 		promops.po_getchar = obpvec->pv_getchar;
899 		promops.po_peekchar = obpvec->pv_nbgetchar;
900 		promops.po_putstr = obpvec->pv_putstr;
901 		promops.po_open = obpvec->pv_v0devops.v0_open;
902 		promops.po_close = (void *)obpvec->pv_v0devops.v0_close;
903 		promops.po_read = obp_v0_read;
904 		promops.po_write = obp_v0_write;
905 		promops.po_interpret = obp_v0_fortheval;
906 		break;
907 	case PROM_OBP_V3:
908 		promops.po_cpustart = obpvec->pv_v3cpustart;
909 		promops.po_cpustop = obpvec->pv_v3cpustop;
910 		promops.po_cpuidle = obpvec->pv_v3cpuidle;
911 		promops.po_cpuresume = obpvec->pv_v3cpuresume;
912 		/*FALLTHROUGH*/
913 	case PROM_OBP_V2:
914 		/* Deref stdio handles one level */
915 		promops.po_stdin = *obpvec->pv_v2bootargs.v2_fd0;
916 		promops.po_stdout = *obpvec->pv_v2bootargs.v2_fd1;
917 
918 		promops.po_bootcookie = &obpvec->pv_v2bootargs;
919 		promops.po_bootpath = obp_v2_getbootpath;
920 		promops.po_bootfile = obp_v2_getbootfile;
921 		promops.po_bootargs = obp_v2_getbootargs;
922 
923 		promops.po_interpret = obpvec->pv_fortheval.v2_eval;
924 
925 		promops.po_putchar = obp_v2_putchar;
926 		promops.po_getchar = obp_v2_getchar;
927 		promops.po_peekchar = obp_v2_peekchar;
928 		promops.po_putstr = obp_v2_putstr;
929 		promops.po_open = obpvec->pv_v2devops.v2_open;
930 		promops.po_close = (void *)obpvec->pv_v2devops.v2_close;
931 		promops.po_read = obpvec->pv_v2devops.v2_read;
932 		promops.po_write = obpvec->pv_v2devops.v2_write;
933 		promops.po_seek = obp_v2_seek;
934 		promops.po_instance_to_package = obpvec->pv_v2devops.v2_fd_phandle;
935 		promops.po_finddevice = obp_v2_finddevice;
936 
937 #ifndef _STANDALONE
938 		prom_printf("OBP version %d, revision %d.%d (plugin rev %x)\n",
939 			obpvec->pv_romvec_vers,
940 			obpvec->pv_printrev >> 16, obpvec->pv_printrev & 0xffff,
941 			obpvec->pv_plugin_vers);
942 #endif
943 		break;
944 	}
945 }
946 
947 static __inline__ void
948 prom_init_opf()
949 {
950 	int node;
951 
952 	promops.po_version = PROM_OPENFIRM;
953 
954 	/*
955 	 * OpenFirmware ops are mostly straightforward.
956 	 */
957 	promops.po_halt = OF_exit;
958 	promops.po_reboot = OF_boot;
959 	promops.po_abort = OF_enter;
960 	promops.po_interpret = OF_interpret;
961 	promops.po_setcallback = (void *)OF_set_callback;
962 	promops.po_ticks = OF_milliseconds;
963 
964 	promops.po_bootpath = opf_getbootpath;
965 	promops.po_bootfile = opf_getbootfile;
966 	promops.po_bootargs = opf_getbootargs;
967 
968 	promops.po_firstchild = OF_child;
969 	promops.po_nextsibling = OF_peer;
970 	promops.po_getproplen = OF_getproplen;
971 	promops.po_getprop = OF_getprop;
972 	promops.po_nextprop = opf_nextprop;
973 	promops.po_setprop = OF_setprop;
974 
975 	/* We can re-use OBP v2 emulation */
976 	promops.po_putchar = obp_v2_putchar;
977 	promops.po_getchar = obp_v2_getchar;
978 	promops.po_peekchar = obp_v2_peekchar;
979 	promops.po_putstr = obp_v2_putstr;
980 
981 	promops.po_open = OF_open;
982 	promops.po_close = OF_close;
983 	promops.po_read = OF_read;
984 	promops.po_write = OF_write;
985 	promops.po_seek = OF_seek;
986 	promops.po_instance_to_package = opf_instance_to_package;
987 	promops.po_finddevice = opf_finddevice;
988 
989 	/* Retrieve and cache stdio handles */
990 	node = findchosen();
991 	OF_getprop(node, "stdin", &promops.po_stdin, sizeof(int));
992 	OF_getprop(node, "stdout", &promops.po_stdout, sizeof(int));
993 }
994 
995 /*
996  * Initialize our PROM operations vector.
997  */
998 void
999 prom_init()
1000 {
1001 
1002 	if (CPU_ISSUN4) {
1003 		prom_init_oldmon();
1004 	} else if (obpvec->pv_magic == OBP_MAGIC) {
1005 		prom_init_obp();
1006 	} else {
1007 		/*
1008 		 * Assume this is an Openfirm machine.
1009 		 */
1010 		prom_init_opf();
1011 	}
1012 }
1013