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