13446Smrj /*
23446Smrj * CDDL HEADER START
33446Smrj *
43446Smrj * The contents of this file are subject to the terms of the
5*11906SGangadhar.M@Sun.COM * Common Development and Distribution License (the "License").
6*11906SGangadhar.M@Sun.COM * You may not use this file except in compliance with the License.
73446Smrj *
83446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj * or http://www.opensolaris.org/os/licensing.
103446Smrj * See the License for the specific language governing permissions
113446Smrj * and limitations under the License.
123446Smrj *
133446Smrj * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj * If applicable, add the following below this CDDL HEADER, with the
163446Smrj * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj *
193446Smrj * CDDL HEADER END
203446Smrj */
213446Smrj /*
22*11906SGangadhar.M@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
233446Smrj * Use is subject to license terms.
243446Smrj */
253446Smrj
263446Smrj
273446Smrj #include "benv.h"
283446Smrj #include <sys/sunddi.h>
293446Smrj #include <sys/ddi_impldefs.h>
303446Smrj #include <sys/openpromio.h>
313446Smrj #include <stdio.h>
323446Smrj
333446Smrj static int getpropval(struct openpromio *opp, char *prop);
343446Smrj
353446Smrj static char *promdev = "/dev/openprom";
363446Smrj static int prom_fd;
373446Smrj static char *mfail = "malloc";
383446Smrj
393446Smrj /*
403446Smrj * 128 is the size of the largest (currently) property name
413446Smrj * 16384 - MAXPROPSIZE - sizeof (int) is the size of the largest
423446Smrj * (currently) property value that is allowed.
433446Smrj * the sizeof (u_int) is from struct openpromio
443446Smrj */
453446Smrj
463446Smrj #define MAXPROPSIZE 128
473446Smrj #define MAXVALSIZE (16384 - MAXPROPSIZE - sizeof (u_int))
483446Smrj #define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (u_int))
493446Smrj #define MINVALSIZE (4 * sizeof (u_long))
503446Smrj #define MINBUFSIZE (MINVALSIZE + sizeof (u_long))
513446Smrj
523446Smrj typedef union {
533446Smrj char buf[BUFSIZE];
543446Smrj struct openpromio opp;
553446Smrj } Oppbuf;
563446Smrj
573446Smrj typedef union {
583446Smrj char buf[MINVALSIZE + sizeof (u_int)];
593446Smrj struct openpromio opp;
603446Smrj } Oppbuf_small;
613446Smrj
623446Smrj static Oppbuf oppbuf;
633446Smrj
643446Smrj static unsigned long
next(unsigned long id)653446Smrj next(unsigned long id)
663446Smrj {
673446Smrj Oppbuf_small oppbuf;
683446Smrj struct openpromio *opp = &(oppbuf.opp);
693446Smrj unsigned long *ip = (unsigned long *)(opp->oprom_array);
703446Smrj
713446Smrj memset(oppbuf.buf, 0, MINBUFSIZE);
723446Smrj opp->oprom_size = MINVALSIZE;
733446Smrj *ip = id;
743446Smrj if (ioctl(prom_fd, OPROMNEXT, opp) < 0)
753446Smrj return (0);
763446Smrj return (*(unsigned long *)opp->oprom_array);
773446Smrj }
783446Smrj
793446Smrj static unsigned long
child(unsigned long id)803446Smrj child(unsigned long id)
813446Smrj {
823446Smrj Oppbuf_small oppbuf;
833446Smrj struct openpromio *opp = &(oppbuf.opp);
843446Smrj unsigned long *ip = (unsigned long *)(opp->oprom_array);
853446Smrj
863446Smrj memset(oppbuf.buf, 0, MINBUFSIZE);
873446Smrj opp->oprom_size = MINVALSIZE;
883446Smrj *ip = id;
893446Smrj if (ioctl(prom_fd, OPROMCHILD, opp) < 0)
903446Smrj return (0);
913446Smrj return (*(unsigned long *)opp->oprom_array);
923446Smrj }
933446Smrj
943446Smrj /*
953446Smrj * Find a node by name from the prom device tree.
963446Smrj * Return the id or 0 if it is not found.
973446Smrj */
983446Smrj static unsigned long
prom_findnode_byname(unsigned long id,char * name)993446Smrj prom_findnode_byname(unsigned long id, char *name)
1003446Smrj {
1013446Smrj struct openpromio *opp = &(oppbuf.opp);
1023446Smrj unsigned long nid;
1033446Smrj
1043446Smrj if (id == 0)
1053446Smrj return (0);
1063446Smrj if (!getpropval(opp, "name"))
1073446Smrj return (0);
1083446Smrj if (strcmp(opp->oprom_array, name) == 0)
1093446Smrj return (id);
1103446Smrj if (nid = prom_findnode_byname(child(id), name))
1113446Smrj return (nid);
1123446Smrj if (nid = prom_findnode_byname(next(id), name))
1133446Smrj return (nid);
1143446Smrj return (0);
1153446Smrj }
1163446Smrj
1173446Smrj /*
1183446Smrj * Make the current prom node be the rootnode and return its id.
1193446Smrj */
1203446Smrj static unsigned long
prom_rootnode()1213446Smrj prom_rootnode()
1223446Smrj {
1233446Smrj return (next(0));
1243446Smrj }
1253446Smrj
1263446Smrj static int
getpropval(struct openpromio * opp,char * prop)1273446Smrj getpropval(struct openpromio *opp, char *prop)
1283446Smrj {
1293446Smrj opp->oprom_size = MAXVALSIZE;
1303446Smrj
1313446Smrj (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE);
1323446Smrj if (ioctl(prom_fd, OPROMGETPROP, opp) < 0)
1333446Smrj return (0);
1343446Smrj if (opp->oprom_size == 0)
1353446Smrj return (0);
1363446Smrj return (1);
1373446Smrj }
1383446Smrj
1393446Smrj static int
getnextprop(struct openpromio * opp,char * prop)1403446Smrj getnextprop(struct openpromio *opp, char *prop)
1413446Smrj {
1423446Smrj opp->oprom_size = MAXVALSIZE;
1433446Smrj
1443446Smrj (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE);
1453446Smrj if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0)
1463446Smrj return (0);
1473446Smrj if (opp->oprom_size == 0)
1483446Smrj return (0);
1493446Smrj return (1);
1503446Smrj }
1513446Smrj
152*11906SGangadhar.M@Sun.COM char *
getbootcmd(void)153*11906SGangadhar.M@Sun.COM getbootcmd(void)
154*11906SGangadhar.M@Sun.COM {
155*11906SGangadhar.M@Sun.COM struct openpromio *opp = &(oppbuf.opp);
156*11906SGangadhar.M@Sun.COM opp->oprom_size = MAXVALSIZE;
157*11906SGangadhar.M@Sun.COM if (ioctl(prom_fd, OPROMGETBOOTPATH, opp) < 0)
158*11906SGangadhar.M@Sun.COM return (NULL);
159*11906SGangadhar.M@Sun.COM return (opp->oprom_array);
160*11906SGangadhar.M@Sun.COM }
161*11906SGangadhar.M@Sun.COM
1623446Smrj /*
1633446Smrj * Get a pointer to the requested property from the current node.
1643446Smrj * The property is stored in static storage and the returned pointer
1653446Smrj * points into the static storage. The property length is placed in
1663446Smrj * the location pointed to by the third argument.
1673446Smrj */
1683446Smrj static unsigned char *
prom_getprop(char * prop,int * lenp)1693446Smrj prom_getprop(char *prop, int *lenp)
1703446Smrj {
1713446Smrj struct openpromio *opp = &(oppbuf.opp);
1723446Smrj
1733446Smrj if (!getpropval(opp, prop))
1743446Smrj return (NULL);
1753446Smrj *lenp = opp->oprom_size;
1763446Smrj return ((unsigned char *)opp->oprom_array);
1773446Smrj }
1783446Smrj
1793446Smrj static unsigned char *
prom_nextprop(char * prop)1803446Smrj prom_nextprop(char *prop)
1813446Smrj {
1823446Smrj struct openpromio *opp = &(oppbuf.opp);
1833446Smrj
1843446Smrj if (!getnextprop(opp, prop))
1853446Smrj return ((unsigned char *)0);
1863446Smrj return ((unsigned char *)opp->oprom_array);
1873446Smrj }
1883446Smrj
1893446Smrj ddi_prop_t *
get_proplist(char * name)1903446Smrj get_proplist(char *name)
1913446Smrj {
1923446Smrj ddi_prop_t *plist, *npp, *plast;
1933446Smrj char *curprop, *newprop;
1943446Smrj unsigned char *propval;
1953446Smrj unsigned long id;
1963446Smrj
1973446Smrj plist = NULL;
1983446Smrj plast = NULL;
1993446Smrj id = prom_findnode_byname(prom_rootnode(), name);
2003446Smrj if (id == 0)
2013446Smrj return (plist);
2023446Smrj curprop = "";
2033446Smrj while (newprop = (char *)prom_nextprop(curprop)) {
2043446Smrj curprop = strdup(newprop);
2053446Smrj npp = (ddi_prop_t *)malloc(sizeof (ddi_prop_t));
2063446Smrj if (npp == 0)
2073446Smrj exit(_error(PERROR, mfail));
2083446Smrj propval = prom_getprop(curprop, &npp->prop_len);
2093446Smrj npp->prop_name = curprop;
2103446Smrj if (propval != NULL) {
2113446Smrj npp->prop_val = (char *)malloc(npp->prop_len);
2123446Smrj if (npp->prop_val == 0)
2133446Smrj exit(_error(PERROR, mfail));
2143446Smrj memcpy(npp->prop_val, propval, npp->prop_len);
2153446Smrj } else
2163446Smrj npp->prop_val = NULL;
2173446Smrj npp->prop_next = NULL;
2183446Smrj if (plast == NULL) {
2193446Smrj plist = npp;
2203446Smrj } else {
2213446Smrj plast->prop_next = npp;
2223446Smrj }
2233446Smrj plast = npp;
2243446Smrj }
2253446Smrj return (plist);
2263446Smrj }
2273446Smrj
2283446Smrj caddr_t
get_propval(char * name,char * node)2293446Smrj get_propval(char *name, char *node)
2303446Smrj {
2313446Smrj ddi_prop_t *prop, *plist;
2323446Smrj
2333446Smrj if ((plist = get_proplist(node)) == NULL)
2343446Smrj return (NULL);
2353446Smrj
2363446Smrj for (prop = plist; prop != NULL; prop = prop->prop_next)
2373446Smrj if (strcmp(prop->prop_name, name) == 0)
2383446Smrj return (prop->prop_val);
2393446Smrj
2403446Smrj return (NULL);
2413446Smrj }
2423446Smrj
2433446Smrj void
get_kbenv(void)2443446Smrj get_kbenv(void)
2453446Smrj {
2463446Smrj if ((prom_fd = open(promdev, O_RDONLY)) < 0) {
2473446Smrj exit(_error(PERROR, "prom open failed"));
2483446Smrj }
2493446Smrj }
2503446Smrj
2513446Smrj void
close_kbenv(void)2523446Smrj close_kbenv(void)
2533446Smrj {
2543446Smrj (void) close(prom_fd);
2553446Smrj }
256