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
33static int getpropval(struct openpromio *opp, char *prop);
34
35static char *promdev = "/dev/openprom";
36static int prom_fd;
37static 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
52typedef union {
53	char buf[BUFSIZE];
54	struct openpromio opp;
55} Oppbuf;
56
57typedef union {
58	char buf[MINVALSIZE + sizeof (u_int)];
59	struct openpromio opp;
60} Oppbuf_small;
61
62static Oppbuf	oppbuf;
63
64static unsigned long
65next(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
79static unsigned long
80child(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 */
98static unsigned long
99prom_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 */
120static unsigned long
121prom_rootnode()
122{
123	return (next(0));
124}
125
126static int
127getpropval(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
139static int
140getnextprop(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
152char *
153getbootcmd(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 */
168static unsigned char *
169prom_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
179static unsigned char *
180prom_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
189ddi_prop_t *
190get_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
228caddr_t
229get_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
243void
244get_kbenv(void)
245{
246	if ((prom_fd = open(promdev, O_RDONLY)) < 0) {
247		exit(_error(PERROR, "prom open failed"));
248	}
249}
250
251void
252close_kbenv(void)
253{
254	(void) close(prom_fd);
255}
256