Home | History | Annotate | Line # | Download | only in sparc
      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
    100 null_prom_to_devhandle(int node __unused)
    101 {
    102 	return devhandle_invalid();
    103 }
    104 
    105 static int
    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
    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
    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
    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
    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
    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 }
    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 *
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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  */
    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  */
    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
    587 prom_halt(void)
    588 {
    589 
    590 	prom_setcallback(NULL);
    591 	_prom_halt();
    592 	panic("PROM exit failed");
    593 }
    594 
    595 void
    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
    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
    638 obp_v0_fortheval(const char *s)
    639 {
    640 
    641 	obpvec->pv_fortheval.v0_eval(strlen(s), s);
    642 }
    643 
    644 int
    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
    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
    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
    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
    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
    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 *
    728 obp_v0_getbootpath(void)
    729 {
    730 	struct v0bootargs *ba = promops.po_bootcookie;
    731 	return (ba->ba_argv[0]);
    732 }
    733 
    734 const char *
    735 obp_v0_getbootargs(void)
    736 {
    737 	struct v0bootargs *ba = promops.po_bootcookie;
    738 	return (ba->ba_argv[1]);
    739 }
    740 
    741 const char *
    742 obp_v0_getbootfile(void)
    743 {
    744 	struct v0bootargs *ba = promops.po_bootcookie;
    745 	return (ba->ba_kernel);
    746 }
    747 
    748 char *
    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 *
    770 obp_v2_getbootpath(void)
    771 {
    772 	struct v2bootargs *ba = promops.po_bootcookie;
    773 	return (*ba->v2_bootpath);
    774 }
    775 
    776 const char *
    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 *
    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 *
    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
    851 obp_v2_putstr(const char *str, int len)
    852 {
    853 	prom_write(prom_stdout(), str, len);
    854 }
    855 
    856 void
    857 obp_set_callback(void (*f)(void))
    858 {
    859 	*obpvec->pv_synchook = f;
    860 }
    861 
    862 int
    863 obp_ticks(void)
    864 {
    865 
    866 	return (*((int *)promops.po_tickdata));
    867 }
    868 
    869 static int
    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
    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
    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 *
    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 *
    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 *
    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 *
    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
    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
    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 *
   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 
   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
   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 *
   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
   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
   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
   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
   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