#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: promlib.c,v 1.54 2026/07/09 21:25:03 palle Exp $");
#if defined(_KERNEL_OPT)
#include "opt_sparc_arch.h"
#endif
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/device.h>
#ifdef _STANDALONE
#include <lib/libsa/stand.h>
#define malloc(s,t,f) alloc(s)
#else
#include <sys/device_calls.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#endif
#include <machine/oldmon.h>
#include <machine/promlib.h>
#include <machine/ctlreg.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/cache.h>
#include <lib/libkern/libkern.h>
#define obpvec ((struct promvec *)romp)
static void notimplemented(void);
static void obp_v0_fortheval(const char *);
static void obp_set_callback(void (*)(void));
static int obp_v0_read(int, void *, int);
static int obp_v0_write(int, const void *, int);
static int obp_v2_getchar(void);
static int obp_v2_peekchar(void);
static void obp_v2_putchar(int);
static void obp_v2_putstr(const char *, int);
static int obp_v2_seek(int, u_quad_t);
static char *parse_bootfile(char *);
static char *parse_bootargs(char *);
static const char *obp_v0_getbootpath(void);
static const char *obp_v0_getbootfile(void);
static const char *obp_v0_getbootargs(void);
static const char *obp_v2_getbootpath(void);
static const char *obp_v2_getbootfile(void);
static const char *obp_v2_getbootargs(void);
static int obp_v2_finddevice(const char *);
static int obp_ticks(void);
static int findchosen(void);
static const char *opf_getbootpath(void);
static const char *opf_getbootfile(void);
static const char *opf_getbootargs(void);
static int opf_finddevice(const char *);
static int opf_instance_to_package(int);
static char *opf_nextprop(int, const char *);
static void opf_interpret_simple(const char *);
#ifndef _STANDALONE
static devhandle_t
null_prom_to_devhandle(int node __unused)
{
return devhandle_invalid();
}
static int
null_devhandle_to_prom(devhandle_t devhandle __unused)
{
return 0;
}
#endif
struct promops promops = {
-1,
-1,
-1,
-1,
NULL,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
NULL,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
(void *)notimplemented,
#ifdef STANDALONE
(void *)notimplemented,
(void *)notimplemented,
#else
(void *)null_prom_to_devhandle,
(void *)null_devhandle_to_prom,
#endif
};
static void
notimplemented(void)
{
char str[64];
int n;
n = snprintf(str, sizeof(str),
"Operation not implemented on ROM version %d\r\n",
promops.po_version);
#if defined(SUN4)
if (CPU_ISSUN4) {
struct om_vector *sun4pvec = (struct om_vector *)PROM_BASE;
(*sun4pvec->fbWriteStr)(str, n);
} else
#endif
if (obpvec->pv_magic == OBP_MAGIC) {
if (obpvec->pv_romvec_vers < 2) {
(*obpvec->pv_putstr)(str, n);
} else {
int fd = *obpvec->pv_v2bootargs.v2_fd1;
(*obpvec->pv_v2devops.v2_write)(fd, str, n);
}
} else {
static int stdout_node;
if (stdout_node == 0) {
int chosen = findchosen();
OF_getprop(chosen, "stdout", &stdout_node, sizeof(int));
}
OF_write(stdout_node, str, n);
}
}
#ifndef _STANDALONE
static device_call_t
obp_devhandle_lookup_device_call(devhandle_t handle, const char *name,
devhandle_t *call_handlep)
{
__link_set_decl(obp_device_calls, struct device_call_descriptor);
struct device_call_descriptor * const *desc;
__link_set_foreach(desc, obp_device_calls) {
if (strcmp((*desc)->name, name) == 0) {
return (*desc)->call;
}
}
return NULL;
}
static const struct devhandle_impl obp_devhandle_impl = {
.type = DEVHANDLE_TYPE_OPENBOOT,
.lookup_device_call = obp_devhandle_lookup_device_call,
};
static devhandle_t
devhandle_from_obp(devhandle_t super_handle, int node)
{
devhandle_type_t super_type = devhandle_type(super_handle);
devhandle_t handle = { 0 };
if (super_type == DEVHANDLE_TYPE_OPENBOOT) {
handle.impl = super_handle.impl;
} else {
KASSERT(super_type == DEVHANDLE_TYPE_INVALID);
handle.impl = &obp_devhandle_impl;
}
handle.integer = node;
return handle;
}
static int
devhandle_to_obp(devhandle_t const handle)
{
KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_OPENBOOT);
return handle.integer;
}
static int
obp_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v)
{
struct device_enumerate_children_args *args = v;
int node = devhandle_to_obp(call_handle);
for (node = prom_firstchild(node); node != 0;
node = prom_nextsibling(node)) {
if (!args->callback(dev, devhandle_from_obp(call_handle, node),
args->callback_arg)) {
break;
}
}
return 0;
}
OBP_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,
obp_device_enumerate_children)
static bool
obp_is_bool_prop(const char *prop __unused, char *propval, int propsize,
bool *valp)
{
#if 0
if (prop[strlen(prop) - 1] != '?') {
return false;
}
#endif
if (propsize >= 4 && memcmp(propval, "true", 4) == 0) {
*valp = true;
return true;
}
if (propsize >= 5 && memcmp(propval, "false", 5) == 0) {
*valp = false;
return true;
}
return false;
}
static int
obp_device_get_property(device_t dev, devhandle_t call_handle, void *v)
{
struct device_get_property_args *args = v;
int node = devhandle_to_obp(call_handle);
int propsize, error = 0;
char *propval = NULL;
bool boolval = true;
prop_type_t proptype = PROP_TYPE_UNKNOWN;
propsize = prom_getproplen(node, args->prop);
if (propsize < 0) {
return ENOENT;
}
if (propsize == 0) {
goto done;
}
propval = kmem_alloc(propsize, KM_SLEEP);
_prom_getprop(node, args->prop, propval, propsize);
if (obp_is_bool_prop(args->prop, propval, propsize, &boolval)) {
proptype = PROP_TYPE_BOOL;
}
if (args->buf == NULL) {
goto done;
}
KASSERT(args->buflen != 0);
switch (args->reqtype) {
case PROP_TYPE_NUMBER:
KASSERT(args->buflen == sizeof(uint64_t));
if (propsize == sizeof(uint32_t)) {
*(uint64_t *)args->buf = *(uint32_t *)propval;
} else if (propsize == sizeof(uint64_t)) {
*(uint64_t *)args->buf = *(uint64_t *)propval;
} else {
error = EFTYPE;
}
break;
case PROP_TYPE_STRING:
memset(args->buf, 0, args->buflen);
case PROP_TYPE_DATA:
if (args->buflen < propsize) {
error = EFBIG;
goto done;
}
memcpy(args->buf, propval, propsize);
if (args->reqtype == PROP_TYPE_STRING) {
((char *)args->buf)[args->buflen - 1] = '\0';
}
break;
case PROP_TYPE_BOOL:
KASSERT(args->buflen == sizeof(bool));
if (proptype == PROP_TYPE_BOOL) {
*(bool *)args->buf = boolval;
} else {
error = EFTYPE;
}
break;
default:
error = EFTYPE;
break;
}
done:
if (propval != NULL) {
KASSERT(propsize > 0);
kmem_free(propval, propsize);
}
args->propsize = propsize;
args->encoding = _BYTE_ORDER;
args->type = proptype;
return error;
}
OBP_DEVICE_CALL_REGISTER(DEVICE_GET_PROPERTY_STR,
obp_device_get_property)
#endif
int
prom_getprop(int node, const char *name, size_t size, int *nitem, void *bufp)
{
void *buf;
int len;
len = prom_getproplen(node, name);
if (len <= 0)
return (ENOENT);
if ((len % size) != 0)
return (EINVAL);
buf = *(void **)bufp;
if (buf == NULL) {
buf = malloc(len, M_DEVBUF, M_NOWAIT);
if (buf == NULL)
return (ENOMEM);
} else {
if (size * (*nitem) < len)
return (ENOMEM);
}
_prom_getprop(node, name, buf, len);
*(void **)bufp = buf;
*nitem = len / size;
return (0);
}
char *
prom_getpropstring(int node, const char *name)
{
static char stringbuf[32];
return (prom_getpropstringA(node, name, stringbuf, sizeof stringbuf));
}
char *
prom_getpropstringA(int node, const char *name, char *buf, size_t bufsize)
{
int len = bufsize - 1;
if (prom_getprop(node, name, 1, &len, &buf) != 0)
len = 0;
buf[len] = '\0';
return (buf);
}
int
prom_getpropint(int node, const char *name, int deflt)
{
int intbuf, *ip = &intbuf;
int len = 1;
if (prom_getprop(node, name, sizeof(int), &len, &ip) != 0)
return (deflt);
return (*ip);
}
uint64_t
prom_getpropuint64(int node, const char *name, uint64_t deflt)
{
uint64_t uint64buf, *uint64p = &uint64buf;
int len = 2;
if (prom_getprop(node, name, sizeof(uint64_t), &len, &uint64p) != 0)
return deflt;
return uint64buf;
}
static int
prom_matchname(int node, const char *name)
{
char buf[32], *cp;
prom_getpropstringA(node, "name", buf, sizeof buf);
if (strcmp(buf, name) == 0)
return (1);
if (strchr(name, ','))
return (0);
if ((cp = strchr(buf, ',')) != NULL) {
if (strcmp(cp + 1, name) == 0)
return (1);
}
return (0);
}
int
prom_opennode(const char *path)
{
int fd;
if (prom_version() < 2) {
printf("WARNING: opennode not valid on PROM version %d\n",
promops.po_version);
return (0);
}
fd = prom_open(path);
if (fd == 0)
return (0);
return (prom_instance_to_package(fd));
}
int
prom_findroot(void)
{
static int rootnode;
int node;
if ((node = rootnode) == 0 && (node = prom_nextsibling(0)) == 0)
panic("no PROM root device");
rootnode = node;
return (node);
}
int
prom_findnode(int first, const char *name)
{
int node;
for (node = first; node != 0; node = prom_nextsibling(node)) {
if (prom_matchname(node, name))
return (node);
}
return (0);
}
int
prom_node_has_property(int node, const char *prop)
{
return (prom_getproplen(node, prop) != -1);
}
int
prom_search(int node, const char *name)
{
if (node == 0)
node = prom_findroot();
if (prom_matchname(node, name))
return (node);
for (node = prom_firstchild(node); node != 0;
node = prom_nextsibling(node)) {
int cnode;
if ((cnode = prom_search(node, name)) != 0)
return (cnode);
}
return (0);
}
int
obp_v2_finddevice(const char *path)
{
int node;
char component[64];
char c, *cp;
const char *startp, *endp;
#define IS_SEP(c) ((c) == '/' || (c) == '@' || (c) == ':')
if (path == NULL)
return (-1);
node = prom_findroot();
for (startp = path; *startp != '\0'; ) {
while (*startp == '/')
startp++;
endp = startp;
while ((c = *endp) != '\0' && !IS_SEP(c))
endp++;
for (cp = component; startp != endp;) {
if (cp > component + sizeof component - 1)
return (-1);
*cp++ = *startp++;
}
*cp = '\0';
while ((c = *startp) != '\0' && c != '/')
startp++;
node = prom_findnode(prom_firstchild(node), component);
if (node == 0)
return (-1);
}
return (node);
}
int prom_getoptionsnode(void)
{
static int optionsnode;
if (optionsnode == 0) {
optionsnode = prom_findnode(prom_firstchild(prom_findroot()),
"options");
}
return optionsnode;
}
int prom_getoption(const char *name, char *buf, int buflen)
{
int node = prom_getoptionsnode();
int error, len;
if (buflen == 0)
return (EINVAL);
if (node == 0)
return (ENOENT);
len = buflen - 1;
if ((error = prom_getprop(node, name, 1, &len, &buf)) != 0)
return error;
buf[len] = '\0';
return (0);
}
void
prom_halt(void)
{
prom_setcallback(NULL);
_prom_halt();
panic("PROM exit failed");
}
void
prom_boot(char *str)
{
prom_setcallback(NULL);
_prom_boot(str);
panic("PROM boot failed");
}
void
prom_printf(const char *fmt, ...)
{
static char buf[256];
int i, len;
va_list ap;
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
#if _obp_not_cooked_
(*promops.po_write)(promops.po_stdout, buf, len);
#endif
for (i = 0; i < len; i++) {
int c = buf[i];
if (c == '\n')
(*promops.po_putchar)('\r');
(*promops.po_putchar)(c);
}
}
static void
obp_v0_fortheval(const char *s)
{
obpvec->pv_fortheval.v0_eval(strlen(s), s);
}
int
obp_v0_read(int fd, void *buf, int len)
{
if (fd != prom_stdin())
prom_printf("obp_v0_read: unimplemented read from %d\n", fd);
return (-1);
}
int
obp_v0_write(int fd, const void *buf, int len)
{
if (fd != prom_stdout())
prom_printf("obp_v0_write: unimplemented write on %d\n", fd);
(*obpvec->pv_putstr)(buf, len);
return (-1);
}
inline void
obp_v2_putchar(int c)
{
char c0;
c0 = (c & 0x7f);
(*promops.po_write)(promops.po_stdout, &c0, 1);
}
#if 0
void
obp_v2_putchar_cooked(int c)
{
if (c == '\n')
obp_v2_putchar('\r');
obp_v2_putchar(c);
}
#endif
int
obp_v2_getchar(void)
{
char c;
int n;
while ((n = (*promops.po_read)(promops.po_stdin, &c, 1)) != 1)
;
if (c == '\r')
c = '\n';
return (c);
}
int
obp_v2_peekchar(void)
{
char c;
int n;
n = (*promops.po_read)(promops.po_stdin, &c, 1);
if (n < 0)
return (-1);
if (c == '\r')
c = '\n';
return (c);
}
int
obp_v2_seek(int handle, u_quad_t offset)
{
uint32_t hi, lo;
lo = offset & ((uint32_t)-1);
hi = (offset >> 32) & ((uint32_t)-1);
(*obpvec->pv_v2devops.v2_seek)(handle, hi, lo);
return (0);
}
const char *
obp_v0_getbootpath(void)
{
struct v0bootargs *ba = promops.po_bootcookie;
return (ba->ba_argv[0]);
}
const char *
obp_v0_getbootargs(void)
{
struct v0bootargs *ba = promops.po_bootcookie;
return (ba->ba_argv[1]);
}
const char *
obp_v0_getbootfile(void)
{
struct v0bootargs *ba = promops.po_bootcookie;
return (ba->ba_kernel);
}
char *
parse_bootargs(char *args)
{
char *cp;
for (cp = args; *cp != '\0'; cp++) {
if (*cp == '-') {
int c;
if (cp == args)
break;
if ((c = *(cp-1)) == ' ' || c == '\t')
break;
}
}
return (cp);
}
const char *
obp_v2_getbootpath(void)
{
struct v2bootargs *ba = promops.po_bootcookie;
return (*ba->v2_bootpath);
}
const char *
obp_v2_getbootargs(void)
{
struct v2bootargs *ba = promops.po_bootcookie;
return (parse_bootargs(*ba->v2_bootargs));
}
static char storage[128];
char *
parse_bootfile(char *args)
{
char *cp, *dp;
cp = args;
dp = storage;
while (*cp != 0 && *cp != ' ' && *cp != '\t') {
if (dp >= storage + sizeof(storage) - 1) {
prom_printf("v2_bootargs too long\n");
return (NULL);
}
if (*cp == '-') {
int c;
if (cp == args)
break;
if ((c = *(cp-1)) == ' ' || c == '\t')
break;
}
*dp++ = *cp++;
}
*dp = '\0';
return (storage);
}
const char *
obp_v2_getbootfile(void)
{
struct v2bootargs *ba = promops.po_bootcookie;
char *kernel = parse_bootfile(*ba->v2_bootargs);
char buf[4+1];
const char *prop;
if (kernel[0] != '\0')
return kernel;
prop = (prom_getoption("diag-switch?", buf, sizeof buf) != 0 ||
strcmp(buf, "true") != 0)
? "diag-file"
: "boot-file";
if (prom_getoption(prop, storage, sizeof storage) != 0)
return (NULL);
return (storage);
}
void
obp_v2_putstr(const char *str, int len)
{
prom_write(prom_stdout(), str, len);
}
void
obp_set_callback(void (*f)(void))
{
*obpvec->pv_synchook = f;
}
int
obp_ticks(void)
{
return (*((int *)promops.po_tickdata));
}
static int
findchosen(void)
{
static int chosennode;
int node;
if ((node = chosennode) == 0 && (node = OF_finddevice("/chosen")) == -1)
panic("no CHOSEN node");
chosennode = node;
return (node);
}
static int
opf_finddevice(const char *name)
{
int phandle = OF_finddevice(name);
if (phandle == -1)
return (0);
else
return (phandle);
}
static int
opf_instance_to_package(int ihandle)
{
int phandle = OF_instance_to_package(ihandle);
if (phandle == -1)
return (0);
else
return (phandle);
}
static const char *
opf_getbootpath(void)
{
int node = findchosen();
char *buf = storage;
int blen = sizeof storage;
if (prom_getprop(node, "bootpath", 1, &blen, &buf) != 0)
return ("");
return (buf);
}
static const char *
opf_getbootargs(void)
{
int node = findchosen();
char *buf = storage;
int blen = sizeof storage;
if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0)
return ("");
return (parse_bootargs(buf));
}
static const char *
opf_getbootfile(void)
{
int node = findchosen();
char *buf = storage;
int blen = sizeof storage;
if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0)
return ("");
return (parse_bootfile(buf));
}
static char *
opf_nextprop(int node, const char *prop)
{
#define OF_NEXTPROP_BUF_SIZE 32
static char buf[OF_NEXTPROP_BUF_SIZE];
OF_nextprop(node, prop, buf);
return (buf);
}
void
opf_interpret_simple(const char *s)
{
(void)OF_interpret(s, 0, 0);
}
int
prom_makememarr(struct memarr *ap, int xmax, int which)
{
struct v0mlist *mp;
int node, n;
const char *prop;
if (which != MEMARR_AVAILPHYS && which != MEMARR_TOTALPHYS)
panic("makememarr");
switch (prom_version()) {
struct promvec *promvec;
struct om_vector *oldpvec;
case PROM_OLDMON:
oldpvec = (struct om_vector *)PROM_BASE;
n = 1;
if (ap != NULL) {
ap[0].zero = 0;
ap[0].addr = 0;
ap[0].len = (which == MEMARR_AVAILPHYS)
? *oldpvec->memoryAvail
: *oldpvec->memorySize;
}
break;
case PROM_OBP_V0:
promvec = romp;
mp = (which == MEMARR_AVAILPHYS)
? *promvec->pv_v0mem.v0_physavail
: *promvec->pv_v0mem.v0_phystot;
for (n = 0; mp != NULL; mp = mp->next, n++) {
if (ap == NULL)
continue;
if (n >= xmax) {
printf("makememarr: WARNING: lost some memory\n");
break;
}
ap->zero = 0;
ap->addr = (u_long)mp->addr;
ap->len = mp->nbytes;
ap++;
}
break;
default:
printf("makememarr: hope version %d PROM is like version 2\n",
prom_version());
case PROM_OBP_V3:
case PROM_OBP_V2:
node = findnode(firstchild(findroot()), "memory");
goto case_common;
case PROM_OPENFIRM:
node = OF_finddevice("/memory");
if (node == -1)
node = 0;
case_common:
if (node == 0)
panic("makememarr: cannot find \"memory\" node");
prop = (which == MEMARR_AVAILPHYS) ? "available" : "reg";
if (ap == NULL) {
n = prom_getproplen(node, prop);
} else {
n = xmax;
if (prom_getprop(node, prop, sizeof(struct memarr),
&n, &ap) != 0)
panic("makememarr: cannot get property");
}
break;
}
if (n <= 0)
panic("makememarr: no memory found");
return (n);
}
static struct idprom idprom;
#ifdef _STANDALONE
long hostid;
#endif
struct idprom *
prom_getidprom(void)
{
int node, len;
u_long h;
u_char *dst;
if (idprom.idp_format != 0)
return (&idprom);
dst = (u_char *)&idprom;
len = sizeof(struct idprom);
switch (prom_version()) {
case PROM_OLDMON:
#ifdef AC_IDPROM
{
u_char *src = (u_char *)AC_IDPROM;
do {
*dst++ = lduba(src++, ASI_CONTROL);
} while (--len > 0);
}
#endif
break;
case PROM_OBP_V0:
case PROM_OBP_V2:
case PROM_OPENFIRM:
case PROM_OBP_V3:
node = prom_findroot();
if (prom_getprop(node, "idprom", 1, &len, &dst) != 0) {
printf("`idprom' property cannot be read: "
"cannot get ethernet address");
}
break;
}
h = (u_int)idprom.idp_machtype << 24;
h |= idprom.idp_serialnum[0] << 16;
h |= idprom.idp_serialnum[1] << 8;
h |= idprom.idp_serialnum[2];
hostid = h;
return (&idprom);
}
void prom_getether(int node, u_char *cp)
{
struct idprom *idp;
if (prom_get_node_ether(node, cp))
return;
idp = prom_getidprom();
memcpy(cp, idp->idp_etheraddr, 6);
}
bool
prom_get_node_ether(int node, u_char *cp)
{
char buf[6+1], *bp;
int nitem;
if (node == 0)
return false;
nitem = 6+1;
bp = buf;
if (prom_getprop(node, "mac-address", 1, &nitem, &bp) == 0 &&
nitem >= 6) {
memcpy(cp, bp, 6);
return true;
}
if (prom_getoption("local-mac-address?", buf, sizeof buf) != 0 ||
strcmp(buf, "true") != 0)
return false;
nitem = 6;
if (prom_getprop(node, "local-mac-address", 1, &nitem, &cp) == 0 &&
nitem == 6)
return true;
return false;
}
const char *
prom_pa_location(u_int phys_lo, u_int phys_hi)
{
static char *(*unum)(u_int, u_int);
char *str;
const char *unk = "<Unknown>";
switch (prom_version()) {
case PROM_OLDMON:
case PROM_OPENFIRM:
default:
break;
case PROM_OBP_V0:
case PROM_OBP_V2:
case PROM_OBP_V3:
if (unum == NULL)
unum = (char *(*)(u_int,u_int))(u_long)
prom_getpropint(prom_findroot(), "get-unum", 0);
if (unum == NULL || (str = unum(phys_lo, phys_hi)) == NULL)
break;
return (str);
}
return (unk);
}
static void prom_init_oldmon(void);
static void prom_init_obp(void);
static void prom_init_opf(void);
static inline void
prom_init_oldmon(void)
{
struct om_vector *oldpvec = (struct om_vector *)PROM_BASE;
promops.po_version = PROM_OLDMON;
promops.po_revision = oldpvec->monId[0];
promops.po_stdin = *oldpvec->inSource;
promops.po_stdout = *oldpvec->outSink;
promops.po_bootcookie = *oldpvec->bootParam;
promops.po_bootpath = obp_v0_getbootpath;
promops.po_bootfile = obp_v0_getbootfile;
promops.po_bootargs = obp_v0_getbootargs;
promops.po_putchar = oldpvec->putChar;
promops.po_getchar = oldpvec->getChar;
promops.po_peekchar = oldpvec->mayGet;
promops.po_putstr = oldpvec->fbWriteStr;
promops.po_reboot = oldpvec->reBoot;
promops.po_abort = oldpvec->abortEntry;
promops.po_halt = oldpvec->exitToMon;
promops.po_ticks = obp_ticks;
promops.po_tickdata = oldpvec->nmiClock;
promops.po_setcallback = (void *)sparc_noop;
promops.po_setcontext = oldpvec->setcxsegmap;
#ifdef SUN4
#ifndef _STANDALONE
if (oldpvec->romvecVersion >= 2) {
*oldpvec->vector_cmd = oldmon_w_cmd;
}
#endif
#endif
}
static inline void
prom_init_obp(void)
{
struct nodeops *no;
switch (obpvec->pv_romvec_vers) {
case 0:
promops.po_version = PROM_OBP_V0;
break;
case 2:
promops.po_version = PROM_OBP_V2;
break;
case 3:
promops.po_version = PROM_OBP_V3;
break;
default:
obpvec->pv_halt();
}
promops.po_revision = obpvec->pv_printrev;
promops.po_halt = obpvec->pv_halt;
promops.po_reboot = obpvec->pv_reboot;
promops.po_abort = obpvec->pv_abort;
promops.po_setcontext = obpvec->pv_setctxt;
promops.po_setcallback = obp_set_callback;
promops.po_ticks = obp_ticks;
promops.po_tickdata = obpvec->pv_ticks;
no = obpvec->pv_nodeops;
promops.po_firstchild = no->no_child;
promops.po_nextsibling = no->no_nextnode;
promops.po_getproplen = no->no_proplen;
promops.po_getprop = (void *)no->no_getprop;
promops.po_setprop = no->no_setprop;
promops.po_nextprop = no->no_nextprop;
#ifndef _STANDALONE
promops.po_node_to_devhandle = devhandle_from_obp;
promops.po_devhandle_to_node = devhandle_to_obp;
#endif
switch (promops.po_version) {
case PROM_OBP_V0:
promops.po_stdin = *obpvec->pv_stdin;
promops.po_stdout = *obpvec->pv_stdout;
promops.po_bootcookie = *obpvec->pv_v0bootargs;
promops.po_bootpath = obp_v0_getbootpath;
promops.po_bootfile = obp_v0_getbootfile;
promops.po_bootargs = obp_v0_getbootargs;
promops.po_putchar = obpvec->pv_putchar;
promops.po_getchar = obpvec->pv_getchar;
promops.po_peekchar = obpvec->pv_nbgetchar;
promops.po_putstr = obpvec->pv_putstr;
promops.po_open = obpvec->pv_v0devops.v0_open;
promops.po_close = (void *)obpvec->pv_v0devops.v0_close;
promops.po_read = obp_v0_read;
promops.po_write = obp_v0_write;
promops.po_interpret = obp_v0_fortheval;
break;
case PROM_OBP_V3:
promops.po_cpustart = obpvec->pv_v3cpustart;
promops.po_cpustop = obpvec->pv_v3cpustop;
promops.po_cpuidle = obpvec->pv_v3cpuidle;
promops.po_cpuresume = obpvec->pv_v3cpuresume;
case PROM_OBP_V2:
promops.po_stdin = *obpvec->pv_v2bootargs.v2_fd0;
promops.po_stdout = *obpvec->pv_v2bootargs.v2_fd1;
promops.po_bootcookie = &obpvec->pv_v2bootargs;
promops.po_bootpath = obp_v2_getbootpath;
promops.po_bootfile = obp_v2_getbootfile;
promops.po_bootargs = obp_v2_getbootargs;
promops.po_interpret = obpvec->pv_fortheval.v2_eval;
promops.po_putchar = obp_v2_putchar;
promops.po_getchar = obp_v2_getchar;
promops.po_peekchar = obp_v2_peekchar;
promops.po_putstr = obp_v2_putstr;
promops.po_open = obpvec->pv_v2devops.v2_open;
promops.po_close = (void *)obpvec->pv_v2devops.v2_close;
promops.po_read = obpvec->pv_v2devops.v2_read;
promops.po_write = obpvec->pv_v2devops.v2_write;
promops.po_seek = obp_v2_seek;
promops.po_instance_to_package = obpvec->pv_v2devops.v2_fd_phandle;
promops.po_finddevice = obp_v2_finddevice;
#ifndef _STANDALONE
prom_printf("OBP version %d, revision %d.%d (plugin rev %x)\n",
obpvec->pv_romvec_vers,
obpvec->pv_printrev >> 16, obpvec->pv_printrev & 0xffff,
obpvec->pv_plugin_vers);
#endif
break;
}
}
static inline void
prom_init_opf(void)
{
int node;
promops.po_version = PROM_OPENFIRM;
promops.po_halt = OF_exit;
promops.po_reboot = OF_boot;
promops.po_abort = OF_enter;
promops.po_interpret = opf_interpret_simple;
promops.po_setcallback = (void *)OF_set_callback;
promops.po_ticks = OF_milliseconds;
promops.po_bootpath = opf_getbootpath;
promops.po_bootfile = opf_getbootfile;
promops.po_bootargs = opf_getbootargs;
promops.po_firstchild = OF_child;
promops.po_nextsibling = OF_peer;
promops.po_getproplen = OF_getproplen;
promops.po_getprop = OF_getprop;
promops.po_nextprop = opf_nextprop;
promops.po_setprop = OF_setprop;
promops.po_putchar = obp_v2_putchar;
promops.po_getchar = obp_v2_getchar;
promops.po_peekchar = obp_v2_peekchar;
promops.po_putstr = obp_v2_putstr;
promops.po_open = OF_open;
promops.po_close = OF_close;
promops.po_read = OF_read;
promops.po_write = OF_write;
promops.po_seek = OF_seek;
promops.po_instance_to_package = opf_instance_to_package;
promops.po_finddevice = opf_finddevice;
#ifndef _STANDALONE
#ifdef __sparc64__
promops.po_node_to_devhandle = devhandle_from_of;
promops.po_devhandle_to_node = devhandle_to_of;
#else
promops.po_node_to_devhandle = devhandle_from_obp;
promops.po_devhandle_to_node = devhandle_to_obp;
#endif
#endif
node = findchosen();
OF_getprop(node, "stdin", &promops.po_stdin, sizeof(int));
OF_getprop(node, "stdout", &promops.po_stdout, sizeof(int));
OF_init();
}
void
prom_init(void)
{
#ifdef _STANDALONE
int node;
char *cp;
#endif
if (CPU_ISSUN4) {
prom_init_oldmon();
} else if (obpvec->pv_magic == OBP_MAGIC) {
prom_init_obp();
} else {
prom_init_opf();
}
#ifdef _STANDALONE
if (cputyp == CPU_SUN4 || cputyp == CPU_SUN4M)
return;
node = prom_findroot();
cp = prom_getpropstring(node, "compatible");
if (*cp == '\0' || strcmp(cp, "sun4c") == 0)
cputyp = CPU_SUN4C;
else if (strcmp(cp, "sun4m") == 0)
cputyp = CPU_SUN4M;
else if (strcmp(cp, "sun4d") == 0)
cputyp = CPU_SUN4D;
else
printf("Unknown CPU type (compatible=`%s')\n", cp);
#endif
}