summaryrefslogtreecommitdiff
path: root/usr/src/psm/promif/ieee1275/common/prom_prop.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/psm/promif/ieee1275/common/prom_prop.c')
-rw-r--r--usr/src/psm/promif/ieee1275/common/prom_prop.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/usr/src/psm/promif/ieee1275/common/prom_prop.c b/usr/src/psm/promif/ieee1275/common/prom_prop.c
new file mode 100644
index 0000000000..5440be79e0
--- /dev/null
+++ b/usr/src/psm/promif/ieee1275/common/prom_prop.c
@@ -0,0 +1,348 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Stuff for mucking about with properties
+ *
+ * XXX: There is no distinction between intefer and non-integer properties
+ * XXX: and no functions included for decoding properties. As is, this
+ * XXX: file is suitable for a big-endian machine, since properties are
+ * XXX: encoded using an XDR-like property encoding mechanism, which is
+ * XXX: big-endian native ordering. To fix this, you need to add type-
+ * XXX: sensitive decoding mechanisms and have the consumer of the data
+ * XXX: decode the data, since only the consumer can claim to know the
+ * XXX: the type of the data. (It can't be done automatically.)
+ */
+
+#include <sys/promif.h>
+#include <sys/promimpl.h>
+#include <sys/platform_module.h>
+
+static void prom_setprop_null(void);
+
+
+/*
+ * prom_setprop_{enter,exit} are set to plat_setprop_{enter,exit} on
+ * platforms which require access to the seeproms to be serialized.
+ * Otherwise these default to null functions. These functions must be
+ * called before promif_preprom, since it can sleep and change CPU's,
+ * thereby failing the assert in promif_postprom().
+ */
+void (*prom_setprop_enter)(void) = prom_setprop_null;
+void (*prom_setprop_exit)(void) = prom_setprop_null;
+
+int
+prom_asr_export_len()
+{
+ cell_t ci[4];
+
+ ci[0] = p1275_ptr2cell("SUNW,asr-export-len"); /* Service name */
+ ci[1] = (cell_t)0; /* #argument cells */
+ ci[2] = (cell_t)1; /* #return cells */
+ ci[3] = (cell_t)-1; /* Res1: Prime result */
+
+ promif_preprom();
+ (void) p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (p1275_cell2int(ci[3])); /* Res1: buf length */
+}
+
+int
+prom_asr_list_keys_len()
+{
+ cell_t ci[4];
+
+ ci[0] = p1275_ptr2cell("SUNW,asr-list-keys-len");
+ ci[1] = (cell_t)0; /* #argument cells */
+ ci[2] = (cell_t)1; /* #return cells */
+ ci[3] = (cell_t)-1; /* Res1: Prime result */
+
+ promif_preprom();
+ (void) p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (p1275_cell2int(ci[3])); /* Res1: buf length */
+}
+
+int
+prom_asr_export(caddr_t value)
+{
+ int rv;
+ cell_t ci[5];
+
+ ci[0] = p1275_ptr2cell("SUNW,asr-export"); /* Service name */
+ ci[1] = (cell_t)1; /* #argument cells */
+ ci[2] = (cell_t)1; /* #return cells */
+ ci[3] = p1275_ptr2cell(value); /* Arg1: buffer address */
+ ci[4] = -1; /* Res1: buf len */
+
+ promif_preprom();
+ rv = p1275_cif_handler(&ci);
+ promif_postprom();
+
+ if (rv != 0)
+ return (-1);
+ return (p1275_cell2int(ci[4])); /* Res1: buf length */
+}
+
+int
+prom_asr_list_keys(caddr_t value)
+{
+ int rv;
+ cell_t ci[5];
+
+ ci[0] = p1275_ptr2cell("SUNW,asr-list-keys"); /* Service name */
+ ci[1] = (cell_t)1; /* #argument cells */
+ ci[2] = (cell_t)1; /* #return cells */
+ ci[3] = p1275_ptr2cell(value); /* Arg1: buffer address */
+ ci[4] = -1; /* Res1: buf len */
+
+ promif_preprom();
+ rv = p1275_cif_handler(&ci);
+ promif_postprom();
+
+ if (rv != 0)
+ return (-1);
+ return (p1275_cell2int(ci[4])); /* Res1: buf length */
+}
+
+int
+prom_asr_disable(char *keystr, int keystr_len,
+ char *reason, int reason_len)
+{
+ int rv;
+ cell_t ci[5];
+
+ ci[0] = p1275_ptr2cell("SUNW,asr-disable"); /* Service name */
+ ci[1] = (cell_t)4; /* #argument cells */
+ ci[2] = (cell_t)0; /* #return cells */
+ ci[3] = p1275_ptr2cell(keystr); /* Arg1: key address */
+ ci[3] = p1275_int2cell(keystr_len); /* Arg2: key len */
+ ci[3] = p1275_ptr2cell(reason); /* Arg1: reason address */
+ ci[3] = p1275_int2cell(reason_len); /* Arg2: reason len */
+
+ promif_preprom();
+ rv = p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (rv);
+}
+
+int
+prom_asr_enable(char *keystr, int keystr_len)
+{
+ int rv;
+ cell_t ci[5];
+
+ ci[0] = p1275_ptr2cell("SUNW,asr-enable"); /* Service name */
+ ci[1] = (cell_t)2; /* #argument cells */
+ ci[2] = (cell_t)0; /* #return cells */
+ ci[3] = p1275_ptr2cell(keystr); /* Arg1: key address */
+ ci[3] = p1275_int2cell(keystr_len); /* Arg2: key len */
+
+ promif_preprom();
+ rv = p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (rv);
+}
+
+static void
+prom_setprop_null(void)
+{
+}
+
+int
+prom_getproplen(dnode_t nodeid, caddr_t name)
+{
+ cell_t ci[6];
+
+ ci[0] = p1275_ptr2cell("getproplen"); /* Service name */
+ ci[1] = (cell_t)2; /* #argument cells */
+ ci[2] = (cell_t)1; /* #return cells */
+ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
+ ci[4] = p1275_ptr2cell(name); /* Arg2: Property name */
+ ci[5] = (cell_t)-1; /* Res1: Prime result */
+
+ promif_preprom();
+ (void) p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (p1275_cell2int(ci[5])); /* Res1: Property length */
+}
+
+
+int
+prom_getprop(dnode_t nodeid, caddr_t name, caddr_t value)
+{
+ int len, rv;
+ cell_t ci[8];
+
+ /*
+ * This function assumes the buffer is large enough to
+ * hold the result, so in 1275 mode, we pass in the length
+ * of the property as the length of the buffer, since we
+ * have no way of knowing the size of the buffer. Pre-1275
+ * OpenBoot(tm) PROMs did not have a bounded getprop.
+ *
+ * Note that we ignore the "length" result of the service.
+ */
+
+ if ((len = prom_getproplen(nodeid, name)) <= 0)
+ return (len);
+
+ ci[0] = p1275_ptr2cell("getprop"); /* Service name */
+ ci[1] = (cell_t)4; /* #argument cells */
+ ci[2] = (cell_t)0; /* #result cells */
+ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
+ ci[4] = p1275_ptr2cell(name); /* Arg2: property name */
+ ci[5] = p1275_ptr2cell(value); /* Arg3: buffer address */
+ ci[6] = len; /* Arg4: buf len (assumed) */
+
+ promif_preprom();
+ rv = p1275_cif_handler(&ci);
+ promif_postprom();
+
+ if (rv != 0)
+ return (-1);
+ return (len); /* Return known length */
+}
+
+int
+prom_bounded_getprop(dnode_t nodeid, caddr_t name, caddr_t value, int len)
+{
+ cell_t ci[8];
+
+ ci[0] = p1275_ptr2cell("getprop"); /* Service name */
+ ci[1] = (cell_t)4; /* #argument cells */
+ ci[2] = (cell_t)1; /* #result cells */
+ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */
+ ci[4] = p1275_ptr2cell(name); /* Arg2: property name */
+ ci[5] = p1275_ptr2cell(value); /* Arg3: buffer address */
+ ci[6] = p1275_int2cell(len); /* Arg4: buffer length */
+ ci[7] = (cell_t)-1; /* Res1: Prime result */
+
+ promif_preprom();
+ (void) p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (p1275_cell2int(ci[7])); /* Res1: Returned length */
+}
+
+caddr_t
+prom_nextprop(dnode_t nodeid, caddr_t previous, caddr_t next)
+{
+ cell_t ci[7];
+
+ (void) prom_strcpy(next, ""); /* Prime result, in case call fails */
+
+ ci[0] = p1275_ptr2cell("nextprop"); /* Service name */
+ ci[1] = (cell_t)3; /* #argument cells */
+ ci[2] = (cell_t)0; /* #result cells */
+ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: phandle */
+ ci[4] = p1275_ptr2cell(previous); /* Arg2: addr of prev name */
+ ci[5] = p1275_ptr2cell(next); /* Arg3: addr of 32 byte buf */
+
+ promif_preprom();
+ (void) p1275_cif_handler(&ci);
+ promif_postprom();
+
+ return (next);
+}
+
+int
+prom_setprop(dnode_t nodeid, caddr_t name, caddr_t value, int len)
+{
+ cell_t ci[8];
+#ifdef PROM_32BIT_ADDRS
+ caddr_t ovalue = NULL;
+
+ if ((uintptr_t)value > (uint32_t)-1) {
+ ovalue = value;
+ value = promplat_alloc(len);
+ if (value == NULL) {
+ return (-1);
+ }
+ promplat_bcopy(ovalue, value, len);
+ }
+#endif
+
+ prom_setprop_enter();
+
+ promif_preprom();
+
+ ci[0] = p1275_ptr2cell("setprop"); /* Service name */
+ ci[1] = (cell_t)4; /* #argument cells */
+ ci[2] = (cell_t)1; /* #result cells */
+ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: phandle */
+ ci[4] = p1275_ptr2cell(name); /* Arg2: property name */
+ ci[5] = p1275_ptr2cell(value); /* Arg3: New value ptr */
+ ci[6] = p1275_int2cell(len); /* Arg4: New value len */
+ ci[7] = (cell_t)-1; /* Res1: Prime result */
+
+ (void) p1275_cif_handler(&ci);
+
+ promif_postprom();
+
+ prom_setprop_exit();
+
+#ifdef PROM_32BIT_ADDRS
+ if (ovalue != NULL)
+ promplat_free(value, len);
+#endif
+
+ return (p1275_cell2int(ci[7])); /* Res1: Actual new size */
+}
+
+/*
+ * prom_decode_composite_string:
+ *
+ * Returns successive strings in a composite string property.
+ * A composite string property is a buffer containing one or more
+ * NULL terminated strings contained within the length of the buffer.
+ *
+ * Always call with the base address and length of the property buffer.
+ * On the first call, call with prev == 0, call successively
+ * with prev == to the last value returned from this function
+ * until the routine returns zero which means no more string values.
+ */
+char *
+prom_decode_composite_string(void *buf, size_t buflen, char *prev)
+{
+ if ((buf == 0) || (buflen == 0) || ((int)buflen == -1))
+ return ((char *)0);
+
+ if (prev == 0)
+ return ((char *)buf);
+
+ prev += prom_strlen(prev) + 1;
+ if (prev >= ((char *)buf + buflen))
+ return ((char *)0);
+ return (prev);
+}