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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Stuff for mucking about with properties
31  *
32  * XXX: There is no distinction between intefer and non-integer properties
33  * XXX: and no functions included for decoding properties.  As is, this
34  * XXX: file is suitable for a big-endian machine, since properties are
35  * XXX: encoded using an XDR-like property encoding mechanism, which is
36  * XXX: big-endian native ordering.  To fix this, you need to add type-
37  * XXX: sensitive decoding mechanisms and have the consumer of the data
38  * XXX: decode the data, since only the consumer can claim to know the
39  * XXX: the type of the data. (It can't be done automatically.)
40  */
41 
42 #include <sys/promif.h>
43 #include <sys/promimpl.h>
44 #include <sys/platform_module.h>
45 
46 static void prom_setprop_null(void);
47 
48 
49 /*
50  * prom_setprop_{enter,exit} are set to plat_setprop_{enter,exit} on
51  * platforms which require access to the seeproms to be serialized.
52  * Otherwise these default to null functions.  These functions must be
53  * called before promif_preprom, since it can sleep and change CPU's,
54  * thereby failing the assert in promif_postprom().
55  */
56 void (*prom_setprop_enter)(void) = prom_setprop_null;
57 void (*prom_setprop_exit)(void) = prom_setprop_null;
58 
59 int
prom_asr_export_len()60 prom_asr_export_len()
61 {
62 	cell_t ci[4];
63 
64 	ci[0] = p1275_ptr2cell("SUNW,asr-export-len");	/* Service name */
65 	ci[1] = (cell_t)0;			/* #argument cells */
66 	ci[2] = (cell_t)1;			/* #return cells */
67 	ci[3] = (cell_t)-1;			/* Res1: Prime result */
68 
69 	promif_preprom();
70 	(void) p1275_cif_handler(&ci);
71 	promif_postprom();
72 
73 	return (p1275_cell2int(ci[3]));		/* Res1: buf length */
74 }
75 
76 int
prom_asr_list_keys_len()77 prom_asr_list_keys_len()
78 {
79 	cell_t ci[4];
80 
81 	ci[0] = p1275_ptr2cell("SUNW,asr-list-keys-len");
82 	ci[1] = (cell_t)0;			/* #argument cells */
83 	ci[2] = (cell_t)1;			/* #return cells */
84 	ci[3] = (cell_t)-1;			/* Res1: Prime result */
85 
86 	promif_preprom();
87 	(void) p1275_cif_handler(&ci);
88 	promif_postprom();
89 
90 	return (p1275_cell2int(ci[3]));		/* Res1: buf length */
91 }
92 
93 int
prom_asr_export(caddr_t value)94 prom_asr_export(caddr_t value)
95 {
96 	int rv;
97 	cell_t ci[5];
98 
99 	ci[0] = p1275_ptr2cell("SUNW,asr-export");	/* Service name */
100 	ci[1] = (cell_t)1;			/* #argument cells */
101 	ci[2] = (cell_t)1;			/* #return cells */
102 	ci[3] = p1275_ptr2cell(value);		/* Arg1: buffer address */
103 	ci[4] = -1;				/* Res1: buf len */
104 
105 	promif_preprom();
106 	rv = p1275_cif_handler(&ci);
107 	promif_postprom();
108 
109 	if (rv != 0)
110 		return (-1);
111 	return (p1275_cell2int(ci[4]));		/* Res1: buf length */
112 }
113 
114 int
prom_asr_list_keys(caddr_t value)115 prom_asr_list_keys(caddr_t value)
116 {
117 	int rv;
118 	cell_t ci[5];
119 
120 	ci[0] = p1275_ptr2cell("SUNW,asr-list-keys");	/* Service name */
121 	ci[1] = (cell_t)1;			/* #argument cells */
122 	ci[2] = (cell_t)1;			/* #return cells */
123 	ci[3] = p1275_ptr2cell(value);		/* Arg1: buffer address */
124 	ci[4] = -1;				/* Res1: buf len */
125 
126 	promif_preprom();
127 	rv = p1275_cif_handler(&ci);
128 	promif_postprom();
129 
130 	if (rv != 0)
131 		return (-1);
132 	return (p1275_cell2int(ci[4]));		/* Res1: buf length */
133 }
134 
135 int
prom_asr_disable(char * keystr,int keystr_len,char * reason,int reason_len)136 prom_asr_disable(char *keystr, int keystr_len,
137     char *reason, int reason_len)
138 {
139 	int rv;
140 	cell_t ci[5];
141 
142 	ci[0] = p1275_ptr2cell("SUNW,asr-disable");	/* Service name */
143 	ci[1] = (cell_t)4;			/* #argument cells */
144 	ci[2] = (cell_t)0;			/* #return cells */
145 	ci[3] = p1275_ptr2cell(keystr);		/* Arg1: key address */
146 	ci[3] = p1275_int2cell(keystr_len);	/* Arg2: key len */
147 	ci[3] = p1275_ptr2cell(reason);		/* Arg1: reason address */
148 	ci[3] = p1275_int2cell(reason_len);	/* Arg2: reason len */
149 
150 	promif_preprom();
151 	rv = p1275_cif_handler(&ci);
152 	promif_postprom();
153 
154 	return (rv);
155 }
156 
157 int
prom_asr_enable(char * keystr,int keystr_len)158 prom_asr_enable(char *keystr, int keystr_len)
159 {
160 	int rv;
161 	cell_t ci[5];
162 
163 	ci[0] = p1275_ptr2cell("SUNW,asr-enable");	/* Service name */
164 	ci[1] = (cell_t)2;			/* #argument cells */
165 	ci[2] = (cell_t)0;			/* #return cells */
166 	ci[3] = p1275_ptr2cell(keystr);		/* Arg1: key address */
167 	ci[3] = p1275_int2cell(keystr_len);	/* Arg2: key len */
168 
169 	promif_preprom();
170 	rv = p1275_cif_handler(&ci);
171 	promif_postprom();
172 
173 	return (rv);
174 }
175 
176 static void
prom_setprop_null(void)177 prom_setprop_null(void)
178 {
179 }
180 
181 int
prom_getproplen(pnode_t nodeid,caddr_t name)182 prom_getproplen(pnode_t nodeid, caddr_t name)
183 {
184 	cell_t ci[6];
185 
186 	ci[0] = p1275_ptr2cell("getproplen");	/* Service name */
187 	ci[1] = (cell_t)2;			/* #argument cells */
188 	ci[2] = (cell_t)1;			/* #return cells */
189 	ci[3] = p1275_phandle2cell((phandle_t)nodeid);	/* Arg1: package */
190 	ci[4] = p1275_ptr2cell(name);		/* Arg2: Property name */
191 	ci[5] = (cell_t)-1;			/* Res1: Prime result */
192 
193 	promif_preprom();
194 	(void) p1275_cif_handler(&ci);
195 	promif_postprom();
196 
197 	return (p1275_cell2int(ci[5]));		/* Res1: Property length */
198 }
199 
200 
201 int
prom_getprop(pnode_t nodeid,caddr_t name,caddr_t value)202 prom_getprop(pnode_t nodeid, caddr_t name, caddr_t value)
203 {
204 	int len, rv;
205 	cell_t ci[8];
206 
207 	/*
208 	 * This function assumes the buffer is large enough to
209 	 * hold the result, so in 1275 mode, we pass in the length
210 	 * of the property as the length of the buffer, since we
211 	 * have no way of knowing the size of the buffer. Pre-1275
212 	 * OpenBoot(tm) PROMs did not have a bounded getprop.
213 	 *
214 	 * Note that we ignore the "length" result of the service.
215 	 */
216 
217 	if ((len = prom_getproplen(nodeid, name)) <= 0)
218 		return (len);
219 
220 	ci[0] = p1275_ptr2cell("getprop");	/* Service name */
221 	ci[1] = (cell_t)4;			/* #argument cells */
222 	ci[2] = (cell_t)0;			/* #result cells */
223 	ci[3] = p1275_phandle2cell((phandle_t)nodeid);	/* Arg1: package */
224 	ci[4] = p1275_ptr2cell(name);		/* Arg2: property name */
225 	ci[5] = p1275_ptr2cell(value);		/* Arg3: buffer address */
226 	ci[6] = len;				/* Arg4: buf len (assumed) */
227 
228 	promif_preprom();
229 	rv = p1275_cif_handler(&ci);
230 	promif_postprom();
231 
232 	if (rv != 0)
233 		return (-1);
234 	return (len);				/* Return known length */
235 }
236 
237 int
prom_bounded_getprop(pnode_t nodeid,caddr_t name,caddr_t value,int len)238 prom_bounded_getprop(pnode_t nodeid, caddr_t name, caddr_t value, int len)
239 {
240 	cell_t ci[8];
241 
242 	ci[0] = p1275_ptr2cell("getprop");	/* Service name */
243 	ci[1] = (cell_t)4;			/* #argument cells */
244 	ci[2] = (cell_t)1;			/* #result cells */
245 	ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
246 	ci[4] = p1275_ptr2cell(name);		/* Arg2: property name */
247 	ci[5] = p1275_ptr2cell(value);		/* Arg3: buffer address */
248 	ci[6] = p1275_int2cell(len);		/* Arg4: buffer length */
249 	ci[7] = (cell_t)-1;			/* Res1: Prime result */
250 
251 	promif_preprom();
252 	(void) p1275_cif_handler(&ci);
253 	promif_postprom();
254 
255 	return (p1275_cell2int(ci[7]));		/* Res1: Returned length */
256 }
257 
258 caddr_t
prom_nextprop(pnode_t nodeid,caddr_t previous,caddr_t next)259 prom_nextprop(pnode_t nodeid, caddr_t previous, caddr_t next)
260 {
261 	cell_t ci[7];
262 
263 	(void) prom_strcpy(next, "");	/* Prime result, in case call fails */
264 
265 	ci[0] = p1275_ptr2cell("nextprop");	/* Service name */
266 	ci[1] = (cell_t)3;			/* #argument cells */
267 	ci[2] = (cell_t)0;			/* #result cells */
268 	ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: phandle */
269 	ci[4] = p1275_ptr2cell(previous);	/* Arg2: addr of prev name */
270 	ci[5] = p1275_ptr2cell(next);		/* Arg3: addr of 32 byte buf */
271 
272 	promif_preprom();
273 	(void) p1275_cif_handler(&ci);
274 	promif_postprom();
275 
276 	return (next);
277 }
278 
279 int
prom_setprop(pnode_t nodeid,caddr_t name,caddr_t value,int len)280 prom_setprop(pnode_t nodeid, caddr_t name, caddr_t value, int len)
281 {
282 	cell_t ci[8];
283 #ifdef PROM_32BIT_ADDRS
284 	caddr_t ovalue = NULL;
285 
286 	if ((uintptr_t)value > (uint32_t)-1) {
287 		ovalue = value;
288 		value = promplat_alloc(len);
289 		if (value == NULL) {
290 			return (-1);
291 		}
292 		promplat_bcopy(ovalue, value, len);
293 	}
294 #endif
295 
296 	prom_setprop_enter();
297 
298 	promif_preprom();
299 
300 	ci[0] = p1275_ptr2cell("setprop");	/* Service name */
301 	ci[1] = (cell_t)4;			/* #argument cells */
302 	ci[2] = (cell_t)1;			/* #result cells */
303 	ci[3] = p1275_phandle2cell((phandle_t)nodeid);	/* Arg1: phandle */
304 	ci[4] = p1275_ptr2cell(name);		/* Arg2: property name */
305 	ci[5] = p1275_ptr2cell(value);		/* Arg3: New value ptr */
306 	ci[6] = p1275_int2cell(len);		/* Arg4: New value len */
307 	ci[7] = (cell_t)-1;			/* Res1: Prime result */
308 
309 	(void) p1275_cif_handler(&ci);
310 
311 	promif_postprom();
312 
313 	prom_setprop_exit();
314 
315 #ifdef PROM_32BIT_ADDRS
316 	if (ovalue != NULL)
317 		promplat_free(value, len);
318 #endif
319 
320 	return (p1275_cell2int(ci[7]));		/* Res1: Actual new size */
321 }
322 
323 /*
324  * prom_decode_composite_string:
325  *
326  * Returns successive strings in a composite string property.
327  * A composite string property is a buffer containing one or more
328  * NULL terminated strings contained within the length of the buffer.
329  *
330  * Always call with the base address and length of the property buffer.
331  * On the first call, call with prev == 0, call successively
332  * with prev == to the last value returned from this function
333  * until the routine returns zero which means no more string values.
334  */
335 char *
prom_decode_composite_string(void * buf,size_t buflen,char * prev)336 prom_decode_composite_string(void *buf, size_t buflen, char *prev)
337 {
338 	if ((buf == 0) || (buflen == 0) || ((int)buflen == -1))
339 		return ((char *)0);
340 
341 	if (prev == 0)
342 		return ((char *)buf);
343 
344 	prev += prom_strlen(prev) + 1;
345 	if (prev >= ((char *)buf + buflen))
346 		return ((char *)0);
347 	return (prev);
348 }
349