diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-21 21:24:37 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-21 21:24:37 +0000 |
commit | 83c576b6d74a03b0e4b3f92fced981cedef35226 (patch) | |
tree | 151ad57cb005fad99f950e1712b0a9e2aafb9ea4 | |
parent | 95546d558b3af0d3eb898a9fba073d2be5583731 (diff) |
Implement openprom(4) for armv7.
ok deraadt@
-rw-r--r-- | sys/arch/arm/arm/conf.c | 4 | ||||
-rw-r--r-- | sys/arch/arm/arm/openprom.c | 263 | ||||
-rw-r--r-- | sys/arch/arm/include/conf.h | 11 | ||||
-rw-r--r-- | sys/arch/arm/include/openpromio.h | 57 | ||||
-rw-r--r-- | sys/arch/armv7/conf/files.armv7 | 3 | ||||
-rw-r--r-- | sys/arch/armv7/include/openpromio.h | 3 | ||||
-rw-r--r-- | sys/dev/ofw/fdt.c | 100 |
7 files changed, 433 insertions, 8 deletions
diff --git a/sys/arch/arm/arm/conf.c b/sys/arch/arm/arm/conf.c index a376e6c4429..343dcd6f9cc 100644 --- a/sys/arch/arm/arm/conf.c +++ b/sys/arch/arm/arm/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.44 2016/04/25 20:09:14 tedu Exp $ */ +/* $OpenBSD: conf.c,v 1.45 2016/05/21 21:24:36 kettenis Exp $ */ /* $NetBSD: conf.c,v 1.10 2002/04/19 01:04:38 wiz Exp $ */ /* @@ -353,7 +353,7 @@ struct cdevsw cdevsw[] = { cdev_notdef(), /* 79: removed device */ cdev_notdef(), /* 80: removed device */ cdev_notdef(), /* 81: removed device */ - cdev_notdef(), /* 82: removed device */ + cdev_openprom_init(1,openprom), /* 82: /dev/openprom */ cdev_notdef(), /* 83: removed device */ cdev_notdef(), /* 84: removed device */ cdev_notdef(), /* 85: removed device */ diff --git a/sys/arch/arm/arm/openprom.c b/sys/arch/arm/arm/openprom.c new file mode 100644 index 00000000000..db2793738e5 --- /dev/null +++ b/sys/arch/arm/arm/openprom.c @@ -0,0 +1,263 @@ +/* $OpenBSD: openprom.c,v 1.1 2016/05/21 21:24:36 kettenis Exp $ */ +/* $NetBSD: openprom.c,v 1.4 2002/01/10 06:21:53 briggs Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)openprom.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/conf.h> +#include <sys/device.h> + +#include <machine/openpromio.h> +#include <machine/conf.h> + +#include <dev/ofw/openfirm.h> + +#define OPROMMAXPARAM 32 + +static int lastnode; /* speed hack */ +static int optionsnode; /* node ID of ROM's options */ + +static int openpromcheckid(int, int); +static int openpromgetstr(int, char *, char **); + +int +openpromopen(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} + +int +openpromclose(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} + +/* + * Verify target ID is valid (exists in the OPENPROM tree), as + * listed from node ID sid forward. + */ +int +openpromcheckid(int sid, int tid) +{ + for (; sid != 0; sid = OF_peer(sid)) + if (sid == tid || openpromcheckid(OF_child(sid), tid)) + return (1); + + return (0); +} + +int +openpromgetstr(int len, char *user, char **cpp) +{ + int error; + char *cp; + + /* Reject obvious bogus requests */ + if ((u_int)len > (8 * 1024) - 1) + return (ENAMETOOLONG); + + *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK); + error = copyin(user, cp, len); + cp[len] = '\0'; + return (error); +} + +int +openpromioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) +{ + struct opiocdesc *op; + int node, len, ok, error, s; + char *name, *value, *nextprop; + static char buf[32]; /* XXX */ + + if (optionsnode == 0) { + s = splhigh(); + optionsnode = OF_getnodebyname(0, "options"); + splx(s); + } + + /* All too easy... */ + if (cmd == OPIOCGETOPTNODE) { + *(int *)data = optionsnode; + return (0); + } + + /* Verify node id */ + op = (struct opiocdesc *)data; + node = op->op_nodeid; + if (node != 0 && node != lastnode && node != optionsnode) { + /* Not an easy one, must search for it */ + s = splhigh(); + ok = openpromcheckid(OF_peer(0), node); + splx(s); + if (!ok) + return (EINVAL); + lastnode = node; + } + + name = value = NULL; + error = 0; + switch (cmd) { + + case OPIOCGET: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openpromgetstr(op->op_namelen, op->op_name, &name); + if (error) + break; + s = splhigh(); + strlcpy(buf, name, 32); /* XXX */ + len = OF_getproplen(node, buf); + splx(s); + if (len > op->op_buflen) { + error = ENOMEM; + break; + } + op->op_buflen = len; + /* -1 means no entry; 0 means no value */ + if (len <= 0) + break; + value = malloc(len, M_TEMP, M_WAITOK); + s = splhigh(); + strlcpy(buf, name, 32); /* XXX */ + OF_getprop(node, buf, value, len); + splx(s); + error = copyout(value, op->op_buf, len); + break; + +#if 0 + case OPIOCSET: + if ((flags & FWRITE) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openpromgetstr(op->op_namelen, op->op_name, &name); + if (error) + break; + error = openpromgetstr(op->op_buflen, op->op_buf, &value); + if (error) + break; + s = splhigh(); + strlcpy(buf, name, 32); /* XXX */ + len = OF_setprop(node, buf, value, op->op_buflen + 1); + splx(s); + if (len != op->op_buflen) + error = EINVAL; + break; +#endif + + case OPIOCNEXTPROP: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openpromgetstr(op->op_namelen, op->op_name, &name); + if (error) + break; + if (op->op_buflen <= 0) { + error = ENAMETOOLONG; + break; + } + value = nextprop = malloc(OPROMMAXPARAM, M_TEMP, + M_WAITOK | M_CANFAIL); + if (nextprop == NULL) { + error = ENOMEM; + break; + } + s = splhigh(); + strlcpy(buf, name, 32); /* XXX */ + error = OF_nextprop(node, buf, nextprop); + splx(s); + if (error == -1) { + error = EINVAL; + break; + } + if (error == 0) { + char nul = '\0'; + + op->op_buflen = 0; + error = copyout(&nul, op->op_buf, sizeof(char)); + break; + } + len = strlen(nextprop); + if (len > op->op_buflen) + len = op->op_buflen; + else + op->op_buflen = len; + error = copyout(nextprop, op->op_buf, len); + break; + + case OPIOCGETNEXT: + if ((flags & FREAD) == 0) + return (EBADF); + s = splhigh(); + node = OF_peer(node); + splx(s); + *(int *)data = lastnode = node; + break; + + case OPIOCGETCHILD: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + s = splhigh(); + node = OF_child(node); + splx(s); + *(int *)data = lastnode = node; + break; + + default: + return (ENOTTY); + } + + free(name, M_TEMP, 0); + free(value, M_TEMP, 0); + + return (error); +} diff --git a/sys/arch/arm/include/conf.h b/sys/arch/arm/include/conf.h index a0f49a5e616..8b12391c7ab 100644 --- a/sys/arch/arm/include/conf.h +++ b/sys/arch/arm/include/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.10 2011/07/04 16:52:41 nicm Exp $ */ +/* $OpenBSD: conf.h,v 1.11 2016/05/21 21:24:36 kettenis Exp $ */ /* $NetBSD: conf.h,v 1.7 2002/04/19 01:04:39 wiz Exp $ */ /* @@ -70,4 +70,13 @@ cdev_decl(pci); cdev_decl(apm); cdev_decl(spkr); +/* open, close, ioctl */ +#define cdev_openprom_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) nullop, 0, selfalse, \ + (dev_type_mmap((*))) enodev } + +cdev_decl(openprom); + #endif /* _ARM_CONF_H__ */ diff --git a/sys/arch/arm/include/openpromio.h b/sys/arch/arm/include/openpromio.h new file mode 100644 index 00000000000..8d934496505 --- /dev/null +++ b/sys/arch/arm/include/openpromio.h @@ -0,0 +1,57 @@ +/* $OpenBSD: openpromio.h,v 1.1 2016/05/21 21:24:36 kettenis Exp $ */ +/* $NetBSD: openpromio.h,v 1.1.1.1 1998/06/20 04:58:52 eeh Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)openpromio.h 8.1 (Berkeley) 6/11/93 + */ + +struct opiocdesc { + int op_nodeid; /* passed or returned node id */ + int op_namelen; /* length of op_name */ + char *op_name; /* pointer to field name */ + int op_buflen; /* length of op_buf (value-result) */ + char *op_buf; /* pointer to field value */ +}; + +#define OPIOCGET _IOWR('O', 1, struct opiocdesc) /* get openprom field */ +#define OPIOCSET _IOW('O', 2, struct opiocdesc) /* set openprom field */ +#define OPIOCNEXTPROP _IOWR('O', 3, struct opiocdesc) /* get next property */ +#define OPIOCGETOPTNODE _IOR('O', 4, int) /* get openprom field */ +#define OPIOCGETNEXT _IOWR('O', 5, int) /* get next node of node */ +#define OPIOCGETCHILD _IOWR('O', 6, int) /* get first child of node */ diff --git a/sys/arch/armv7/conf/files.armv7 b/sys/arch/armv7/conf/files.armv7 index 847fbcbf013..996f1357c99 100644 --- a/sys/arch/armv7/conf/files.armv7 +++ b/sys/arch/armv7/conf/files.armv7 @@ -1,4 +1,4 @@ -# $OpenBSD: files.armv7,v 1.17 2016/05/02 08:15:55 patrick Exp $ +# $OpenBSD: files.armv7,v 1.18 2016/05/21 21:24:36 kettenis Exp $ maxpartitions 16 maxusers 2 8 64 @@ -26,6 +26,7 @@ file arch/armv7/armv7/armv7_machdep.c file arch/armv7/armv7/autoconf.c file arch/armv7/armv7/platform.c file arch/arm/arm/disksubr.c disk +file arch/arm/arm/openprom.c include "dev/sdmmc/files.sdmmc" diff --git a/sys/arch/armv7/include/openpromio.h b/sys/arch/armv7/include/openpromio.h new file mode 100644 index 00000000000..b69d6f651cb --- /dev/null +++ b/sys/arch/armv7/include/openpromio.h @@ -0,0 +1,3 @@ +/* $OpenBSD: openpromio.h,v 1.1 2016/05/21 21:24:36 kettenis Exp $ */ + +#include <arm/openpromio.h> diff --git a/sys/dev/ofw/fdt.c b/sys/dev/ofw/fdt.c index 988cdbb8030..9844d80b408 100644 --- a/sys/dev/ofw/fdt.c +++ b/sys/dev/ofw/fdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fdt.c,v 1.9 2016/05/16 21:12:17 kettenis Exp $ */ +/* $OpenBSD: fdt.c,v 1.10 2016/05/21 21:24:36 kettenis Exp $ */ /* * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> @@ -17,7 +17,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> @@ -25,6 +24,9 @@ #include <dev/ofw/fdt.h> #include <dev/ofw/openfirm.h> +/* XXX */ +#define OPROMMAXPARAM 32 + unsigned int fdt_check_head(void *); char *fdt_get_str(u_int32_t); void *skip_property(u_int32_t *); @@ -252,6 +254,42 @@ fdt_next_node(void *node) return (ptr + 1); } +int +fdt_next_property(void *node, char *name, char **nextname) +{ + u_int32_t *ptr; + u_int32_t nameid; + + if (!tree_inited) + return 0; + + ptr = (u_int32_t *)node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return 0; + + ptr = skip_node_name(ptr + 1); + + while (betoh32(*ptr) == FDT_PROPERTY) { + nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ + if (strcmp(name, "") == 0) { + *nextname = fdt_get_str(nameid); + return 1; + } + if (strcmp(name, fdt_get_str(nameid)) == 0) { + ptr = skip_property(ptr); + if (betoh32(*ptr) != FDT_PROPERTY) + break; + nameid = betoh32(*(ptr + 2)); + *nextname = fdt_get_str(nameid); + return 1; + } + ptr = skip_property(ptr); + } + *nextname = ""; + return 1; +} + /* * Retrieves node property as integers and puts them in the given * integer array. @@ -664,12 +702,48 @@ OF_finddevice(char *name) } int +OF_getnodebyname(int handle, const char *name) +{ + void *node = (char *)tree.header + handle; + + if (handle == 0) + node = fdt_find_node("/"); + + while (node) { + if (strcmp(name, fdt_node_name(node)) == 0) + break; + + node = fdt_next_node(node); + } + + return node ? ((char *)node - (char *)tree.header) : 0; +} + +int OF_getproplen(int handle, char *prop) { void *node = (char *)tree.header + handle; - char *data; + char *data, *name; + int len; + + len = fdt_node_property(node, prop, &data); + + /* + * The "name" property is optional since version 16 of the + * flattened device tree specification, so we synthesize one + * from the unit name of the node if it is missing. + */ + if (len == 0 && strcmp(prop, "name") == 0) { + name = fdt_node_name(node); + data = strchr(name, '@'); + if (data) + len = data - name; + else + len = strlen(name); + return len + 1; + } - return fdt_node_property(node, prop, &data); + return len; } int @@ -703,6 +777,24 @@ OF_getprop(int handle, char *prop, void *buf, int buflen) } int +OF_nextprop(int handle, char *prop, void *nextprop) +{ + void *node = (char *)tree.header + handle; + char *data; + + if (fdt_node_property(node, "name", &data) == 0) { + if (strcmp(prop, "") == 0) + return strlcpy(nextprop, "name", OPROMMAXPARAM); + if (strcmp(prop, "name") == 0) + prop = ""; + } + + if (fdt_next_property(node, prop, &data)) + return strlcpy(nextprop, data, OPROMMAXPARAM); + return -1; +} + +int OF_is_compatible(int handle, const char *name) { void *node = (char *)tree.header + handle; |