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 2004 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 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 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 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 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 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 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 177 prom_setprop_null(void) 178 { 179 } 180 181 int 182 prom_getproplen(dnode_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 202 prom_getprop(dnode_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 238 prom_bounded_getprop(dnode_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 259 prom_nextprop(dnode_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 280 prom_setprop(dnode_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 * 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