I have revised tipru(4) according to advice given in this thread: On Mon, Jul 4, 2016 at 10:30 PM, Jonathan Gray <[email protected]> wrote: > There aren't any suser checks either.
On Tue, Jul 5, 2016 at 12:56 AM, Jonathan Gray <[email protected]> wrote: > Perhaps it could only permit access at a particular securelevel > like gpio or be disabled by default. On Tue, Jul 5, 2016 at 4:18 AM, Damien Miller <[email protected]> wrote: > +1 for doing something like gpio, e.g. an ioctl or sysctl to enable it > that can only be set at kern.securelevel=0 I've implemented a securelevel(7)-based safeguard system and superuser checks, summarized by new manpage section replicated below: SECURITY CONSIDERATIONS The PRU has comprehensive and unconditional access to all physical memory present in the system. Accordingly, tipru implements a number of additional safeguards to prevent exploitation, listed below: * tipru will only grant file descriptors, honor write(2) attempts, and process ioctl(2) calls from real root (ruid 0) regardless of the device file's permission bits, user login class, or current securelevel(7). * tipru comes disabled by default. Attempts to enable tipru, and following modification of the instruction/data/shared memory spaces, are only allowed when the system's securelevel(7) is equal or lesser than zero. When the system's securelevel(7) is greater than zero the PRU cores may only be started or halted via the PRUCTL ioctl(2) call, and the driver itself may be disabled via the PRUKILL ioctl(2) call which effectively halts and prevents the PRU from performing any actions until the system is rebooted. tipru(4) manpage has been heavily revised to cover these new safeguards and define their functionality very explicitly. For convenience, I've uploaded the new revision here: http://ce.gl/tipru.4-rev2.html The patch below contains my rough implementation of these new safeguards. It compiles, is complete, but untested as of yet. I'm only including it to provide a sense of continuity between revisions, I would like to know whether these new safeguards are the right approach before I finalize and test the code. Don't bother going over it with a fine-toothed comb just yet. mainbus -> fdt is next. Index: etc/etc.armv7/MAKEDEV.md =================================================================== RCS file: /cvs/src/etc/etc.armv7/MAKEDEV.md,v retrieving revision 1.12 diff -u -p -r1.12 MAKEDEV.md --- etc/etc.armv7/MAKEDEV.md 21 May 2016 21:30:22 -0000 1.12 +++ etc/etc.armv7/MAKEDEV.md 6 Jul 2016 07:44:53 -0000 @@ -27,6 +27,8 @@ dnl ADVISED OF THE POSSIBILITY OF SUCH D dnl dnl __devitem(apm, apm, Power management device)dnl +__devitem(tipru, tipru, Programmable realtime unit)dnl +_mkdev(tipru, tipru*, {-M tipru c major_tipru_c 0 200-})dnl _TITLE(make) _DEV(all) _DEV(ramdisk) @@ -64,6 +66,7 @@ _DEV(ulpt, 66) _DEV(usb, 64) _TITLE(spec) _DEV(apm, 34) +_DEV(tipru, 29) _DEV(au, 36) _DEV(bio, 52) _DEV(bktr, 75) @@ -114,3 +117,4 @@ target(all, cd, 0, 1)dnl target(all, sd, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)dnl target(all, vnd, 0, 1, 2, 3)dnl target(all, gpio, 0, 1, 2, 3, 4, 5, 6, 7, 8)dnl +target(all, tipru, 0)dnl Index: share/man/man4/man4.armv7/tipru.4 =================================================================== RCS file: share/man/man4/man4.armv7/tipru.4 diff -N share/man/man4/man4.armv7/tipru.4 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man4/man4.armv7/tipru.4 6 Jul 2016 07:45:07 -0000 @@ -0,0 +1,221 @@ +.\" Copyright (c) 2016 Ian Sutton <[email protected]> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 11 2016 $ +.Dt TIPRU 4 armv7 +.Os +.Sh NAME +.Nm tipru +.Nd Texas Instruments programmable realtime unit controller +.Sh SYNOPSIS +.Nm "tipru* at omap0" +.Sh DESCRIPTION +The +.Nm +driver supports the Programmable Realtime Unit and Industrial Communication +Subsystem (PRU-ICSS) integrated in Texas Instruments' line of AM335x SoCs. The +PRU is a pair of 32-bit modified Harvard architecture processor cores which run +a simple RISC instruction set. The PRU forgoes any kind of heuristic caching +mechanisms (TLBs, L1/L2/etc caches) as well as instruction pipelining as to +allow for completely predictable and deterministic timing behavior. The PRU is +clocked at 200MHz and executes one instruction every cycle insofar as it +operates within its local data/instruction/shared memory spaces (See +.Sx CAVEATS +for additional details.) +.Pp +.Nm Ap +s primary interface is through its write-only character device file. Writes to +this file populate the PRU's data/instruction/shared memory and must occur at +predefined offsets. Further +.Xr ioctl 2 +calls control the PRU's execution. All +.Xr write 2 +operations and some +.Xr ioctl 2 +operations must occur when the system's +.Xr securelevel 7 +is equal to or lesser than zero, and only after +.Nm +has been explicitly enabled via +.Xr ioctl 2 +call listed in the following section. (See +.Sx SECURITY CONSIDERATIONS +for additional details.) +.Sh IOCTLS +The following +.Xr ioctl 2 +commands are supported, and allowed only when system +.Xr securelevel 7 +is lesser than or equal to zero: +.Bl -tag -width Ds -offset XXX +.It Dv PRUEN +Enables the +.Nm +driver itself. All the following +.Xr ioctl 2 +calls in this section, along with all +.Xr open 2 +and +.Xr write 2 +operations attempted on +.Nm Ap s +character device file will fail if they are attempted before a successful call +to this +.Xr ioctl 2 Ns . +.It Dv PRUIRQEN Fa "int *" +Not yet implemented. +.It Dv PRURESET +Halts all PRU cores, zeroes all data/instruction/shared memory, and resets +cores' program counters. +.El +.Pp +The following +.Xr ioctl 2 +commands are supported, and allowed only when system +.Xr securelevel 7 +is greater than zero: +.Bl -tag -width Ds -offset XXX +.It Dv PRUIRQBLOCK Fa "int *" +Not yet implemented. +.It Dv PRUKILL +Halts and resets PRU cores, and zeroes all data/instruction/shared memory +spaces. No further PRU activity occurs (or is even possible) after this +.Xr ioctl 2 +call is made until the system is rebooted. +.El +.Pp +The following +.Xr ioctl 2 +commands are supported, and allowed regardless of system +.Xr securelevel 7 Ns : +.Bl -tag -width Ds -offset XXX +.It Dv PRUCTL Fa "int *" +Start/halt PRU cores. Setting a core's *_SEL bit will change its execution state +to whatever the corresponding *_EN bit specifies. +.El +.Sh FILES +.Bl -tag -width XXXXXXXXXXXXXXX -compact +.It Pa /dev/tipru +Character device for accessing PRU instruction/data space and +controlling chip. +.El +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ENODEV +Character device was opened with mode other than +.Dv O_WRONLY +or a +.Xr read 2 +call was attempted. +.It Bq Er EBUSY +Another process already has an open file descriptor on the character device file. +.It Bq Er ENOTSUPP +Driver received an unsupported +.Xr ioctl 2 +call. +.It Bq Er ENOSYS +Driver received an unimplemented +.Xr ioctl 2 +call. +.It Bq Er EFAULT +.Xr write 2 +attempted at offset not corresponding to top of PRU's data/instruction/shared memory. +.It Bq Er EOVERFLOW +.Xr write 2 +attempted that would overflow targeted memory space. +.It Bq Er EPERM +.Xr write 2 Ns , +.Xr open 2 Ns , +or +.Xr ioctl 2 +call attempted by user other than root, or attempted when the system was in an +improper +.Xr securelevel 7 +for the attempted call. +.It Bq Er ECANCELED +Operation attempted after +.Nm +driver was disabled via +.Dv PRUKILL +.Xr ioctl 2 +call or attempted before a +.Dv PRUEN +.Xr ioctl 2 +call completed successfully. +.El +.Sh SEE ALSO +.Xr pructl 1 , +.Xr intro 4 , +.Xr securelevel 7 +.Sh HISTORY +The +.Nm +driver will hopefully soon appear in +.Ox 6.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Ian Sutton Aq Mt [email protected] . +.Sh CAVEATS +While the PRU has its own data/instruction/shared memory, it is capable of +accessing all physical addresses on the system (even its own control registers). +Disabling the OCP ports (the mechanism through which the PRU accesses outside +memory) provides no extra security as the PRU itself can arbitrarily enable it +(See +.Sx BUGS +for additional details.) +.Pp +The PRU's runtime characteristics are only deterministic insofar as it accesses +memory within its own local address space. All timing guarantees are forfeit +once non-local memory is accessed. +.Sh BUGS +If the PRU attempts to access memory outside its own local address space, the +system will hang unless the OCP master ports are enabled via the SYSCFG +register. This is due to a silicon bug wholly irrectifiable by software (See +AM335x Technical Reference Manual for additional details.) +.Sh SECURITY CONSIDERATIONS +The PRU has comprehensive and unconditional access to all physical memory +present in the system. Accordingly, +.Nm +implements a number of additional safeguards to prevent exploitation, listed below: +.Bl -bullet -width left +.It +.Nm +will only grant file descriptors, honor +.Xr write 2 +attempts, and process +.Xr ioctl 2 +calls from real root (ruid 0) regardless of the device file's permission bits, +user login class, or current +.Xr securelevel 7 Ns . +.It +.Nm +comes disabled by default. Attempts to enable +.Nm Ns , +and following modification of the instruction/data/shared memory spaces, are only +allowed when the system's +.Xr securelevel 7 +is equal or lesser than zero. When the system's +.Xr securelevel 7 +is greater than zero the PRU cores may only be started or halted via the +.Dv PRUCTL +.Xr ioctl 2 +call, and the driver itself may be disabled via the +.Dv PRUKILL +.Xr ioctl 2 +call which effectively halts and prevents the PRU from performing any actions +until the system is rebooted. +.El Index: share/man/man8/man8.armv7/MAKEDEV.8 =================================================================== RCS file: /cvs/src/share/man/man8/man8.armv7/MAKEDEV.8,v retrieving revision 1.12 diff -u -p -r1.12 MAKEDEV.8 --- share/man/man8/man8.armv7/MAKEDEV.8 28 Apr 2016 18:17:31 -0000 1.12 +++ share/man/man8/man8.armv7/MAKEDEV.8 6 Jul 2016 07:45:07 -0000 @@ -1,10 +1,10 @@ -.\" $OpenBSD: MAKEDEV.8,v 1.12 2016/04/28 18:17:31 natano Exp $ +.\" $OpenBSD$ .\" .\" THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. .\" generated from: .\" -.\" OpenBSD: etc.armv7/MAKEDEV.md,v 1.10 2016/04/25 20:38:10 tedu Exp -.\" OpenBSD: MAKEDEV.common,v 1.86 2016/04/25 20:39:42 tedu Exp +.\" OpenBSD: etc.armv7/MAKEDEV.md,v 1.12 2016/05/21 21:30:22 kettenis Exp +.\" OpenBSD: MAKEDEV.common,v 1.89 2016/05/26 16:29:51 deraadt Exp .\" OpenBSD: MAKEDEV.man,v 1.8 2016/03/12 17:59:27 espie Exp .\" OpenBSD: MAKEDEV.mansub,v 1.2 2004/02/20 19:13:01 miod Exp .\" @@ -23,7 +23,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 28 2016 $ +.Dd $Mdocdate: March 12 2016 $ .Dt MAKEDEV 8 armv7 .Os .Sh NAME @@ -170,6 +170,9 @@ Bus control devices used by usbd for att .It Ar apm Power management device, see .Xr apm 4 . +.It Ar tipru +Programmable realtime unit, see +.Xr tipru 4 . .It Ar audio* Audio devices, see .Xr audio 4 . Index: sys/arch/arm/arm/conf.c =================================================================== RCS file: /cvs/src/sys/arch/arm/arm/conf.c,v retrieving revision 1.46 diff -u -p -r1.46 conf.c --- sys/arch/arm/arm/conf.c 23 May 2016 00:05:34 -0000 1.46 +++ sys/arch/arm/arm/conf.c 6 Jul 2016 07:45:07 -0000 @@ -145,6 +145,8 @@ cdev_decl(radio); #include <arm/conf.h> +cdev_decl(tipru); + /* Block devices */ struct bdevsw bdevsw[] = { @@ -301,7 +303,7 @@ struct cdevsw cdevsw[] = { cdev_disk_init(NCD,cd), /* 26: SCSI CD-ROM */ cdev_ch_init(NCH,ch), /* 27: SCSI autochanger */ cdev_uk_init(NUK,uk), /* 28: SCSI unknown */ - cdev_notdef(), /* 29: */ + cdev_disk_init(1, tipru), /* 29: Realtime processor */ cdev_notdef(), /* 30: */ cdev_notdef(), /* 31: */ cdev_notdef(), /* 32: */ Index: sys/arch/armv7/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v retrieving revision 1.27 diff -u -p -r1.27 GENERIC --- sys/arch/armv7/conf/GENERIC 28 Jun 2016 04:41:37 -0000 1.27 +++ sys/arch/armv7/conf/GENERIC 6 Jul 2016 07:45:07 -0000 @@ -76,6 +76,7 @@ cpsw* at fdt? com* at fdt? # onboard uarts ommmc* at fdt? # SD/MMC card controller sdmmc* at ommmc? # SD/MMC bus +tipru* at omap? # PRU-ICSS ehci* at omap? # EHCI (shim) usb* at ehci? Index: sys/arch/armv7/conf/RAMDISK =================================================================== RCS file: /cvs/src/sys/arch/armv7/conf/RAMDISK,v retrieving revision 1.24 diff -u -p -r1.24 RAMDISK --- sys/arch/armv7/conf/RAMDISK 28 Jun 2016 04:41:37 -0000 1.24 +++ sys/arch/armv7/conf/RAMDISK 6 Jul 2016 07:45:07 -0000 @@ -75,6 +75,7 @@ cpsw* at fdt? com* at fdt? # onboard uarts ommmc* at fdt? # SD/MMC card controller sdmmc* at ommmc? # SD/MMC bus +tipru* at omap? # Realtime processor ehci* at omap? # EHCI (shim) usb* at ehci? Index: sys/arch/armv7/omap/am335x.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/am335x.c,v retrieving revision 1.7 diff -u -p -r1.7 am335x.c --- sys/arch/armv7/omap/am335x.c 18 Mar 2014 07:34:17 -0000 1.7 +++ sys/arch/armv7/omap/am335x.c 6 Jul 2016 07:45:07 -0000 @@ -105,6 +105,17 @@ #define IIC1_IRQ 71 #define IIC2_IRQ 30 +#define PRU_SIZE 0x80000 +#define PRU_ADDR 0x4A300000 +#define PRU_IRQ0 20 +#define PRU_IRQ1 21 +#define PRU_IRQ2 22 +#define PRU_IRQ3 23 +#define PRU_IRQ4 24 +#define PRU_IRQ5 25 +#define PRU_IRQ6 26 +#define PRU_IRQ7 27 + struct armv7_dev am335x_devs[] = { /* @@ -166,6 +177,16 @@ struct armv7_dev am335x_devs[] = { { .name = "omdog", .unit = 0, .mem = { { WD_ADDR, WD_SIZE } } + }, + + /* + * PRU + */ + + { .name = "tipru", + .unit = 0, + .mem = { { PRU_ADDR, PRU_SIZE } }, + .irq = { PRU_IRQ0 } }, /* Index: sys/arch/armv7/omap/am335x_prcmreg.h =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/am335x_prcmreg.h,v retrieving revision 1.4 diff -u -p -r1.4 am335x_prcmreg.h --- sys/arch/armv7/omap/am335x_prcmreg.h 18 Mar 2014 07:34:17 -0000 1.4 +++ sys/arch/armv7/omap/am335x_prcmreg.h 6 Jul 2016 07:45:07 -0000 @@ -31,6 +31,7 @@ #define PRCM_AM335X_GPIO2_CLKCTRL 0x00b0 #define PRCM_AM335X_GPIO3_CLKCTRL 0x00b4 #define PRCM_AM335X_TPCC_CLKCTRL 0x00bc +#define PRCM_AM335X_PRU_ICSS_CLKCTRL 0x00e8 #define PRCM_AM335X_MMC1_CLKCTRL 0x00f4 #define PRCM_AM335X_MMC2_CLKCTRL 0x00f8 #define PRCM_AM335X_TPTC1_CLKCTRL 0x00fc Index: sys/arch/armv7/omap/files.omap =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/files.omap,v retrieving revision 1.13 diff -u -p -r1.13 files.omap --- sys/arch/armv7/omap/files.omap 26 Jun 2016 09:06:35 -0000 1.13 +++ sys/arch/armv7/omap/files.omap 6 Jul 2016 07:45:07 -0000 @@ -26,6 +26,10 @@ attach sitaracm at omap file arch/armv7/omap/am335x_cm_padconf.c sitaracm file arch/armv7/omap/sitara_cm.c sitaracm +device tipru +attach tipru at omap +file arch/armv7/omap/tipru.c tipru + device omgpio: gpiobus attach omgpio at omap file arch/armv7/omap/omgpio.c omgpio Index: sys/arch/armv7/omap/omap.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/omap.c,v retrieving revision 1.15 diff -u -p -r1.15 omap.c --- sys/arch/armv7/omap/omap.c 26 Jun 2016 09:06:35 -0000 1.15 +++ sys/arch/armv7/omap/omap.c 6 Jul 2016 07:45:07 -0000 @@ -57,6 +57,7 @@ struct board_dev beaglebone_devs[] = { { "edma", 0 }, { "dmtimer", 0 }, { "dmtimer", 1 }, + { "tipru", 0 }, { "omgpio", 0 }, { "omgpio", 1 }, { "omgpio", 2 }, Index: sys/arch/armv7/omap/prcm.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/prcm.c,v retrieving revision 1.9 diff -u -p -r1.9 prcm.c --- sys/arch/armv7/omap/prcm.c 8 May 2014 21:17:01 -0000 1.9 +++ sys/arch/armv7/omap/prcm.c 6 Jul 2016 07:45:07 -0000 @@ -325,6 +325,8 @@ prcm_am335x_clkctrl(int mod) return PRCM_AM335X_I2C1_CLKCTRL; case PRCM_I2C2: return PRCM_AM335X_I2C2_CLKCTRL; + case PRCM_PRU_ICSS: + return PRCM_AM335X_PRU_ICSS_CLKCTRL; default: panic("%s: module not found\n", __func__); } @@ -353,6 +355,11 @@ prcm_am335x_enablemodule(struct prcm_sof clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK; clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE; bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl); + + /* PRU has its own special reset register */ + if(reg == PRCM_AM335X_PRU_ICSS_CLKCTRL) { + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_PRM_PER, 0); + } /* wait until module is enabled */ while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000) Index: sys/arch/armv7/omap/prcmvar.h =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/prcmvar.h,v retrieving revision 1.5 diff -u -p -r1.5 prcmvar.h --- sys/arch/armv7/omap/prcmvar.h 18 Mar 2014 07:34:17 -0000 1.5 +++ sys/arch/armv7/omap/prcmvar.h 6 Jul 2016 07:45:07 -0000 @@ -51,6 +51,7 @@ enum PRCM_MODULES { PRCM_I2C0, PRCM_I2C1, PRCM_I2C2, + PRCM_PRU_ICSS, }; #define PRCM_REG_MAX 6 Index: sys/arch/armv7/omap/tipru.c =================================================================== RCS file: sys/arch/armv7/omap/tipru.c diff -N sys/arch/armv7/omap/tipru.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/tipru.c 6 Jul 2016 07:45:07 -0000 @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2016 Ian Sutton <[email protected]> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/malloc.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> + +#include <machine/bus.h> + +#include <armv7/armv7/armv7var.h> +#include <armv7/omap/prcmvar.h> + +#include <sys/fcntl.h> +#include <sys/stat.h> + +#include "tipru.h" + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) + +#define DEVNAME(sc) (sc)->sc_dev.dv_xname +#define DEVUNIT(x) (minor(x) & 0x7f) + +struct tipru_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +#define PRU_RUN 0x1 +#define PRU_OCP 0x2 +#define PRU_STEP 0x4 +#define PRU_SLEEP 0x8 + uint8_t sc_hwflags; +#define PRU_XCLUDE 0x1 +#define PRU_ENABLED 0x2 +#define PRU_KILLED 0x4 + uint8_t sc_swflags; +}; + +void tipru_attach(struct device *, struct device *, void *); +void tipru_ctl(struct tipru_softc *, int); +/*int tipru_intr(void *); */ +int tipru_seclevel(struct tipru_softc *); +void tipru_reset(struct tipru_softc *); + +struct cfattach tipru_ca = { + sizeof(struct tipru_softc), NULL, tipru_attach +}; + +struct cfdriver tipru_cd = { + NULL, "tipru", DV_DULL +}; + +void +tipru_attach(struct device *parent, struct device *self, void *args) +{ + struct tipru_softc *sc = (struct tipru_softc *) self; + struct armv7_attach_args *aa = args; + uint32_t rev; + + sc->sc_iot = aa->aa_iot; + if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, + aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + prcm_enablemodule(PRCM_PRU_ICSS); + + rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PRUx_CFG + PRUx_CFG_REVID); + printf(" revid 0x%08x\n", rev); + + HSET4(sc, PRUx_CFG + PRUx_CFG_SYSCFG, PRUx_CFG_SYSCFG_STANDBY_INIT); + while(HREAD4(sc, PRUx_CFG + PRUx_CFG_SYSCFG_SUB_MWAIT)); +} + +int +tipruopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct tipru_softc *sc; + int unit; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + + if(p->p_ucred->cr_ruid || p->p_ucred->cr_uid) + return EPERM; + + if(ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + sc = tipru_cd.cd_devs[unit]; + + if(ISSET(flag, O_WRONLY)) + return ENODEV; + else if(ISSET(sc->sc_swflags, PRU_XCLUDE)) + return EBUSY; + + sc->sc_swflags |= PRU_XCLUDE; + + return 0; +} + +int +tipruclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct tipru_softc *sc; + int unit; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + + sc = tipru_cd.cd_devs[unit]; + + if(ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + sc->sc_swflags &= (sc->sc_swflags & ~PRU_XCLUDE); + return 0; +} + +int +tipruioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct tipru_softc *sc; + int unit, securelevel; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + + if(p->p_ucred->cr_ruid || p->p_ucred->cr_uid) + return EPERM; + + sc = tipru_cd.cd_devs[unit]; + securelevel = tipru_seclevel(sc); + + if (ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + if (cmd == PRUEN) { + if(securelevel > 0) + return ECANCELED; + sc->sc_swflags |= PRU_ENABLED; + return 0; + } else if (!ISSET(sc->sc_swflags, PRU_ENABLED)) + return ECANCELED; + + switch(cmd) { + /* Begin seclevel 0 ioctls */ + case PRUIRQEN: + if(securelevel > 0) + return EPERM; + return ENOSYS; + break; + case PRURESET: /* XXX maybe we allow this in any securelevel */ + if(securelevel > 0) + return EPERM; + tipru_reset(sc); + break; + /* End prior, begin seclevel 1 ioctls */ + case PRUIRQBLOCK: + if(securelevel < 1) + return EPERM; + return ENOSYS; + break; + case PRUKILL: + if(securelevel < 1) + return EPERM; + tipru_reset(sc); + sc->sc_swflags |= PRU_KILLED; + sc->sc_swflags &= ~PRU_ENABLED; + /* End prior, begin seclevel-agnostic ioctls */ + case PRUCTL: + tipru_ctl(sc, (int)*data); + break; + default: + return EOPNOTSUPP; + } + + return 0; +} + +int +tipruread(dev_t dev, struct uio *uio, int flags) +{ + return ENODEV; +} + +int +tipruwrite(dev_t dev, struct uio *uio, int flags) +{ + struct tipru_softc *sc; + int unit, lim, securelevel, i, j; + uint32_t *wbuf; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + + sc = tipru_cd.cd_devs[unit]; + securelevel = tipru_seclevel(sc); + + if(uio->uio_procp->p_ucred->cr_ruid || uio->uio_procp->p_ucred->cr_uid + || securelevel > 0) + return EPERM; + + if(!ISSET(sc->sc_swflags, PRU_ENABLED) || ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + switch(uio->uio_offset) { + case PRU0_DRAM: + case PRU1_DRAM: + case PRU0_IRAM: + case PRU1_IRAM: + /* FALLTHROUGH */ + lim = PRU_RAM_SIZE; + break; + case PRUx_SHRRAM: + lim = PRU_SHR_SIZE; + break; + default: + return EFAULT; + } + + for(i = 0; i < uio->uio_iovcnt; i++) { + if(uio->uio_iov[i].iov_len > lim) + return EOVERFLOW; + + for(j = 0; j < uio->uio_iov[i].iov_len / 4; j++) { + wbuf = uio->uio_iov[i].iov_base + 4 * j; + HWRITE4(sc, uio->uio_offset + j * 4, *wbuf); + } + } + + return 0; +} + +/* XXX clear intrs. here when irqs implemented. pending intrs. prevent hw halt */ +void +tipru_ctl(struct tipru_softc *sc, int target_runstate) +{ + if(target_runstate & PRUCTL_PRU0_SEL && target_runstate & PRUCTL_PRU0_EN) { + HSET4(sc, PRU0_CTRL, PRUx_CTRL_EN); + while(!ISSET(HREAD4(sc, PRU0_CTRL) , PRUx_CTRL_RUNSTATE)); + } else if(target_runstate & PRUCTL_PRU0_SEL) { + HCLR4(sc, PRU0_CTRL, PRUx_CTRL_EN); + while(ISSET(HREAD4(sc, PRU0_CTRL) , PRUx_CTRL_RUNSTATE)); + } + + if(target_runstate & PRUCTL_PRU1_SEL && target_runstate & PRUCTL_PRU1_EN) { + HSET4(sc, PRU1_CTRL, PRUx_CTRL_EN); + while(!ISSET(HREAD4(sc, PRU1_CTRL) , PRUx_CTRL_RUNSTATE)); + } else if(target_runstate & PRUCTL_PRU1_SEL) { + HCLR4(sc, PRU1_CTRL, PRUx_CTRL_EN); + while(ISSET(HREAD4(sc, PRU1_CTRL) , PRUx_CTRL_RUNSTATE)); + } +} + +int +tipru_seclevel(struct tipru_softc *sc) +{ + int mib[2], securelevel; + size_t len; + + mib[0] = CTL_KERN; + mib[1] = KERN_SECURELVL; + len = sizeof(securelevel); + + securelevel = 2; + if (sysctl_int(&securelevel, &len, NULL, 0, mib) == -1) { + printf("%s: sysctl failed, assuming highest securitylevel\n", DEVNAME(sc)); + /* XXX figure out if this sysctl could ever fail, fix this */ + panic("tipru: failed to determine securelevel via sysctl(3)\n"); + } + + return securelevel; + +} + +void +tipru_reset(struct tipru_softc *sc) +{ + int i; + + tipru_ctl(sc, 0x0); + HCLR4(sc, PRU0_CTRL, PRUx_CTRL_PCTR_RST_VAL_MASK); + HCLR4(sc, PRU1_CTRL, PRUx_CTRL_PCTR_RST_VAL_MASK); + + for(i = 0; i < 2048; i++) { + HWRITE4(sc, PRU0_DRAM + i*4, 0x0); + HWRITE4(sc, PRU1_DRAM + i*4, 0x0); + HWRITE4(sc, PRU0_IRAM + i*4, 0x0); + HWRITE4(sc, PRU1_IRAM + i*4, 0x0); + } + + for(i = 0; i < 3072; i++) + HWRITE4(sc, PRUx_SHRRAM + i*4, 0x0); +} Index: sys/arch/armv7/omap/tipru.h =================================================================== RCS file: sys/arch/armv7/omap/tipru.h diff -N sys/arch/armv7/omap/tipru.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/tipru.h 6 Jul 2016 07:45:07 -0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 Ian Sutton <[email protected]> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +/* RAM segments, global context */ +#define PRU0_DRAM 0x00000 +#define PRU1_DRAM 0x02000 +#define PRUx_SHRRAM 0x10000 +#define PRU0_IRAM 0x34000 +#define PRU1_IRAM 0x38000 + +#define PRU_RAM_SIZE 0x02000 +#define PRU_SHR_SIZE 0x03000 + +/* register groups, global context */ +#define PRUx_INTC 0x20000 +#define PRU0_CTRL 0x22000 +#define PRU1_CTRL 0x24000 +#define PRU0_DBG 0x22400 +#define PRU1_DBG 0x24400 +#define PRUx_CFG 0x26000 +#define PRUx_UART 0x28000 +#define PRUx_IEP 0x2e000 +#define PRUx_ECAP 0x30000 + +/* control registers */ +#define PRUx_CTRL_PCTR_RST_VAL_SHAMT 16 +#define PRUx_CTRL_PCTR_RST_VAL_MASK (16 << PRUx_CTRL_PCTR_RST_VAL_SHAMT) +#define PRUx_CTRL_RUNSTATE (1 << 15) +#define PRUx_CTRL_SINGLE_STEP (1 << 8) +#define PRUx_CTRL_CTR_EN (1 << 3) +#define PRUx_CTRL_SLEEPING (1 << 2) +#define PRUx_CTRL_EN (1 << 1) +#define PRUx_CTRL_SOFT_RST_N (1 << 0) + +#define PRUx_CTRL_STS 0x04 +#define PRUx_CTRL_STS_PCTR_SHAMT 0 +#define PRUx_CTRL_SYS_PCTR_MASK (16 << PRUx_SYS_PCTR_SHAMT) + +#define PRUx_CTRL_WAKEUP_EN 0x08 +#define PRUx_CTRL_CYCLE_OFST 0x0C +#define PRUx_CTRL_STALL_OFST 0x10 + +/* intr. registers XXX */ + +/* configuration registers */ +#define PRUx_CFG_REVID 0x00 + +#define PRUx_CFG_SYSCFG 0x04 +#define PRUx_CFG_SYSCFG_SUB_MWAIT (1 << 5) +#define PRUx_CFG_SYSCFG_STANDBY_INIT (1 << 4) +#define PRUx_CFG_SYSCFG_STANDBY_MODE_SHAMT 2 +#define PRUx_CFG_SYSCFG_STANDBY_MODE_MASK (2 << PRUx_CFG_SYSCFG_STANDBY_MODE_SHAMT) +#define PRUx_CFG_SYSCFG_IDLE_MODE_SHAMT 0 +#define PRUx_CFG_SYSCFG_IDLE_MODE_MASK (2 << PRUx_CFG_SYSCFG_IDLE_MODE_SHAMT) + +#define PRUCTL_PRU0_SEL 0x1 +#define PRUCTL_PRU1_SEL 0x2 +#define PRUCTL_PRU0_EN 0x4 +#define PRUCTL_PRU1_EN 0x8 + +#define PRUCTL _IOW('P', 0, int) +#define PRUIRQEN _IOW('P', 1, int) +#define PRUIRQBLOCK _IOW('P', 2, int) +#define PRURESET _IO ('P', 3) +#define PRUEN _IO ('P', 4) +#define PRUKILL _IO ('P', 5)
