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