1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 #include "benv.h"
28 #include <sys/sunddi.h>
29 #include <sys/ddi_impldefs.h>
30 #include <sys/openpromio.h>
31 #include <stdio.h>
32
33 static int getpropval(struct openpromio *opp, char *prop);
34
35 static char *promdev = "/dev/openprom";
36 static int prom_fd;
37 static char *mfail = "malloc";
38
39 /*
40 * 128 is the size of the largest (currently) property name
41 * 16384 - MAXPROPSIZE - sizeof (int) is the size of the largest
42 * (currently) property value that is allowed.
43 * the sizeof (u_int) is from struct openpromio
44 */
45
46 #define MAXPROPSIZE 128
47 #define MAXVALSIZE (16384 - MAXPROPSIZE - sizeof (u_int))
48 #define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (u_int))
49 #define MINVALSIZE (4 * sizeof (u_long))
50 #define MINBUFSIZE (MINVALSIZE + sizeof (u_long))
51
52 typedef union {
53 char buf[BUFSIZE];
54 struct openpromio opp;
55 } Oppbuf;
56
57 typedef union {
58 char buf[MINVALSIZE + sizeof (u_int)];
59 struct openpromio opp;
60 } Oppbuf_small;
61
62 static Oppbuf oppbuf;
63
64 static unsigned long
next(unsigned long id)65 next(unsigned long id)
66 {
67 Oppbuf_small oppbuf;
68 struct openpromio *opp = &(oppbuf.opp);
69 unsigned long *ip = (unsigned long *)(opp->oprom_array);
70
71 memset(oppbuf.buf, 0, MINBUFSIZE);
72 opp->oprom_size = MINVALSIZE;
73 *ip = id;
74 if (ioctl(prom_fd, OPROMNEXT, opp) < 0)
75 return (0);
76 return (*(unsigned long *)opp->oprom_array);
77 }
78
79 static unsigned long
child(unsigned long id)80 child(unsigned long id)
81 {
82 Oppbuf_small oppbuf;
83 struct openpromio *opp = &(oppbuf.opp);
84 unsigned long *ip = (unsigned long *)(opp->oprom_array);
85
86 memset(oppbuf.buf, 0, MINBUFSIZE);
87 opp->oprom_size = MINVALSIZE;
88 *ip = id;
89 if (ioctl(prom_fd, OPROMCHILD, opp) < 0)
90 return (0);
91 return (*(unsigned long *)opp->oprom_array);
92 }
93
94 /*
95 * Find a node by name from the prom device tree.
96 * Return the id or 0 if it is not found.
97 */
98 static unsigned long
prom_findnode_byname(unsigned long id,char * name)99 prom_findnode_byname(unsigned long id, char *name)
100 {
101 struct openpromio *opp = &(oppbuf.opp);
102 unsigned long nid;
103
104 if (id == 0)
105 return (0);
106 if (!getpropval(opp, "name"))
107 return (0);
108 if (strcmp(opp->oprom_array, name) == 0)
109 return (id);
110 if (nid = prom_findnode_byname(child(id), name))
111 return (nid);
112 if (nid = prom_findnode_byname(next(id), name))
113 return (nid);
114 return (0);
115 }
116
117 /*
118 * Make the current prom node be the rootnode and return its id.
119 */
120 static unsigned long
prom_rootnode()121 prom_rootnode()
122 {
123 return (next(0));
124 }
125
126 static int
getpropval(struct openpromio * opp,char * prop)127 getpropval(struct openpromio *opp, char *prop)
128 {
129 opp->oprom_size = MAXVALSIZE;
130
131 (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE);
132 if (ioctl(prom_fd, OPROMGETPROP, opp) < 0)
133 return (0);
134 if (opp->oprom_size == 0)
135 return (0);
136 return (1);
137 }
138
139 static int
getnextprop(struct openpromio * opp,char * prop)140 getnextprop(struct openpromio *opp, char *prop)
141 {
142 opp->oprom_size = MAXVALSIZE;
143
144 (void) strlcpy(opp->oprom_array, prop, MAXPROPSIZE);
145 if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0)
146 return (0);
147 if (opp->oprom_size == 0)
148 return (0);
149 return (1);
150 }
151
152 char *
getbootcmd(void)153 getbootcmd(void)
154 {
155 struct openpromio *opp = &(oppbuf.opp);
156 opp->oprom_size = MAXVALSIZE;
157 if (ioctl(prom_fd, OPROMGETBOOTPATH, opp) < 0)
158 return (NULL);
159 return (opp->oprom_array);
160 }
161
162 /*
163 * Get a pointer to the requested property from the current node.
164 * The property is stored in static storage and the returned pointer
165 * points into the static storage. The property length is placed in
166 * the location pointed to by the third argument.
167 */
168 static unsigned char *
prom_getprop(char * prop,int * lenp)169 prom_getprop(char *prop, int *lenp)
170 {
171 struct openpromio *opp = &(oppbuf.opp);
172
173 if (!getpropval(opp, prop))
174 return (NULL);
175 *lenp = opp->oprom_size;
176 return ((unsigned char *)opp->oprom_array);
177 }
178
179 static unsigned char *
prom_nextprop(char * prop)180 prom_nextprop(char *prop)
181 {
182 struct openpromio *opp = &(oppbuf.opp);
183
184 if (!getnextprop(opp, prop))
185 return ((unsigned char *)0);
186 return ((unsigned char *)opp->oprom_array);
187 }
188
189 ddi_prop_t *
get_proplist(char * name)190 get_proplist(char *name)
191 {
192 ddi_prop_t *plist, *npp, *plast;
193 char *curprop, *newprop;
194 unsigned char *propval;
195 unsigned long id;
196
197 plist = NULL;
198 plast = NULL;
199 id = prom_findnode_byname(prom_rootnode(), name);
200 if (id == 0)
201 return (plist);
202 curprop = "";
203 while (newprop = (char *)prom_nextprop(curprop)) {
204 curprop = strdup(newprop);
205 npp = (ddi_prop_t *)malloc(sizeof (ddi_prop_t));
206 if (npp == 0)
207 exit(_error(PERROR, mfail));
208 propval = prom_getprop(curprop, &npp->prop_len);
209 npp->prop_name = curprop;
210 if (propval != NULL) {
211 npp->prop_val = (char *)malloc(npp->prop_len);
212 if (npp->prop_val == 0)
213 exit(_error(PERROR, mfail));
214 memcpy(npp->prop_val, propval, npp->prop_len);
215 } else
216 npp->prop_val = NULL;
217 npp->prop_next = NULL;
218 if (plast == NULL) {
219 plist = npp;
220 } else {
221 plast->prop_next = npp;
222 }
223 plast = npp;
224 }
225 return (plist);
226 }
227
228 caddr_t
get_propval(char * name,char * node)229 get_propval(char *name, char *node)
230 {
231 ddi_prop_t *prop, *plist;
232
233 if ((plist = get_proplist(node)) == NULL)
234 return (NULL);
235
236 for (prop = plist; prop != NULL; prop = prop->prop_next)
237 if (strcmp(prop->prop_name, name) == 0)
238 return (prop->prop_val);
239
240 return (NULL);
241 }
242
243 void
get_kbenv(void)244 get_kbenv(void)
245 {
246 if ((prom_fd = open(promdev, O_RDONLY)) < 0) {
247 exit(_error(PERROR, "prom open failed"));
248 }
249 }
250
251 void
close_kbenv(void)252 close_kbenv(void)
253 {
254 (void) close(prom_fd);
255 }
256