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