xref: /illumos-gate/usr/src/cmd/eeprom/i386/benv_kvm.c (revision b23a7923c0fe493ed4beebaf775ad634ea217080)
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
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
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
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
121 prom_rootnode()
122 {
123 	return (next(0));
124 }
125 
126 static int
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
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 *
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 *
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 *
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 *
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
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
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
252 close_kbenv(void)
253 {
254 	(void) close(prom_fd);
255 }
256