10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Stuff for mucking about with properties
310Sstevel@tonic-gate *
320Sstevel@tonic-gate * XXX: There is no distinction between intefer and non-integer properties
330Sstevel@tonic-gate * XXX: and no functions included for decoding properties. As is, this
340Sstevel@tonic-gate * XXX: file is suitable for a big-endian machine, since properties are
350Sstevel@tonic-gate * XXX: encoded using an XDR-like property encoding mechanism, which is
360Sstevel@tonic-gate * XXX: big-endian native ordering. To fix this, you need to add type-
370Sstevel@tonic-gate * XXX: sensitive decoding mechanisms and have the consumer of the data
380Sstevel@tonic-gate * XXX: decode the data, since only the consumer can claim to know the
390Sstevel@tonic-gate * XXX: the type of the data. (It can't be done automatically.)
400Sstevel@tonic-gate */
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include <sys/promif.h>
430Sstevel@tonic-gate #include <sys/promimpl.h>
440Sstevel@tonic-gate #include <sys/platform_module.h>
450Sstevel@tonic-gate
460Sstevel@tonic-gate static void prom_setprop_null(void);
470Sstevel@tonic-gate
480Sstevel@tonic-gate
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate * prom_setprop_{enter,exit} are set to plat_setprop_{enter,exit} on
510Sstevel@tonic-gate * platforms which require access to the seeproms to be serialized.
520Sstevel@tonic-gate * Otherwise these default to null functions. These functions must be
530Sstevel@tonic-gate * called before promif_preprom, since it can sleep and change CPU's,
540Sstevel@tonic-gate * thereby failing the assert in promif_postprom().
550Sstevel@tonic-gate */
560Sstevel@tonic-gate void (*prom_setprop_enter)(void) = prom_setprop_null;
570Sstevel@tonic-gate void (*prom_setprop_exit)(void) = prom_setprop_null;
580Sstevel@tonic-gate
590Sstevel@tonic-gate int
prom_asr_export_len()600Sstevel@tonic-gate prom_asr_export_len()
610Sstevel@tonic-gate {
620Sstevel@tonic-gate cell_t ci[4];
630Sstevel@tonic-gate
640Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,asr-export-len"); /* Service name */
650Sstevel@tonic-gate ci[1] = (cell_t)0; /* #argument cells */
660Sstevel@tonic-gate ci[2] = (cell_t)1; /* #return cells */
670Sstevel@tonic-gate ci[3] = (cell_t)-1; /* Res1: Prime result */
680Sstevel@tonic-gate
690Sstevel@tonic-gate promif_preprom();
700Sstevel@tonic-gate (void) p1275_cif_handler(&ci);
710Sstevel@tonic-gate promif_postprom();
720Sstevel@tonic-gate
730Sstevel@tonic-gate return (p1275_cell2int(ci[3])); /* Res1: buf length */
740Sstevel@tonic-gate }
750Sstevel@tonic-gate
760Sstevel@tonic-gate int
prom_asr_list_keys_len()770Sstevel@tonic-gate prom_asr_list_keys_len()
780Sstevel@tonic-gate {
790Sstevel@tonic-gate cell_t ci[4];
800Sstevel@tonic-gate
810Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,asr-list-keys-len");
820Sstevel@tonic-gate ci[1] = (cell_t)0; /* #argument cells */
830Sstevel@tonic-gate ci[2] = (cell_t)1; /* #return cells */
840Sstevel@tonic-gate ci[3] = (cell_t)-1; /* Res1: Prime result */
850Sstevel@tonic-gate
860Sstevel@tonic-gate promif_preprom();
870Sstevel@tonic-gate (void) p1275_cif_handler(&ci);
880Sstevel@tonic-gate promif_postprom();
890Sstevel@tonic-gate
900Sstevel@tonic-gate return (p1275_cell2int(ci[3])); /* Res1: buf length */
910Sstevel@tonic-gate }
920Sstevel@tonic-gate
930Sstevel@tonic-gate int
prom_asr_export(caddr_t value)940Sstevel@tonic-gate prom_asr_export(caddr_t value)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate int rv;
970Sstevel@tonic-gate cell_t ci[5];
980Sstevel@tonic-gate
990Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,asr-export"); /* Service name */
1000Sstevel@tonic-gate ci[1] = (cell_t)1; /* #argument cells */
1010Sstevel@tonic-gate ci[2] = (cell_t)1; /* #return cells */
1020Sstevel@tonic-gate ci[3] = p1275_ptr2cell(value); /* Arg1: buffer address */
1030Sstevel@tonic-gate ci[4] = -1; /* Res1: buf len */
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate promif_preprom();
1060Sstevel@tonic-gate rv = p1275_cif_handler(&ci);
1070Sstevel@tonic-gate promif_postprom();
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate if (rv != 0)
1100Sstevel@tonic-gate return (-1);
1110Sstevel@tonic-gate return (p1275_cell2int(ci[4])); /* Res1: buf length */
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate int
prom_asr_list_keys(caddr_t value)1150Sstevel@tonic-gate prom_asr_list_keys(caddr_t value)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate int rv;
1180Sstevel@tonic-gate cell_t ci[5];
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,asr-list-keys"); /* Service name */
1210Sstevel@tonic-gate ci[1] = (cell_t)1; /* #argument cells */
1220Sstevel@tonic-gate ci[2] = (cell_t)1; /* #return cells */
1230Sstevel@tonic-gate ci[3] = p1275_ptr2cell(value); /* Arg1: buffer address */
1240Sstevel@tonic-gate ci[4] = -1; /* Res1: buf len */
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate promif_preprom();
1270Sstevel@tonic-gate rv = p1275_cif_handler(&ci);
1280Sstevel@tonic-gate promif_postprom();
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate if (rv != 0)
1310Sstevel@tonic-gate return (-1);
1320Sstevel@tonic-gate return (p1275_cell2int(ci[4])); /* Res1: buf length */
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate int
prom_asr_disable(char * keystr,int keystr_len,char * reason,int reason_len)1360Sstevel@tonic-gate prom_asr_disable(char *keystr, int keystr_len,
1370Sstevel@tonic-gate char *reason, int reason_len)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate int rv;
1400Sstevel@tonic-gate cell_t ci[5];
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,asr-disable"); /* Service name */
1430Sstevel@tonic-gate ci[1] = (cell_t)4; /* #argument cells */
1440Sstevel@tonic-gate ci[2] = (cell_t)0; /* #return cells */
1450Sstevel@tonic-gate ci[3] = p1275_ptr2cell(keystr); /* Arg1: key address */
1460Sstevel@tonic-gate ci[3] = p1275_int2cell(keystr_len); /* Arg2: key len */
1470Sstevel@tonic-gate ci[3] = p1275_ptr2cell(reason); /* Arg1: reason address */
1480Sstevel@tonic-gate ci[3] = p1275_int2cell(reason_len); /* Arg2: reason len */
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate promif_preprom();
1510Sstevel@tonic-gate rv = p1275_cif_handler(&ci);
1520Sstevel@tonic-gate promif_postprom();
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate return (rv);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate int
prom_asr_enable(char * keystr,int keystr_len)1580Sstevel@tonic-gate prom_asr_enable(char *keystr, int keystr_len)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate int rv;
1610Sstevel@tonic-gate cell_t ci[5];
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,asr-enable"); /* Service name */
1640Sstevel@tonic-gate ci[1] = (cell_t)2; /* #argument cells */
1650Sstevel@tonic-gate ci[2] = (cell_t)0; /* #return cells */
1660Sstevel@tonic-gate ci[3] = p1275_ptr2cell(keystr); /* Arg1: key address */
1670Sstevel@tonic-gate ci[3] = p1275_int2cell(keystr_len); /* Arg2: key len */
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate promif_preprom();
1700Sstevel@tonic-gate rv = p1275_cif_handler(&ci);
1710Sstevel@tonic-gate promif_postprom();
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate return (rv);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate static void
prom_setprop_null(void)1770Sstevel@tonic-gate prom_setprop_null(void)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate int
prom_getproplen(pnode_t nodeid,caddr_t name)182*789Sahrens prom_getproplen(pnode_t nodeid, caddr_t name)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate cell_t ci[6];
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate ci[0] = p1275_ptr2cell("getproplen"); /* Service name */
1870Sstevel@tonic-gate ci[1] = (cell_t)2; /* #argument cells */
1880Sstevel@tonic-gate ci[2] = (cell_t)1; /* #return cells */
1890Sstevel@tonic-gate ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
1900Sstevel@tonic-gate ci[4] = p1275_ptr2cell(name); /* Arg2: Property name */
1910Sstevel@tonic-gate ci[5] = (cell_t)-1; /* Res1: Prime result */
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate promif_preprom();
1940Sstevel@tonic-gate (void) p1275_cif_handler(&ci);
1950Sstevel@tonic-gate promif_postprom();
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate return (p1275_cell2int(ci[5])); /* Res1: Property length */
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate int
prom_getprop(pnode_t nodeid,caddr_t name,caddr_t value)202*789Sahrens prom_getprop(pnode_t nodeid, caddr_t name, caddr_t value)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate int len, rv;
2050Sstevel@tonic-gate cell_t ci[8];
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate * This function assumes the buffer is large enough to
2090Sstevel@tonic-gate * hold the result, so in 1275 mode, we pass in the length
2100Sstevel@tonic-gate * of the property as the length of the buffer, since we
2110Sstevel@tonic-gate * have no way of knowing the size of the buffer. Pre-1275
2120Sstevel@tonic-gate * OpenBoot(tm) PROMs did not have a bounded getprop.
2130Sstevel@tonic-gate *
2140Sstevel@tonic-gate * Note that we ignore the "length" result of the service.
2150Sstevel@tonic-gate */
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate if ((len = prom_getproplen(nodeid, name)) <= 0)
2180Sstevel@tonic-gate return (len);
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate ci[0] = p1275_ptr2cell("getprop"); /* Service name */
2210Sstevel@tonic-gate ci[1] = (cell_t)4; /* #argument cells */
2220Sstevel@tonic-gate ci[2] = (cell_t)0; /* #result cells */
2230Sstevel@tonic-gate ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
2240Sstevel@tonic-gate ci[4] = p1275_ptr2cell(name); /* Arg2: property name */
2250Sstevel@tonic-gate ci[5] = p1275_ptr2cell(value); /* Arg3: buffer address */
2260Sstevel@tonic-gate ci[6] = len; /* Arg4: buf len (assumed) */
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate promif_preprom();
2290Sstevel@tonic-gate rv = p1275_cif_handler(&ci);
2300Sstevel@tonic-gate promif_postprom();
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate if (rv != 0)
2330Sstevel@tonic-gate return (-1);
2340Sstevel@tonic-gate return (len); /* Return known length */
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate int
prom_bounded_getprop(pnode_t nodeid,caddr_t name,caddr_t value,int len)238*789Sahrens prom_bounded_getprop(pnode_t nodeid, caddr_t name, caddr_t value, int len)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate cell_t ci[8];
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate ci[0] = p1275_ptr2cell("getprop"); /* Service name */
2430Sstevel@tonic-gate ci[1] = (cell_t)4; /* #argument cells */
2440Sstevel@tonic-gate ci[2] = (cell_t)1; /* #result cells */
2450Sstevel@tonic-gate ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
2460Sstevel@tonic-gate ci[4] = p1275_ptr2cell(name); /* Arg2: property name */
2470Sstevel@tonic-gate ci[5] = p1275_ptr2cell(value); /* Arg3: buffer address */
2480Sstevel@tonic-gate ci[6] = p1275_int2cell(len); /* Arg4: buffer length */
2490Sstevel@tonic-gate ci[7] = (cell_t)-1; /* Res1: Prime result */
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate promif_preprom();
2520Sstevel@tonic-gate (void) p1275_cif_handler(&ci);
2530Sstevel@tonic-gate promif_postprom();
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate return (p1275_cell2int(ci[7])); /* Res1: Returned length */
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate caddr_t
prom_nextprop(pnode_t nodeid,caddr_t previous,caddr_t next)259*789Sahrens prom_nextprop(pnode_t nodeid, caddr_t previous, caddr_t next)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate cell_t ci[7];
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate (void) prom_strcpy(next, ""); /* Prime result, in case call fails */
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate ci[0] = p1275_ptr2cell("nextprop"); /* Service name */
2660Sstevel@tonic-gate ci[1] = (cell_t)3; /* #argument cells */
2670Sstevel@tonic-gate ci[2] = (cell_t)0; /* #result cells */
2680Sstevel@tonic-gate ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: phandle */
2690Sstevel@tonic-gate ci[4] = p1275_ptr2cell(previous); /* Arg2: addr of prev name */
2700Sstevel@tonic-gate ci[5] = p1275_ptr2cell(next); /* Arg3: addr of 32 byte buf */
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate promif_preprom();
2730Sstevel@tonic-gate (void) p1275_cif_handler(&ci);
2740Sstevel@tonic-gate promif_postprom();
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate return (next);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate int
prom_setprop(pnode_t nodeid,caddr_t name,caddr_t value,int len)280*789Sahrens prom_setprop(pnode_t nodeid, caddr_t name, caddr_t value, int len)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate cell_t ci[8];
2830Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS
2840Sstevel@tonic-gate caddr_t ovalue = NULL;
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate if ((uintptr_t)value > (uint32_t)-1) {
2870Sstevel@tonic-gate ovalue = value;
2880Sstevel@tonic-gate value = promplat_alloc(len);
2890Sstevel@tonic-gate if (value == NULL) {
2900Sstevel@tonic-gate return (-1);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate promplat_bcopy(ovalue, value, len);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate #endif
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate prom_setprop_enter();
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate promif_preprom();
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate ci[0] = p1275_ptr2cell("setprop"); /* Service name */
3010Sstevel@tonic-gate ci[1] = (cell_t)4; /* #argument cells */
3020Sstevel@tonic-gate ci[2] = (cell_t)1; /* #result cells */
3030Sstevel@tonic-gate ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: phandle */
3040Sstevel@tonic-gate ci[4] = p1275_ptr2cell(name); /* Arg2: property name */
3050Sstevel@tonic-gate ci[5] = p1275_ptr2cell(value); /* Arg3: New value ptr */
3060Sstevel@tonic-gate ci[6] = p1275_int2cell(len); /* Arg4: New value len */
3070Sstevel@tonic-gate ci[7] = (cell_t)-1; /* Res1: Prime result */
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate (void) p1275_cif_handler(&ci);
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate promif_postprom();
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate prom_setprop_exit();
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS
3160Sstevel@tonic-gate if (ovalue != NULL)
3170Sstevel@tonic-gate promplat_free(value, len);
3180Sstevel@tonic-gate #endif
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate return (p1275_cell2int(ci[7])); /* Res1: Actual new size */
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate * prom_decode_composite_string:
3250Sstevel@tonic-gate *
3260Sstevel@tonic-gate * Returns successive strings in a composite string property.
3270Sstevel@tonic-gate * A composite string property is a buffer containing one or more
3280Sstevel@tonic-gate * NULL terminated strings contained within the length of the buffer.
3290Sstevel@tonic-gate *
3300Sstevel@tonic-gate * Always call with the base address and length of the property buffer.
3310Sstevel@tonic-gate * On the first call, call with prev == 0, call successively
3320Sstevel@tonic-gate * with prev == to the last value returned from this function
3330Sstevel@tonic-gate * until the routine returns zero which means no more string values.
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate char *
prom_decode_composite_string(void * buf,size_t buflen,char * prev)3360Sstevel@tonic-gate prom_decode_composite_string(void *buf, size_t buflen, char *prev)
3370Sstevel@tonic-gate {
3380Sstevel@tonic-gate if ((buf == 0) || (buflen == 0) || ((int)buflen == -1))
3390Sstevel@tonic-gate return ((char *)0);
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (prev == 0)
3420Sstevel@tonic-gate return ((char *)buf);
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate prev += prom_strlen(prev) + 1;
3450Sstevel@tonic-gate if (prev >= ((char *)buf + buflen))
3460Sstevel@tonic-gate return ((char *)0);
3470Sstevel@tonic-gate return (prev);
3480Sstevel@tonic-gate }
349