From 930f46e30b5f0497a57f3bc801aa702e68f08e5d Mon Sep 17 00:00:00 2001 From: tmm Date: Fri, 18 Oct 2002 15:23:43 +0000 Subject: Add a pseudo device which allows to access the OpenFirmware device tree via ioctl()s. This was ported from NetBSD and adapted a bit to better match our OpenFirmware support code. --- sys/dev/ofw/openfirmio.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++ sys/dev/ofw/openfirmio.h | 81 +++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 sys/dev/ofw/openfirmio.c create mode 100644 sys/dev/ofw/openfirmio.h (limited to 'sys/dev/ofw') diff --git a/sys/dev/ofw/openfirmio.c b/sys/dev/ofw/openfirmio.c new file mode 100644 index 0000000..6f40619 --- /dev/null +++ b/sys/dev/ofw/openfirmio.c @@ -0,0 +1,308 @@ +/* $NetBSD: openfirmio.c,v 1.4 2002/09/06 13:23:19 gehenna 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. 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, Berkeley and its contributors. + * 4. 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. + * + * @(#)openfirm.c 8.1 (Berkeley) 6/11/93 + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static dev_t openfirm_dev; + +static d_ioctl_t openfirm_ioctl; + +#define CDEV_MAJOR 177 +#define OPENFIRM_MINOR 0 + +static struct cdevsw openfirm_cdevsw = { + /* open */ nullopen, + /* close */ nullclose, + /* read */ noread, + /* write */ nowrite, + /* ioctl */ openfirm_ioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "openfirm", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, + /* kqfilter */ nokqfilter +}; + +static phandle_t lastnode; /* speed hack */ + +static int openfirm_checkid(phandle_t, phandle_t); +static int openfirm_getstr(int, const char *, char **); + +/* Maximum accepted name length. */ +#define OFW_NAME_MAX 8191 + +/* + * Verify target ID is valid (exists in the OPENPROM tree), as + * listed from node ID sid forward. + */ +static int +openfirm_checkid(phandle_t sid, phandle_t tid) +{ + + for (; sid != 0; sid = OF_peer(sid)) + if (sid == tid || openfirm_checkid(OF_child(sid), tid)) + return (1); + + return (0); +} + +static int +openfirm_getstr(int len, const char *user, char **cpp) +{ + int error; + char *cp; + + /* Reject obvious bogus requests */ + if ((u_int)len > OFW_NAME_MAX) + return (ENAMETOOLONG); + + *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK); + if (cp == NULL) + return (ENOMEM); + error = copyin(user, cp, len); + cp[len] = '\0'; + return (error); +} + +int +openfirm_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, + struct thread *td) +{ + struct ofiocdesc *of; + phandle_t node; + int len, ok, error; + char *name, *value; + char newname[32]; + + of = (struct ofiocdesc *)data; + switch (cmd) { + case OFIOCGETOPTNODE: + *(phandle_t *) data = OF_finddevice("/options"); + return (0); + case OFIOCGET: +#if 0 + case OFIOCSET: +#endif + case OFIOCNEXTPROP: + case OFIOCFINDDEVICE: + node = of->of_nodeid; + break; + case OFIOCGETNEXT: + case OFIOCGETCHILD: + node = *(phandle_t *)data; + break; + default: + return (ENOTTY); + } + + if (node != 0 && node != lastnode) { + /* Not an easy one, must search for it */ + ok = openfirm_checkid(OF_peer(0), node); + if (!ok) + return (EINVAL); + lastnode = node; + } + + name = value = NULL; + error = 0; + switch (cmd) { + + case OFIOCGET: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openfirm_getstr(of->of_namelen, of->of_name, &name); + if (error) + break; + len = OF_getproplen(node, name); + if (len > of->of_buflen) { + error = ENOMEM; + break; + } + of->of_buflen = len; + /* -1 means no entry; 0 means no value */ + if (len <= 0) + break; + value = malloc(len, M_TEMP, M_WAITOK); + if (value == NULL) { + error = ENOMEM; + break; + } + len = OF_getprop(node, name, (void *)value, len); + error = copyout(value, of->of_buf, len); + break; + +#if 0 + case OFIOCSET: + if ((flags & FWRITE) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openfirm_getstr(of->of_namelen, of->of_name, &name); + if (error) + break; + error = openfirm_getstr(of->of_buflen, of->of_buf, &value); + if (error) + break; + len = OF_setprop(node, name, value, of->of_buflen); + if (len != of->of_buflen) + error = EINVAL; + break; +#endif + + case OFIOCNEXTPROP: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0 || of->of_buflen < 0) + return (EINVAL); + if (of->of_namelen != 0) { + error = openfirm_getstr(of->of_namelen, of->of_name, + &name); + if (error) + break; + } + ok = OF_nextprop(node, name, newname); + if (ok == 0) { + error = ENOENT; + break; + } + if (ok == -1) { + error = EINVAL; + break; + } + len = strlen(newname) + 1; + if (len > of->of_buflen) + len = of->of_buflen; + else + of->of_buflen = len; + error = copyout(newname, of->of_buf, len); + break; + + case OFIOCGETNEXT: + if ((flags & FREAD) == 0) + return (EBADF); + node = OF_peer(node); + *(phandle_t *)data = lastnode = node; + break; + + case OFIOCGETCHILD: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + node = OF_child(node); + *(phandle_t *)data = lastnode = node; + break; + + case OFIOCFINDDEVICE: + if ((flags & FREAD) == 0) + return (EBADF); + error = openfirm_getstr(of->of_namelen, of->of_name, &name); + if (error) + break; + node = OF_finddevice(name); + if (node == 0 || node == -1) { + error = ENOENT; + break; + } + of->of_nodeid = lastnode = node; + break; + } + + if (name != NULL) + free(name, M_TEMP); + if (value != NULL) + free(value, M_TEMP); + + return (error); +} + +static int +openfirm_modevent(module_t mod, int type, void *data) +{ + switch(type) { + case MOD_LOAD: + if (bootverbose) + printf("openfirm: \n"); + /* + * Allow only root access by default; this device may allow + * users to peek into firmware passwords, and likely to crash + * the machine on some boxen due to firmware quirks. + */ + openfirm_dev = make_dev(&openfirm_cdevsw, OPENFIRM_MINOR, + UID_ROOT, GID_WHEEL, 0600, "openfirm"); + return 0; + + case MOD_UNLOAD: + destroy_dev(openfirm_dev); + return 0; + + case MOD_SHUTDOWN: + return 0; + + default: + return EOPNOTSUPP; + } +} + +DEV_MODULE(openfirm, openfirm_modevent, NULL); diff --git a/sys/dev/ofw/openfirmio.h b/sys/dev/ofw/openfirmio.h new file mode 100644 index 0000000..2a1a7c1 --- /dev/null +++ b/sys/dev/ofw/openfirmio.h @@ -0,0 +1,81 @@ +/* $NetBSD: openfirmio.h,v 1.4 2002/09/06 13:23:19 gehenna 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. 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, Berkeley and its contributors. + * 4. 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 + * + * $FreeBSD$ + */ + +#ifndef _DEV_OFW_OPENFIRMIO_H_ +#define _DEV_OFW_OPENFIRMIO_H_ + +#include + +struct ofiocdesc { + phandle_t of_nodeid; /* passed or returned node id */ + int of_namelen; /* length of op_name */ + const char *of_name; /* pointer to field name */ + int of_buflen; /* length of op_buf (value-result) */ + char *of_buf; /* pointer to field value */ +}; + +#define OFIOC_BASE 'O' + +/* Get openprom field. */ +#define OFIOCGET _IOWR(OFIOC_BASE, 1, struct ofiocdesc) +#if 0 +/* Set openprom field. */ +#define OFIOCSET _IOW(OFIOC_BASE, 2, struct ofiocdesc) +#endif +/* Get next property. */ +#define OFIOCNEXTPROP _IOWR(OFIOC_BASE, 3, struct ofiocdesc) +/* Get options node. */ +#define OFIOCGETOPTNODE _IOR(OFIOC_BASE, 4, phandle_t) +/* Get next node of node. */ +#define OFIOCGETNEXT _IOWR(OFIOC_BASE, 5, phandle_t) +/* Get first child of node. */ +#define OFIOCGETCHILD _IOWR(OFIOC_BASE, 6, phandle_t) +/* Find a specific device. */ +#define OFIOCFINDDEVICE _IOWR(OFIOC_BASE, 7, struct ofiocdesc) + +#endif /* _DEV_OFW_OPENFIRMIO_H_ */ -- cgit v1.1