diff options
102 files changed, 33017 insertions, 0 deletions
diff --git a/sys/arch/arc/Makefile b/sys/arch/arc/Makefile new file mode 100644 index 00000000000..d358d6b5abf --- /dev/null +++ b/sys/arch/arc/Makefile @@ -0,0 +1,28 @@ +# from: @(#)Makefile 8.1 (Berkeley) 6/16/93 +# $Id: Makefile,v 1.1 1996/06/24 09:07:17 pefo Exp $ + +# Makefile for pica links, tags file + +.include "../../kern/Make.tags.inc" + +all: + @echo "make links or tags only" + +DIRS= conf dev dist include pica + +links:: + -for i in ${DIRS}; do \ + (cd $$i && { rm -f tags; ln -s ${SYSTAGS} tags; }) done + +PICA= /sys/pica/dev/*.[ch] /sys/pica/include/*.[ch] \ + /sys/pica/pica/*.[ch] /sys/pica/ultrix/*.[ch] +APICA= /sys/pica/pica/*.s + +tags:: + -ctags -wdtif ${COMM} ${PICA} + egrep "^LEAF(.*)|^[AN]LEAF(.*)|^NON_LEAF(.*)" ${APICA} | \ + sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \ + >> tags + sort -o tags tags + +.include <bsd.prog.mk> diff --git a/sys/arch/arc/TODO b/sys/arch/arc/TODO new file mode 100644 index 00000000000..ce4530ec694 --- /dev/null +++ b/sys/arch/arc/TODO @@ -0,0 +1,27 @@ +To do list (not in any particular order). + + o Improve pmap_zero_page and pmap_copy_page. Speed and flushing. + + o Move the RO and WIRED attribute from the pte to the pv table. + This saves four instructions in the tlb miss handler. +InWork: Have a test version. The system hangs after a while. Not solved yet. + Also, is it worth the effort to remove 4 instr. in TLB-miss handler? + + o Boot. Standalone boot program instead of booting the kernel directly? + + o Create boot package for distribution. + + o sigsetjmp/siglongjmp missing.... + + o Add more videomodes to pccons driver. 50kHz and 64kHz monitors? +InWork: This seems to be hard. Need more info on the chip. + + o Find out why bitmap load to S3-928 flashes screen. +Know why (enable linear mode). Need S3 info. + + o Would be nice to have Motif... + + o Can we have 32 double registers? + + +Lots of other things..... diff --git a/sys/arch/arc/arc/arctype.h b/sys/arch/arc/arc/arctype.h new file mode 100644 index 00000000000..d309d3e5d48 --- /dev/null +++ b/sys/arch/arc/arc/arctype.h @@ -0,0 +1,46 @@ +/* $OpenBSD: arctype.h,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University, + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * from: @(#)arctype.h 8.1 (Berkeley) 6/10/93 + * $Id: arctype.h,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + +/* + * Mother board type byte of "systype" environment variable. + */ +#define ACER_PICA_61 0x1 /* Acer Labs Pica 61 */ +#define DESKSTATION 0x2 /* Deskstation xxx */ diff --git a/sys/arch/arc/arc/autoconf.c b/sys/arch/arc/arc/autoconf.c new file mode 100644 index 00000000000..2a90388362a --- /dev/null +++ b/sys/arch/arc/arc/autoconf.c @@ -0,0 +1,230 @@ +/* $OpenBSD: autoconf.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: autoconf.c 1.31 91/01/21 + * + * from: @(#)autoconf.c 8.1 (Berkeley) 6/10/93 + * $Id: autoconf.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ + */ + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/disklabel.h> +#include <sys/conf.h> +#include <sys/reboot.h> +#include <sys/device.h> + +#include <machine/autoconf.h> + +/* + * The following several variables are related to + * the configuration process, and are used in initializing + * the machine. + */ +int cold = 1; /* if 1, still working on cold-start */ +int cpuspeed = 150; /* approx # instr per usec. */ + +/* + * Configure all devices found that we know about. + * This is done at boot time. + */ +configure() +{ + (void)splhigh(); /* To be really shure.. */ + if(config_rootfound("mainbus", "mainbus") == 0) + panic("no mainbus found"); + (void)spl0(); + +#ifdef GENERIC + if ((boothowto & RB_ASKNAME) == 0) + setroot(); + setconf(); +#else + setroot(); +#endif + swapconf(); + cold = 0; +} + +/* + * Configure swap space and related parameters. + */ +swapconf() +{ + register struct swdevt *swp; + register int nblks; + + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (bdevsw[major(swp->sw_dev)].d_psize) { + nblks = + (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); + if (nblks != -1 && + (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) + swp->sw_nblks = nblks; + swp->sw_nblks = ctod(dtoc(swp->sw_nblks)); + } + } + dumpconf(); +} + +#define DOSWAP /* Change swdevt and dumpdev too */ +u_long bootdev; /* should be dev_t, but not until 32 bits */ + +static char devname[][2] = { + 's','d', /* 0 = sd */ + 'x','x', /* 1 = unused */ + 'x','x', /* 2 = unused */ + 'x','x', /* 3 = unused */ + 'x','x', /* 4 = unused */ + 'x','x', /* 5 = unused */ + 'x','x', /* 6 = unused */ + 'f','d', /* 7 = floppy */ +}; + +#define PARTITIONMASK 0x7 +#define PARTITIONSHIFT 3 + +/* + * Attempt to find the device from which we were booted. + * If we can do so, and not instructed not to do so, + * change rootdev to correspond to the load device. + */ +setroot() +{ + int majdev, mindev, unit, part, controller; + dev_t temp, orootdev; + struct swdevt *swp; + + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != B_DEVMAGIC) + return; + majdev = B_TYPE(bootdev); + if (majdev >= sizeof(devname) / sizeof(devname[0])) + return; + controller = B_CONTROLLER(bootdev); + part = B_PARTITION(bootdev); + unit = B_UNIT(bootdev); + + mindev = (unit << PARTITIONSHIFT) + part; + orootdev = rootdev; + rootdev = makedev(majdev, mindev); + /* + * If the original rootdev is the same as the one + * just calculated, don't need to adjust the swap configuration. + */ + if (rootdev == orootdev) + return; + + printf("changing root device to %c%c%d%c\n", + devname[majdev][0], devname[majdev][1], + unit, part + 'a'); + +#ifdef DOSWAP + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (majdev == major(swp->sw_dev) && + (mindev / MAXPARTITIONS) == (minor(swp->sw_dev) / MAXPARTITIONS)) { + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev == NODEV) + return; + + /* + * If dumpdev was the same as the old primary swap + * device, move it to the new primary swap device. + */ + if (temp == dumpdev) + dumpdev = swdevt[0].sw_dev; +#endif +} + +/* + * Look at the string 'cp' and decode the boot device. + * Boot names look like: scsi()disk(n)rdisk()partition(1)\bsd + */ +void +makebootdev(cp) + char *cp; +{ + int majdev, unit, part, ctrl; + char dv[8]; + + bootdev = B_DEVMAGIC; + + dv[0] = *cp; + ctrl = getpno(&cp); + if(*cp++ == ')') { + dv[1] = *cp; + unit = getpno(&cp); + + for (majdev = 0; majdev < sizeof(devname)/sizeof(devname[0]); majdev++) + if (dv[0] == devname[majdev][0] && + dv[1] == devname[majdev][1] && cp[0] == ')') + bootdev = MAKEBOOTDEV(majdev, 0, ctrl, unit,0); + } +} +getpno(cp) + char **cp; +{ + int val = 0; + char *cx = *cp; + + while(*cx && *cx != '(') + cx++; + if(*cx == '(') { + cx++; + while(*cx && *cx != ')') { + val = val * 10 + *cx - '0'; + cx++; + } + } + *cp = cx; + return val; +} diff --git a/sys/arch/arc/arc/clock.c b/sys/arch/arc/arc/clock.c new file mode 100644 index 00000000000..b247f2ff5d5 --- /dev/null +++ b/sys/arch/arc/arc/clock.c @@ -0,0 +1,314 @@ +/* $OpenBSD: clock.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: clock.c 1.18 91/01/21 + * + * from: @(#)clock.c 8.1 (Berkeley) 6/10/93 + * $Id: clock.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <arc/arc/clockvar.h> +#include <arc/arc/arctype.h> + + +extern int cputype; /* What kind of cpu we are running on */ + +/* Definition of the driver for autoconfig. */ +static int clockmatch __P((struct device *, void *, void *)); +static void clockattach __P((struct device *, struct device *, void *)); + +struct cfattach clock_ca = { + sizeof(struct clock_softc), clockmatch, clockattach +}; +struct cfdriver clock_cd = { + NULL, "clock", DV_DULL, NULL, 0 +}; + +void mcclock_attach __P((struct device *, struct device *, void *)); + +#define SECMIN ((unsigned)60) /* seconds per minute */ +#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ +#define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */ +#define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */ + +#define LEAPYEAR(year) (((year) % 4) == 0) + +static int +clockmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* See how many clocks this system has */ + switch (cputype) { + + case ACER_PICA_61: + /* make sure that we're looking for this type of device. */ + if (!BUS_MATCHNAME(ca, "dallas_rtc")) + return (0); + + if (cf->cf_unit >= 1) + return (0); + + break; + + default: + panic("unknown CPU"); + } + + return (1); +} + +static void +clockattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + + switch (cputype) { + + case ACER_PICA_61: + mcclock_attach(parent, self, aux); + break; + + default: + panic("clockattach: it didn't get here. really."); + } + + + /* + * establish the clock interrupt; it's a special case + */ + BUS_INTR_ESTABLISH((struct confargs *)aux, (intr_handler_t)hardclock, self); + + printf("\n"); +} + +/* + * Wait "n" microseconds. This doesn't belong here. XXX. + */ +void +delay(n) + int n; +{ + DELAY(n); +} + +/* + * Machine-dependent clock routines. + * + * Startrtclock restarts the real-time clock, which provides + * hardclock interrupts to kern_clock.c. + * + * Inittodr initializes the time of day hardware which provides + * date functions. Its primary function is to use some file + * system information in case the hardare clock lost state. + * + * Resettodr restores the time of day hardware after a time change. + */ + + +/* + * Start the real-time and statistics clocks. Leave stathz 0 since there + * are no other timers available. + */ +void +cpu_initclocks() +{ + extern int tickadj; + struct clock_softc *csc = (struct clock_softc *)clock_cd.cd_devs[0]; + + hz = 100; /* 100 Hz */ + tick = 1000000 / hz; /* number of micro-seconds between interrupts */ + + /* + * Start the clock. + */ + (*csc->sc_init)(csc); +} + +/* + * We assume newhz is either stathz or profhz, and that neither will + * change after being set up above. Could recalculate intervals here + * but that would be a drag. + */ +void +setstatclockrate(newhz) + int newhz; +{ +} + +/* + * This code is defunct after 2099. + * Will Unix still be here then?? + */ +static short dayyr[12] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +/* + * Initialze the time of day register, based on the time base which is, e.g. + * from a filesystem. Base provides the time to within six months, + * and the time of year clock (if any) provides the rest. + */ +void +inittodr(base) + time_t base; +{ + struct tod_time c; + struct clock_softc *csc = (struct clock_softc *)clock_cd.cd_devs[0]; + register int days, yr; + long deltat; + int badbase, s; + + if (base < 5*SECYR) { + printf("WARNING: preposterous time in file system"); + /* read the system clock anyway */ + base = 6*SECYR + 186*SECDAY + SECDAY/2; + badbase = 1; + } else + badbase = 0; + + /* Read RTC chip registers */ + (*csc->sc_get)(csc, base, &c); + + csc->sc_initted = 1; + + /* simple sanity checks */ + c.year = c.year+80; /* must be multiple of 4 because chip knows leap */ + if (c.year < 70 || c.mon < 1 || c.mon > 12 || c.day < 1 || + c.day > 31 || c.hour > 23 || c.min > 59 || c.sec > 59) { + /* + * Believe the time in the file system for lack of + * anything better, resetting the TODR. + */ + time.tv_sec = base; + if (!badbase) { + printf("WARNING: preposterous clock chip time\n"); + resettodr(); + } + goto bad; + } + days = 0; + for (yr = 70; yr < c.year; yr++) + days += LEAPYEAR(yr) ? 366 : 365; + days += dayyr[c.mon - 1] + c.day - 1; + if (LEAPYEAR(yr) && c.mon > 2) + days++; + /* now have days since Jan 1, 1970; the rest is easy... */ + time.tv_sec = days * SECDAY + c.hour * 3600 + c.min * 60 + c.sec; + + if (!badbase) { + /* + * See if we gained/lost two or more days; + * if so, assume something is amiss. + */ + deltat = time.tv_sec - base; + if (deltat < 0) + deltat = -deltat; + if (deltat < 2 * SECDAY) + return; + printf("WARNING: clock %s %d days", + time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); + } +bad: + printf(" -- CHECK AND RESET THE DATE!\n"); +} + +/* + * Reset the TODR based on the time value; used when the TODR + * has a preposterous value and also when the time is reset + * by the stime system call. Also called when the TODR goes past + * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight) + * to wrap the TODR around. + */ +void +resettodr() +{ + struct tod_time c; + struct clock_softc *csc = (struct clock_softc *)clock_cd.cd_devs[0]; + register int t, t2; + int s; + + if(!csc->sc_initted) + return; + + /* compute the day of week. 1 is Sunday*/ + t2 = time.tv_sec / SECDAY; + c.dow = (t2 + 5) % 7; /* 1/1/1970 was thursday */ + + /* compute the year */ + t2 = time.tv_sec / SECDAY; + c.year = 69; + while (t2 >= 0) { /* whittle off years */ + t = t2; + c.year++; + t2 -= LEAPYEAR(c.year) ? 366 : 365; + } + + /* t = month + day; separate */ + t2 = LEAPYEAR(c.year); + for (c.mon = 1; c.mon < 12; c.mon++) + if (t < dayyr[c.mon] + (t2 && c.mon > 1)) + break; + + c.day = t - dayyr[c.mon - 1] + 1; + if (t2 && c.mon > 2) + c.day--; + + /* the rest is easy */ + t = time.tv_sec % SECDAY; + c.hour = t / 3600; + t %= 3600; + c.min = t / 60; + c.sec = t % 60; + c.year = c.year-80; /* must be multiple of 4 because chip knows leap */ + + (*csc->sc_set)(csc, &c); +} diff --git a/sys/arch/arc/arc/clock_mc.c b/sys/arch/arc/arc/clock_mc.c new file mode 100644 index 00000000000..88261cac0ed --- /dev/null +++ b/sys/arch/arc/arc/clock_mc.c @@ -0,0 +1,216 @@ +/* $OpenBSD: clock_mc.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* $NetBSD: clock_mc.c,v 1.2 1995/06/28 04:30:30 cgd Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: clock.c 1.18 91/01/21 + * + * @(#)clock.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/pio.h> + +#include <arc/arc/clockvar.h> +#include <arc/arc/arctype.h> +#include <arc/pica/pica.h> +#include <dev/ic/mc146818reg.h> + +extern u_int cputype; +extern int cpu_int_mask; + +void mcclock_attach __P((struct device *parent, + struct device *self, void *aux)); +static void mcclock_init __P((struct clock_softc *csc)); +static void mcclock_get __P((struct clock_softc *csc, time_t base, + struct tod_time *ct)); +static void mcclock_set __P((struct clock_softc *csc, + struct tod_time *ct)); + +struct mcclockdata { + void (*mc_write) __P((struct clock_softc *csc, u_int reg, + u_int datum)); + u_int (*mc_read) __P((struct clock_softc *csc, u_int reg)); + void *mc_addr; +}; + +#define mc146818_write(sc, reg, datum) \ + (*((struct mcclockdata *)sc->sc_data)->mc_write)(sc, reg, datum) +#define mc146818_read(sc, reg) \ + (*((struct mcclockdata *)sc->sc_data)->mc_read)(sc, reg) + +#if defined(ACER_PICA_61) +static void mc_write_arc __P((struct clock_softc *csc, u_int reg, + u_int datum)); +static u_int mc_read_arc __P((struct clock_softc *csc, u_int reg)); +static struct mcclockdata mcclockdata_arc = { mc_write_arc, mc_read_arc }; +#endif + +void +mcclock_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct clock_softc *csc = (struct clock_softc *)self; + + register volatile struct chiptime *c; + struct confargs *ca = aux; + + printf(": mc146818 or compatible"); + + csc->sc_init = mcclock_init; + csc->sc_get = mcclock_get; + csc->sc_set = mcclock_set; + + switch (cputype) { + + case ACER_PICA_61: + /* + * XXX should really allocate a new one and copy, or + * something. unlikely we'll have more than one... + */ + csc->sc_data = &mcclockdata_arc; + mcclockdata_arc.mc_addr = BUS_CVTADDR(ca); + break; + + default: + printf("\n"); + panic("don't know how to set up for other system types."); + } + + /* Turn interrupts off, just in case. */ + mc146818_write(csc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR); +} + +static void +mcclock_init(csc) + struct clock_softc *csc; +{ +/* XXX Does not really belong here but for the moment we don't care */ + out32(PICA_SYS_IT_VALUE, 9); /* 10ms - 1 */ + /* Enable periodic clock interrupt */ + out32(PICA_SYS_EXT_IMASK, cpu_int_mask); +} + +/* + * Get the time of day, based on the clock's value and/or the base value. + */ +static void +mcclock_get(csc, base, ct) + struct clock_softc *csc; + time_t base; + struct tod_time *ct; +{ + mc_todregs regs; + int s; + + s = splclock(); + MC146818_GETTOD(csc, ®s) + splx(s); + + ct->sec = regs[MC_SEC]; + ct->min = regs[MC_MIN]; + ct->hour = regs[MC_HOUR]; + ct->dow = regs[MC_DOW]; + ct->day = regs[MC_DOM]; + ct->mon = regs[MC_MONTH]; + ct->year = regs[MC_YEAR]; +} + +/* + * Reset the TODR based on the time value. + */ +static void +mcclock_set(csc, ct) + struct clock_softc *csc; + struct tod_time *ct; +{ + mc_todregs regs; + int s; + + s = splclock(); + MC146818_GETTOD(csc, ®s); + splx(s); + + regs[MC_SEC] = ct->sec; + regs[MC_MIN] = ct->min; + regs[MC_HOUR] = ct->hour; + regs[MC_DOW] = ct->dow; + regs[MC_DOM] = ct->day; + regs[MC_MONTH] = ct->mon; + regs[MC_YEAR] = ct->year; + + s = splclock(); + MC146818_PUTTOD(csc, ®s); + splx(s); +} + + +#if defined(ACER_PICA_61) + +static void +mc_write_arc(csc, reg, datum) + struct clock_softc *csc; + u_int reg, datum; +{ + int i,as; + + as = in32(PICA_SYS_ISA_AS) & 0x80; + out32(PICA_SYS_ISA_AS, as | reg); + outb(PICA_SYS_CLOCK, datum); +} + +static u_int +mc_read_arc(csc, reg) + struct clock_softc *csc; + u_int reg; +{ + int i,as; + + as = in32(PICA_SYS_ISA_AS) & 0x80; + out32(PICA_SYS_ISA_AS, as | reg); + i = inb(PICA_SYS_CLOCK); + return(i); +} +#endif /*ACER_PICA_61*/ diff --git a/sys/arch/arc/arc/clockvar.h b/sys/arch/arc/arc/clockvar.h new file mode 100644 index 00000000000..9f4f677e9f1 --- /dev/null +++ b/sys/arch/arc/arc/clockvar.h @@ -0,0 +1,79 @@ +/* $OpenBSD: clockvar.h,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* $NetBSD: clockvar.h,v 1.1 1995/06/28 02:44:59 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * Adopted for r4400: Per Fogelstrom + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Definitions for "cpu-independent" clock handling for the mips arc arch. + */ + +/* + * clocktime structure: + * + * structure passed to TOY clocks when setting them. broken out this + * way, so that the time_t -> field conversion can be shared. + */ +struct tod_time { + int year; /* year - 1900 */ + int mon; /* month (1 - 12) */ + int day; /* day (1 - 31) */ + int hour; /* hour (0 - 23) */ + int min; /* minute (0 - 59) */ + int sec; /* second (0 - 59) */ + int dow; /* day of week (0 - 6; 0 = Sunday) */ +}; + +/* + * clockdesc structure: + * + * provides clock-specific functions to do necessary operations. + */ +struct clock_softc { + struct device sc_dev; + + /* + * The functions that all types of clock provide. + */ + void (*sc_attach) __P((struct device *parent, struct device *self, + void *aux)); + void (*sc_init) __P((struct clock_softc *csc)); + void (*sc_get) __P((struct clock_softc *csc, time_t base, + struct tod_time *ct)); + void (*sc_set) __P((struct clock_softc *csc, struct tod_time *ct)); + + /* + * Private storage for particular clock types. + */ + void *sc_data; + + /* + * Has the time been initialized? + */ + int sc_initted; +}; diff --git a/sys/arch/arc/arc/conf.c b/sys/arch/arc/arc/conf.c new file mode 100644 index 00000000000..7bfd2009c58 --- /dev/null +++ b/sys/arch/arc/arc/conf.c @@ -0,0 +1,330 @@ +/* $OpenBSD: conf.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)conf.c 8.2 (Berkeley) 11/14/93 + * $Id: conf.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/ioctl.h> +#include <sys/proc.h> +#include <sys/vnode.h> +#include <sys/tty.h> +#include <sys/conf.h> + +int ttselect __P((dev_t, int, struct proc *)); + +/* + * Block devices. + */ + +#include "vnd.h" +bdev_decl(vnd); +bdev_decl(sw); +#include "sd.h" +bdev_decl(sd); +#include "cd.h" +bdev_decl(cd); +#include "fdc.h" +bdev_decl(fd); + +struct bdevsw bdevsw[] = +{ + bdev_disk_init(NSD,sd), /* 0: SCSI disk */ + bdev_swap_init(1,sw), /* 1: should be here swap pseudo-dev */ + bdev_disk_init(NVND,vnd), /* 2: vnode disk driver */ + bdev_disk_init(NCD,cd), /* 3: SCSI CD-ROM */ + bdev_notdef(), /* 4: */ + bdev_notdef(), /* 5: */ + bdev_notdef(), /* 6: */ + bdev_disk_init(NFDC,fd), /* 7: Floppy disk driver */ + bdev_notdef(), /* 8: */ + bdev_notdef(), /* 9: */ + bdev_notdef(), /* 10: */ + bdev_notdef(), /* 11: */ + bdev_notdef(), /* 12: */ + bdev_notdef(), /* 13: */ + bdev_notdef(), /* 14: */ + bdev_notdef(), /* 15: */ +}; + +int nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]); + +/* + * Character devices. + */ + +/* open, close, read, write, ioctl, tty, mmap */ +#define cdev_pc_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \ + dev_init(c,n,write), dev_init(c,n,ioctl), dev_init(c,n,stop), \ + dev_init(c,n,tty), ttselect, dev_init(c,n,mmap), D_TTY } + +/* open, close, write, ioctl */ +#define cdev_lpt_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \ + 0, seltrue, (dev_type_mmap((*))) enodev } + +/* open, close, write, ioctl */ +#define cdev_spkr_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \ + 0, seltrue, (dev_type_mmap((*))) enodev } + +cdev_decl(cn); +cdev_decl(sw); +cdev_decl(ctty); +#define mmread mmrw +#define mmwrite mmrw +dev_type_read(mmrw); +cdev_decl(mm); +#include "pty.h" +#define ptstty ptytty +#define ptsioctl ptyioctl +cdev_decl(pts); +#define ptctty ptytty +#define ptcioctl ptyioctl +cdev_decl(ptc); +cdev_decl(log); +cdev_decl(fd); +#include "st.h" +cdev_decl(st); +#include "fdc.h" +bdev_decl(fd); +cdev_decl(vnd); +#include "bpfilter.h" +cdev_decl(bpf); +#include "ace.h" +cdev_decl(ace); +#include "lpt.h" +cdev_decl(lpt); +cdev_decl(sd); +#include "pc.h" +cdev_decl(pc); +cdev_decl(pms); +cdev_decl(cd); + +/* open, close, read, ioctl */ +cdev_decl(ipl); +#ifdef IPFILTER +#define NIPF 1 +#else +#define NIPF 0 +#endif + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_swap_init(1,sw), /* 1: /dev/drum (swap pseudo-device) */ + cdev_ctty_init(1,ctty), /* 2: controlling terminal */ + cdev_mm_init(1,mm), /* 3: /dev/{null,mem,kmem,...} */ + cdev_tty_init(NPTY,pts), /* 4: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 5: pseudo-tty master */ + cdev_log_init(1,log), /* 6: /dev/klog */ + cdev_fd_init(1,filedesc), /* 7: file descriptor pseudo-dev */ + cdev_disk_init(NCD,cd), /* 8: SCSI CD */ + cdev_disk_init(NSD,sd), /* 9: SCSI disk */ + cdev_tape_init(NST,st), /* 10: SCSI tape */ + cdev_disk_init(NVND,vnd), /* 11: vnode disk */ + cdev_bpftun_init(NBPFILTER,bpf),/* 12: berkeley packet filter */ + cdev_disk_init(NFDC,fd), /* 13: Floppy disk */ + cdev_pc_init(NPC,pc), /* 14: builtin pc style console dev */ + cdev_mouse_init(1,pms), /* 15: builtin PS2 style mouse */ + cdev_lpt_init(NLPT,lpt), /* 16: lpt paralell printer interface */ + cdev_tty_init(NCOM,ace), /* 17: ace 16C450 serial interface */ + cdev_notdef(), /* 18: */ + cdev_notdef(), /* 19: */ + cdev_tty_init(NPTY,pts), /* 20: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 21: pseudo-tty master */ + cdev_notdef(), /* 22: */ + cdev_notdef(), /* 23: */ + cdev_notdef(), /* 24: */ + cdev_notdef(), /* 25: */ + cdev_notdef(), /* 26: */ + cdev_notdef(), /* 27: */ + cdev_notdef(), /* 28: */ + cdev_notdef(), /* 29: */ + cdev_notdef(), /* 30: */ + cdev_gen_ipf(NIPF,ipl), /* 31: IP filter log */ +}; + +int nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]); + +int mem_no = 2; /* major device number of memory special file */ + +/* + * Swapdev is a fake device implemented + * in sw.c used only internally to get to swstrategy. + * It cannot be provided to the users, because the + * swstrategy routine munches the b_dev and b_blkno entries + * before calling the appropriate driver. This would horribly + * confuse, e.g. the hashing routines. Instead, /dev/drum is + * provided as a character (raw) device. + */ +dev_t swapdev = makedev(1, 0); + +/* + * Routine that identifies /dev/mem and /dev/kmem. + * + * A minimal stub routine can always return 0. + */ +iskmemdev(dev) + dev_t dev; +{ + +#ifdef COMPAT_BSD44 + if (major(dev) == 2 && (minor(dev) == 0 || minor(dev) == 1)) +#else + if (major(dev) == 3 && (minor(dev) == 0 || minor(dev) == 1)) +#endif + return (1); + return (0); +} + +/* + * Returns true if def is /dev/zero + */ +iszerodev(dev) + dev_t dev; +{ +#ifdef COMPAT_BSD44 + return (major(dev) == 2 && minor(dev) == 12); +#else + return (major(dev) == 3 && minor(dev) == 12); +#endif +} + + +#define MAXDEV 57 +static int chrtoblktbl[MAXDEV] = { + /* VCHR */ /* VBLK */ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ NODEV, + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ NODEV, + /* 9 */ 0, + /* 10 */ NODEV, + /* 11 */ 2, + /* 12 */ NODEV, + /* 13 */ 7, + /* 14 */ NODEV, + /* 15 */ NODEV, + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ NODEV, + /* 19 */ NODEV, + /* 20 */ NODEV, + /* 21 */ NODEV, + /* 22 */ NODEV, + /* 23 */ NODEV, + /* 24 */ NODEV, + /* 25 */ NODEV, + /* 26 */ NODEV, + /* 27 */ NODEV, + /* 28 */ NODEV, + /* 29 */ NODEV, + /* 30 */ NODEV, + /* 31 */ NODEV, + /* 32 */ NODEV, + /* 33 */ NODEV, + /* 34 */ NODEV, + /* 35 */ NODEV, + /* 36 */ NODEV, + /* 37 */ NODEV, + /* 38 */ NODEV, + /* 39 */ NODEV, + /* 40 */ NODEV, + /* 41 */ NODEV, + /* 42 */ NODEV, + /* 43 */ NODEV, + /* 44 */ NODEV, + /* 45 */ NODEV, + /* 46 */ NODEV, + /* 47 */ NODEV, + /* 48 */ NODEV, + /* 49 */ NODEV, + /* 50 */ NODEV, + /* 51 */ NODEV, + /* 52 */ NODEV, + /* 53 */ NODEV, + /* 54 */ NODEV, + /* 55 */ NODEV, + /* 56 */ NODEV, +}; +/* + * Routine to convert from character to block device number. + * + * A minimal stub routine can always return NODEV. + */ +chrtoblk(dev) + dev_t dev; +{ + int blkmaj; + + if (major(dev) >= MAXDEV || (blkmaj = chrtoblktbl[major(dev)]) == NODEV) + return (NODEV); + return (makedev(blkmaj, minor(dev))); +} + +/* + * This entire table could be autoconfig()ed but that would mean that + * the kernel's idea of the console would be out of sync with that of + * the standalone boot. I think it best that they both use the same + * known algorithm unless we see a pressing need otherwise. + */ +#include <dev/cons.h> + +cons_decl(pc); +cons_decl(ace); + +struct consdev constab[] = { +#if NPC + NVT > 0 + cons_init(pc), +#endif +#if NCOM > 0 + cons_init(ace), +#endif + { 0 }, +}; diff --git a/sys/arch/arc/arc/cpu.c b/sys/arch/arc/arc/cpu.c new file mode 100644 index 00000000000..5917761ebf6 --- /dev/null +++ b/sys/arch/arc/arc/cpu.c @@ -0,0 +1,188 @@ +/* $OpenBSD: cpu.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Per Fogelstrom + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/device.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> + + +/* Definition of the driver for autoconfig. */ +static int cpumatch(struct device *, void *, void *); +static void cpuattach(struct device *, struct device *, void *); + +struct cfattach cpu_ca = { + sizeof(struct device), cpumatch, cpuattach +}; +struct cfdriver cpu_cd = { + NULL, "cpu", DV_DULL, NULL, 0 +}; + +static int cpuprint __P((void *, char *pnp)); + +static int +cpumatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* make sure that we're looking for a CPU. */ + if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0) + return (0); + + return (1); +} + +static void +cpuattach(parent, dev, aux) + struct device *parent; + struct device *dev; + void *aux; +{ + struct pcs *p; + int needcomma, needrev, i; + + printf(": "); + + switch(cpu_id.cpu.cp_imp) { + + case MIPS_R2000: + printf("MIPS R2000 CPU"); + break; + case MIPS_R3000: + printf("MIPS R3000 CPU"); + break; + case MIPS_R6000: + printf("MIPS R6000 CPU"); + break; + case MIPS_R4000: + if(machPrimaryInstCacheSize == 16384) + printf("MIPS R4400 CPU"); + else + printf("MIPS R4000 CPU"); + break; + case MIPS_R3LSI: + printf("LSI Logic R3000 derivate"); + break; + case MIPS_R6000A: + printf("MIPS R6000A CPU"); + break; + case MIPS_R3IDT: + printf("IDT R3000 derivate"); + break; + case MIPS_R10000: + printf("MIPS R10000/T5 CPU"); + break; + case MIPS_R4200: + printf("MIPS R4200 CPU (ICE)"); + break; + case MIPS_R8000: + printf("MIPS R8000 Blackbird/TFP CPU"); + break; + case MIPS_R4600: + printf("QED R4600 Orion CPU"); + break; + case MIPS_R3SONY: + printf("Sony R3000 based CPU"); + break; + case MIPS_R3TOSH: + printf("Toshiba R3000 based CPU"); + break; + case MIPS_R3NKK: + printf("NKK R3000 based CPU"); + break; + case MIPS_UNKC1: + case MIPS_UNKC2: + default: + printf("Unknown CPU type (0x%x)",cpu_id.cpu.cp_imp); + break; + } + printf(" Rev. %d.%d with ", cpu_id.cpu.cp_majrev, cpu_id.cpu.cp_minrev); + + + switch(fpu_id.cpu.cp_imp) { + + case MIPS_SOFT: + printf("Software emulation float"); + break; + case MIPS_R2360: + printf("MIPS R2360 FPC"); + break; + case MIPS_R2010: + printf("MIPS R2010 FPC"); + break; + case MIPS_R3010: + printf("MIPS R3010 FPC"); + break; + case MIPS_R6010: + printf("MIPS R6010 FPC"); + break; + case MIPS_R4010: + printf("MIPS R4010 FPC"); + break; + case MIPS_R31LSI: + printf("FPC"); + break; + case MIPS_R10010: + printf("MIPS R10000/T5 FPU"); + break; + case MIPS_R4210: + printf("MIPS R4200 FPC (ICE)"); + case MIPS_R8000: + printf("MIPS R8000 Blackbird/TFP"); + break; + case MIPS_R4600: + printf("QED R4600 Orion FPC"); + break; + case MIPS_R3SONY: + printf("Sony R3000 based FPC"); + break; + case MIPS_R3TOSH: + printf("Toshiba R3000 based FPC"); + break; + case MIPS_R3NKK: + printf("NKK R3000 based FPC"); + break; + case MIPS_UNKF1: + default: + printf("Unknown FPU type (0x%x)", fpu_id.cpu.cp_imp); + break; + } + printf(" Rev. %d.%d", fpu_id.cpu.cp_majrev, fpu_id.cpu.cp_minrev); + printf("\n"); + + printf(" Primary cache size: %dkb Instruction, %dkb Data.\n", + machPrimaryInstCacheSize / 1024, + machPrimaryDataCacheSize / 1024); +} + diff --git a/sys/arch/arc/arc/cpu_exec.c b/sys/arch/arc/arc/cpu_exec.c new file mode 100644 index 00000000000..4e3e657011a --- /dev/null +++ b/sys/arch/arc/arc/cpu_exec.c @@ -0,0 +1,104 @@ +/* $NetBSD: cpu_exec.c,v 1.4 1995/04/25 19:16:46 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by Ralph + * Campbell. + * + * 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. + * + * @(#)machdep.c 8.3 (Berkeley) 1/12/94 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/exec.h> +#include <sys/resourcevar.h> +#include <vm/vm.h> + +#include <sys/exec_ecoff.h> +#include <machine/reg.h> + +/* + * cpu_exec_aout_makecmds(): + * cpu-dependent a.out format hook for execve(). + * + * Determine of the given exec package refers to something which we + * understand and, if so, set up the vmcmds for it. + * + */ +int +cpu_exec_aout_makecmds(p, epp) + struct proc *p; + struct exec_package *epp; +{ + return ENOEXEC; +} + +#ifdef COMPAT_ULTRIX +extern struct emul emul_ultrix; + +void +cpu_exec_ecoff_setregs(p, pack, stack, retval) + struct proc *p; + struct exec_package *pack; + u_long stack; + register_t *retval; +{ + struct ecoff_aouthdr *eap; + + setregs(p, pack, stack, retval); + eap = (struct ecoff_aouthdr *) + ((caddr_t)pack->ep_hdr + sizeof(struct ecoff_filehdr)); + p->p_md.md_regs[GP] = eap->ea_gp_value; +} + +/* + * cpu_exec_ecoff_hook(): + * cpu-dependent ECOFF format hook for execve(). + * + * Do any machine-dependent diddling of the exec package when doing ECOFF. + * + */ +int +cpu_exec_ecoff_hook(p, epp, eap) + struct proc *p; + struct exec_package *epp; + struct ecoff_aouthdr *eap; +{ + + epp->ep_emul = &emul_ultrix; + return 0; +} +#endif diff --git a/sys/arch/arc/arc/disksubr.c b/sys/arch/arc/arc/disksubr.c new file mode 100644 index 00000000000..4f84136f3a8 --- /dev/null +++ b/sys/arch/arc/arc/disksubr.c @@ -0,0 +1,323 @@ +/* $OpenBSD: disksubr.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* $NetBSD: disksubr.c,v 1.3 1995/04/22 12:43:22 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Authors: Keith Bostic, Chris G. Demetriou, Per Fogelstrom (R4000) + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/ioccom.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/disk.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> + +extern struct device *bootdv; + +/* was this the boot device ? */ +void +dk_establish(dk, dev) + struct disk *dk; + struct device *dev; +{ +} + +/* + * Attempt to read a disk label from a device + * using the indicated stategy routine. + * The label must be partly set up before this: + * secpercyl and anything required in the strategy routine + * (e.g., sector size) must be filled in before calling us. + * Returns null on success and an error string on failure. + */ +char * +readdisklabel(dev, strat, lp, clp) + dev_t dev; + void (*strat)(); + struct disklabel *lp; + struct cpu_disklabel *clp; +{ + struct buf *bp; + struct disklabel *dlp; + struct dos_partition *dp = clp->dosparts; + char *msg = NULL; + int dospartoff = 0; + int i; + + /* minimal requirements for archtypal disk label */ + if (lp->d_secperunit == 0) + lp->d_secperunit = 0x1fffffff; + lp->d_npartitions = RAW_PART + 1; + for(i = 0; i < RAW_PART; i++) { + lp->d_partitions[i].p_size = 0; + lp->d_partitions[i].p_offset = 0; + } + if (lp->d_partitions[RAW_PART].p_size == 0) + lp->d_partitions[RAW_PART].p_size = 0x1fffffff; + lp->d_partitions[RAW_PART].p_offset = 0; + + /* obtain buffer to probe drive with */ + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + + /* do dos partitions in the process of getting disklabel? */ + if (dp) { + /* read master boot record */ + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_resid = 0; + (*strat)(bp); + + /* if successful, wander through dos partition table */ + if (biowait(bp)) { + msg = "dos partition I/O error"; + goto done; + } else if (*(unsigned int *)(bp->b_data) == 0x8ec033fa) { + /* XXX how do we check veracity/bounds of this? */ + bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp)); + for (i = 0; i < NDOSPART; i++, dp++) { + /* is this ours? */ + if (dp->dp_size && dp->dp_typ == DOSPTYP_386BSD + && dospartoff == 0) { + dospartoff = dp->dp_start; + + /* set part a to show NetBSD part */ + lp->d_partitions[0].p_size = dp->dp_size; + lp->d_partitions[0].p_offset = dp->dp_start; + lp->d_ntracks = dp->dp_ehd + 1; + lp->d_nsectors = DPSECT(dp->dp_esect); + lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; + } + } + } + + } + /* next, dig out disk label */ + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_resid = 0; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if (biowait(bp)) { + msg = "disk label read error"; + goto done; + } + + dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); + if (dlp->d_magic == DISKMAGIC) { + if (dkcksum(dlp)) { + msg = "NetBSD disk label corrupted"; + goto done; + } + *lp = *dlp; + goto done; + } + msg = "no disk label"; +done: + bp->b_flags = B_INVAL | B_AGE | B_READ; + brelse(bp); + return (msg); +} + +/* + * Check new disk label for sensibility before setting it. + */ +int +setdisklabel(olp, nlp, openmask, clp) + register struct disklabel *olp, *nlp; + u_long openmask; + struct cpu_disklabel *clp; +{ + register i; + register struct partition *opp, *npp; + + /* sanity clause */ + if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 || + (nlp->d_secsize % DEV_BSIZE) != 0) + return(EINVAL); + +#ifdef notdef + /* XXX WHY WAS THIS HERE?! */ + /* special case to allow disklabel to be invalidated */ + if (nlp->d_magic == 0xffffffff) { + *olp = *nlp; + return (0); + } +#endif + + if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || + dkcksum(nlp) != 0) + return (EINVAL); + + while ((i = ffs((long)openmask)) != 0) { + i--; + openmask &= ~(1 << i); + if (nlp->d_npartitions <= i) + return (EBUSY); + opp = &olp->d_partitions[i]; + npp = &nlp->d_partitions[i]; + if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) + return (EBUSY); + /* + * Copy internally-set partition information + * if new label doesn't include it. XXX + */ + if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { + npp->p_fstype = opp->p_fstype; + npp->p_fsize = opp->p_fsize; + npp->p_frag = opp->p_frag; + npp->p_cpg = opp->p_cpg; + } + } + nlp->d_checksum = 0; + nlp->d_checksum = dkcksum(nlp); + *olp = *nlp; + return (0); +} + +/* + * Write disk label back to device after modification. + * this means write out the Rigid disk blocks to represent the + * label. Hope the user was carefull. + */ +int +writedisklabel(dev, strat, lp, clp) + dev_t dev; + void (*strat)(); + register struct disklabel *lp; + struct cpu_disklabel *clp; +{ + struct buf *bp; + struct disklabel *dlp; + struct dos_partition *dp = clp->dosparts; + int error = 0, i; + int dospartoff = 0; + + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + + /* do dos partitions in the process of getting disklabel? */ + if (dp) { + /* read master boot record */ + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_resid = 0; + (*strat)(bp); + + if (((error = biowait(bp)) == 0) + && *(unsigned int *)(bp->b_data) == 0x8ec033fa) { + /* XXX how do we check veracity/bounds of this? */ + bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp)); + for (i = 0; i < NDOSPART; i++, dp++) { + /* is this ours? */ + if (dp->dp_size && dp->dp_typ == DOSPTYP_386BSD + && dospartoff == 0) { + dospartoff = dp->dp_start; + } + } + } + + } + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_resid = 0; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_READ; /* get current label */ + (*strat)(bp); + if (error = biowait(bp)) + goto done; + + dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); + *dlp = *lp; /* struct assignment */ + + bp->b_flags = B_WRITE; + (*strat)(bp); + error = biowait(bp); + +done: + brelse(bp); + return (error); +} + + +/* + * Determine the size of the transfer, and make sure it is + * within the boundaries of the partition. Adjust transfer + * if needed, and signal errors or early completion. + */ +int +bounds_check_with_label(bp, lp, wlabel) + struct buf *bp; + struct disklabel *lp; + int wlabel; +{ +#define dkpart(dev) (minor(dev) & 7) + + struct partition *p = lp->d_partitions + dkpart(bp->b_dev); + int labelsect = lp->d_partitions[RAW_PART].p_offset; + int maxsz = p->p_size; + int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; + + /* overwriting disk label ? */ + /* XXX should also protect bootstrap in first 8K */ + if (bp->b_blkno + p->p_offset == LABELSECTOR + labelsect && + (bp->b_flags & B_READ) == 0 && wlabel == 0) { + bp->b_error = EROFS; + goto bad; + } + + /* beyond partition? */ + if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { + /* if exactly at end of disk, return an EOF */ + if (bp->b_blkno == maxsz) { + bp->b_resid = bp->b_bcount; + return(0); + } + /* or truncate if part of it fits */ + sz = maxsz - bp->b_blkno; + if (sz <= 0) { + bp->b_error = EINVAL; + goto bad; + } + bp->b_bcount = sz << DEV_BSHIFT; + } + + /* calculate cylinder for disksort to order transfers with */ + bp->b_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl; + return(1); +bad: + bp->b_flags |= B_ERROR; + return(-1); +} diff --git a/sys/arch/arc/arc/fp.S b/sys/arch/arc/arc/fp.S new file mode 100644 index 00000000000..af2470947a1 --- /dev/null +++ b/sys/arch/arc/arc/fp.S @@ -0,0 +1,3611 @@ +/* $OpenBSD: fp.S,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)fp.s 8.1 (Berkeley) 6/10/93 + * $Id: fp.S,v 1.1 1996/06/24 09:07:20 pefo Exp $ + */ + +/* + * Standard header stuff. + */ + +#include <machine/regdef.h> +#include <machine/asm.h> +#include <machine/cpu.h> + +#include "assym.h" + +#define SEXP_INF 0xff +#define DEXP_INF 0x7ff +#define SEXP_BIAS 127 +#define DEXP_BIAS 1023 +#define SEXP_MIN -126 +#define DEXP_MIN -1022 +#define SEXP_MAX 127 +#define DEXP_MAX 1023 +#define WEXP_MAX 30 /* maximum unbiased exponent for int */ +#define WEXP_MIN -1 /* minimum unbiased exponent for int */ +#define SFRAC_BITS 23 +#define DFRAC_BITS 52 +#define SIMPL_ONE 0x00800000 +#define DIMPL_ONE 0x00100000 +#define SLEAD_ZEROS 31 - 23 +#define DLEAD_ZEROS 31 - 20 +#define STICKYBIT 1 +#define GUARDBIT 0x80000000 +#define SSIGNAL_NAN 0x00400000 +#define DSIGNAL_NAN 0x00080000 +#define SQUIET_NAN 0x003fffff +#define DQUIET_NAN0 0x0007ffff +#define DQUIET_NAN1 0xffffffff +#define INT_MIN 0x80000000 +#define INT_MAX 0x7fffffff + +#define COND_UNORDERED 0x1 +#define COND_EQUAL 0x2 +#define COND_LESS 0x4 +#define COND_SIGNAL 0x8 + +/*---------------------------------------------------------------------------- + * + * MachEmulateFP -- + * + * Emulate unimplemented floating point operations. + * This routine should only be called by MachFPInterrupt(). + * + * MachEmulateFP(instr) + * unsigned instr; + * + * Results: + * None. + * + * Side effects: + * Floating point registers are modified according to instruction. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(MachEmulateFP, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) +/* + * Decode the FMT field (bits 24-21) and FUNCTION field (bits 5-0). + */ + srl v0, a0, 21 - 2 # get FMT field + and v0, v0, 0xF << 2 # mask FMT field + and v1, a0, 0x3F # mask FUNC field + sll v1, v1, 5 # align for table lookup + bgt v0, 4 << 2, ill # illegal format + + or v1, v1, v0 + cfc1 a1, FPC_CSR # get exception register + lw a3, func_fmt_tbl(v1) # switch on FUNC & FMT + and a1, a1, ~FPC_EXCEPTION_UNIMPL # clear exception + ctc1 a1, FPC_CSR + j a3 + + .rdata +func_fmt_tbl: + .word add_s # 0 + .word add_d # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word sub_s # 1 + .word sub_d # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word mul_s # 2 + .word mul_d # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word div_s # 3 + .word div_d # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word abs_s # 5 + .word abs_d # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word mov_s # 6 + .word mov_d # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word neg_s # 7 + .word neg_d # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 32 + .word cvt_s_d # 32 + .word ill # 32 + .word ill # 32 + .word cvt_s_w # 32 + .word ill # 32 + .word ill # 32 + .word ill # 32 + .word cvt_d_s # 33 + .word ill # 33 + .word ill # 33 + .word ill # 33 + .word cvt_d_w # 33 + .word ill # 33 + .word ill # 33 + .word ill # 33 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word cvt_w_s # 36 + .word cvt_w_d # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word cmp_s # 48 + .word cmp_d # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word cmp_s # 49 + .word cmp_d # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word cmp_s # 50 + .word cmp_d # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word cmp_s # 51 + .word cmp_d # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word cmp_s # 52 + .word cmp_d # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word cmp_s # 53 + .word cmp_d # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word cmp_s # 54 + .word cmp_d # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word cmp_s # 55 + .word cmp_d # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word cmp_s # 56 + .word cmp_d # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word cmp_s # 57 + .word cmp_d # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word cmp_s # 58 + .word cmp_d # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word cmp_s # 59 + .word cmp_d # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word cmp_s # 60 + .word cmp_d # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word cmp_s # 61 + .word cmp_d # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word cmp_s # 62 + .word cmp_d # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word cmp_s # 63 + .word cmp_d # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .text + +/* + * Single precision subtract. + */ +sub_s: + jal get_ft_fs_s + xor t4, t4, 1 # negate FT sign bit + b add_sub_s +/* + * Single precision add. + */ +add_s: + jal get_ft_fs_s +add_sub_s: + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t5, SEXP_INF, result_fs_s # if FT is not inf, result=FS + bne t2, zero, result_fs_s # if FS is NAN, result is FS + bne t6, zero, result_ft_s # if FT is NAN, result is FT + bne t0, t4, invalid_s # both infinities same sign? + b result_fs_s # result is in FS +1: + beq t5, SEXP_INF, result_ft_s # if FT is inf, result=FT + bne t1, zero, 4f # is FS a denormalized num? + beq t2, zero, 3f # is FS zero? + bne t5, zero, 2f # is FT a denormalized num? + beq t6, zero, result_fs_s # FT is zero, result=FS + jal renorm_fs_s + jal renorm_ft_s + b 5f +2: + jal renorm_fs_s + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit + b 5f +3: + bne t5, zero, result_ft_s # if FT != 0, result=FT + bne t6, zero, result_ft_s + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_s +1: + and t0, t0, t4 # compute result sign + b result_fs_s +4: + bne t5, zero, 2f # is FT a denormalized num? + beq t6, zero, result_fs_s # FT is zero, result=FS + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit + jal renorm_ft_s + b 5f +2: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +/* + * Perform the addition. + */ +5: + move t8, zero # no shifted bits (sticky reg) + beq t1, t5, 4f # no shift needed + subu v0, t1, t5 # v0 = difference of exponents + move v1, v0 # v1 = abs(difference) + bge v0, zero, 1f + negu v1 +1: + ble v1, SFRAC_BITS+2, 2f # is difference too great? + li t8, STICKYBIT # set the sticky bit + bge v0, zero, 1f # check which exp is larger + move t1, t5 # result exp is FTs + move t2, zero # FSs fraction shifted is zero + b 4f +1: + move t6, zero # FTs fraction shifted is zero + b 4f +2: + li t9, 32 # compute 32 - abs(exp diff) + subu t9, t9, v1 + bgt v0, zero, 3f # if FS > FT, shift FTs frac + move t1, t5 # FT > FS, result exp is FTs + sll t8, t2, t9 # save bits shifted out + srl t2, t2, v1 # shift FSs fraction + b 4f +3: + sll t8, t6, t9 # save bits shifted out + srl t6, t6, v1 # shift FTs fraction +4: + bne t0, t4, 1f # if signs differ, subtract + addu t2, t2, t6 # add fractions + b norm_s +1: + blt t2, t6, 3f # subtract larger from smaller + bne t2, t6, 2f # if same, result=0 + move t1, zero # result=0 + move t2, zero + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_s +1: + and t0, t0, t4 # compute result sign + b result_fs_s +2: + sltu t9, zero, t8 # compute t2:zero - t6:t8 + subu t8, zero, t8 + subu t2, t2, t6 # subtract fractions + subu t2, t2, t9 # subtract barrow + b norm_s +3: + move t0, t4 # sign of result = FTs + sltu t9, zero, t8 # compute t6:zero - t2:t8 + subu t8, zero, t8 + subu t2, t6, t2 # subtract fractions + subu t2, t2, t9 # subtract barrow + b norm_s + +/* + * Double precision subtract. + */ +sub_d: + jal get_ft_fs_d + xor t4, t4, 1 # negate sign bit + b add_sub_d +/* + * Double precision add. + */ +add_d: + jal get_ft_fs_d +add_sub_d: + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t5, DEXP_INF, result_fs_d # if FT is not inf, result=FS + bne t2, zero, result_fs_d # if FS is NAN, result is FS + bne t3, zero, result_fs_d + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + bne t0, t4, invalid_d # both infinities same sign? + b result_fs_d # result is in FS +1: + beq t5, DEXP_INF, result_ft_d # if FT is inf, result=FT + bne t1, zero, 4f # is FS a denormalized num? + bne t2, zero, 1f # is FS zero? + beq t3, zero, 3f +1: + bne t5, zero, 2f # is FT a denormalized num? + bne t6, zero, 1f + beq t7, zero, result_fs_d # FT is zero, result=FS +1: + jal renorm_fs_d + jal renorm_ft_d + b 5f +2: + jal renorm_fs_d + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit + b 5f +3: + bne t5, zero, result_ft_d # if FT != 0, result=FT + bne t6, zero, result_ft_d + bne t7, zero, result_ft_d + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_d +1: + and t0, t0, t4 # compute result sign + b result_fs_d +4: + bne t5, zero, 2f # is FT a denormalized num? + bne t6, zero, 1f + beq t7, zero, result_fs_d # FT is zero, result=FS +1: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit + jal renorm_ft_d + b 5f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +/* + * Perform the addition. + */ +5: + move t8, zero # no shifted bits (sticky reg) + beq t1, t5, 4f # no shift needed + subu v0, t1, t5 # v0 = difference of exponents + move v1, v0 # v1 = abs(difference) + bge v0, zero, 1f + negu v1 +1: + ble v1, DFRAC_BITS+2, 2f # is difference too great? + li t8, STICKYBIT # set the sticky bit + bge v0, zero, 1f # check which exp is larger + move t1, t5 # result exp is FTs + move t2, zero # FSs fraction shifted is zero + move t3, zero + b 4f +1: + move t6, zero # FTs fraction shifted is zero + move t7, zero + b 4f +2: + li t9, 32 + bge v0, zero, 3f # if FS > FT, shift FTs frac + move t1, t5 # FT > FS, result exp is FTs + blt v1, t9, 1f # shift right by < 32? + subu v1, v1, t9 + subu t9, t9, v1 + sll t8, t2, t9 # save bits shifted out + sltu t9, zero, t3 # dont lose any one bits + or t8, t8, t9 # save sticky bit + srl t3, t2, v1 # shift FSs fraction + move t2, zero + b 4f +1: + subu t9, t9, v1 + sll t8, t3, t9 # save bits shifted out + srl t3, t3, v1 # shift FSs fraction + sll t9, t2, t9 # save bits shifted out of t2 + or t3, t3, t9 # and put into t3 + srl t2, t2, v1 + b 4f +3: + blt v1, t9, 1f # shift right by < 32? + subu v1, v1, t9 + subu t9, t9, v1 + sll t8, t6, t9 # save bits shifted out + srl t7, t6, v1 # shift FTs fraction + move t6, zero + b 4f +1: + subu t9, t9, v1 + sll t8, t7, t9 # save bits shifted out + srl t7, t7, v1 # shift FTs fraction + sll t9, t6, t9 # save bits shifted out of t2 + or t7, t7, t9 # and put into t3 + srl t6, t6, v1 +4: + bne t0, t4, 1f # if signs differ, subtract + addu t3, t3, t7 # add fractions + sltu t9, t3, t7 # compute carry + addu t2, t2, t6 # add fractions + addu t2, t2, t9 # add carry + b norm_d +1: + blt t2, t6, 3f # subtract larger from smaller + bne t2, t6, 2f + bltu t3, t7, 3f + bne t3, t7, 2f # if same, result=0 + move t1, zero # result=0 + move t2, zero + move t3, zero + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_d +1: + and t0, t0, t4 # compute result sign + b result_fs_d +2: + beq t8, zero, 1f # compute t2:t3:zero - t6:t7:t8 + subu t8, zero, t8 + sltu v0, t3, 1 # compute barrow out + subu t3, t3, 1 # subtract barrow + subu t2, t2, v0 +1: + sltu v0, t3, t7 + subu t3, t3, t7 # subtract fractions + subu t2, t2, t6 # subtract fractions + subu t2, t2, v0 # subtract barrow + b norm_d +3: + move t0, t4 # sign of result = FTs + beq t8, zero, 1f # compute t6:t7:zero - t2:t3:t8 + subu t8, zero, t8 + sltu v0, t7, 1 # compute barrow out + subu t7, t7, 1 # subtract barrow + subu t6, t6, v0 +1: + sltu v0, t7, t3 + subu t3, t7, t3 # subtract fractions + subu t2, t6, t2 # subtract fractions + subu t2, t2, v0 # subtract barrow + b norm_d + +/* + * Single precision multiply. + */ +mul_s: + jal get_ft_fs_s + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, SEXP_INF, 2f # is FS an infinity? + bne t2, zero, result_fs_s # if FS is a NAN, result=FS + bne t5, SEXP_INF, 1f # FS is inf, is FT an infinity? + bne t6, zero, result_ft_s # if FT is a NAN, result=FT + b result_fs_s # result is infinity +1: + bne t5, zero, result_fs_s # inf * zero? if no, result=FS + bne t6, zero, result_fs_s + b invalid_s # infinity * zero is invalid +2: + bne t5, SEXP_INF, 1f # FS != inf, is FT an infinity? + bne t1, zero, result_ft_s # zero * inf? if no, result=FT + bne t2, zero, result_ft_s + bne t6, zero, result_ft_s # if FT is a NAN, result=FT + b invalid_s # zero * infinity is invalid +1: + bne t1, zero, 1f # is FS zero? + beq t2, zero, result_fs_s # result is zero + jal renorm_fs_s + b 2f +1: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit +2: + bne t5, zero, 1f # is FT zero? + beq t6, zero, result_ft_s # result is zero + jal renorm_ft_s + b 2f +1: + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +2: + addu t1, t1, t5 # compute result exponent + addu t1, t1, 9 # account for binary point + multu t2, t6 # multiply fractions + mflo t8 + mfhi t2 + b norm_s + +/* + * Double precision multiply. + */ +mul_d: + jal get_ft_fs_d + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, DEXP_INF, 2f # is FS an infinity? + bne t2, zero, result_fs_d # if FS is a NAN, result=FS + bne t3, zero, result_fs_d + bne t5, DEXP_INF, 1f # FS is inf, is FT an infinity? + bne t6, zero, result_ft_d # if FT is a NAN, result=FT + bne t7, zero, result_ft_d + b result_fs_d # result is infinity +1: + bne t5, zero, result_fs_d # inf * zero? if no, result=FS + bne t6, zero, result_fs_d + bne t7, zero, result_fs_d + b invalid_d # infinity * zero is invalid +2: + bne t5, DEXP_INF, 1f # FS != inf, is FT an infinity? + bne t1, zero, result_ft_d # zero * inf? if no, result=FT + bne t2, zero, result_ft_d # if FS is a NAN, result=FS + bne t3, zero, result_ft_d + bne t6, zero, result_ft_d # if FT is a NAN, result=FT + bne t7, zero, result_ft_d + b invalid_d # zero * infinity is invalid +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_d # result is zero +1: + jal renorm_fs_d + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + beq t7, zero, result_ft_d # result is zero +1: + jal renorm_ft_d + b 3f +2: + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +3: + addu t1, t1, t5 # compute result exponent + addu t1, t1, 12 # ??? + multu t3, t7 # multiply fractions (low * low) + move t4, t2 # free up t2,t3 for result + move t5, t3 + mflo a3 # save low order bits + mfhi t8 + not v0, t8 + multu t4, t7 # multiply FS(high) * FT(low) + mflo v1 + mfhi t3 # init low result + sltu v0, v0, v1 # compute carry + addu t8, v1 + multu t5, t6 # multiply FS(low) * FT(high) + addu t3, t3, v0 # add carry + not v0, t8 + mflo v1 + mfhi t2 + sltu v0, v0, v1 + addu t8, v1 + multu t4, t6 # multiply FS(high) * FT(high) + addu t3, v0 + not v1, t3 + sltu v1, v1, t2 + addu t3, t2 + not v0, t3 + mfhi t2 + addu t2, v1 + mflo v1 + sltu v0, v0, v1 + addu t2, v0 + addu t3, v1 + sltu a3, zero, a3 # reduce t8,a3 to just t8 + or t8, a3 + b norm_d + +/* + * Single precision divide. + */ +div_s: + jal get_ft_fs_s + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, result_fs_s # if FS is NAN, result is FS + bne t5, SEXP_INF, result_fs_s # is FT an infinity? + bne t6, zero, result_ft_s # if FT is NAN, result is FT + b invalid_s # infinity/infinity is invalid +1: + bne t5, SEXP_INF, 1f # is FT an infinity? + bne t6, zero, result_ft_s # if FT is NAN, result is FT + move t1, zero # x / infinity is zero + move t2, zero + b result_fs_s +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + bne t5, zero, result_fs_s # FS=zero, is FT zero? + beq t6, zero, invalid_s # 0 / 0 + b result_fs_s # result = zero +1: + jal renorm_fs_s + b 3f +2: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 + and v0, a1, FPC_ENABLE_DIV0 # trap enabled? + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + li t1, SEXP_INF # result is infinity + move t2, zero + b result_fs_s +1: + jal renorm_ft_s + b 3f +2: + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +3: + subu t1, t1, t5 # compute exponent + subu t1, t1, 3 # compensate for result position + li v0, SFRAC_BITS+3 # number of bits to divide + move t8, t2 # init dividend + move t2, zero # init result +1: + bltu t8, t6, 3f # is dividend >= divisor? +2: + subu t8, t8, t6 # subtract divisor from dividend + or t2, t2, 1 # remember that we did + bne t8, zero, 3f # if not done, continue + sll t2, t2, v0 # shift result to final position + b norm_s +3: + sll t8, t8, 1 # shift dividend + sll t2, t2, 1 # shift result + subu v0, v0, 1 # are we done? + bne v0, zero, 1b # no, continue + b norm_s + +/* + * Double precision divide. + */ +div_d: + jal get_ft_fs_d + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, result_fs_d # if FS is NAN, result is FS + bne t3, zero, result_fs_d + bne t5, DEXP_INF, result_fs_d # is FT an infinity? + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + b invalid_d # infinity/infinity is invalid +1: + bne t5, DEXP_INF, 1f # is FT an infinity? + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + move t1, zero # x / infinity is zero + move t2, zero + move t3, zero + b result_fs_d +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + bne t3, zero, 1f + bne t5, zero, result_fs_d # FS=zero, is FT zero? + bne t6, zero, result_fs_d + beq t7, zero, invalid_d # 0 / 0 + b result_fs_d # result = zero +1: + jal renorm_fs_d + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + bne t7, zero, 1f + or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 + and v0, a1, FPC_ENABLE_DIV0 # trap enabled? + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # Save exceptions + li t1, DEXP_INF # result is infinity + move t2, zero + move t3, zero + b result_fs_d +1: + jal renorm_ft_d + b 3f +2: + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +3: + subu t1, t1, t5 # compute exponent + subu t1, t1, 3 # compensate for result position + li v0, DFRAC_BITS+3 # number of bits to divide + move t8, t2 # init dividend + move t9, t3 + move t2, zero # init result + move t3, zero +1: + bltu t8, t6, 3f # is dividend >= divisor? + bne t8, t6, 2f + bltu t9, t7, 3f +2: + sltu v1, t9, t7 # subtract divisor from dividend + subu t9, t9, t7 + subu t8, t8, t6 + subu t8, t8, v1 + or t3, t3, 1 # remember that we did + bne t8, zero, 3f # if not done, continue + bne t9, zero, 3f + li v1, 32 # shift result to final position + blt v0, v1, 2f # shift < 32 bits? + subu v0, v0, v1 # shift by > 32 bits + sll t2, t3, v0 # shift upper part + move t3, zero + b norm_d +2: + subu v1, v1, v0 # shift by < 32 bits + sll t2, t2, v0 # shift upper part + srl t9, t3, v1 # save bits shifted out + or t2, t2, t9 # and put into upper part + sll t3, t3, v0 + b norm_d +3: + sll t8, t8, 1 # shift dividend + srl v1, t9, 31 # save bit shifted out + or t8, t8, v1 # and put into upper part + sll t9, t9, 1 + sll t2, t2, 1 # shift result + srl v1, t3, 31 # save bit shifted out + or t2, t2, v1 # and put into upper part + sll t3, t3, 1 + subu v0, v0, 1 # are we done? + bne v0, zero, 1b # no, continue + sltu v0, zero, t9 # be sure to save any one bits + or t8, t8, v0 # from the lower remainder + b norm_d + +/* + * Single precision absolute value. + */ +abs_s: + jal get_fs_s + move t0, zero # set sign positive + b result_fs_s + +/* + * Double precision absolute value. + */ +abs_d: + jal get_fs_d + move t0, zero # set sign positive + b result_fs_d + +/* + * Single precision move. + */ +mov_s: + jal get_fs_s + b result_fs_s + +/* + * Double precision move. + */ +mov_d: + jal get_fs_d + b result_fs_d + +/* + * Single precision negate. + */ +neg_s: + jal get_fs_s + xor t0, t0, 1 # reverse sign + b result_fs_s + +/* + * Double precision negate. + */ +neg_d: + jal get_fs_d + xor t0, t0, 1 # reverse sign + b result_fs_d + +/* + * Convert double to single. + */ +cvt_s_d: + jal get_fs_d + bne t1, DEXP_INF, 1f # is FS an infinity? + li t1, SEXP_INF # convert to single + sll t2, t2, 3 # convert D fraction to S + srl t8, t3, 32 - 3 + or t2, t2, t8 + b result_fs_s +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_s # result=0 +1: + jal renorm_fs_d + subu t1, t1, 3 # correct exp for shift below + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias exponent + or t2, t2, DIMPL_ONE # add implied one bit +3: + sll t2, t2, 3 # convert D fraction to S + srl t8, t3, 32 - 3 + or t2, t2, t8 + sll t8, t3, 3 + b norm_noshift_s + +/* + * Convert integer to single. + */ +cvt_s_w: + jal get_fs_int + bne t2, zero, 1f # check for zero + move t1, zero + b result_fs_s +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ +1: + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count leading zeros + li t1, 23 # init exponent + subu t1, t1, t9 # compute exponent + beq t9, zero, 1f + li v0, 32 + blt t9, zero, 2f # if shift < 0, shift right + subu v0, v0, t9 + sll t2, t2, t9 # shift left +1: + add t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + b result_fs_s +2: + negu t9 # shift right by t9 + subu v0, v0, t9 + sll t8, t2, v0 # save bits shifted out + srl t2, t2, t9 + b norm_noshift_s + +/* + * Convert single to double. + */ +cvt_d_s: + jal get_fs_s + move t3, zero + bne t1, SEXP_INF, 1f # is FS an infinity? + li t1, DEXP_INF # convert to double + b result_fs_d +1: + bne t1, zero, 2f # is FS denormalized or zero? + beq t2, zero, result_fs_d # is FS zero? + jal renorm_fs_s + move t8, zero + b norm_d +2: + addu t1, t1, DEXP_BIAS - SEXP_BIAS # bias exponent correctly + sll t3, t2, 32 - 3 # convert S fraction to D + srl t2, t2, 3 + b result_fs_d + +/* + * Convert integer to double. + */ +cvt_d_w: + jal get_fs_int + bne t2, zero, 1f # check for zero + move t1, zero # result=0 + move t3, zero + b result_fs_d +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ +1: + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count leading zeros + li t1, DEXP_BIAS + 20 # init exponent + subu t1, t1, t9 # compute exponent + beq t9, zero, 1f + li v0, 32 + blt t9, zero, 2f # if shift < 0, shift right + subu v0, v0, t9 + sll t2, t2, t9 # shift left +1: + and t2, t2, ~DIMPL_ONE # clear implied one bit + move t3, zero + b result_fs_d +2: + negu t9 # shift right by t9 + subu v0, v0, t9 + sll t3, t2, v0 + srl t2, t2, t9 + and t2, t2, ~DIMPL_ONE # clear implied one bit + b result_fs_d + +/* + * Convert single to integer. + */ +cvt_w_s: + jal get_fs_s + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, invalid_w # invalid conversion +1: + bne t1, zero, 1f # is FS zero? + beq t2, zero, result_fs_w # result is zero + move t2, zero # result is an inexact zero + b inexact_w +1: + subu t1, t1, SEXP_BIAS # unbias exponent + or t2, t2, SIMPL_ONE # add implied one bit + sll t3, t2, 32 - 3 # convert S fraction to D + srl t2, t2, 3 + b cvt_w + +/* + * Convert double to integer. + */ +cvt_w_d: + jal get_fs_d + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, invalid_w # invalid conversion + bne t3, zero, invalid_w # invalid conversion +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_w # result is zero +1: + move t2, zero # result is an inexact zero + b inexact_w +2: + subu t1, t1, DEXP_BIAS # unbias exponent + or t2, t2, DIMPL_ONE # add implied one bit +cvt_w: + blt t1, WEXP_MIN, underflow_w # is exponent too small? + li v0, WEXP_MAX+1 + bgt t1, v0, overflow_w # is exponent too large? + bne t1, v0, 1f # special check for INT_MIN + beq t0, zero, overflow_w # if positive, overflow + bne t2, DIMPL_ONE, overflow_w + bne t3, zero, overflow_w + li t2, INT_MIN # result is INT_MIN + b result_fs_w +1: + subu v0, t1, 20 # compute amount to shift + beq v0, zero, 2f # is shift needed? + li v1, 32 + blt v0, zero, 1f # if shift < 0, shift right + subu v1, v1, v0 # shift left + sll t2, t2, v0 + srl t9, t3, v1 # save bits shifted out of t3 + or t2, t2, t9 # and put into t2 + sll t3, t3, v0 # shift FSs fraction + b 2f +1: + negu v0 # shift right by v0 + subu v1, v1, v0 + sll t8, t3, v1 # save bits shifted out + sltu t8, zero, t8 # dont lose any ones + srl t3, t3, v0 # shift FSs fraction + or t3, t3, t8 + sll t9, t2, v1 # save bits shifted out of t2 + or t3, t3, t9 # and put into t3 + srl t2, t2, v0 +/* + * round result (t0 is sign, t2 is integer part, t3 is fractional part). + */ +2: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t3, zero, 5f # if no fraction bits, continue + addu t2, t2, 1 # add rounding bit + blt t2, zero, overflow_w # overflow? + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t3 # add remainder + sltu v1, v0, t3 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result + blt t2, zero, overflow_w # overflow? +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + beq t0, zero, 1f # result positive? + negu t2 # convert to negative integer +1: + beq t3, zero, result_fs_w # is result exact? +/* + * Handle inexact exception. + */ +inexact_w: + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b result_fs_w + +/* + * Conversions to integer which overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an invalid exception. + */ +overflow_w: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + bne v0, zero, fpe_trap + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, inexact_w # inexact traps enabled? + b invalid_w + +/* + * Conversions to integer which underflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an invalid exception. + */ +underflow_w: + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + and v0, a1, FPC_ENABLE_UNDERFLOW + bne v0, zero, fpe_trap + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, inexact_w # inexact traps enabled? + b invalid_w + +/* + * Compare single. + */ +cmp_s: + jal get_cmp_s + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, unordered # FS is a NAN +1: + bne t5, SEXP_INF, 2f # is FT an infinity? + bne t6, zero, unordered # FT is a NAN +2: + sll t1, t1, 23 # reassemble exp & frac + or t1, t1, t2 + sll t5, t5, 23 # reassemble exp & frac + or t5, t5, t6 + beq t0, zero, 1f # is FS positive? + negu t1 +1: + beq t4, zero, 1f # is FT positive? + negu t5 +1: + li v0, COND_LESS + blt t1, t5, test_cond # is FS < FT? + li v0, COND_EQUAL + beq t1, t5, test_cond # is FS == FT? + move v0, zero # FS > FT + b test_cond + +/* + * Compare double. + */ +cmp_d: + jal get_cmp_d + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, unordered + bne t3, zero, unordered # FS is a NAN +1: + bne t5, DEXP_INF, 2f # is FT an infinity? + bne t6, zero, unordered + bne t7, zero, unordered # FT is a NAN +2: + sll t1, t1, 20 # reassemble exp & frac + or t1, t1, t2 + sll t5, t5, 20 # reassemble exp & frac + or t5, t5, t6 + beq t0, zero, 1f # is FS positive? + not t3 # negate t1,t3 + not t1 + addu t3, t3, 1 + seq v0, t3, zero # compute carry + addu t1, t1, v0 +1: + beq t4, zero, 1f # is FT positive? + not t7 # negate t5,t7 + not t5 + addu t7, t7, 1 + seq v0, t7, zero # compute carry + addu t5, t5, v0 +1: + li v0, COND_LESS + blt t1, t5, test_cond # is FS(MSW) < FT(MSW)? + move v0, zero + bne t1, t5, test_cond # is FS(MSW) > FT(MSW)? + li v0, COND_LESS + bltu t3, t7, test_cond # is FS(LSW) < FT(LSW)? + li v0, COND_EQUAL + beq t3, t7, test_cond # is FS(LSW) == FT(LSW)? + move v0, zero # FS > FT +test_cond: + and v0, v0, a0 # condition match instruction? +set_cond: + bne v0, zero, 1f + and a1, a1, ~FPC_COND_BIT # clear condition bit + b 2f +1: + or a1, a1, FPC_COND_BIT # set condition bit +2: + ctc1 a1, FPC_CSR # save condition bit + b done + +unordered: + and v0, a0, COND_UNORDERED # this cmp match unordered? + bne v0, zero, 1f + and a1, a1, ~FPC_COND_BIT # clear condition bit + b 2f +1: + or a1, a1, FPC_COND_BIT # set condition bit +2: + and v0, a0, COND_SIGNAL + beq v0, zero, 1f # is this a signaling cmp? + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap +1: + ctc1 a1, FPC_CSR # save condition bit + b done + +/* + * Determine the amount to shift the fraction in order to restore the + * normalized position. After that, round and handle exceptions. + */ +norm_s: + move v0, t2 + move t9, zero # t9 = num of leading zeros + bne t2, zero, 1f + move v0, t8 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t8 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count leading zeros + subu t1, t1, t9 # adjust the exponent + beq t9, zero, norm_noshift_s + li v1, 32 + blt t9, zero, 1f # if shift < 0, shift right + subu v1, v1, t9 + sll t2, t2, t9 # shift t2,t8 left + srl v0, t8, v1 # save bits shifted out + or t2, t2, v0 + sll t8, t8, t9 + b norm_noshift_s +1: + negu t9 # shift t2,t8 right by t9 + subu v1, v1, t9 + sll v0, t8, v1 # save bits shifted out + sltu v0, zero, v0 # be sure to save any one bits + srl t8, t8, t9 + or t8, t8, v0 + sll v0, t2, v1 # save bits shifted out + or t8, t8, v0 + srl t2, t2, t9 +norm_noshift_s: + move t5, t1 # save unrounded exponent + move t6, t2 # save unrounded fraction + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t2, t2, 1 # add rounding bit + bne t2, SIMPL_ONE<<1, 5f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result + bne t2, SIMPL_ONE<<1, 4f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + bgt t1, SEXP_MAX, overflow_s # overflow? + blt t1, SEXP_MIN, underflow_s # underflow? + bne t8, zero, inexact_s # is result inexact? + addu t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + b result_fs_s + +/* + * Handle inexact exception. + */ +inexact_s: + addu t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit +inexact_nobias_s: + jal set_fd_s # save result + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an infinity. + */ +overflow_s: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + beq v0, zero, 1f + subu t1, t1, 192 # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + jal set_fd_s # save result + b fpe_trap +1: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 2f # round to +infinity + bne t0, zero, 3f +1: + li t1, SEXP_MAX # result is max finite + li t2, 0x007fffff + b inexact_s +2: + bne t0, zero, 1b +3: + li t1, SEXP_MAX + 1 # result is infinity + move t2, zero + b inexact_s + +/* + * In this implementation, "tininess" is detected "after rounding" and + * "loss of accuracy" is detected as "an inexact result". + */ +underflow_s: + and v0, a1, FPC_ENABLE_UNDERFLOW + beq v0, zero, 1f +/* + * Underflow is enabled so compute the result and trap. + */ + addu t1, t1, 192 # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + jal set_fd_s # save result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + b fpe_trap +/* + * Underflow is not enabled so compute the result, + * signal inexact result (if it is) and trap (if enabled). + */ +1: + move t1, t5 # get unrounded exponent + move t2, t6 # get unrounded fraction + li t9, SEXP_MIN # compute shift amount + subu t9, t9, t1 # shift t2,t8 right by t9 + blt t9, SFRAC_BITS+2, 3f # shift all the bits out? + move t1, zero # result is inexact zero + move t2, zero + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW +/* + * Now round the zero result. + * Only need to worry about rounding to +- infinity when the sign matches. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, inexact_nobias_s # round to nearest + beq v0, FPC_ROUND_RZ, inexact_nobias_s # round to zero + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, inexact_nobias_s # if sign is positive, truncate + b 2f +1: + bne t0, zero, inexact_nobias_s # if sign is negative, truncate +2: + addu t2, t2, 1 # add rounding bit + b inexact_nobias_s +3: + li v1, 32 + subu v1, v1, t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t2, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t2, t2, t9 +/* + * Now round the denormalized result. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t2, t2, 1 # add rounding bit + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + move t1, zero # denorm or zero exponent + jal set_fd_s # save result + beq t8, zero, done # check for exact result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Determine the amount to shift the fraction in order to restore the + * normalized position. After that, round and handle exceptions. + */ +norm_d: + move v0, t2 + move t9, zero # t9 = num of leading zeros + bne t2, zero, 1f + move v0, t3 + addu t9, 32 + bne t3, zero, 1f + move v0, t8 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t3,t8 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count leading zeros + subu t1, t1, t9 # adjust the exponent + beq t9, zero, norm_noshift_d + li v1, 32 + blt t9, zero, 2f # if shift < 0, shift right + blt t9, v1, 1f # shift by < 32? + subu t9, t9, v1 # shift by >= 32 + subu v1, v1, t9 + sll t2, t3, t9 # shift left by t9 + srl v0, t8, v1 # save bits shifted out + or t2, t2, v0 + sll t3, t8, t9 + move t8, zero + b norm_noshift_d +1: + subu v1, v1, t9 + sll t2, t2, t9 # shift left by t9 + srl v0, t3, v1 # save bits shifted out + or t2, t2, v0 + sll t3, t3, t9 + srl v0, t8, v1 # save bits shifted out + or t3, t3, v0 + sll t8, t8, t9 + b norm_noshift_d +2: + negu t9 # shift right by t9 + subu v1, v1, t9 # (known to be < 32 bits) + sll v0, t8, v1 # save bits shifted out + sltu v0, zero, v0 # be sure to save any one bits + srl t8, t8, t9 + or t8, t8, v0 + sll v0, t3, v1 # save bits shifted out + or t8, t8, v0 + srl t3, t3, t9 + sll v0, t2, v1 # save bits shifted out + or t3, t3, v0 + srl t2, t2, t9 +norm_noshift_d: + move t5, t1 # save unrounded exponent + move t6, t2 # save unrounded fraction (MS) + move t7, t3 # save unrounded fraction (LS) + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 5f # branch if no carry + addu t2, t2, 1 # add carry + bne t2, DIMPL_ONE<<1, 5f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # branch if no carry + addu t3, t3, 1 # add carry + bne t3, zero, 4f # branch if no carry + addu t2, t2, 1 # add carry to result + bne t2, DIMPL_ONE<<1, 4f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction +4: + bne v0, zero, 5f # if rounded remainder is zero + and t3, t3, ~1 # clear LSB (round to nearest) +5: + bgt t1, DEXP_MAX, overflow_d # overflow? + blt t1, DEXP_MIN, underflow_d # underflow? + bne t8, zero, inexact_d # is result inexact? + addu t1, t1, DEXP_BIAS # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + b result_fs_d + +/* + * Handle inexact exception. + */ +inexact_d: + addu t1, t1, DEXP_BIAS # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit +inexact_nobias_d: + jal set_fd_d # save result + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an infinity. + */ +overflow_d: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + beq v0, zero, 1f + subu t1, t1, 1536 # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + jal set_fd_d # save result + b fpe_trap +1: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 2f # round to +infinity + bne t0, zero, 3f +1: + li t1, DEXP_MAX # result is max finite + li t2, 0x000fffff + li t3, 0xffffffff + b inexact_d +2: + bne t0, zero, 1b +3: + li t1, DEXP_MAX + 1 # result is infinity + move t2, zero + move t3, zero + b inexact_d + +/* + * In this implementation, "tininess" is detected "after rounding" and + * "loss of accuracy" is detected as "an inexact result". + */ +underflow_d: + and v0, a1, FPC_ENABLE_UNDERFLOW + beq v0, zero, 1f +/* + * Underflow is enabled so compute the result and trap. + */ + addu t1, t1, 1536 # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + jal set_fd_d # save result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + b fpe_trap +/* + * Underflow is not enabled so compute the result, + * signal inexact result (if it is) and trap (if enabled). + */ +1: + move t1, t5 # get unrounded exponent + move t2, t6 # get unrounded fraction (MS) + move t3, t7 # get unrounded fraction (LS) + li t9, DEXP_MIN # compute shift amount + subu t9, t9, t1 # shift t2,t8 right by t9 + blt t9, DFRAC_BITS+2, 3f # shift all the bits out? + move t1, zero # result is inexact zero + move t2, zero + move t3, zero + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW +/* + * Now round the zero result. + * Only need to worry about rounding to +- infinity when the sign matches. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, inexact_nobias_d # round to nearest + beq v0, FPC_ROUND_RZ, inexact_nobias_d # round to zero + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, inexact_nobias_d # if sign is positive, truncate + b 2f +1: + bne t0, zero, inexact_nobias_d # if sign is negative, truncate +2: + addu t3, t3, 1 # add rounding bit + b inexact_nobias_d +3: + li v1, 32 + blt t9, v1, 1f # shift by < 32? + subu t9, t9, v1 # shift right by >= 32 + subu v1, v1, t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t2, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t3, t2, t9 + move t2, zero + b 2f +1: + subu v1, v1, t9 # shift right by t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t3, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t3, t3, t9 + sll v0, t2, v1 # save bits shifted out + or t3, t3, v0 + srl t2, t2, t9 +/* + * Now round the denormalized result. + */ +2: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 5f # if no carry, continue + addu t2, t2, 1 # add carry + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry +4: + bne v0, zero, 5f # if rounded remainder is zero + and t3, t3, ~1 # clear LSB (round to nearest) +5: + move t1, zero # denorm or zero exponent + jal set_fd_d # save result + beq t8, zero, done # check for exact result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is a quiet NAN. + */ +invalid_s: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + move t0, zero # result is a quiet NAN + li t1, SEXP_INF + li t2, SQUIET_NAN + jal set_fd_s # save result (in t0,t1,t2) + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is a quiet NAN. + */ +invalid_d: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + move t0, zero # result is a quiet NAN + li t1, DEXP_INF + li t2, DQUIET_NAN0 + li t3, DQUIET_NAN1 + jal set_fd_d # save result (in t0,t1,t2,t3) + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is INT_MAX or INT_MIN. + */ +invalid_w: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + bne t0, zero, 1f + li t2, INT_MAX # result is INT_MAX + b result_fs_w +1: + li t2, INT_MIN # result is INT_MIN + b result_fs_w + +/* + * Trap if the hardware should have handled this case. + */ +fpe_trap: + move a2, a1 # code = FP CSR + ctc1 a1, FPC_CSR # save exceptions + break 0 + +/* + * Send an illegal instruction signal to the current process. + */ +ill: + ctc1 a1, FPC_CSR # save exceptions + move a2, a0 # code = FP instruction + break 0 + +result_ft_s: + move t0, t4 # result is FT + move t1, t5 + move t2, t6 +result_fs_s: # result is FS + jal set_fd_s # save result (in t0,t1,t2) + b done + +result_fs_w: + jal set_fd_word # save result (in t2) + b done + +result_ft_d: + move t0, t4 # result is FT + move t1, t5 + move t2, t6 + move t3, t7 +result_fs_d: # result is FS + jal set_fd_d # save result (in t0,t1,t2,t3) + +done: + lw ra, STAND_RA_OFFSET(sp) + addu sp, sp, STAND_FRAME_SIZE + j ra +END(MachEmulateFP) + +/*---------------------------------------------------------------------------- + * get_fs_int -- + * + * Read (integer) the FS register (bits 15-11). + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the sign + * t2 contains the fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_fs_int) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_int_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_int_tbl: + .word get_fs_int_f0 + .word get_fs_int_f2 + .word get_fs_int_f4 + .word get_fs_int_f6 + .word get_fs_int_f8 + .word get_fs_int_f10 + .word get_fs_int_f12 + .word get_fs_int_f14 + .word get_fs_int_f16 + .word get_fs_int_f18 + .word get_fs_int_f20 + .word get_fs_int_f22 + .word get_fs_int_f24 + .word get_fs_int_f26 + .word get_fs_int_f28 + .word get_fs_int_f30 + .text + +get_fs_int_f0: + mfc1 t2, $f0 + b get_fs_int_done +get_fs_int_f2: + mfc1 t2, $f2 + b get_fs_int_done +get_fs_int_f4: + mfc1 t2, $f4 + b get_fs_int_done +get_fs_int_f6: + mfc1 t2, $f6 + b get_fs_int_done +get_fs_int_f8: + mfc1 t2, $f8 + b get_fs_int_done +get_fs_int_f10: + mfc1 t2, $f10 + b get_fs_int_done +get_fs_int_f12: + mfc1 t2, $f12 + b get_fs_int_done +get_fs_int_f14: + mfc1 t2, $f14 + b get_fs_int_done +get_fs_int_f16: + mfc1 t2, $f16 + b get_fs_int_done +get_fs_int_f18: + mfc1 t2, $f18 + b get_fs_int_done +get_fs_int_f20: + mfc1 t2, $f20 + b get_fs_int_done +get_fs_int_f22: + mfc1 t2, $f22 + b get_fs_int_done +get_fs_int_f24: + mfc1 t2, $f24 + b get_fs_int_done +get_fs_int_f26: + mfc1 t2, $f26 + b get_fs_int_done +get_fs_int_f28: + mfc1 t2, $f28 + b get_fs_int_done +get_fs_int_f30: + mfc1 t2, $f30 +get_fs_int_done: + srl t0, t2, 31 # init the sign bit + bge t2, zero, 1f + negu t2 +1: + j ra +END(get_fs_int) + +/*---------------------------------------------------------------------------- + * get_ft_fs_s -- + * + * Read (single precision) the FT register (bits 20-16) and + * the FS register (bits 15-11) and break up into fields. + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the FS sign + * t1 contains the FS (biased) exponent + * t2 contains the FS fraction + * t4 contains the FT sign + * t5 contains the FT (biased) exponent + * t6 contains the FT fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_ft_fs_s) + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, get_ft_s_tbl(a3) # switch on register number + j a3 + + .rdata +get_ft_s_tbl: + .word get_ft_s_f0 + .word get_ft_s_f2 + .word get_ft_s_f4 + .word get_ft_s_f6 + .word get_ft_s_f8 + .word get_ft_s_f10 + .word get_ft_s_f12 + .word get_ft_s_f14 + .word get_ft_s_f16 + .word get_ft_s_f18 + .word get_ft_s_f20 + .word get_ft_s_f22 + .word get_ft_s_f24 + .word get_ft_s_f26 + .word get_ft_s_f28 + .word get_ft_s_f30 + .text + +get_ft_s_f0: + mfc1 t4, $f0 + b get_ft_s_done +get_ft_s_f2: + mfc1 t4, $f2 + b get_ft_s_done +get_ft_s_f4: + mfc1 t4, $f4 + b get_ft_s_done +get_ft_s_f6: + mfc1 t4, $f6 + b get_ft_s_done +get_ft_s_f8: + mfc1 t4, $f8 + b get_ft_s_done +get_ft_s_f10: + mfc1 t4, $f10 + b get_ft_s_done +get_ft_s_f12: + mfc1 t4, $f12 + b get_ft_s_done +get_ft_s_f14: + mfc1 t4, $f14 + b get_ft_s_done +get_ft_s_f16: + mfc1 t4, $f16 + b get_ft_s_done +get_ft_s_f18: + mfc1 t4, $f18 + b get_ft_s_done +get_ft_s_f20: + mfc1 t4, $f20 + b get_ft_s_done +get_ft_s_f22: + mfc1 t4, $f22 + b get_ft_s_done +get_ft_s_f24: + mfc1 t4, $f24 + b get_ft_s_done +get_ft_s_f26: + mfc1 t4, $f26 + b get_ft_s_done +get_ft_s_f28: + mfc1 t4, $f28 + b get_ft_s_done +get_ft_s_f30: + mfc1 t4, $f30 +get_ft_s_done: + srl t5, t4, 23 # get exponent + and t5, t5, 0xFF + and t6, t4, 0x7FFFFF # get fraction + srl t4, t4, 31 # get sign + bne t5, SEXP_INF, 1f # is it a signaling NAN? + and v0, t6, SSIGNAL_NAN + bne v0, zero, invalid_s +1: + /* fall through to get FS */ + +/*---------------------------------------------------------------------------- + * get_fs_s -- + * + * Read (single precision) the FS register (bits 15-11) and + * break up into fields. + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * + *---------------------------------------------------------------------------- + */ +ALEAF(get_fs_s) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_s_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_s_tbl: + .word get_fs_s_f0 + .word get_fs_s_f2 + .word get_fs_s_f4 + .word get_fs_s_f6 + .word get_fs_s_f8 + .word get_fs_s_f10 + .word get_fs_s_f12 + .word get_fs_s_f14 + .word get_fs_s_f16 + .word get_fs_s_f18 + .word get_fs_s_f20 + .word get_fs_s_f22 + .word get_fs_s_f24 + .word get_fs_s_f26 + .word get_fs_s_f28 + .word get_fs_s_f30 + .text + +get_fs_s_f0: + mfc1 t0, $f0 + b get_fs_s_done +get_fs_s_f2: + mfc1 t0, $f2 + b get_fs_s_done +get_fs_s_f4: + mfc1 t0, $f4 + b get_fs_s_done +get_fs_s_f6: + mfc1 t0, $f6 + b get_fs_s_done +get_fs_s_f8: + mfc1 t0, $f8 + b get_fs_s_done +get_fs_s_f10: + mfc1 t0, $f10 + b get_fs_s_done +get_fs_s_f12: + mfc1 t0, $f12 + b get_fs_s_done +get_fs_s_f14: + mfc1 t0, $f14 + b get_fs_s_done +get_fs_s_f16: + mfc1 t0, $f16 + b get_fs_s_done +get_fs_s_f18: + mfc1 t0, $f18 + b get_fs_s_done +get_fs_s_f20: + mfc1 t0, $f20 + b get_fs_s_done +get_fs_s_f22: + mfc1 t0, $f22 + b get_fs_s_done +get_fs_s_f24: + mfc1 t0, $f24 + b get_fs_s_done +get_fs_s_f26: + mfc1 t0, $f26 + b get_fs_s_done +get_fs_s_f28: + mfc1 t0, $f28 + b get_fs_s_done +get_fs_s_f30: + mfc1 t0, $f30 +get_fs_s_done: + srl t1, t0, 23 # get exponent + and t1, t1, 0xFF + and t2, t0, 0x7FFFFF # get fraction + srl t0, t0, 31 # get sign + bne t1, SEXP_INF, 1f # is it a signaling NAN? + and v0, t2, SSIGNAL_NAN + bne v0, zero, invalid_s +1: + j ra +END(get_ft_fs_s) + +/*---------------------------------------------------------------------------- + * get_ft_fs_d -- + * + * Read (double precision) the FT register (bits 20-16) and + * the FS register (bits 15-11) and break up into fields. + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the FS sign + * t1 contains the FS (biased) exponent + * t2 contains the FS fraction + * t3 contains the FS remaining fraction + * t4 contains the FT sign + * t5 contains the FT (biased) exponent + * t6 contains the FT fraction + * t7 contains the FT remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_ft_fs_d) + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, get_ft_d_tbl(a3) # switch on register number + j a3 + + .rdata +get_ft_d_tbl: + .word get_ft_d_f0 + .word get_ft_d_f2 + .word get_ft_d_f4 + .word get_ft_d_f6 + .word get_ft_d_f8 + .word get_ft_d_f10 + .word get_ft_d_f12 + .word get_ft_d_f14 + .word get_ft_d_f16 + .word get_ft_d_f18 + .word get_ft_d_f20 + .word get_ft_d_f22 + .word get_ft_d_f24 + .word get_ft_d_f26 + .word get_ft_d_f28 + .word get_ft_d_f30 + .text + +get_ft_d_f0: + mfc1 t7, $f0 + mfc1 t4, $f1 + b get_ft_d_done +get_ft_d_f2: + mfc1 t7, $f2 + mfc1 t4, $f3 + b get_ft_d_done +get_ft_d_f4: + mfc1 t7, $f4 + mfc1 t4, $f5 + b get_ft_d_done +get_ft_d_f6: + mfc1 t7, $f6 + mfc1 t4, $f7 + b get_ft_d_done +get_ft_d_f8: + mfc1 t7, $f8 + mfc1 t4, $f9 + b get_ft_d_done +get_ft_d_f10: + mfc1 t7, $f10 + mfc1 t4, $f11 + b get_ft_d_done +get_ft_d_f12: + mfc1 t7, $f12 + mfc1 t4, $f13 + b get_ft_d_done +get_ft_d_f14: + mfc1 t7, $f14 + mfc1 t4, $f15 + b get_ft_d_done +get_ft_d_f16: + mfc1 t7, $f16 + mfc1 t4, $f17 + b get_ft_d_done +get_ft_d_f18: + mfc1 t7, $f18 + mfc1 t4, $f19 + b get_ft_d_done +get_ft_d_f20: + mfc1 t7, $f20 + mfc1 t4, $f21 + b get_ft_d_done +get_ft_d_f22: + mfc1 t7, $f22 + mfc1 t4, $f23 + b get_ft_d_done +get_ft_d_f24: + mfc1 t7, $f24 + mfc1 t4, $f25 + b get_ft_d_done +get_ft_d_f26: + mfc1 t7, $f26 + mfc1 t4, $f27 + b get_ft_d_done +get_ft_d_f28: + mfc1 t7, $f28 + mfc1 t4, $f29 + b get_ft_d_done +get_ft_d_f30: + mfc1 t7, $f30 + mfc1 t4, $f31 +get_ft_d_done: + srl t5, t4, 20 # get exponent + and t5, t5, 0x7FF + and t6, t4, 0xFFFFF # get fraction + srl t4, t4, 31 # get sign + bne t5, DEXP_INF, 1f # is it a signaling NAN? + and v0, t6, DSIGNAL_NAN + bne v0, zero, invalid_d +1: + /* fall through to get FS */ + +/*---------------------------------------------------------------------------- + * get_fs_d -- + * + * Read (double precision) the FS register (bits 15-11) and + * break up into fields. + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +ALEAF(get_fs_d) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_d_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_d_tbl: + .word get_fs_d_f0 + .word get_fs_d_f2 + .word get_fs_d_f4 + .word get_fs_d_f6 + .word get_fs_d_f8 + .word get_fs_d_f10 + .word get_fs_d_f12 + .word get_fs_d_f14 + .word get_fs_d_f16 + .word get_fs_d_f18 + .word get_fs_d_f20 + .word get_fs_d_f22 + .word get_fs_d_f24 + .word get_fs_d_f26 + .word get_fs_d_f28 + .word get_fs_d_f30 + .text + +get_fs_d_f0: + mfc1 t3, $f0 + mfc1 t0, $f1 + b get_fs_d_done +get_fs_d_f2: + mfc1 t3, $f2 + mfc1 t0, $f3 + b get_fs_d_done +get_fs_d_f4: + mfc1 t3, $f4 + mfc1 t0, $f5 + b get_fs_d_done +get_fs_d_f6: + mfc1 t3, $f6 + mfc1 t0, $f7 + b get_fs_d_done +get_fs_d_f8: + mfc1 t3, $f8 + mfc1 t0, $f9 + b get_fs_d_done +get_fs_d_f10: + mfc1 t3, $f10 + mfc1 t0, $f11 + b get_fs_d_done +get_fs_d_f12: + mfc1 t3, $f12 + mfc1 t0, $f13 + b get_fs_d_done +get_fs_d_f14: + mfc1 t3, $f14 + mfc1 t0, $f15 + b get_fs_d_done +get_fs_d_f16: + mfc1 t3, $f16 + mfc1 t0, $f17 + b get_fs_d_done +get_fs_d_f18: + mfc1 t3, $f18 + mfc1 t0, $f19 + b get_fs_d_done +get_fs_d_f20: + mfc1 t3, $f20 + mfc1 t0, $f21 + b get_fs_d_done +get_fs_d_f22: + mfc1 t3, $f22 + mfc1 t0, $f23 + b get_fs_d_done +get_fs_d_f24: + mfc1 t3, $f24 + mfc1 t0, $f25 + b get_fs_d_done +get_fs_d_f26: + mfc1 t3, $f26 + mfc1 t0, $f27 + b get_fs_d_done +get_fs_d_f28: + mfc1 t3, $f28 + mfc1 t0, $f29 + b get_fs_d_done +get_fs_d_f30: + mfc1 t3, $f30 + mfc1 t0, $f31 +get_fs_d_done: + srl t1, t0, 20 # get exponent + and t1, t1, 0x7FF + and t2, t0, 0xFFFFF # get fraction + srl t0, t0, 31 # get sign + bne t1, DEXP_INF, 1f # is it a signaling NAN? + and v0, t2, DSIGNAL_NAN + bne v0, zero, invalid_d +1: + j ra +END(get_ft_fs_d) + +/*---------------------------------------------------------------------------- + * get_cmp_s -- + * + * Read (single precision) the FS register (bits 15-11) and + * the FT register (bits 20-16) and break up into fields. + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t4 contains the sign + * t5 contains the (biased) exponent + * t6 contains the fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_cmp_s) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, cmp_fs_s_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_fs_s_tbl: + .word cmp_fs_s_f0 + .word cmp_fs_s_f2 + .word cmp_fs_s_f4 + .word cmp_fs_s_f6 + .word cmp_fs_s_f8 + .word cmp_fs_s_f10 + .word cmp_fs_s_f12 + .word cmp_fs_s_f14 + .word cmp_fs_s_f16 + .word cmp_fs_s_f18 + .word cmp_fs_s_f20 + .word cmp_fs_s_f22 + .word cmp_fs_s_f24 + .word cmp_fs_s_f26 + .word cmp_fs_s_f28 + .word cmp_fs_s_f30 + .text + +cmp_fs_s_f0: + mfc1 t0, $f0 + b cmp_fs_s_done +cmp_fs_s_f2: + mfc1 t0, $f2 + b cmp_fs_s_done +cmp_fs_s_f4: + mfc1 t0, $f4 + b cmp_fs_s_done +cmp_fs_s_f6: + mfc1 t0, $f6 + b cmp_fs_s_done +cmp_fs_s_f8: + mfc1 t0, $f8 + b cmp_fs_s_done +cmp_fs_s_f10: + mfc1 t0, $f10 + b cmp_fs_s_done +cmp_fs_s_f12: + mfc1 t0, $f12 + b cmp_fs_s_done +cmp_fs_s_f14: + mfc1 t0, $f14 + b cmp_fs_s_done +cmp_fs_s_f16: + mfc1 t0, $f16 + b cmp_fs_s_done +cmp_fs_s_f18: + mfc1 t0, $f18 + b cmp_fs_s_done +cmp_fs_s_f20: + mfc1 t0, $f20 + b cmp_fs_s_done +cmp_fs_s_f22: + mfc1 t0, $f22 + b cmp_fs_s_done +cmp_fs_s_f24: + mfc1 t0, $f24 + b cmp_fs_s_done +cmp_fs_s_f26: + mfc1 t0, $f26 + b cmp_fs_s_done +cmp_fs_s_f28: + mfc1 t0, $f28 + b cmp_fs_s_done +cmp_fs_s_f30: + mfc1 t0, $f30 +cmp_fs_s_done: + srl t1, t0, 23 # get exponent + and t1, t1, 0xFF + and t2, t0, 0x7FFFFF # get fraction + srl t0, t0, 31 # get sign + + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, cmp_ft_s_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_ft_s_tbl: + .word cmp_ft_s_f0 + .word cmp_ft_s_f2 + .word cmp_ft_s_f4 + .word cmp_ft_s_f6 + .word cmp_ft_s_f8 + .word cmp_ft_s_f10 + .word cmp_ft_s_f12 + .word cmp_ft_s_f14 + .word cmp_ft_s_f16 + .word cmp_ft_s_f18 + .word cmp_ft_s_f20 + .word cmp_ft_s_f22 + .word cmp_ft_s_f24 + .word cmp_ft_s_f26 + .word cmp_ft_s_f28 + .word cmp_ft_s_f30 + .text + +cmp_ft_s_f0: + mfc1 t4, $f0 + b cmp_ft_s_done +cmp_ft_s_f2: + mfc1 t4, $f2 + b cmp_ft_s_done +cmp_ft_s_f4: + mfc1 t4, $f4 + b cmp_ft_s_done +cmp_ft_s_f6: + mfc1 t4, $f6 + b cmp_ft_s_done +cmp_ft_s_f8: + mfc1 t4, $f8 + b cmp_ft_s_done +cmp_ft_s_f10: + mfc1 t4, $f10 + b cmp_ft_s_done +cmp_ft_s_f12: + mfc1 t4, $f12 + b cmp_ft_s_done +cmp_ft_s_f14: + mfc1 t4, $f14 + b cmp_ft_s_done +cmp_ft_s_f16: + mfc1 t4, $f16 + b cmp_ft_s_done +cmp_ft_s_f18: + mfc1 t4, $f18 + b cmp_ft_s_done +cmp_ft_s_f20: + mfc1 t4, $f20 + b cmp_ft_s_done +cmp_ft_s_f22: + mfc1 t4, $f22 + b cmp_ft_s_done +cmp_ft_s_f24: + mfc1 t4, $f24 + b cmp_ft_s_done +cmp_ft_s_f26: + mfc1 t4, $f26 + b cmp_ft_s_done +cmp_ft_s_f28: + mfc1 t4, $f28 + b cmp_ft_s_done +cmp_ft_s_f30: + mfc1 t4, $f30 +cmp_ft_s_done: + srl t5, t4, 23 # get exponent + and t5, t5, 0xFF + and t6, t4, 0x7FFFFF # get fraction + srl t4, t4, 31 # get sign + j ra +END(get_cmp_s) + +/*---------------------------------------------------------------------------- + * get_cmp_d -- + * + * Read (double precision) the FS register (bits 15-11) and + * the FT register (bits 20-16) and break up into fields. + * This is an internal routine used by MachEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * t4 contains the sign + * t5 contains the (biased) exponent + * t6 contains the fraction + * t7 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_cmp_d) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, cmp_fs_d_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_fs_d_tbl: + .word cmp_fs_d_f0 + .word cmp_fs_d_f2 + .word cmp_fs_d_f4 + .word cmp_fs_d_f6 + .word cmp_fs_d_f8 + .word cmp_fs_d_f10 + .word cmp_fs_d_f12 + .word cmp_fs_d_f14 + .word cmp_fs_d_f16 + .word cmp_fs_d_f18 + .word cmp_fs_d_f20 + .word cmp_fs_d_f22 + .word cmp_fs_d_f24 + .word cmp_fs_d_f26 + .word cmp_fs_d_f28 + .word cmp_fs_d_f30 + .text + +cmp_fs_d_f0: + mfc1 t3, $f0 + mfc1 t0, $f1 + b cmp_fs_d_done +cmp_fs_d_f2: + mfc1 t3, $f2 + mfc1 t0, $f3 + b cmp_fs_d_done +cmp_fs_d_f4: + mfc1 t3, $f4 + mfc1 t0, $f5 + b cmp_fs_d_done +cmp_fs_d_f6: + mfc1 t3, $f6 + mfc1 t0, $f7 + b cmp_fs_d_done +cmp_fs_d_f8: + mfc1 t3, $f8 + mfc1 t0, $f9 + b cmp_fs_d_done +cmp_fs_d_f10: + mfc1 t3, $f10 + mfc1 t0, $f11 + b cmp_fs_d_done +cmp_fs_d_f12: + mfc1 t3, $f12 + mfc1 t0, $f13 + b cmp_fs_d_done +cmp_fs_d_f14: + mfc1 t3, $f14 + mfc1 t0, $f15 + b cmp_fs_d_done +cmp_fs_d_f16: + mfc1 t3, $f16 + mfc1 t0, $f17 + b cmp_fs_d_done +cmp_fs_d_f18: + mfc1 t3, $f18 + mfc1 t0, $f19 + b cmp_fs_d_done +cmp_fs_d_f20: + mfc1 t3, $f20 + mfc1 t0, $f21 + b cmp_fs_d_done +cmp_fs_d_f22: + mfc1 t3, $f22 + mfc1 t0, $f23 + b cmp_fs_d_done +cmp_fs_d_f24: + mfc1 t3, $f24 + mfc1 t0, $f25 + b cmp_fs_d_done +cmp_fs_d_f26: + mfc1 t3, $f26 + mfc1 t0, $f27 + b cmp_fs_d_done +cmp_fs_d_f28: + mfc1 t3, $f28 + mfc1 t0, $f29 + b cmp_fs_d_done +cmp_fs_d_f30: + mfc1 t3, $f30 + mfc1 t0, $f31 +cmp_fs_d_done: + srl t1, t0, 20 # get exponent + and t1, t1, 0x7FF + and t2, t0, 0xFFFFF # get fraction + srl t0, t0, 31 # get sign + + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, cmp_ft_d_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_ft_d_tbl: + .word cmp_ft_d_f0 + .word cmp_ft_d_f2 + .word cmp_ft_d_f4 + .word cmp_ft_d_f6 + .word cmp_ft_d_f8 + .word cmp_ft_d_f10 + .word cmp_ft_d_f12 + .word cmp_ft_d_f14 + .word cmp_ft_d_f16 + .word cmp_ft_d_f18 + .word cmp_ft_d_f20 + .word cmp_ft_d_f22 + .word cmp_ft_d_f24 + .word cmp_ft_d_f26 + .word cmp_ft_d_f28 + .word cmp_ft_d_f30 + .text + +cmp_ft_d_f0: + mfc1 t7, $f0 + mfc1 t4, $f1 + b cmp_ft_d_done +cmp_ft_d_f2: + mfc1 t7, $f2 + mfc1 t4, $f3 + b cmp_ft_d_done +cmp_ft_d_f4: + mfc1 t7, $f4 + mfc1 t4, $f5 + b cmp_ft_d_done +cmp_ft_d_f6: + mfc1 t7, $f6 + mfc1 t4, $f7 + b cmp_ft_d_done +cmp_ft_d_f8: + mfc1 t7, $f8 + mfc1 t4, $f9 + b cmp_ft_d_done +cmp_ft_d_f10: + mfc1 t7, $f10 + mfc1 t4, $f11 + b cmp_ft_d_done +cmp_ft_d_f12: + mfc1 t7, $f12 + mfc1 t4, $f13 + b cmp_ft_d_done +cmp_ft_d_f14: + mfc1 t7, $f14 + mfc1 t4, $f15 + b cmp_ft_d_done +cmp_ft_d_f16: + mfc1 t7, $f16 + mfc1 t4, $f17 + b cmp_ft_d_done +cmp_ft_d_f18: + mfc1 t7, $f18 + mfc1 t4, $f19 + b cmp_ft_d_done +cmp_ft_d_f20: + mfc1 t7, $f20 + mfc1 t4, $f21 + b cmp_ft_d_done +cmp_ft_d_f22: + mfc1 t7, $f22 + mfc1 t4, $f23 + b cmp_ft_d_done +cmp_ft_d_f24: + mfc1 t7, $f24 + mfc1 t4, $f25 + b cmp_ft_d_done +cmp_ft_d_f26: + mfc1 t7, $f26 + mfc1 t4, $f27 + b cmp_ft_d_done +cmp_ft_d_f28: + mfc1 t7, $f28 + mfc1 t4, $f29 + b cmp_ft_d_done +cmp_ft_d_f30: + mfc1 t7, $f30 + mfc1 t4, $f31 +cmp_ft_d_done: + srl t5, t4, 20 # get exponent + and t5, t5, 0x7FF + and t6, t4, 0xFFFFF # get fraction + srl t4, t4, 31 # get sign + j ra +END(get_cmp_d) + +/*---------------------------------------------------------------------------- + * set_fd_s -- + * + * Write (single precision) the FD register (bits 10-6). + * This is an internal routine used by MachEmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * + * set_fd_word -- + * + * Write (integer) the FD register (bits 10-6). + * This is an internal routine used by MachEmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t2 contains the integer + * + *---------------------------------------------------------------------------- + */ +LEAF(set_fd_s) + sll t0, t0, 31 # position sign + sll t1, t1, 23 # position exponent + or t2, t2, t0 + or t2, t2, t1 +ALEAF(set_fd_word) + srl a3, a0, 7 - 2 # get FD field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, set_fd_s_tbl(a3) # switch on register number + j a3 + + .rdata +set_fd_s_tbl: + .word set_fd_s_f0 + .word set_fd_s_f2 + .word set_fd_s_f4 + .word set_fd_s_f6 + .word set_fd_s_f8 + .word set_fd_s_f10 + .word set_fd_s_f12 + .word set_fd_s_f14 + .word set_fd_s_f16 + .word set_fd_s_f18 + .word set_fd_s_f20 + .word set_fd_s_f22 + .word set_fd_s_f24 + .word set_fd_s_f26 + .word set_fd_s_f28 + .word set_fd_s_f30 + .text + +set_fd_s_f0: + mtc1 t2, $f0 + j ra +set_fd_s_f2: + mtc1 t2, $f2 + j ra +set_fd_s_f4: + mtc1 t2, $f4 + j ra +set_fd_s_f6: + mtc1 t2, $f6 + j ra +set_fd_s_f8: + mtc1 t2, $f8 + j ra +set_fd_s_f10: + mtc1 t2, $f10 + j ra +set_fd_s_f12: + mtc1 t2, $f12 + j ra +set_fd_s_f14: + mtc1 t2, $f14 + j ra +set_fd_s_f16: + mtc1 t2, $f16 + j ra +set_fd_s_f18: + mtc1 t2, $f18 + j ra +set_fd_s_f20: + mtc1 t2, $f20 + j ra +set_fd_s_f22: + mtc1 t2, $f22 + j ra +set_fd_s_f24: + mtc1 t2, $f24 + j ra +set_fd_s_f26: + mtc1 t2, $f26 + j ra +set_fd_s_f28: + mtc1 t2, $f28 + j ra +set_fd_s_f30: + mtc1 t2, $f30 + j ra +END(set_fd_s) + +/*---------------------------------------------------------------------------- + * set_fd_d -- + * + * Write (double precision) the FT register (bits 10-6). + * This is an internal routine used by MachEmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(set_fd_d) + sll t0, t0, 31 # set sign + sll t1, t1, 20 # set exponent + or t0, t0, t1 + or t0, t0, t2 # set fraction + srl a3, a0, 7 - 2 # get FD field (even regs only) + and a3, a3, 0xF << 2 # mask FD field + lw a3, set_fd_d_tbl(a3) # switch on register number + j a3 + + .rdata +set_fd_d_tbl: + .word set_fd_d_f0 + .word set_fd_d_f2 + .word set_fd_d_f4 + .word set_fd_d_f6 + .word set_fd_d_f8 + .word set_fd_d_f10 + .word set_fd_d_f12 + .word set_fd_d_f14 + .word set_fd_d_f16 + .word set_fd_d_f18 + .word set_fd_d_f20 + .word set_fd_d_f22 + .word set_fd_d_f24 + .word set_fd_d_f26 + .word set_fd_d_f28 + .word set_fd_d_f30 + .text + +set_fd_d_f0: + mtc1 t3, $f0 + mtc1 t0, $f1 + j ra +set_fd_d_f2: + mtc1 t3, $f2 + mtc1 t0, $f3 + j ra +set_fd_d_f4: + mtc1 t3, $f4 + mtc1 t0, $f5 + j ra +set_fd_d_f6: + mtc1 t3, $f6 + mtc1 t0, $f7 + j ra +set_fd_d_f8: + mtc1 t3, $f8 + mtc1 t0, $f9 + j ra +set_fd_d_f10: + mtc1 t3, $f10 + mtc1 t0, $f11 + j ra +set_fd_d_f12: + mtc1 t3, $f12 + mtc1 t0, $f13 + j ra +set_fd_d_f14: + mtc1 t3, $f14 + mtc1 t0, $f15 + j ra +set_fd_d_f16: + mtc1 t3, $f16 + mtc1 t0, $f17 + j ra +set_fd_d_f18: + mtc1 t3, $f18 + mtc1 t0, $f19 + j ra +set_fd_d_f20: + mtc1 t3, $f20 + mtc1 t0, $f21 + j ra +set_fd_d_f22: + mtc1 t3, $f22 + mtc1 t0, $f23 + j ra +set_fd_d_f24: + mtc1 t3, $f24 + mtc1 t0, $f25 + j ra +set_fd_d_f26: + mtc1 t3, $f26 + mtc1 t0, $f27 + j ra +set_fd_d_f28: + mtc1 t3, $f28 + mtc1 t0, $f29 + j ra +set_fd_d_f30: + mtc1 t3, $f30 + mtc1 t0, $f31 + j ra +END(set_fd_d) + +/*---------------------------------------------------------------------------- + * renorm_fs_s -- + * + * Results: + * t1 unbiased exponent + * t2 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_fs_s) +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros + li t1, SEXP_MIN + subu t1, t1, t9 # adjust exponent + sll t2, t2, t9 + j ra +END(renorm_fs_s) + +/*---------------------------------------------------------------------------- + * renorm_fs_d -- + * + * Results: + * t1 unbiased exponent + * t2,t3 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_fs_d) +/* + * Find out how many leading zero bits are in t2,t3 and put in t9. + */ + move v0, t2 + move t9, zero + bne t2, zero, 1f + move v0, t3 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t3 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros + li t1, DEXP_MIN + subu t1, t1, t9 # adjust exponent + li v0, 32 + blt t9, v0, 1f + subu t9, t9, v0 # shift fraction left >= 32 bits + sll t2, t3, t9 + move t3, zero + j ra +1: + subu v0, v0, t9 # shift fraction left < 32 bits + sll t2, t2, t9 + srl v1, t3, v0 + or t2, t2, v1 + sll t3, t3, t9 + j ra +END(renorm_fs_d) + +/*---------------------------------------------------------------------------- + * renorm_ft_s -- + * + * Results: + * t5 unbiased exponent + * t6 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_ft_s) +/* + * Find out how many leading zero bits are in t6 and put in t9. + */ + move v0, t6 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t6 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros + li t5, SEXP_MIN + subu t5, t5, t9 # adjust exponent + sll t6, t6, t9 + j ra +END(renorm_ft_s) + +/*---------------------------------------------------------------------------- + * renorm_ft_d -- + * + * Results: + * t5 unbiased exponent + * t6,t7 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_ft_d) +/* + * Find out how many leading zero bits are in t6,t7 and put in t9. + */ + move v0, t6 + move t9, zero + bne t6, zero, 1f + move v0, t7 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t6,t7 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros + li t5, DEXP_MIN + subu t5, t5, t9 # adjust exponent + li v0, 32 + blt t9, v0, 1f + subu t9, t9, v0 # shift fraction left >= 32 bits + sll t6, t7, t9 + move t7, zero + j ra +1: + subu v0, v0, t9 # shift fraction left < 32 bits + sll t6, t6, t9 + srl v1, t7, v0 + or t6, t6, v1 + sll t7, t7, t9 + j ra +END(renorm_ft_d) diff --git a/sys/arch/arc/arc/genassym.c b/sys/arch/arc/arc/genassym.c new file mode 100644 index 00000000000..5e3be6b774a --- /dev/null +++ b/sys/arch/arc/arc/genassym.c @@ -0,0 +1,74 @@ +/* $OpenBSD: genassym.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)genassym.c 8.2 (Berkeley) 9/23/93 + * $Id: genassym.c,v 1.1 1996/06/24 09:07:20 pefo Exp $ + */ + + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/map.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/user.h> + +#include <machine/reg.h> + +main() +{ + register struct proc *p = (struct proc *)0; + register struct user *up = (struct user *)0; + register struct vmmeter *vm = (struct vmmeter *)0; + register int size, s, n; + + printf("#define\tP_FORW %d\n", &p->p_forw); + printf("#define\tP_BACK %d\n", &p->p_back); + printf("#define\tP_PRIORITY %d\n", &p->p_priority); + printf("#define\tP_ADDR %d\n", &p->p_addr); + printf("#define\tP_UPTE %d\n", p->p_md.md_upte); + printf("#define\tU_PCB_REGS %d\n", up->u_pcb.pcb_regs); + printf("#define\tU_PCB_FPREGS %d\n", &up->u_pcb.pcb_regs[F0]); + printf("#define\tU_PCB_CONTEXT %d\n", &up->u_pcb.pcb_context); + printf("#define\tU_PCB_ONFAULT %d\n", &up->u_pcb.pcb_onfault); + printf("#define\tU_PCB_SEGTAB %d\n", &up->u_pcb.pcb_segtab); + printf("#define\tVM_MIN_ADDRESS 0x%x\n", VM_MIN_ADDRESS); + printf("#define\tVM_MIN_KERNEL_ADDRESS 0x%x\n", VM_MIN_KERNEL_ADDRESS); + printf("#define\tV_SWTCH %d\n", &vm->v_swtch); + printf("#define\tSIGILL %d\n", SIGILL); + printf("#define\tSIGFPE %d\n", SIGFPE); + exit(0); +} diff --git a/sys/arch/arc/arc/locore.S b/sys/arch/arc/arc/locore.S new file mode 100644 index 00000000000..5c3e375c0d1 --- /dev/null +++ b/sys/arch/arc/arc/locore.S @@ -0,0 +1,2880 @@ +/* $OpenBSD: locore.S,v 1.1 1996/06/24 09:07:20 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Digital Equipment Corporation and Ralph Campbell. + * + * 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. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, + * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, + * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, + * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) + * + * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 + * $Id: locore.S,v 1.1 1996/06/24 09:07:20 pefo Exp $ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include <sys/errno.h> +#include <sys/syscall.h> + +#include <machine/param.h> +#include <machine/psl.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/regnum.h> +#include <machine/pte.h> + +#include "assym.h" + + .set noreorder + +/* + * Amount to take off of the stack for the benefit of the debugger. + */ +#define START_FRAME ((4 * 4) + 4 + 4) + + .globl start +start: + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mtc0 zero, COP_0_CAUSE_REG # Clear soft interrupts + +/* + * Initialize stack and call machine startup. + */ + la sp, start - START_FRAME + la gp, _gp + sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger + jal mips_init # mips_init(argc, argv, envp) + sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger + + li t0, SR_COP_1_BIT # Disable interrupts and + mtc0 t0, COP_0_STATUS_REG # enable the fp coprocessor + li sp, KERNELSTACK - START_FRAME # switch to standard stack + mfc0 t0, COP_0_PRID # read processor ID register + nop + nop # wait for new status to + nop # to be effective + nop + cfc1 t1, FPC_ID # read FPU ID register + sw t0, cpu_id # save PRID register + sw t1, fpu_id # save FPU ID register + jal main # main(regs) + move a0, zero +/* + * proc[1] == /etc/init now running here. + * Restore user registers and return. + */ + .set noat + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtlo t0 + mthi t1 + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + li a0, PSL_USERSET + mtc0 a0, COP_0_STATUS_REG # switch to user mode (when eret...) + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + eret + .set at + +/* + * Primitives + */ + +/* + * This table is indexed by u.u_pcb.pcb_onfault in trap(). + * The reason for using this table rather than storing an address in + * u.u_pcb.pcb_onfault is simply to make the code faster. + */ + .globl onfault_table + .data + .align 2 +onfault_table: + .word 0 # invalid index number +#define BADERR 1 + .word baderr +#define COPYERR 2 + .word copyerr +#define FSWBERR 3 + .word fswberr +#define FSWINTRBERR 4 + .word fswintrberr +#ifdef DEBUG +#define MDBERR 5 + .word mdberr +#endif + .text + +/* + * See if access to addr with a len type instruction causes a machine check. + * len is length of access (1=byte, 2=short, 4=long) + * + * badaddr(addr, len) + * char *addr; + * int len; + */ +LEAF(badaddr) + li v0, BADERR + bne a1, 1, 2f + sw v0, UADDR+U_PCB_ONFAULT + b 5f + lbu v0, (a0) +2: + bne a1, 2, 4f + nop + b 5f + lhu v0, (a0) +4: + lw v0, (a0) +5: + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero # made it w/o errors +baderr: + j ra + li v0, 1 # trap sends us here +END(badaddr) + +/* + * This code is copied the user's stack for returning from signal handlers + * (see sendsig() and sigreturn()). We have to compute the address + * of the sigcontext struct for the sigreturn call. + */ + .globl sigcode +sigcode: + addu a0, sp, 16 # address of sigcontext + li v0, SYS_sigreturn # sigreturn(scp) + syscall + break 0 # just in case sigreturn fails + .globl esigcode +esigcode: + +/* + * Copy a null terminated string within the kernel address space. + * Maxlength may be null if count not wanted. + * copystr(fromaddr, toaddr, maxlength, &lencopied) + * caddr_t fromaddr; + * caddr_t toaddr; + * u_int maxlength; + * u_int *lencopied; + */ +LEAF(copystr) + move t2, a2 # Save the number of bytes +1: + lbu t0, 0(a0) + subu a2, a2, 1 + beq t0, zero, 2f + sb t0, 0(a1) + addu a0, a0, 1 + bne a2, zero, 1b + addu a1, a1, 1 +2: + beq a3, zero, 3f + subu a2, t2, a2 # compute length copied + sw a2, 0(a3) +3: + j ra + move v0, zero +END(copystr) + +/* + * fillw(pat, addr, count) + */ +LEAF(fillw) +1: + addiu a2, a2, -1 + sh a0, 0(a1) + bne a2,zero, 1b + addiu a1, a1, 2 + + jr ra + nop +END(fillw) + +/* + * Copy a null terminated string from the user address space into + * the kernel address space. + * + * copyinstr(fromaddr, toaddr, maxlength, &lencopied) + * caddr_t fromaddr; + * caddr_t toaddr; + * u_int maxlength; + * u_int *lencopied; + */ +NON_LEAF(copyinstr, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a0, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal copystr + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyinstr) + +/* + * Copy a null terminated string from the kernel address space into + * the user address space. + * + * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) + * caddr_t fromaddr; + * caddr_t toaddr; + * u_int maxlength; + * u_int *lencopied; + */ +NON_LEAF(copyoutstr, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a1, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal copystr + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyoutstr) + +/* + * Copy specified amount of data from user space into the kernel + * copyin(from, to, len) + * caddr_t *from; (user source address) + * caddr_t *to; (kernel destination address) + * unsigned len; + */ +NON_LEAF(copyin, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a0, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal bcopy + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyin) + +/* + * Copy specified amount of data from kernel to the user space + * copyout(from, to, len) + * caddr_t *from; (kernel source address) + * caddr_t *to; (user destination address) + * unsigned len; + */ +NON_LEAF(copyout, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a1, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal bcopy + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyout) + +LEAF(copyerr) + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + li v0, EFAULT # return error +END(copyerr) + +/* + * Copy the kernel stack to the new process and save the current context so + * the new process will return nonzero when it is resumed by cpu_switch(). + * + * copykstack(up) + * struct user *up; + */ +LEAF(copykstack) + subu v0, sp, UADDR # compute offset into stack + addu v0, v0, a0 # v0 = new stack address + move v1, sp # v1 = old stack address + li t1, KERNELSTACK +1: + lw t0, 0(v1) # copy stack data + addu v1, v1, 4 + sw t0, 0(v0) + bne v1, t1, 1b + addu v0, v0, 4 + /* FALLTHROUGH */ +/* + * Save registers and state so we can do a longjmp later. + * Note: this only works if p != curproc since + * cpu_switch() will copy over pcb_context. + * + * savectx(up) + * struct user *up; + */ +ALEAF(savectx) + sw s0, U_PCB_CONTEXT+0(a0) + sw s1, U_PCB_CONTEXT+4(a0) + sw s2, U_PCB_CONTEXT+8(a0) + sw s3, U_PCB_CONTEXT+12(a0) + mfc0 v0, COP_0_STATUS_REG + sw s4, U_PCB_CONTEXT+16(a0) + sw s5, U_PCB_CONTEXT+20(a0) + sw s6, U_PCB_CONTEXT+24(a0) + sw s7, U_PCB_CONTEXT+28(a0) + sw sp, U_PCB_CONTEXT+32(a0) + sw s8, U_PCB_CONTEXT+36(a0) + sw ra, U_PCB_CONTEXT+40(a0) + sw v0, U_PCB_CONTEXT+44(a0) + j ra + move v0, zero +END(copykstack) + +/* + * The following primitives manipulate the run queues. _whichqs tells which + * of the 32 queues _qs have processes in them. Setrunqueue puts processes + * into queues, Remrq removes them from queues. The running process is on + * no queue, other processes are on a queue related to p->p_priority, divided + * by 4 actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ +/* + * setrunqueue(p) + * proc *p; + * + * Call should be made at splclock(), and p->p_stat should be SRUN. + */ +NON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + lw t0, P_BACK(a0) ## firewall: p->p_back must be 0 + sw ra, STAND_RA_OFFSET(sp) ## + beq t0, zero, 1f ## + lbu t0, P_PRIORITY(a0) # put on p->p_priority / 4 queue + PANIC("setrunqueue") ## +1: + li t1, 1 # compute corresponding bit + srl t0, t0, 2 # compute index into 'whichqs' + sll t1, t1, t0 + lw t2, whichqs # set corresponding bit + nop + or t2, t2, t1 + sw t2, whichqs + sll t0, t0, 3 # compute index into 'qs' + la t1, qs + addu t0, t0, t1 # t0 = qp = &qs[pri >> 2] + lw t1, P_BACK(t0) # t1 = qp->ph_rlink + sw t0, P_FORW(a0) # p->p_forw = qp + sw t1, P_BACK(a0) # p->p_back = qp->ph_rlink + sw a0, P_FORW(t1) # p->p_back->p_forw = p; + sw a0, P_BACK(t0) # qp->ph_rlink = p + j ra + addu sp, sp, STAND_FRAME_SIZE +END(setrunqueue) + +/* + * Remrq(p) + * + * Call should be made at splclock(). + */ +NON_LEAF(remrq, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + lbu t0, P_PRIORITY(a0) # get from p->p_priority / 4 queue + li t1, 1 # compute corresponding bit + srl t0, t0, 2 # compute index into 'whichqs' + lw t2, whichqs # check corresponding bit + sll t1, t1, t0 + and v0, t2, t1 + sw ra, STAND_RA_OFFSET(sp) ## + bne v0, zero, 1f ## + lw v0, P_BACK(a0) # v0 = p->p_back + PANIC("remrq") ## it wasnt recorded to be on its q +1: + lw v1, P_FORW(a0) # v1 = p->p_forw + nop + sw v1, P_FORW(v0) # p->p_back->p_forw = p->p_forw; + sw v0, P_BACK(v1) # p->p_forw->p_back = p->r_rlink + sll t0, t0, 3 # compute index into 'qs' + la v0, qs + addu t0, t0, v0 # t0 = qp = &qs[pri >> 2] + lw v0, P_FORW(t0) # check if queue empty + nop + bne v0, t0, 2f # No. qp->ph_link != qp + nop + xor t2, t2, t1 # clear corresponding bit in 'whichqs' + sw t2, whichqs +2: + sw zero, P_BACK(a0) ## for firewall checking + j ra + addu sp, sp, STAND_FRAME_SIZE +END(remrq) + +/* + * switch_exit() + * + * At exit of a process, do a cpu_switch for the last time. + * The mapping of the pcb at p->p_addr has already been deleted, + * and the memory for the pcb+stack has been freed. + * All interrupts should be blocked at this point. + */ +LEAF(switch_exit) + la v1, nullproc # save state into garbage proc + lw t0, P_UPTE+0(v1) # t0 = first u. pte + lw t1, P_UPTE+4(v1) # t1 = 2nd u. pte + li v0, UADDR # v0 = first HI entry + mtc0 zero, COP_0_TLB_INDEX # set the index register + dmtc0 v0, COP_0_TLB_HI # init high entry + dmtc0 t0, COP_0_TLB_LO0 # init low entry0 + dmtc0 t1, COP_0_TLB_LO1 # init low entry1 + nop + tlbwi # Write the TLB entry. + nop + nop + sw zero, curproc + b cpu_switch + li sp, KERNELSTACK - START_FRAME # switch to standard stack +END(switch_exit) + +/* + * When no processes are on the runq, cpu_switch branches to idle + * to wait for something to come ready. + * Note: this is really a part of cpu_switch() but defined here for kernel + * profiling. + */ +LEAF(idle) + li t0, (INT_MASK | SR_INT_ENAB) + mtc0 t0, COP_0_STATUS_REG # enable all interrupts + sw zero, curproc # set curproc NULL for stats +1: + lw t0, whichqs # look for non-empty queue + nop + beq t0, zero, 1b + nop + b sw1 + mtc0 zero, COP_0_STATUS_REG # Disable all interrupts +END(idle) + +/* + * cpu_switch() + * Find the highest priority process and resume it. + */ +NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) + sw sp, UADDR+U_PCB_CONTEXT+32 # save old sp + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + lw t2, cnt+V_SWTCH # for statistics + lw t1, whichqs # look for non-empty queue + sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()' + sw s1, UADDR+U_PCB_CONTEXT+4 + sw s2, UADDR+U_PCB_CONTEXT+8 + sw s3, UADDR+U_PCB_CONTEXT+12 + mfc0 t0, COP_0_STATUS_REG # t0 = saved status register + sw s4, UADDR+U_PCB_CONTEXT+16 + sw s5, UADDR+U_PCB_CONTEXT+20 + sw s6, UADDR+U_PCB_CONTEXT+24 + sw s7, UADDR+U_PCB_CONTEXT+28 + sw s8, UADDR+U_PCB_CONTEXT+36 + sw ra, UADDR+U_PCB_CONTEXT+40 # save return address + sw t0, UADDR+U_PCB_CONTEXT+44 # save status register + addu t2, t2, 1 + sw t2, cnt+V_SWTCH + beq t1, zero, idle # if none, idle + mtc0 zero, COP_0_STATUS_REG # Disable all interrupts +sw1: + nop # wait for intrs disabled + nop + nop + nop + lw t0, whichqs # look for non-empty queue + li t2, -1 # t2 = lowest bit set + beq t0, zero, idle # if none, idle + move t3, t0 # t3 = saved whichqs +1: + addu t2, t2, 1 + and t1, t0, 1 # bit set? + beq t1, zero, 1b + srl t0, t0, 1 # try next bit +/* + * Remove process from queue. + */ + sll t0, t2, 3 + la t1, qs + addu t0, t0, t1 # t0 = qp = &qs[highbit] + lw a0, P_FORW(t0) # a0 = p = highest pri process + nop + lw v0, P_FORW(a0) # v0 = p->p_forw + bne t0, a0, 2f # make sure something in queue + sw v0, P_FORW(t0) # qp->ph_link = p->p_forw; + PANIC("cpu_switch") # nothing in queue +2: + sw t0, P_BACK(v0) # p->p_forw->p_back = qp + bne v0, t0, 3f # queue still not empty + sw zero, P_BACK(a0) ## for firewall checking + li v1, 1 # compute bit in 'whichqs' + sll v1, v1, t2 + xor t3, t3, v1 # clear bit in 'whichqs' + sw t3, whichqs +3: +/* + * Switch to new context. + */ + sw zero, want_resched + jal pmap_alloc_tlbpid # v0 = TLB PID + move s0, a0 # BDSLOT: save p + sw s0, curproc # set curproc + lw t0, P_UPTE+0(s0) # t0 = first u. pte + lw t1, P_UPTE+4(s0) # t1 = 2nd u. pte + or v0, v0, UADDR # v0 = first HI entry +/* + * Resume process indicated by the pte's for its u struct + * NOTE: This is hard coded to UPAGES == 2. + * Also, there should be no TLB faults at this point. + */ + mtc0 zero, COP_0_TLB_INDEX # set the index register + dmtc0 v0, COP_0_TLB_HI # init high entry + dmtc0 t0, COP_0_TLB_LO0 # init low entry0 + dmtc0 t1, COP_0_TLB_LO1 # init low entry1 + nop + tlbwi # Write the TLB entry. + nop # Delay for effect + nop # Delay for effect + nop + nop +/* + * Now running on new u struct. + * Restore registers and return. + */ + lw v0, UADDR+U_PCB_CONTEXT+44 # restore kernel context + lw ra, UADDR+U_PCB_CONTEXT+40 + lw s0, UADDR+U_PCB_CONTEXT+0 + lw s1, UADDR+U_PCB_CONTEXT+4 + lw s2, UADDR+U_PCB_CONTEXT+8 + lw s3, UADDR+U_PCB_CONTEXT+12 + lw s4, UADDR+U_PCB_CONTEXT+16 + lw s5, UADDR+U_PCB_CONTEXT+20 + lw s6, UADDR+U_PCB_CONTEXT+24 + lw s7, UADDR+U_PCB_CONTEXT+28 + lw sp, UADDR+U_PCB_CONTEXT+32 + lw s8, UADDR+U_PCB_CONTEXT+36 + mtc0 v0, COP_0_STATUS_REG + j ra + li v0, 1 # possible return to 'savectx()' +END(cpu_switch) + +/* + * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to + * user text space. + * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to + * user data space. + */ +LEAF(fuword) +ALEAF(fuiword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + lw v0, 0(a0) # fetch word + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fuword) + +LEAF(fusword) +ALEAF(fuisword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + lhu v0, 0(a0) # fetch short + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fusword) + +LEAF(fubyte) +ALEAF(fuibyte) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + lbu v0, 0(a0) # fetch byte + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fubyte) + +LEAF(suword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sw a1, 0(a0) # store word + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(suword) + +/* + * Have to flush instruction cache afterwards. + */ +LEAF(suiword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sw a1, 0(a0) # store word + sw zero, UADDR+U_PCB_ONFAULT + move v0, zero + b MachFlushICache # NOTE: this should not clobber v0! + li a1, 4 # size of word +END(suiword) + +/* + * Will have to flush the instruction cache if byte merging is done in hardware. + */ +LEAF(susword) +ALEAF(suisword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sh a1, 0(a0) # store short + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(susword) + +LEAF(subyte) +ALEAF(suibyte) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sb a1, 0(a0) # store byte + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(subyte) + +LEAF(fswberr) + j ra + li v0, -1 +END(fswberr) + +/* + * fuswintr and suswintr are just like fusword and susword except that if + * the page is not in memory or would cause a trap, then we return an error. + * The important thing is to prevent sleep() and switch(). + */ +LEAF(fuswintr) + blt a0, zero, fswintrberr # make sure address is in user space + li v0, FSWINTRBERR + sw v0, UADDR+U_PCB_ONFAULT + lhu v0, 0(a0) # fetch short + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fuswintr) + +LEAF(suswintr) + blt a0, zero, fswintrberr # make sure address is in user space + li v0, FSWINTRBERR + sw v0, UADDR+U_PCB_ONFAULT + sh a1, 0(a0) # store short + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(suswintr) + +LEAF(fswintrberr) + j ra + li v0, -1 +END(fswintrberr) + +/* + * Insert 'p' after 'q'. + * _insque(p, q) + * caddr_t p, q; + */ +LEAF(_insque) + lw v0, 0(a1) # v0 = q->next + sw a1, 4(a0) # p->prev = q + sw v0, 0(a0) # p->next = q->next + sw a0, 4(v0) # q->next->prev = p + j ra + sw a0, 0(a1) # q->next = p +END(_insque) + +/* + * Remove item 'p' from queue. + * _remque(p) + * caddr_t p; + */ +LEAF(_remque) + lw v0, 0(a0) # v0 = p->next + lw v1, 4(a0) # v1 = p->prev + nop + sw v0, 0(v1) # p->prev->next = p->next + j ra + sw v1, 4(v0) # p->next->prev = p->prev +END(_remque) + +/* + * This code is copied to the TLB exception vector address to + * handle TLB translation misses. + * NOTE: This code must be relocatable and max 32 instructions!!! + * Don't check for invalid pte's here. We load them as well and + * let the processor trap to load the correct value after service. + */ + .globl MachTLBMiss +MachTLBMiss: + .set noat + dmfc0 k0, COP_0_BAD_VADDR # get the virtual address + lw k1, UADDR+U_PCB_SEGTAB # get the current segment table + bltz k0, 1f # kernel address space -> + srl k0, k0, SEGSHIFT - 2 # compute segment table index + andi k0, k0, 0x7fc # PMAP_SEGTABSIZ-1 + addu k1, k1, k0 + dmfc0 k0, COP_0_BAD_VADDR # get the virtual address + lw k1, 0(k1) # get pointer to segment map + srl k0, k0, PGSHIFT - 2 # compute segment map index + andi k0, k0, ((NPTEPG/2) - 1) << 3 + beq k1, zero, 2f # invalid segment map + addu k1, k1, k0 # index into segment map + lw k0, 0(k1) # get page PTE + lw k1, 4(k1) + dsll k0, k0, 34 + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 + dsll k1, k1, 34 + dsrl k1, k1, 34 + dmtc0 k1, COP_0_TLB_LO1 + nop + tlbwr # update TLB + nop + nop + nop + nop + nop + eret +1: + j MachTLBMissException + nop +2: + j SlowFault + nop + + .globl MachTLBMissEnd +MachTLBMissEnd: + .set at + +/* + * This code is copied to the general exception vector address to + * handle all execptions except RESET and TLBMiss. + * NOTE: This code must be relocatable!!! + */ + .globl MachException +MachException: +/* + * Find out what mode we came from and jump to the proper handler. + */ + .set noat + mfc0 k0, COP_0_STATUS_REG # Get the status register + mfc0 k1, COP_0_CAUSE_REG # Get the cause register value. + and k0, k0, SR_KSU_USER # test for user mode + # sneaky but the bits are + # with us........ + sll k0, k0, 3 # shift user bit for cause index + and k1, k1, CR_EXC_CODE # Mask out the cause bits. + or k1, k1, k0 # change index to user table +1: + la k0, machExceptionTable # get base of the jump table + addu k0, k0, k1 # Get the address of the + # function entry. Note that + # the cause is already + # shifted left by 2 bits so + # we dont have to shift. + lw k0, 0(k0) # Get the function address + nop + j k0 # Jump to the function. + nop + .set at + .globl MachExceptionEnd +MachExceptionEnd: + +/* + * We couldn't find a TLB entry. + * Find out what mode we came from and call the appropriate handler. + */ +SlowFault: + .set noat + mfc0 k0, COP_0_STATUS_REG + nop + and k0, k0, SR_KSU_USER + bne k0, zero, MachUserGenException + nop + .set at +/* + * Fall though ... + */ + +/*---------------------------------------------------------------------------- + * + * MachKernGenException -- + * + * Handle an exception from kernel mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +/* + * The kernel exception stack contains 18 saved general registers, + * the status register and the multiply lo and high registers. + * In addition, we set this up for linkage conventions. + */ +#define KERN_REG_SIZE (18 * 4) +#define KERN_REG_OFFSET (STAND_FRAME_SIZE) +#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) +#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) +#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) +#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) + +NNON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra) + .set noat +#ifdef DEBUG + la k0, mdbpcb # save registers for mdb + sw s0, (S0 * 4)(k0) + sw s1, (S1 * 4)(k0) + sw s2, (S2 * 4)(k0) + sw s3, (S3 * 4)(k0) + sw s4, (S4 * 4)(k0) + sw s5, (S5 * 4)(k0) + sw s6, (S6 * 4)(k0) + sw s7, (S7 * 4)(k0) + sw s8, (S8 * 4)(k0) + sw gp, (GP * 4)(k0) + sw sp, (SP * 4)(k0) +#endif + subu sp, sp, KERN_EXC_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + * We don't need to save s0 - s8, sp and gp because + * the compiler does it for us. + */ + sw AT, KERN_REG_OFFSET + 0(sp) + sw v0, KERN_REG_OFFSET + 4(sp) + sw v1, KERN_REG_OFFSET + 8(sp) + sw a0, KERN_REG_OFFSET + 12(sp) + mflo v0 + mfhi v1 + sw a1, KERN_REG_OFFSET + 16(sp) + sw a2, KERN_REG_OFFSET + 20(sp) + sw a3, KERN_REG_OFFSET + 24(sp) + sw t0, KERN_REG_OFFSET + 28(sp) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, KERN_REG_OFFSET + 32(sp) + sw t2, KERN_REG_OFFSET + 36(sp) + sw t3, KERN_REG_OFFSET + 40(sp) + sw t4, KERN_REG_OFFSET + 44(sp) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, KERN_REG_OFFSET + 48(sp) + sw t6, KERN_REG_OFFSET + 52(sp) + sw t7, KERN_REG_OFFSET + 56(sp) + sw t8, KERN_REG_OFFSET + 60(sp) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr. + sw t9, KERN_REG_OFFSET + 64(sp) + sw ra, KERN_REG_OFFSET + 68(sp) + sw v0, KERN_MULT_LO_OFFSET(sp) + sw v1, KERN_MULT_HI_OFFSET(sp) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + sw a0, KERN_SR_OFFSET(sp) + + mtc0 zero,COP_0_STATUS_REG # Set kernel no error level +/* + * Call the exception handler. + */ + jal trap + sw a3, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the exception. + * v0 contains the return address. + */ + mtc0 zero,COP_0_STATUS_REG # Make shure int disabled + lw a0, KERN_SR_OFFSET(sp) + lw t0, KERN_MULT_LO_OFFSET(sp) + lw t1, KERN_MULT_HI_OFFSET(sp) + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + mtlo t0 + mthi t1 + dmtc0 v0, COP_0_EXC_PC # set return address + lw AT, KERN_REG_OFFSET + 0(sp) + lw v0, KERN_REG_OFFSET + 4(sp) + lw v1, KERN_REG_OFFSET + 8(sp) + lw a0, KERN_REG_OFFSET + 12(sp) + lw a1, KERN_REG_OFFSET + 16(sp) + lw a2, KERN_REG_OFFSET + 20(sp) + lw a3, KERN_REG_OFFSET + 24(sp) + lw t0, KERN_REG_OFFSET + 28(sp) + lw t1, KERN_REG_OFFSET + 32(sp) + lw t2, KERN_REG_OFFSET + 36(sp) + lw t3, KERN_REG_OFFSET + 40(sp) + lw t4, KERN_REG_OFFSET + 44(sp) + lw t5, KERN_REG_OFFSET + 48(sp) + lw t6, KERN_REG_OFFSET + 52(sp) + lw t7, KERN_REG_OFFSET + 56(sp) + lw t8, KERN_REG_OFFSET + 60(sp) + lw t9, KERN_REG_OFFSET + 64(sp) + lw ra, KERN_REG_OFFSET + 68(sp) + addu sp, sp, KERN_EXC_FRAME_SIZE + eret # exception. + .set at +END(MachKernGenException) + +/*---------------------------------------------------------------------------- + * + * MachUserGenException -- + * + * Handle an exception from user mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save all of the registers except for the kernel temporaries in u.u_pcb. + */ + sw AT, UADDR+U_PCB_REGS+(AST * 4) + sw v0, UADDR+U_PCB_REGS+(V0 * 4) + sw v1, UADDR+U_PCB_REGS+(V1 * 4) + sw a0, UADDR+U_PCB_REGS+(A0 * 4) + mflo v0 + sw a1, UADDR+U_PCB_REGS+(A1 * 4) + sw a2, UADDR+U_PCB_REGS+(A2 * 4) + sw a3, UADDR+U_PCB_REGS+(A3 * 4) + sw t0, UADDR+U_PCB_REGS+(T0 * 4) + mfhi v1 + sw t1, UADDR+U_PCB_REGS+(T1 * 4) + sw t2, UADDR+U_PCB_REGS+(T2 * 4) + sw t3, UADDR+U_PCB_REGS+(T3 * 4) + sw t4, UADDR+U_PCB_REGS+(T4 * 4) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t5, UADDR+U_PCB_REGS+(T5 * 4) + sw t6, UADDR+U_PCB_REGS+(T6 * 4) + sw t7, UADDR+U_PCB_REGS+(T7 * 4) + sw s0, UADDR+U_PCB_REGS+(S0 * 4) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw s1, UADDR+U_PCB_REGS+(S1 * 4) + sw s2, UADDR+U_PCB_REGS+(S2 * 4) + sw s3, UADDR+U_PCB_REGS+(S3 * 4) + sw s4, UADDR+U_PCB_REGS+(S4 * 4) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr + sw s5, UADDR+U_PCB_REGS+(S5 * 4) + sw s6, UADDR+U_PCB_REGS+(S6 * 4) + sw s7, UADDR+U_PCB_REGS+(S7 * 4) + sw t8, UADDR+U_PCB_REGS+(T8 * 4) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + sw t9, UADDR+U_PCB_REGS+(T9 * 4) + sw gp, UADDR+U_PCB_REGS+(GP * 4) + sw sp, UADDR+U_PCB_REGS+(SP * 4) + sw s8, UADDR+U_PCB_REGS+(S8 * 4) + li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP + sw ra, UADDR+U_PCB_REGS+(RA * 4) + sw v0, UADDR+U_PCB_REGS+(MULLO * 4) + sw v1, UADDR+U_PCB_REGS+(MULHI * 4) + sw a0, UADDR+U_PCB_REGS+(SR * 4) + la gp, _gp # switch to kernel GP + sw a3, UADDR+U_PCB_REGS+(PC * 4) + sw a3, STAND_RA_OFFSET(sp) # for debugging + .set at +# Turn off fpu and enter kernel mode + and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_KSU_MASK | SR_INT_ENAB) + .set noat +/* + * Call the exception handler. + */ + jal trap + mtc0 t0, COP_0_STATUS_REG +/* + * Restore user registers and return. + * First disable interrupts and set exeption level. + */ + mtc0 zero, COP_0_STATUS_REG # disable int + nop + nop + nop + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtc0 a0, COP_0_STATUS_REG # still exeption level + mtlo t0 + mthi t1 + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + eret + .set at +END(MachUserGenException) + +/*---------------------------------------------------------------------------- + * + * MachKernIntr -- + * + * Handle an interrupt from kernel mode. + * Interrupts use the standard kernel stack. + * switch_exit sets up a kernel stack after exit so interrupts won't fail. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) +#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) +#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) +#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) +#define KINTR_MULT_GP_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) +#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16) + +NNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra) + .set noat + subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame + .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + * We don't need to save s0 - s8, sp and gp because + * the compiler does it for us. + */ + sw AT, KINTR_REG_OFFSET + 0(sp) + sw v0, KINTR_REG_OFFSET + 4(sp) + sw v1, KINTR_REG_OFFSET + 8(sp) + sw a0, KINTR_REG_OFFSET + 12(sp) + mflo v0 + mfhi v1 + sw a1, KINTR_REG_OFFSET + 16(sp) + sw a2, KINTR_REG_OFFSET + 20(sp) + sw a3, KINTR_REG_OFFSET + 24(sp) + sw t0, KINTR_REG_OFFSET + 28(sp) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, KINTR_REG_OFFSET + 32(sp) + sw t2, KINTR_REG_OFFSET + 36(sp) + sw t3, KINTR_REG_OFFSET + 40(sp) + sw t4, KINTR_REG_OFFSET + 44(sp) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, KINTR_REG_OFFSET + 48(sp) + sw t6, KINTR_REG_OFFSET + 52(sp) + sw t7, KINTR_REG_OFFSET + 56(sp) + sw t8, KINTR_REG_OFFSET + 60(sp) + mfc0 a2, COP_0_EXC_PC # Third arg is the pc. + sw t9, KINTR_REG_OFFSET + 64(sp) + sw ra, KINTR_REG_OFFSET + 68(sp) + sw v0, KINTR_MULT_LO_OFFSET(sp) + sw v1, KINTR_MULT_HI_OFFSET(sp) + sw a0, KINTR_SR_OFFSET(sp) + + mtc0 zero, COP_0_STATUS_REG # Reset exl, trap possible. +/* + * Call the interrupt handler. + */ + jal interrupt + sw a2, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the interrupt. + */ + mtc0 zero, COP_0_STATUS_REG # Disable interrupt + lw a0, KINTR_SR_OFFSET(sp) + lw t0, KINTR_MULT_LO_OFFSET(sp) + lw t1, KINTR_MULT_HI_OFFSET(sp) + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + mtlo t0 + mthi t1 + lw a0, STAND_RA_OFFSET(sp) + lw AT, KINTR_REG_OFFSET + 0(sp) + lw v0, KINTR_REG_OFFSET + 4(sp) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, KINTR_REG_OFFSET + 8(sp) + lw a0, KINTR_REG_OFFSET + 12(sp) + lw a1, KINTR_REG_OFFSET + 16(sp) + lw a2, KINTR_REG_OFFSET + 20(sp) + lw a3, KINTR_REG_OFFSET + 24(sp) + lw t0, KINTR_REG_OFFSET + 28(sp) + lw t1, KINTR_REG_OFFSET + 32(sp) + lw t2, KINTR_REG_OFFSET + 36(sp) + lw t3, KINTR_REG_OFFSET + 40(sp) + lw t4, KINTR_REG_OFFSET + 44(sp) + lw t5, KINTR_REG_OFFSET + 48(sp) + lw t6, KINTR_REG_OFFSET + 52(sp) + lw t7, KINTR_REG_OFFSET + 56(sp) + lw t8, KINTR_REG_OFFSET + 60(sp) + lw t9, KINTR_REG_OFFSET + 64(sp) + lw ra, KINTR_REG_OFFSET + 68(sp) + addu sp, sp, KINTR_FRAME_SIZE + eret # interrupt. + .set at +END(MachKernIntr) + +/*---------------------------------------------------------------------------- + * + * MachUserIntr -- + * + * Handle an interrupt from user mode. + * Note: we save minimal state in the u.u_pcb struct and use the standard + * kernel stack since there has to be a u page if we came from user mode. + * If there is a pending software interrupt, then save the remaining state + * and call softintr(). This is all because if we call switch() inside + * interrupt(), not all the user registers have been saved in u.u_pcb. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save the relevant user registers into the u.u_pcb struct. + * We don't need to save s0 - s8 because + * the compiler does it for us. + */ + sw AT, UADDR+U_PCB_REGS+(AST * 4) + sw v0, UADDR+U_PCB_REGS+(V0 * 4) + sw v1, UADDR+U_PCB_REGS+(V1 * 4) + sw a0, UADDR+U_PCB_REGS+(A0 * 4) + mflo v0 + mfhi v1 + sw a1, UADDR+U_PCB_REGS+(A1 * 4) + sw a2, UADDR+U_PCB_REGS+(A2 * 4) + sw a3, UADDR+U_PCB_REGS+(A3 * 4) + sw t0, UADDR+U_PCB_REGS+(T0 * 4) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, UADDR+U_PCB_REGS+(T1 * 4) + sw t2, UADDR+U_PCB_REGS+(T2 * 4) + sw t3, UADDR+U_PCB_REGS+(T3 * 4) + sw t4, UADDR+U_PCB_REGS+(T4 * 4) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, UADDR+U_PCB_REGS+(T5 * 4) + sw t6, UADDR+U_PCB_REGS+(T6 * 4) + sw t7, UADDR+U_PCB_REGS+(T7 * 4) + sw t8, UADDR+U_PCB_REGS+(T8 * 4) + mfc0 a2, COP_0_EXC_PC # Third arg is the pc. + sw t9, UADDR+U_PCB_REGS+(T9 * 4) + sw gp, UADDR+U_PCB_REGS+(GP * 4) + sw sp, UADDR+U_PCB_REGS+(SP * 4) + sw ra, UADDR+U_PCB_REGS+(RA * 4) + li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP + sw v0, UADDR+U_PCB_REGS+(MULLO * 4) + sw v1, UADDR+U_PCB_REGS+(MULHI * 4) + sw a0, UADDR+U_PCB_REGS+(SR * 4) + sw a2, UADDR+U_PCB_REGS+(PC * 4) + la gp, _gp # switch to kernel GP +# Turn off fpu and enter kernel mode + .set at + and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) + .set noat + mtc0 t0, COP_0_STATUS_REG +/* + * Call the interrupt handler. + */ + jal interrupt + sw a2, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the interrupt. + */ + mtc0 zero, COP_0_STATUS_REG + nop + nop + nop + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw v0, astpending # any pending interrupts? + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + bne v0, zero, 1f # dont restore, call softintr + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + mtlo t0 + mthi t1 + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + eret # interrupt. + +1: +/* + * We have pending software interrupts; save remaining user state in u.u_pcb. + */ + sw s0, UADDR+U_PCB_REGS+(S0 * 4) + sw s1, UADDR+U_PCB_REGS+(S1 * 4) + sw s2, UADDR+U_PCB_REGS+(S2 * 4) + sw s3, UADDR+U_PCB_REGS+(S3 * 4) + sw s4, UADDR+U_PCB_REGS+(S4 * 4) + sw s5, UADDR+U_PCB_REGS+(S5 * 4) + sw s6, UADDR+U_PCB_REGS+(S6 * 4) + sw s7, UADDR+U_PCB_REGS+(S7 * 4) + sw s8, UADDR+U_PCB_REGS+(S8 * 4) + li t0, HARD_INT_MASK | SR_INT_ENAB +/* + * Call the software interrupt handler. + */ + jal softintr + mtc0 t0, COP_0_STATUS_REG # enable interrupts (spl0) +/* + * Restore user registers and return. NOTE: interrupts are enabled. + */ + mtc0 zero, COP_0_STATUS_REG + nop + nop + nop + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtc0 a0, COP_0_STATUS_REG # this should disable interrupts + mtlo t0 + mthi t1 + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + eret + .set at +END(MachUserIntr) + +/*---------------------------------------------------------------------------- + * + * MachTLBMInvalidException -- + * + * Handle a TLB invalid exception from kernel mode in kernel space. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(MachTLBInvalidException) + .set noat + dmfc0 k0, COP_0_BAD_VADDR # get the fault address + li k1, VM_MIN_KERNEL_ADDRESS # compute index + subu k0, k0, k1 + lw k1, Sysmapsize # index within range? + srl k0, k0, PGSHIFT + sltu k1, k0, k1 + beq k1, zero, sys_stk_chk # No. check for valid stack + lw k1, Sysmap + + sll k0, k0, 2 # compute offset from index + tlbp # Probe the invalid entry + addu k1, k1, k0 + and k0, k0, 4 # check even/odd page + bne k0, zero, KernTLBIOdd + nop + + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, sys_stk_chk + sltiu k0, k0, 8 + + bne k0, zero, sys_stk_chk + lw k0, 0(k1) # get PTE entry + + dsll k0, k0, 34 # get rid of "wired" bit + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 # load PTE entry + and k0, k0, PG_V # check for valid entry + beq k0, zero, MachKernGenException # PTE invalid + lw k0, 4(k1) # get odd PTE entry + dsll k0, k0, 34 + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO1 # load PTE entry + nop + tlbwi # write TLB + nop + nop + nop + nop + nop + eret + +KernTLBIOdd: + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, sys_stk_chk + sltiu k0, k0, 8 + + bne k0, zero, sys_stk_chk + lw k0, 0(k1) # get PTE entry + + dsll k0, k0, 34 # get rid of wired bit + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO1 # save PTE entry + and k0, k0, PG_V # check for valid entry + beq k0, zero, MachKernGenException # PTE invalid + lw k0, -4(k1) # get even PTE entry + dsll k0, k0, 34 + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 # save PTE entry + nop + tlbwi # update TLB + nop + nop + nop + nop + nop + eret +END(MachTLBInvalidException) + +/*---------------------------------------------------------------------------- + * + * MachTLBMissException -- + * + * Handle a TLB miss exception from kernel mode in kernel space. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(MachTLBMissException) + .set noat + dmfc0 k0, COP_0_BAD_VADDR # get the fault address + li k1, VM_MIN_KERNEL_ADDRESS # compute index + subu k0, k0, k1 + lw k1, Sysmapsize # index within range? + srl k0, k0, PGSHIFT + sltu k1, k0, k1 + beq k1, zero, sys_stk_chk # No. check for valid stack + lw k1, Sysmap + srl k0, k0, 1 + sll k0, k0, 3 # compute offset from index + addu k1, k1, k0 + lw k0, 0(k1) # get PTE entry + lw k1, 4(k1) # get odd PTE entry + dsll k0, k0, 34 # get rid of "wired" bit + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 # load PTE entry + dsll k1, k1, 34 + dsrl k1, k1, 34 + dmtc0 k1, COP_0_TLB_LO1 # load PTE entry + nop + tlbwr # write TLB + nop + nop + nop + nop + nop + eret + +sys_stk_chk: + subu k0, sp, UADDR + 0x200 # check to see if we have a + sltiu k0, UPAGES*NBPG - 0x200 # valid kernel stack + bne k0, zero, MachKernGenException # Go panic + nop + + la a0, start - START_FRAME - 8 # set sp to a valid place + sw sp, 24(a0) + move sp, a0 + la a0, 1f + mfc0 a2, COP_0_STATUS_REG + mfc0 a3, COP_0_CAUSE_REG + dmfc0 a1, COP_0_EXC_PC + sw a2, 16(sp) + sw a3, 20(sp) + move a2, ra + jal printf + dmfc0 a3, COP_0_BAD_VADDR + .data +1: + .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" + .text + + la sp, start - START_FRAME # set sp to a valid place + PANIC("kernel stack overflow") + .set at +END(MachTLBMissException) + +/* + * Set/clear software interrupt routines. + */ + +LEAF(setsoftclock) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + or v0, v0, SOFT_INT_MASK_0 # set soft clock interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(setsoftclock) + +LEAF(clearsoftclock) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + and v0, v0, ~SOFT_INT_MASK_0 # clear soft clock interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(clearsoftclock) + +LEAF(setsoftnet) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + or v0, v0, SOFT_INT_MASK_1 # set soft net interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(setsoftnet) + +LEAF(clearsoftnet) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + and v0, v0, ~SOFT_INT_MASK_1 # clear soft net interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(clearsoftnet) + +/* + * Set/change interrupt priority routines. + */ + +LEAF(MachEnableIntr) + mfc0 v0, COP_0_STATUS_REG # read status register + nop + or v0, v0, SR_INT_ENAB + mtc0 v0, COP_0_STATUS_REG # enable all interrupts + j ra + nop +END(MachEnableIntr) + +LEAF(spl0) + mfc0 v0, COP_0_STATUS_REG # read status register + nop + or t0, v0, (INT_MASK | SR_INT_ENAB) + mtc0 t0, COP_0_STATUS_REG # enable all interrupts + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(spl0) + +LEAF(splsoftclock) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~SOFT_INT_MASK_0 # disable soft clock + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(splsoftclock) + +LEAF(splsoftnet) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(splsoftnet) + +LEAF(Mach_spl0) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_0|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(Mach_spl0) + +LEAF(Mach_spl1) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_1|SOFT_INT_MASK_0|SOFT_INT_MASK_1) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(Mach_spl1) + +LEAF(Mach_spl2) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_2|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(Mach_spl2) + +LEAF(Mach_spl3) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_3|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(Mach_spl3) + +LEAF(Mach_spl4) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_4|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(Mach_spl4) + +LEAF(Mach_spl5) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_5|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(Mach_spl5) + +/* + * We define an alternate entry point after mcount is called so it + * can be used in mcount without causeing a recursive loop. + */ +LEAF(splhigh) +ALEAF(_splhigh) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~SR_INT_ENAB # disable all interrupts + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(splhigh) + +/* + * Restore saved interrupt mask. + */ +LEAF(splx) +ALEAF(_splx) + mfc0 v0, COP_0_STATUS_REG + li t0, ~(INT_MASK | SR_INT_ENAB) + and t0, t0, v0 + or t0, t0, a0 + mtc0 t0, COP_0_STATUS_REG + nop # 3 ins to disable + j ra + nop +END(splx) + +/*---------------------------------------------------------------------------- + * + * wbflush -- + * + * Return when the write buffer is empty. + * + * wbflush() + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(wbflush) + nop + sync + j ra + nop +END(wbflush) + +/*-------------------------------------------------------------------------- + * + * MachTLBWriteIndexed -- + * + * Write the given entry into the TLB at the given index. + * + * MachTLBWriteIndexed(index, tlb) + * unsigned index; + * tlb *tlb; + * + * Results: + * None. + * + * Side effects: + * TLB entry set. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachTLBWriteIndexed) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + nop + lw a2, 8(a1) + lw a3, 12(a1) + dmfc0 t0, COP_0_TLB_HI # Save the current PID. + + dmtc0 a2, COP_0_TLB_LO0 # Set up entry low0. + dmtc0 a3, COP_0_TLB_LO1 # Set up entry low1. + lw a2, 0(a1) + lw a3, 4(a1) + mtc0 a0, COP_0_TLB_INDEX # Set the index. + dmtc0 a2, COP_0_TLB_PG_MASK # Set up entry mask. + dmtc0 a3, COP_0_TLB_HI # Set up entry high. + nop + tlbwi # Write the TLB + nop + nop + nop # Delay for effect + nop + + dmtc0 t0, COP_0_TLB_HI # Restore the PID. + nop + dmtc0 zero, COP_0_TLB_PG_MASK # Default mask value. + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(MachTLBWriteIndexed) + +/*-------------------------------------------------------------------------- + * + * MachSetPID -- + * + * Write the given pid into the TLB pid reg. + * + * MachSetPID(pid) + * int pid; + * + * Results: + * None. + * + * Side effects: + * PID set in the entry hi register. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachSetPID) + dmtc0 a0, COP_0_TLB_HI # Write the hi reg value + j ra + nop +END(MachSetPID) + +/*-------------------------------------------------------------------------- + * + * MachSetWIRED -- + * + * Write the given value into the TLB wired reg. + * + * MachSetPID(wired) + * int wired; + * + * Results: + * None. + * + * Side effects: + * WIRED set in the wired register. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachSetWIRED) + mtc0 a0, COP_0_TLB_WIRED + j ra + nop +END(MachSetWIRED) + +/*-------------------------------------------------------------------------- + * + * MachGetWIRED -- + * + * Get the value from the TLB wired reg. + * + * MachGetWIRED(void) + * + * Results: + * Value of wired reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachGetWIRED) + mfc0 v0, COP_0_TLB_WIRED + j ra + nop +END(MachGetWIRED) + +/*-------------------------------------------------------------------------- + * + * MachTLBFlush -- + * + * Flush the "random" entries from the TLB. + * Uses "wired" register to determine what register to start with. + * + * MachTLBFlush() + * + * Results: + * None. + * + * Side effects: + * The TLB is flushed. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachTLBFlush) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t1, COP_0_TLB_WIRED + li t2, VMNUM_TLB_ENTRIES + li v0, CACHED_MEMORY_ADDR # invalid address + dmfc0 t0, COP_0_TLB_HI # Save the PID + + dmtc0 v0, COP_0_TLB_HI # Mark entry high as invalid + dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry0. + dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry1. + mtc0 zero, COP_0_TLB_PG_MASK # Zero out mask entry. +/* + * Align the starting value (t1) and the upper bound (t2). + */ +1: + mtc0 t1, COP_0_TLB_INDEX # Set the index register. + addu t1, t1, 1 # Increment index. + tlbwi # Write the TLB entry. + nop + nop + bne t1, t2, 1b + nop + + dmtc0 t0, COP_0_TLB_HI # Restore the PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(MachTLBFlush) + + +/*-------------------------------------------------------------------------- + * + * MachTLBFlushAddr -- + * + * Flush any TLB entries for the given address and TLB PID. + * + * MachTLBFlushAddr(TLBhi) + * unsigned TLBhi; + * + * Results: + * None. + * + * Side effects: + * The process's page is flushed from the TLB. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachTLBFlushAddr) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + nop + li v0, (PG_HVPN | PG_ASID) + and a0, a0, v0 # Make shure valid hi value. + dmfc0 t0, COP_0_TLB_HI # Get current PID + dmtc0 a0, COP_0_TLB_HI # look for addr & PID + nop + nop + nop + tlbp # Probe for the entry. + nop + nop # Delay for effect + nop + mfc0 v0, COP_0_TLB_INDEX # See what we got + li t1, CACHED_MEMORY_ADDR # Load invalid entry. + bltz v0, 1f # index < 0 => !found + nop + dmtc0 t1, COP_0_TLB_HI # Mark entry high as invalid + + dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry. + dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry. + nop + tlbwi + nop + nop + nop + nop +1: + dmtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(MachTLBFlushAddr) + +/*-------------------------------------------------------------------------- + * + * MachTLBUpdate -- + * + * Update the TLB if highreg is found; otherwise, enter the data. + * + * MachTLBUpdate(virpageadr, lowregx) + * unsigned virpageadr, lowregx; + * + * Results: + * < 0 if loaded >= 0 if updated. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachTLBUpdate) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + and t1, a0, 0x1000 # t1 = Even/Odd flag + li v0, (PG_HVPN | PG_ASID) + and a0, a0, v0 + dmfc0 t0, COP_0_TLB_HI # Save current PID + dmtc0 a0, COP_0_TLB_HI # Init high reg + and a2, a1, PG_G # Copy global bit + nop + nop + tlbp # Probe for the entry. + dsll a1, a1, 34 + dsrl a1, a1, 34 + bne t1, zero, 2f # Decide even odd + mfc0 v0, COP_0_TLB_INDEX # See what we got +# EVEN + nop + bltz v0, 1f # index < 0 => !found + nop + + tlbr # update, read entry first + nop + nop + nop + dmtc0 a1, COP_0_TLB_LO0 # init low reg0. + nop + tlbwi # update slot found + b 4f + nop +1: + mtc0 zero, COP_0_TLB_PG_MASK # init mask. + dmtc0 a0, COP_0_TLB_HI # init high reg. + dmtc0 a1, COP_0_TLB_LO0 # init low reg0. + dmtc0 a2, COP_0_TLB_LO1 # init low reg1. + nop + tlbwr # enter into a random slot + b 4f + nop +# ODD +2: + nop + bltz v0, 3f # index < 0 => !found + nop + + tlbr # read the entry first + nop + nop + nop + dmtc0 a1, COP_0_TLB_LO1 # init low reg1. + nop + tlbwi # update slot found + b 4f + nop +3: + mtc0 zero, COP_0_TLB_PG_MASK # init mask. + dmtc0 a0, COP_0_TLB_HI # init high reg. + dmtc0 a2, COP_0_TLB_LO0 # init low reg0. + dmtc0 a1, COP_0_TLB_LO1 # init low reg1. + nop + tlbwr # enter into a random slot + +4: # Make shure pipeline + nop # advances before we + nop # uses the tlb. + nop + nop + dmtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(MachTLBUpdate) + +/*-------------------------------------------------------------------------- + * + * MachTLBRead -- + * + * Read the TLB entry. + * + * MachTLBRead(entry, tlb) + * unsigned entry; + * struct tlb *tlb; + * + * Results: + * None. + * + * Side effects: + * tlb will contain the TLB entry found. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachTLBRead) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + nop + nop + nop + dmfc0 t0, COP_0_TLB_HI # Get current PID + + mtc0 a0, COP_0_TLB_INDEX # Set the index register + nop + tlbr # Read from the TLB + nop + nop + nop + mfc0 t2, COP_0_TLB_PG_MASK # fetch the hi entry + dmfc0 t3, COP_0_TLB_HI # fetch the hi entry + dmfc0 t4, COP_0_TLB_LO0 # See what we got + dmfc0 t5, COP_0_TLB_LO1 # See what we got + dmtc0 t0, COP_0_TLB_HI # restore PID + nop + nop + nop # wait for PID active + mtc0 v1, COP_0_STATUS_REG # Restore the status register + sw t2, 0(a1) + sw t3, 4(a1) + sw t4, 8(a1) + j ra + sw t5, 12(a1) +END(MachTLBRead) + +/*-------------------------------------------------------------------------- + * + * MachTLBGetPID -- + * + * MachTLBGetPID() + * + * Results: + * Returns the current TLB pid reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(MachTLBGetPID) + dmfc0 v0, COP_0_TLB_HI # get PID + j ra + and v0, v0, VMTLB_PID # mask off PID +END(MachTLBGetPID) + + +/*---------------------------------------------------------------------------- + * + * MachSwitchFPState -- + * + * Save the current state into 'from' and restore it from 'to'. + * + * MachSwitchFPState(from, to) + * struct proc *from; + * struct user *to; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachSwitchFPState) + mfc0 t1, COP_0_STATUS_REG # Save old SR + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + + beq a0, zero, 1f # skip save if NULL pointer + nop +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + lw a0, P_ADDR(a0) # get pointer to pcb for proc + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + li t3, ~SR_COP_1_BIT + lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register + sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status + and t2, t2, t3 # clear COP_1 enable bit + sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register +/* + * Save the floating point registers. + */ + swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) + swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) + swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) + swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) + swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) + swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) + swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) + swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) + swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) + swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) + swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) + swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) + swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) + swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) + swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) + swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) + swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) + swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) + swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) + swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) + swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) + swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) + swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) + swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) + swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) + swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) + swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) + swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) + swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) + swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) + swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) + swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) + +1: +/* + * Restore the floating point registers. + */ + lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register + lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) + lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) + lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) + lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) + lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) + lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) + lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) + lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) + lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) + lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) + lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) + lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) + lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) + lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) + lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) + lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) + lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) + lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) + lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) + lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) + lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) + lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) + lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) + lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) + lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) + lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) + lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) + lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) + lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) + lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) + lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) + lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) + + and t0, t0, ~FPC_EXCEPTION_BITS + ctc1 t0, FPC_CSR + nop + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + j ra + nop +END(MachSwitchFPState) + +/*---------------------------------------------------------------------------- + * + * MachSaveCurFPState -- + * + * Save the current floating point coprocessor state. + * + * MachSaveCurFPState(p) + * struct proc *p; + * + * Results: + * None. + * + * Side effects: + * machFPCurProcPtr is cleared. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachSaveCurFPState) + lw a0, P_ADDR(a0) # get pointer to pcb for proc + mfc0 t1, COP_0_STATUS_REG # Disable interrupts and + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + sw zero, machFPCurProcPtr # indicate state has been saved +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register + li t3, ~SR_COP_1_BIT + and t2, t2, t3 # clear COP_1 enable bit + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register + sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status +/* + * Save the floating point registers. + */ + swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) + swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) + swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) + swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) + swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) + swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) + swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) + swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) + swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) + swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) + swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) + swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) + swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) + swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) + swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) + swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) + swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) + swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) + swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) + swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) + swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) + swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) + swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) + swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) + swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) + swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) + swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) + swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) + swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) + swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) + swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) + swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + j ra + nop +END(MachSaveCurFPState) + +/*---------------------------------------------------------------------------- + * + * MachFPTrap -- + * + * Handle a floating point Trap. + * + * MachFPTrap(statusReg, causeReg, pc) + * unsigned statusReg; + * unsigned causeReg; + * unsigned pc; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(MachFPTrap, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + mfc0 t0, COP_0_STATUS_REG + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + + or t1, t0, SR_COP_1_BIT + mtc0 t1, COP_0_STATUS_REG + nop + nop + nop + nop + cfc1 t1, FPC_CSR # stall til FP done + cfc1 t1, FPC_CSR # now get status + nop + sll t2, t1, (31 - 17) # unimplemented operation? + bgez t2, 3f # no, normal trap + nop +/* + * We got an unimplemented operation trap so + * fetch the instruction, compute the next PC and emulate the instruction. + */ + bgez a1, 1f # Check the branch delay bit. + nop +/* + * The instruction is in the branch delay slot so the branch will have to + * be emulated to get the resulting PC. + */ + sw a2, STAND_FRAME_SIZE + 8(sp) + li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers + move a1, a2 # second arg is instruction PC + move a2, t1 # third arg is floating point CSR + jal MachEmulateBranch # compute PC after branch + move a3, zero # fourth arg is FALSE +/* + * Now load the floating-point instruction in the branch delay slot + * to be emulated. + */ + lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc + b 2f + lw a0, 4(a2) # a0 = coproc instruction +/* + * This is not in the branch delay slot so calculate the resulting + * PC (epc + 4) into v0 and continue to MachEmulateFP(). + */ +1: + lw a0, 0(a2) # a0 = coproc instruction + addu v0, a2, 4 # v0 = next pc +2: + sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc +/* + * Check to see if the instruction to be emulated is a floating-point + * instruction. + */ + srl a3, a0, OPCODE_SHIFT + beq a3, OPCODE_C1, 4f # this should never fail + nop +/* + * Send a floating point exception signal to the current process. + */ +3: + lw a0, curproc # get current process + cfc1 a2, FPC_CSR # code = FP execptions + ctc1 zero, FPC_CSR # Clear exceptions + jal trapsignal + li a1, SIGFPE + b FPReturn + nop + +/* + * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate. + */ +4: + jal MachEmulateFP + nop + +/* + * Turn off the floating point coprocessor and return. + */ +FPReturn: + mfc0 t0, COP_0_STATUS_REG + lw ra, STAND_RA_OFFSET(sp) + and t0, t0, ~SR_COP_1_BIT + mtc0 t0, COP_0_STATUS_REG + j ra + addu sp, sp, STAND_FRAME_SIZE +END(MachFPTrap) + +/*---------------------------------------------------------------------------- + * + * MachConfigCache -- + * + * Size the caches. + * NOTE: should only be called from mach_init(). + * + * Results: + * None. + * + * Side effects: + * The size of the data cache is stored into machPrimaryDataCacheSize. + * The size of instruction cache is stored into machPrimaryInstCacheSize. + * Alignment mask for cache aliasing test is stored in machCacheAliasMask. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachConfigCache) + mfc0 v0, COP_0_CONFIG # Get configuration register + nop + srl t1, v0, 9 # Get I cache size. + and t1, 3 + li t2, 4096 + sllv t2, t2, t1 + sw t2, machPrimaryDataCacheSize + addiu t2, -1 + and t2, ~(NBPG - 1) + sw t2, machCacheAliasMask + + and t2, v0, 0x20 + srl t2, t2, 1 + addu t2, t2, 16 + sw t2, machPrimaryDataCacheLSize + + srl t1, v0, 6 # Get I cache size. + and t1, 3 + li t2, 4096 + sllv t2, t2, t1 + sw t2, machPrimaryInstCacheSize + + and t2, v0, 0x10 + addu t2, t2, 16 + sw t2, machPrimaryInstCacheLSize + j ra + nop +END(MachConfigCache) + +/*---------------------------------------------------------------------------- + * + * MachFlushCache -- + * + * Flush the caches. Assumes a line size of 16 bytes for speed. + * + * Results: + * None. + * + * Side effects: + * The contents of the caches is flushed. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachFlushCache) + lw t1, machPrimaryInstCacheSize + lw t2, machPrimaryDataCacheSize + # lw t3, machPrimaryInstCacheLSize + # lw t4, machPrimaryDataCacheLSize +/* + * Flush the instruction cache. + */ + li t0, CACHED_MEMORY_ADDR + addu t1, t0, t1 # End address + subu t1, t1, 128 +1: + cache 0, 0(t0) + cache 0, 16(t0) + cache 0, 32(t0) + cache 0, 48(t0) + cache 0, 64(t0) + cache 0, 80(t0) + cache 0, 96(t0) + cache 0, 112(t0) + bne t0, t1, 1b + addu t0, t0, 128 + +/* + * Flush the data cache. + */ + li t0, CACHED_MEMORY_ADDR + addu t1, t0, t2 # End address + subu t1, t1, 128 +1: + cache 1, 0(t0) + cache 1, 16(t0) + cache 1, 32(t0) + cache 1, 48(t0) + cache 1, 64(t0) + cache 1, 80(t0) + cache 1, 96(t0) + cache 1, 112(t0) + bne t0, t1, 1b + addu t0, t0, 128 + + j ra + nop +END(MachFlushCache) + +/*---------------------------------------------------------------------------- + * + * MachFlushICache -- + * + * void MachFlushICache(addr, len) + * vm_offset_t addr, len; + * + * Flush instruction cache for range of addr to addr + len - 1. + * The address can be any valid address so long as no TLB misses occur. + * Assumes a cache line size of 16 bytes for speed. + * + * Results: + * None. + * + * Side effects: + * The contents of the cache is flushed. + * Must not touch v0. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachFlushICache) + addu a1, 127 # Align + srl a1, a1, 7 # Number of unrolled loops +1: + cache 0, 0(a0) + cache 0, 16(a0) + cache 0, 32(a0) + cache 0, 48(a0) + cache 0, 64(a0) + cache 0, 80(a0) + cache 0, 96(a0) + cache 0, 112(a0) + addu a1, -1 + bne a1, zero, 1b + addu a0, 128 + + j ra + nop +END(MachFlushICache) + +/*---------------------------------------------------------------------------- + * + * MachFlushDCache -- + * + * void MachFlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for index range of addr to addr + len - 1. + * The address is reduced to a kseg0 index. + * + * Results: + * None. + * + * Side effects: + * The contents of the cache is written back to primary memory. + * The cache line is invalidated. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachFlushDCache) + lw a2, machPrimaryDataCacheSize + addiu a2, -1 + and a0, a0, a2 + addu a1, 127 # Align + li a2, 0x80000000 + addu a0, a0, a2 + addu a1, a1, a0 + and a0, a0, -128 + subu a1, a1, a0 + srl a1, a1, 7 # Compute number of cache lines +1: + cache 1, 0(a0) + cache 1, 16(a0) + cache 1, 32(a0) + cache 1, 48(a0) + cache 1, 64(a0) + cache 1, 80(a0) + cache 1, 96(a0) + cache 1, 112(a0) + addu a1, -1 + bne a1, zero, 1b + addu a0, 128 + + j ra + nop +END(MachFlushDCache) + +/*---------------------------------------------------------------------------- + * + * MachHitFlushDCache -- + * + * void MachHitFlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for range of addr to addr + len - 1. + * The address can be any valid viritual address as long + * as no TLB invalid traps occur. Only lines with matching + * addr is flushed. + * + * Results: + * None. + * + * Side effects: + * The contents of the cache is written back to primary memory. + * The cache line is invalidated. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachHitFlushDCache) + beq a1, zero, 2f + addu a1, 127 # Align + addu a1, a1, a0 + and a0, a0, -128 + subu a1, a1, a0 + srl a1, a1, 7 # Compute number of cache lines +1: + cache 0x15, 0(a0) + cache 0x15, 16(a0) + cache 0x15, 32(a0) + cache 0x15, 48(a0) + cache 0x15, 64(a0) + cache 0x15, 80(a0) + cache 0x15, 96(a0) + cache 0x15, 112(a0) + addu a1, -1 + bne a1, zero, 1b + addu a0, 128 + +2: + j ra + nop +END(MachHitFlushDCache) +/*---------------------------------------------------------------------------- + * + * MachInvalidateDCache -- + * + * void MachFlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for range of addr to addr + len - 1. + * The address can be any valid address as long as no TLB misses occur. + * (Be sure to use cached K0SEG kernel addresses or mapped addresses) + * Results: + * None. + * + * Side effects: + * The cache line is invalidated. + * + *---------------------------------------------------------------------------- + */ +LEAF(MachInvalidateDCache) + addu a1, a1, a0 # compute ending address +1: + addu a0, a0, 4 + bne a0, a1, 1b + cache 0x11,-4(a0) + + j ra + nop +END(MachInvalidateDCache) + +#ifdef DEBUG +/* + * Read a long and return it. + * Note: addresses can be unaligned! + * + * long +L* mdbpeek(addr) +L* caddt_t addr; +L* { +L* return (*(long *)addr); +L* } + */ +LEAF(mdbpeek) + li v0, MDBERR + sw v0, UADDR+U_PCB_ONFAULT + and v0, a0, 3 # unaligned address? + bne v0, zero, 1f + nop + b 2f + lw v0, (a0) # aligned access +1: + lwr v0, 0(a0) # get next 4 bytes (unaligned) + lwl v0, 3(a0) +2: + j ra # made it w/o errors + sw zero, UADDR+U_PCB_ONFAULT +mdberr: + li v0, 1 # trap sends us here + sw v0, mdbmkfault + j ra + nop +END(mdbpeek) + +/* + * Write a long to 'addr'. + * Note: addresses can be unaligned! + * +L* void +L* mdbpoke(addr, value) +L* caddt_t addr; +L* long value; +L* { +L* *(long *)addr = value; +L* } + */ +LEAF(mdbpoke) + li v0, MDBERR + sw v0, UADDR+U_PCB_ONFAULT + and v0, a0, 3 # unaligned address? + bne v0, zero, 1f + nop + b 2f + sw a1, (a0) # aligned access +1: + swr a1, 0(a0) # store next 4 bytes (unaligned) + swl a1, 3(a0) + and a0, a0, ~3 # align address for cache flush +2: + sw zero, UADDR+U_PCB_ONFAULT + b MachFlushICache # flush instruction cache + li a1, 8 +END(mdbpoke) + +/* + * Save registers and state so we can do a 'mdbreset' (like longjmp) later. + * Always returns zero. + * +L* int mdb_savearea[11]; +L* +L* int +L* mdbsetexit() +L* { +L* mdb_savearea[0] = 0; +L* return (0); +L* } + */ + .comm mdb_savearea, (11 * 4) + +LEAF(mdbsetexit) + la a0, mdb_savearea + sw s0, 0(a0) + sw s1, 4(a0) + sw s2, 8(a0) + sw s3, 12(a0) + sw s4, 16(a0) + sw s5, 20(a0) + sw s6, 24(a0) + sw s7, 28(a0) + sw sp, 32(a0) + sw s8, 36(a0) + sw ra, 40(a0) + j ra + move v0, zero +END(mdbsetexit) + +/* + * Restore registers and state (like longjmp) and return x. + * +L* int +L* mdbreset(x) +L* { +L* return (x); +L* } + */ +LEAF(mdbreset) + la v0, mdb_savearea + lw ra, 40(v0) + lw s0, 0(v0) + lw s1, 4(v0) + lw s2, 8(v0) + lw s3, 12(v0) + lw s4, 16(v0) + lw s5, 20(v0) + lw s6, 24(v0) + lw s7, 28(v0) + lw sp, 32(v0) + lw s8, 36(v0) + j ra + move v0, a0 +END(mdbreset) + +/* + * Trap into the debugger. + * +L* void +L* mdbpanic() +L* { +L* } + */ +LEAF(mdbpanic) + break BREAK_SOVER_VAL + j ra + nop +END(mdbpanic) +#endif /* DEBUG */ + +#ifdef DEBUG +LEAF(cpu_getregs) + sw sp, 0(a0) + sw ra, 4(a0) + j ra + sw s8, 8(a0) +END(cpu_getregs) +#endif /* DEBUG */ + +/* + * Interrupt counters for vmstat. + */ + .data + .globl intrcnt + .globl eintrcnt + .globl intrnames + .globl eintrnames +intrnames: + .asciiz "softclock" + .asciiz "softnet" + .asciiz "local_dma" + .asciiz "local_dev" + .asciiz "isa_dev" + .asciiz "isa_nmi" + .asciiz "clock" + .asciiz "statclock" +eintrnames: + .align 2 +intrcnt: + .word 0,0,0,0,0,0,0,0 +eintrcnt: diff --git a/sys/arch/arc/arc/machdep.c b/sys/arch/arc/arc/machdep.c new file mode 100644 index 00000000000..3ad8d5e1f7b --- /dev/null +++ b/sys/arch/arc/arc/machdep.c @@ -0,0 +1,1165 @@ +/* $OpenBSD: machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department, The Mach Operating System project at + * Carnegie-Mellon University and Ralph Campbell. + * + * 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. + * + * from: @(#)machdep.c 8.3 (Berkeley) 1/12/94 + * $Id: machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + +/* from: Utah Hdr: machdep.c 1.63 91/04/24 */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/signalvar.h> +#include <sys/kernel.h> +#include <sys/map.h> +#include <sys/proc.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/clist.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/msgbuf.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/user.h> +#include <sys/exec.h> +#include <sys/sysctl.h> +#include <sys/mount.h> +#include <sys/syscallargs.h> +#ifdef SYSVSHM +#include <sys/shm.h> +#endif +#ifdef SYSVSEM +#include <sys/sem.h> +#endif +#ifdef SYSVMSG +#include <sys/msg.h> +#endif + +#include <vm/vm_kern.h> + +#include <machine/cpu.h> +#include <machine/reg.h> +#include <machine/pio.h> +#include <machine/psl.h> +#include <machine/pte.h> +#include <machine/autoconf.h> + +#include <sys/exec_ecoff.h> + +#include <dev/cons.h> + +#include <arc/pica/pica.h> +#include <arc/arc/arctype.h> + +#include <asc.h> + +#if NASC > 0 +#include <arc/dev/ascreg.h> +#endif + +extern struct consdev *cn_tab; + +/* the following is used externally (sysctl_hw) */ +char machine[] = "arc"; /* cpu "architecture" */ +char cpu_model[30]; + +vm_map_t buffer_map; + +/* + * Declare these as initialized data so we can patch them. + */ +int nswbuf = 0; +#ifdef NBUF +int nbuf = NBUF; +#else +int nbuf = 0; +#endif +#ifdef BUFPAGES +int bufpages = BUFPAGES; +#else +int bufpages = 0; +#endif +int msgbufmapped = 0; /* set when safe to use msgbuf */ +int maxmem; /* max memory per process */ +int physmem; /* max supported memory, changes to actual */ +int memcfg; /* memory config register */ +int brdcfg; /* motherboard config register */ +int cpucfg; /* Value of processor config register */ +int cputype; /* Mother board type */ +int ncpu = 1; /* At least one cpu in the system */ +int isa_io_base; /* Base address of ISA io port space */ +int isa_mem_base; /* Base address of ISA memory space */ + +extern int Mach_spl0(), Mach_spl1(), Mach_spl2(), Mach_spl3(); +extern int Mach_spl4(), Mach_spl5(), splhigh(); +int (*Mach_splnet)() = splhigh; +int (*Mach_splbio)() = splhigh; +int (*Mach_splimp)() = splhigh; +int (*Mach_spltty)() = splhigh; +int (*Mach_splclock)() = splhigh; +int (*Mach_splstatclock)() = splhigh; + +void vid_print_string(const char *str); +void vid_putchar(dev_t dev, char c); + + +/* + * safepri is a safe priority for sleep to set for a spin-wait + * during autoconfiguration or after a panic. + */ +int safepri = PSL_LOWIPL; + +struct user *proc0paddr; +struct proc nullproc; /* for use by swtch_exit() */ + +/* + * Do all the stuff that locore normally does before calling main(). + * Process arguments passed to us by the BIOS. + * Reset mapping and set up mapping to hardware and init "wired" reg. + * Return the first page address following the system. + */ +mips_init(argc, argv, code) + int argc; + char *argv[]; + u_int code; +{ + register char *cp; + register int i; + register unsigned firstaddr; + register caddr_t v; + caddr_t start; + struct tlb tlb; + extern char edata[], end[]; + extern char MachTLBMiss[], MachTLBMissEnd[]; + extern char MachException[], MachExceptionEnd[]; + +vid_print_string("Starting\n"); + /* clear the BSS segment in NetBSD code */ + v = (caddr_t)pica_round_page(end); + bzero(edata, v - edata); + + /* check what model platform we are running on */ + cputype = ACER_PICA_61; /* FIXME find systemtype */ + + /* + * Get config register now as mapped from BIOS since we are + * going to demap these addresses later. We want as may TLB + * entries as possible to do something useful :-). + */ + + switch (cputype) { + case ACER_PICA_61: /* ALI PICA 61 */ + memcfg = in32(PICA_MEMORY_SIZE_REG); + brdcfg = in32(PICA_CONFIG_REG); + isa_io_base = PICA_V_ISA_IO; + isa_mem_base = PICA_V_ISA_MEM; + break; + default: + memcfg = -1; + break; + } + + /* look at argv[0] and compute bootdev */ + makebootdev(argv[0]); + + /* + * Look at arguments passed to us and compute boothowto. + */ +#ifdef GENERIC + boothowto = RB_SINGLE | RB_ASKNAME; +#else + boothowto = RB_SINGLE; +#endif +#ifdef KADB + boothowto |= RB_KDB; +#endif + if (argc > 1) { + for (i = 1; i < argc; i++) { + if(strncmp("OSLOADOPTIONS=",argv[i],14) == 0) { + for (cp = argv[i]+14; *cp; cp++) { + switch (*cp) { + case 'a': /* autoboot */ + boothowto &= ~RB_SINGLE; + break; + + case 'd': /* use compiled in default root */ + boothowto |= RB_DFLTROOT; + break; + + case 'm': /* mini root present in memory */ + boothowto |= RB_MINIROOT; + break; + + case 'n': /* ask for names */ + boothowto |= RB_ASKNAME; + break; + + case 'N': /* don't ask for names */ + boothowto &= ~RB_ASKNAME; + break; + } + + } + } + } + } + +#ifdef MFS + /* + * Check to see if a mini-root was loaded into memory. It resides + * at the start of the next page just after the end of BSS. + */ + if (boothowto & RB_MINIROOT) { + boothowto |= RB_DFLTROOT; + v += mfs_initminiroot(v); + } +#endif + + /* + * Now its time to abandon the BIOS and be self supplying. + * Start with cleaning out the TLB. Bye bye Microsoft.... + */ + MachSetWIRED(0); + MachTLBFlush(); + MachSetWIRED(VMWIRED_ENTRIES); + + /* + * Set up mapping for hardware the way we want it! + */ + + tlb.tlb_mask = PG_SIZE_256K; + tlb.tlb_hi = vad_to_vpn(PICA_V_LOCAL_IO_BASE); + tlb.tlb_lo0 = vad_to_pfn(PICA_P_LOCAL_IO_BASE) | PG_IOPAGE; + tlb.tlb_lo1 = vad_to_pfn(PICA_P_INT_SOURCE) | PG_IOPAGE; + MachTLBWriteIndexed(1, &tlb); + + tlb.tlb_mask = PG_SIZE_1M; + tlb.tlb_hi = vad_to_vpn(PICA_V_LOCAL_VIDEO_CTRL); + tlb.tlb_lo0 = vad_to_pfn(PICA_P_LOCAL_VIDEO_CTRL) | PG_IOPAGE; + tlb.tlb_lo1 = vad_to_pfn(PICA_P_LOCAL_VIDEO_CTRL + PICA_S_LOCAL_VIDEO_CTRL/2) | PG_IOPAGE; + MachTLBWriteIndexed(2, &tlb); + + tlb.tlb_mask = PG_SIZE_1M; + tlb.tlb_hi = vad_to_vpn(PICA_V_EXTND_VIDEO_CTRL); + tlb.tlb_lo0 = vad_to_pfn(PICA_P_EXTND_VIDEO_CTRL) | PG_IOPAGE; + tlb.tlb_lo1 = vad_to_pfn(PICA_P_EXTND_VIDEO_CTRL + PICA_S_EXTND_VIDEO_CTRL/2) | PG_IOPAGE; + MachTLBWriteIndexed(3, &tlb); + + tlb.tlb_mask = PG_SIZE_4M; + tlb.tlb_hi = vad_to_vpn(PICA_V_LOCAL_VIDEO); + tlb.tlb_lo0 = vad_to_pfn(PICA_P_LOCAL_VIDEO) | PG_IOPAGE; + tlb.tlb_lo1 = vad_to_pfn(PICA_P_LOCAL_VIDEO + PICA_S_LOCAL_VIDEO/2) | PG_IOPAGE; + MachTLBWriteIndexed(4, &tlb); + + tlb.tlb_mask = PG_SIZE_16M; + tlb.tlb_hi = vad_to_vpn(PICA_V_ISA_IO); + tlb.tlb_lo0 = vad_to_pfn(PICA_P_ISA_IO) | PG_IOPAGE; + tlb.tlb_lo1 = vad_to_pfn(PICA_P_ISA_MEM) | PG_IOPAGE; + MachTLBWriteIndexed(5, &tlb); + + /* + * Init mapping for u page(s) for proc[0], pm_tlbpid 1. + */ + v = (caddr_t)((int)v+3 & -4); + start = v; + curproc->p_addr = proc0paddr = (struct user *)v; + curproc->p_md.md_regs = proc0paddr->u_pcb.pcb_regs; + firstaddr = CACHED_TO_PHYS(v); + for (i = 0; i < UPAGES; i+=2) { + tlb.tlb_mask = PG_SIZE_4K; + tlb.tlb_hi = vad_to_vpn((UADDR + (i << PGSHIFT))) | 1; + tlb.tlb_lo0 = vad_to_pfn(firstaddr) | PG_V | PG_M | PG_CACHED; + tlb.tlb_lo1 = vad_to_pfn(firstaddr + NBPG) | PG_V | PG_M | PG_CACHED; + curproc->p_md.md_upte[i] = tlb.tlb_lo0; + curproc->p_md.md_upte[i+1] = tlb.tlb_lo1; + MachTLBWriteIndexed(i,&tlb); + firstaddr += NBPG * 2; + } + v += UPAGES * NBPG; + v = (caddr_t)((int)v+3 & -4); + MachSetPID(1); + + /* + * init nullproc for swtch_exit(). + * init mapping for u page(s), pm_tlbpid 0 + * This could be used for an idle process. + */ + nullproc.p_addr = (struct user *)v; + nullproc.p_md.md_regs = nullproc.p_addr->u_pcb.pcb_regs; + bcopy("nullproc", nullproc.p_comm, sizeof("nullproc")); + firstaddr = CACHED_TO_PHYS(v); + for (i = 0; i < UPAGES; i+=2) { + nullproc.p_md.md_upte[i] = vad_to_pfn(firstaddr) | PG_V | PG_M | PG_CACHED; + nullproc.p_md.md_upte[i+1] = vad_to_pfn(firstaddr + NBPG) | PG_V | PG_M | PG_CACHED; + firstaddr += NBPG * 2; + } + v += UPAGES * NBPG; + + /* clear pages for u areas */ + bzero(start, v - start); + + /* + * Copy down exception vector code. + */ + if (MachTLBMissEnd - MachTLBMiss > 0x80) + panic("startup: TLB code too large"); + bcopy(MachTLBMiss, (char *)TLB_MISS_EXC_VEC, + MachTLBMissEnd - MachTLBMiss); + bcopy(MachException, (char *)GEN_EXC_VEC, + MachExceptionEnd - MachException); + + /* + * Clear out the I and D caches. + */ + cpucfg = MachConfigCache(); + MachFlushCache(); + + /* check what model platform we are running on */ + switch (cputype) { + case ACER_PICA_61: /* ALI PICA 61 */ + /* + * Set up interrupt handling and I/O addresses. + */ +#if 0 /* XXX FIXME */ + Mach_splnet = Mach_spl1; + Mach_splbio = Mach_spl0; + Mach_splimp = Mach_spl1; + Mach_spltty = Mach_spl2; + Mach_splstatclock = Mach_spl3; +#endif + strcpy(cpu_model, "PICA_61"); + break; + + default: + printf("kernel not configured for systype 0x%x\n", i); + boot(RB_HALT | RB_NOSYNC); + } + + /* + * Find out how much memory is available. + */ + + switch (cputype) { + case ACER_PICA_61: /* ALI PICA 61 */ + /* + * Size is determined from the memory config register. + * d0-d2 = bank 0 size (sim id) + * d3-d5 = bank 1 size + * d6 = bus width. (doubels memory size) + */ + if((memcfg & 7) <= 5) + physmem = 2097152 << (memcfg & 7); + if(((memcfg >> 3) & 7) <= 5) + physmem += 2097152 << ((memcfg >> 3) & 7); + + if((memcfg & 0x40) == 0) + physmem += physmem; /* 128 bit config */ + + physmem = btoc(physmem); + break; + + default: + physmem = btoc((u_int)v - KERNBASE); + cp = (char *)PHYS_TO_UNCACHED(physmem << PGSHIFT); + while (cp < (char *)MAX_MEM_ADDR) { + if (badaddr(cp, 4)) + break; + i = *(int *)cp; + *(int *)cp = 0xa5a5a5a5; + /* + * Data will persist on the bus if we read it right away + * Have to be tricky here. + */ + ((int *)cp)[4] = 0x5a5a5a5a; + wbflush(); + if (*(int *)cp != 0xa5a5a5a5) + break; + *(int *)cp = i; + cp += NBPG; + physmem++; + } + break; + } + + maxmem = physmem; + + /* + * Initialize error message buffer (at end of core). + */ + maxmem -= btoc(sizeof (struct msgbuf)); + msgbufp = (struct msgbuf *)(PHYS_TO_CACHED(maxmem << PGSHIFT)); + msgbufmapped = 1; + + /* + * Allocate space for system data structures. + * The first available kernel virtual address is in "v". + * As pages of kernel virtual memory are allocated, "v" is incremented. + * + * These data structures are allocated here instead of cpu_startup() + * because physical memory is directly addressable. We don't have + * to map these into virtual address space. + */ + start = v; + +#define valloc(name, type, num) \ + (name) = (type *)v; v = (caddr_t)((name)+(num)) +#define valloclim(name, type, num, lim) \ + (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) +#ifdef REAL_CLISTS + valloc(cfree, struct cblock, nclist); +#endif + valloc(callout, struct callout, ncallout); + valloc(swapmap, struct map, nswapmap = maxproc * 2); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif +#ifdef SYSVSEM + valloc(sema, struct semid_ds, seminfo.semmni); + valloc(sem, struct sem, seminfo.semmns); + /* This is pretty disgusting! */ + valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); +#endif +#ifdef SYSVMSG + valloc(msgpool, char, msginfo.msgmax); + valloc(msgmaps, struct msgmap, msginfo.msgseg); + valloc(msghdrs, struct msg, msginfo.msgtql); + valloc(msqids, struct msqid_ds, msginfo.msgmni); +#endif + + /* + * Determine how many buffers to allocate. + * We allocate more buffer space than the BSD standard of + * using 10% of memory for the first 2 Meg, 5% of remaining. + * We just allocate a flat 10%. Ensure a minimum of 16 buffers. + * We allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + bufpages = physmem / 10 / CLSIZE; + if (nbuf == 0) { + nbuf = bufpages; + if (nbuf < 16) + nbuf = 16; + } + if (nswbuf == 0) { + nswbuf = (nbuf / 2) &~ 1; /* force even */ + if (nswbuf > 256) + nswbuf = 256; /* sanity */ + } + valloc(swbuf, struct buf, nswbuf); + valloc(buf, struct buf, nbuf); + + /* + * Clear allocated memory. + */ + bzero(start, v - start); + + /* + * Initialize the virtual memory system. + */ + pmap_bootstrap((vm_offset_t)v); +} + +/* + * Console initialization: called early on from main, + * before vm init or startup. Do enough configuration + * to choose and initialize a console. + */ +void +consinit() +{ + static int initted; + + if (initted) + return; + initted = 1; + cninit(); +} + +/* + * cpu_startup: allocate memory for variable-sized tables, + * initialize cpu, and do autoconfiguration. + */ +void +cpu_startup() +{ + register unsigned i; + register caddr_t v; + int base, residual; + vm_offset_t minaddr, maxaddr; + vm_size_t size; +#ifdef DEBUG + extern int pmapdebug; + int opmapdebug = pmapdebug; + + pmapdebug = 0; /* Shut up pmap debug during bootstrap */ +#endif + + /* + * Good {morning,afternoon,evening,night}. + */ + printf(version); + printf("real mem = %d\n", ctob(physmem)); + + /* + * Allocate virtual address space for file I/O buffers. + * Note they are different than the array of headers, 'buf', + * and usually occupy more virtual memory than physical. + */ + size = MAXBSIZE * nbuf; + buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers, + &maxaddr, size, TRUE); + minaddr = (vm_offset_t)buffers; + if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0, + &minaddr, size, FALSE) != KERN_SUCCESS) + panic("startup: cannot allocate buffers"); + base = bufpages / nbuf; + residual = bufpages % nbuf; + for (i = 0; i < nbuf; i++) { + vm_size_t curbufsize; + vm_offset_t curbuf; + + /* + * First <residual> buffers get (base+1) physical pages + * allocated for them. The rest get (base) physical pages. + * + * The rest of each buffer occupies virtual space, + * but has no physical memory allocated for it. + */ + curbuf = (vm_offset_t)buffers + i * MAXBSIZE; + curbufsize = CLBYTES * (i < residual ? base+1 : base); + vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); + vm_map_simplify(buffer_map, curbuf); + } + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + 16 * NCARGS, TRUE); + /* + * Allocate a submap for physio + */ + phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + VM_PHYS_SIZE, TRUE); + + /* + * Finally, allocate mbuf pool. Since mclrefcnt is an off-size + * we use the more space efficient malloc in place of kmem_alloc. + */ + mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, + M_MBUF, M_NOWAIT); + bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); + mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr, + VM_MBUF_SIZE, FALSE); + /* + * Initialize callouts + */ + callfree = callout; + for (i = 1; i < ncallout; i++) + callout[i-1].c_next = &callout[i]; + callout[i-1].c_next = NULL; + +#ifdef DEBUG + pmapdebug = opmapdebug; +#endif + printf("avail mem = %d\n", ptoa(cnt.v_free_count)); + printf("using %d buffers containing %d bytes of memory\n", + nbuf, bufpages * CLBYTES); + /* + * Set up CPU-specific registers, cache, etc. + */ + initcpu(); + + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + /* + * Configure the system. + */ + configure(); +} + +/* + * machine dependent system variables. + */ +cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + dev_t consdev; + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case CPU_CONSDEV: + if (cn_tab != NULL) + consdev = cn_tab->cn_dev; + else + consdev = NODEV; + return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, + sizeof consdev)); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +/* + * Set registers on exec. + * Clear all registers except sp, pc. + */ +void +setregs(p, pack, stack, retval) + register struct proc *p; + struct exec_package *pack; + u_long stack; + register_t *retval; +{ + extern struct proc *machFPCurProcPtr; + + bzero((caddr_t)p->p_md.md_regs, (FSR + 1) * sizeof(int)); + p->p_md.md_regs[SP] = stack; + p->p_md.md_regs[PC] = pack->ep_entry & ~3; + p->p_md.md_regs[T9] = pack->ep_entry & ~3; /* abicall req */ + p->p_md.md_regs[PS] = PSL_USERSET; + p->p_md.md_flags & ~MDP_FPUSED; + if (machFPCurProcPtr == p) + machFPCurProcPtr = (struct proc *)0; + p->p_md.md_ss_addr = 0; +} + +/* + * WARNING: code in locore.s assumes the layout shown for sf_signum + * thru sf_handler so... don't screw with them! + */ +struct sigframe { + int sf_signum; /* signo for handler */ + int sf_code; /* additional info for handler */ + struct sigcontext *sf_scp; /* context ptr for handler */ + sig_t sf_handler; /* handler addr for u_sigc */ + struct sigcontext sf_sc; /* actual context */ +}; + +#ifdef DEBUG +int sigdebug = 0; +int sigpid = 0; +#define SDB_FOLLOW 0x01 +#define SDB_KSTACK 0x02 +#define SDB_FPSTATE 0x04 +#endif + +/* + * Send an interrupt to process. + */ +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig, mask; + u_long code; +{ + register struct proc *p = curproc; + register struct sigframe *fp; + register int *regs; + register struct sigacts *psp = p->p_sigacts; + int oonstack, fsize; + struct sigcontext ksc; + extern char sigcode[], esigcode[]; + + regs = p->p_md.md_regs; + oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; + /* + * Allocate and validate space for the signal handler + * context. Note that if the stack is in data space, the + * call to grow() is a nop, and the copyout() + * will fail if the process has not already allocated + * the space with a `brk'. + */ + fsize = sizeof(struct sigframe); + if ((psp->ps_flags & SAS_ALTSTACK) && + (psp->ps_sigstk.ss_flags & SA_ONSTACK) == 0 && + (psp->ps_sigonstack & sigmask(sig))) { + fp = (struct sigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - fsize); + psp->ps_sigstk.ss_flags |= SA_ONSTACK; + } else + fp = (struct sigframe *)(regs[SP] - fsize); + if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) + (void)grow(p, (unsigned)fp); +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) || + (sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n", + p->p_pid, sig, &oonstack, fp, &fp->sf_sc); +#endif + /* + * Build the signal context to be used by sigreturn. + */ + ksc.sc_onstack = oonstack; + ksc.sc_mask = mask; + ksc.sc_pc = regs[PC]; + ksc.mullo = regs[MULLO]; + ksc.mulhi = regs[MULHI]; + ksc.sc_regs[ZERO] = 0xACEDBADE; /* magic number */ + bcopy((caddr_t)®s[1], (caddr_t)&ksc.sc_regs[1], + sizeof(ksc.sc_regs) - sizeof(int)); + ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED; + if (ksc.sc_fpused) { + extern struct proc *machFPCurProcPtr; + + /* if FPU has current state, save it first */ + if (p == machFPCurProcPtr) + MachSaveCurFPState(p); + bcopy((caddr_t)&p->p_md.md_regs[F0], (caddr_t)ksc.sc_fpregs, + sizeof(ksc.sc_fpregs)); + } + if (copyout((caddr_t)&ksc, (caddr_t)&fp->sf_sc, sizeof(ksc))) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ + SIGACTION(p, SIGILL) = SIG_DFL; + sig = sigmask(SIGILL); + p->p_sigignore &= ~sig; + p->p_sigcatch &= ~sig; + p->p_sigmask &= ~sig; + psignal(p, SIGILL); + return; + } + /* + * Build the argument list for the signal handler. + */ + regs[A0] = sig; + regs[A1] = code; + regs[A2] = (int)&fp->sf_sc; + regs[A3] = (int)catcher; + + regs[PC] = (int)catcher; + regs[T9] = (int)catcher; + regs[SP] = (int)fp; + /* + * Signal trampoline code is at base of user stack. + */ + regs[RA] = (int)PS_STRINGS - (esigcode - sigcode); +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) || + (sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d returns\n", + p->p_pid, sig); +#endif +} + +/* + * System call to cleanup state after a signal + * has been taken. Reset signal mask and + * stack state from context left by sendsig (above). + * Return to previous pc and psl as specified by + * context left by sendsig. Check carefully to + * make sure that the user has not modified the + * psl to gain improper priviledges or to cause + * a machine fault. + */ +/* ARGSUSED */ +sys_sigreturn(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sys_sigreturn_args /* { + syscallarg(struct sigcontext *) sigcntxp; + } */ *uap = v; + register struct sigcontext *scp; + register int *regs; + struct sigcontext ksc; + int error; + + scp = SCARG(uap, sigcntxp); +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); +#endif + regs = p->p_md.md_regs; + /* + * Test and fetch the context structure. + * We grab it all at once for speed. + */ + error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(ksc)); + if (error || ksc.sc_regs[ZERO] != 0xACEDBADE) { +#ifdef DEBUG + if (!(sigdebug & SDB_FOLLOW)) + printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); + printf(" old sp %x ra %x pc %x\n", + regs[SP], regs[RA], regs[PC]); + printf(" new sp %x ra %x pc %x err %d z %x\n", + ksc.sc_regs[SP], ksc.sc_regs[RA], ksc.sc_regs[PC], + error, ksc.sc_regs[ZERO]); +#endif + return (EINVAL); + } + scp = &ksc; + /* + * Restore the user supplied information + */ + if (scp->sc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + p->p_sigmask = scp->sc_mask &~ sigcantmask; + regs[PC] = scp->sc_pc; + regs[MULLO] = scp->mullo; + regs[MULHI] = scp->mulhi; + bcopy((caddr_t)&scp->sc_regs[1], (caddr_t)®s[1], + sizeof(scp->sc_regs) - sizeof(int)); + if (scp->sc_fpused) + bcopy((caddr_t)scp->sc_fpregs, (caddr_t)&p->p_md.md_regs[F0], + sizeof(scp->sc_fpregs)); + return (EJUSTRETURN); +} + +int waittime = -1; + +void +boot(howto) + register int howto; +{ + + /* take a snap shot before clobbering any registers */ + if (curproc) + savectx(curproc->p_addr, 0); + +#ifdef DEBUG + if (panicstr) + stacktrace(); +#endif + + boothowto = howto; + if ((howto & RB_NOSYNC) == 0 && waittime < 0) { + extern struct proc proc0; + /* fill curproc with live object */ + if (curproc == NULL) + curproc = &proc0; + /* + * Synchronize the disks.... + */ + waittime = 0; + vfs_shutdown(); + + /* + * If we've been adjusting the clock, the todr + * will be out of synch; adjust it now. + */ + resettodr(); + } + (void) splhigh(); /* extreme priority */ + if (howto & RB_HALT) + printf("System halted.\n"); + else { + if (howto & RB_DUMP) + dumpsys(); + printf("System restart.\n"); + } + while(1); /* Forever */ + /*NOTREACHED*/ +} + +int dumpmag = (int)0x8fca0101; /* magic number for savecore */ +int dumpsize = 0; /* also for savecore */ +long dumplo = 0; + +dumpconf() +{ + int nblks; + + dumpsize = physmem; + if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) { + nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); + if (dumpsize > btoc(dbtob(nblks - dumplo))) + dumpsize = btoc(dbtob(nblks - dumplo)); + else if (dumplo == 0) + dumplo = nblks - btodb(ctob(physmem)); + } + /* + * Don't dump on the first CLBYTES (why CLBYTES?) + * in case the dump device includes a disk label. + */ + if (dumplo < btodb(CLBYTES)) + dumplo = btodb(CLBYTES); +} + +/* + * Doadump comes here after turning off memory management and + * getting on the dump stack, either when called above, or by + * the auto-restart code. + */ +dumpsys() +{ + int error; + + msgbufmapped = 0; + if (dumpdev == NODEV) + return; + /* + * For dumps during autoconfiguration, + * if dump device has already configured... + */ + if (dumpsize == 0) + dumpconf(); + if (dumplo < 0) + return; + printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); + printf("dump "); + switch (error = (*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { + + case ENXIO: + printf("device bad\n"); + break; + + case EFAULT: + printf("device not ready\n"); + break; + + case EINVAL: + printf("area improper\n"); + break; + + case EIO: + printf("i/o error\n"); + break; + + default: + printf("error %d\n", error); + break; + + case 0: + printf("succeeded\n"); + } +} + +/* + * Return the best possible estimate of the time in the timeval + * to which tvp points. Unfortunately, we can't read the hardware registers. + * We guarantee that the time will be greater than the value obtained by a + * previous call. + */ +void +microtime(tvp) + register struct timeval *tvp; +{ + int s = splclock(); + static struct timeval lasttime; + + *tvp = time; +#ifdef notdef + tvp->tv_usec += clkread(); + while (tvp->tv_usec > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } +#endif + if (tvp->tv_sec == lasttime.tv_sec && + tvp->tv_usec <= lasttime.tv_usec && + (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + lasttime = *tvp; + splx(s); +} + +initcpu() +{ + + /* + * Disable all interrupts. New masks will be set up + * during system configuration + */ + out16(PICA_SYS_LB_IE,0x000); + out32(PICA_SYS_EXT_IMASK, 0x00); + + spl0(); /* safe to turn interrupts on now */ +} + +/* + * Convert an ASCII string into an integer. + */ +int +atoi(s) + char *s; +{ + int c; + unsigned base = 10, d; + int neg = 0, val = 0; + + if (s == 0 || (c = *s++) == 0) + goto out; + + /* skip spaces if any */ + while (c == ' ' || c == '\t') + c = *s++; + + /* parse sign, allow more than one (compat) */ + while (c == '-') { + neg = !neg; + c = *s++; + } + + /* parse base specification, if any */ + if (c == '0') { + c = *s++; + switch (c) { + case 'X': + case 'x': + base = 16; + c = *s++; + break; + case 'B': + case 'b': + base = 2; + c = *s++; + break; + default: + base = 8; + } + } + + /* parse number proper */ + for (;;) { + if (c >= '0' && c <= '9') + d = c - '0'; + else if (c >= 'a' && c <= 'z') + d = c - 'a' + 10; + else if (c >= 'A' && c <= 'Z') + d = c - 'A' + 10; + else + break; + val *= base; + val += d; + c = *s++; + } + if (neg) + val = -val; +out: + return val; +} + +/* + * This code is temporary for debugging at startup + */ + +static int vid_xpos=0, vid_ypos=0; + +static void +vid_wrchar(char c) +{ + volatile unsigned short *video; + + video = (unsigned short *)(0xe08b8000) + vid_ypos * 80 + vid_xpos; + *video = (*video & 0xff00) | 0x0f00 | (unsigned short)c; +} + +static void +vid_scroll() +{ + volatile unsigned short *video; + int i; + + video = (unsigned short *)(0xe08b8000); + for(i = 0; i < 80 * 24; i++) { + *video = *(video + 80); + video++; + } + for(i = 0; i < 80; i++) { + *video = *video & 0xff00 | ' '; + video++; + } +} +void +vid_print_string(const char *str) +{ + unsigned char c; + + while(c = *str++) { + vid_putchar((dev_t)0, c); + } +} + +void +vid_putchar(dev_t dev, char c) +{ + switch(c) { + case '\n': + vid_xpos = 0; + if(vid_ypos == 24) + vid_scroll(); + else + vid_ypos++; + DELAY(500000); + break; + + case '\r': + vid_xpos = 0; + break; + + case '\t': + do { + vid_putchar(dev, ' '); + } while(vid_xpos & 7); + break; + + default: + vid_wrchar(c); + vid_xpos++; + if(vid_xpos == 80) { + vid_xpos = 0; + vid_putchar(dev, '\n'); + } + } +} diff --git a/sys/arch/arc/arc/mainbus.c b/sys/arch/arc/arc/mainbus.c new file mode 100644 index 00000000000..9c73222cd1e --- /dev/null +++ b/sys/arch/arc/arc/mainbus.c @@ -0,0 +1,173 @@ +/* $OpenBSD: mainbus.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* $NetBSD: mainbus.c,v 1.3 1995/06/28 02:45:10 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/reboot.h> + +#include <arc/arc/arctype.h> +#include <machine/autoconf.h> + +struct mainbus_softc { + struct device sc_dv; + struct abus sc_bus; +}; + +/* Definition of the mainbus driver. */ +static int mbmatch __P((struct device *, void *, void *)); +static void mbattach __P((struct device *, struct device *, void *)); +static int mbprint __P((void *, char *)); + +struct cfattach mainbus_ca = { + sizeof(struct device), mbmatch, mbattach +}; +struct cfdriver mainbus_cd = { + NULL, "mainbus", DV_DULL, NULL, 0 +}; + +void mb_intr_establish __P((struct confargs *, int (*)(void *), void *)); +void mb_intr_disestablish __P((struct confargs *)); +caddr_t mb_cvtaddr __P((struct confargs *)); +int mb_matchname __P((struct confargs *, char *)); + +static int +mbmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + + /* + * Only one mainbus, but some people are stupid... + */ + if (cf->cf_unit > 0) + return(0); + + /* + * That one mainbus is always here. + */ + return(1); +} + +static void +mbattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct mainbus_softc *sc = (struct mainbus_softc *)self; + struct confargs nca; + extern int cputype, ncpus; + + printf("\n"); + + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_MAIN; + sc->sc_bus.ab_intr_establish = mb_intr_establish; + sc->sc_bus.ab_intr_disestablish = mb_intr_disestablish; + sc->sc_bus.ab_cvtaddr = mb_cvtaddr; + sc->sc_bus.ab_matchname = mb_matchname; + + /* + * Try to find and attach all of the CPUs in the machine. + * ( Right now only one CPU so code is simple ) + */ + + nca.ca_name = "cpu"; + nca.ca_slot = 0; + nca.ca_offset = 0; + nca.ca_bus = &sc->sc_bus; + config_found(self, &nca, mbprint); + + if (cputype == ACER_PICA_61) { + /* we have a PICA bus! */ + nca.ca_name = "pica"; + nca.ca_slot = 0; + nca.ca_offset = 0; + nca.ca_bus = &sc->sc_bus; + config_found(self, &nca, mbprint); + } + if (cputype == ACER_PICA_61) { + /* we have an ISA bus! */ + nca.ca_name = "isabr"; + nca.ca_slot = 0; + nca.ca_offset = 0; + nca.ca_bus = &sc->sc_bus; + config_found(self, &nca, mbprint); + } +} + +static int +mbprint(aux, pnp) + void *aux; + char *pnp; +{ + + if (pnp) + return (QUIET); + return (UNCONF); +} + +void +mb_intr_establish(ca, handler, val) + struct confargs *ca; + int (*handler) __P((void *)); + void *val; +{ + + panic("can never mb_intr_establish"); +} + +void +mb_intr_disestablish(ca) + struct confargs *ca; +{ + + panic("can never mb_intr_disestablish"); +} + +caddr_t +mb_cvtaddr(ca) + struct confargs *ca; +{ + + return (NULL); +} + +int +mb_matchname(ca, name) + struct confargs *ca; + char *name; +{ + + return (strcmp(name, ca->ca_name) == 0); +} diff --git a/sys/arch/arc/arc/mem.c b/sys/arch/arc/arc/mem.c new file mode 100644 index 00000000000..061291fa8bc --- /dev/null +++ b/sys/arch/arc/arc/mem.c @@ -0,0 +1,173 @@ +/* $OpenBSD: mem.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* $NetBSD: mem.c,v 1.6 1995/04/10 11:55:03 mycroft Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * @(#)mem.c 8.3 (Berkeley) 1/12/94 + */ + +/* + * Memory special file + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/msgbuf.h> +#include <sys/systm.h> +#include <sys/uio.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> + +#include <vm/vm.h> + +extern vm_offset_t avail_end; +caddr_t zeropage; + +/*ARGSUSED*/ +int +mmopen(dev, flag, mode) + dev_t dev; + int flag, mode; +{ + + return (0); +} + +/*ARGSUSED*/ +int +mmclose(dev, flag, mode) + dev_t dev; + int flag, mode; +{ + + return (0); +} + +/*ARGSUSED*/ +int +mmrw(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + register vm_offset_t o, v; + register int c; + register struct iovec *iov; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("mmrw"); + continue; + } + switch (minor(dev)) { + +/* minor device 0 is physical memory */ + case 0: + v = uio->uio_offset; + c = iov->iov_len; + if (v + c > ctob(physmem)) + return (EFAULT); + v += CACHED_MEMORY_ADDR; + error = uiomove((caddr_t)v, c, uio); + continue; + +/* minor device 1 is kernel memory */ + case 1: + v = uio->uio_offset; + c = min(iov->iov_len, MAXPHYS); + if (v < CACHED_MEMORY_ADDR) + return (EFAULT); + if (v + c > PHYS_TO_CACHED(avail_end + + sizeof (struct msgbuf)) && + (v < KSEG2_ADDR || + !kernacc((caddr_t)v, c, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE))) + return (EFAULT); + + error = uiomove((caddr_t)v, c, uio); + continue; + +/* minor device 2 is EOF/RATHOLE */ + case 2: + if (uio->uio_rw == UIO_WRITE) + uio->uio_resid = 0; + return (0); + +/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ + case 12: + if (uio->uio_rw == UIO_WRITE) { + c = iov->iov_len; + break; + } + if (zeropage == NULL) { + zeropage = (caddr_t) + malloc(CLBYTES, M_TEMP, M_WAITOK); + bzero(zeropage, CLBYTES); + } + c = min(iov->iov_len, CLBYTES); + error = uiomove(zeropage, c, uio); + continue; + + default: + return (ENXIO); + } + if (error) + break; + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; + } + return (error); +} + +int +mmmmap(dev, off, prot) + dev_t dev; + int off, prot; +{ + + return (EOPNOTSUPP); +} diff --git a/sys/arch/arc/arc/minidebug.c b/sys/arch/arc/arc/minidebug.c new file mode 100644 index 00000000000..dae2760638b --- /dev/null +++ b/sys/arch/arc/arc/minidebug.c @@ -0,0 +1,1111 @@ +/* $OpenBSD: minidebug.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + * $Id: minidebug.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + +/* + * Define machine dependent primitives for mdb. + */ + +#include <sys/types.h> +#include <machine/pte.h> +#include <vm/vm_prot.h> +#undef SP +#include <machine/cpu.h> +#include <machine/reg.h> +#include <machine/pcb.h> +#include <machine/trap.h> +#include <machine/mips_opcode.h> + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +void arc_dump_tlb(int, int); + +static char *op_name[64] = { +/* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", +/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", +/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", +/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", +/*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", +/*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", +/*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", +/*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" +}; + +static char *spec_name[64] = { +/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", +/* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", +/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", +/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", +/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", +/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", +/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", +/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" +}; + +static char *bcond_name[32] = { +/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", +/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", +/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", +/*24 */ "?", "?", "?", "?", "?", "?", "?", "?", +}; + +static char *cop1_name[64] = { +/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", +/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", +/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", +/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", +/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", +/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", +/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", + "fcmp.ole","fcmp.ule", +/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", + "fcmp.le","fcmp.ngt" +}; + +static char *fmt_name[16] = { + "s", "d", "e", "fmt3", + "w", "fmt5", "fmt6", "fmt7", + "fmt8", "fmt9", "fmta", "fmtb", + "fmtc", "fmtd", "fmte", "fmtf" +}; + +static char *reg_name[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char *c0_opname[64] = { + "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", + "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", + "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", + "eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", + "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", + "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", + "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", + "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", +}; + +static char *c0_reg[32] = { + "index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7", + "badvaddr","count","tlbhi","c0r11","sr","cause","epc", "prid", + "config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23", + "c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31" +}; + +extern char *trap_type[]; + +struct pcb mdbpcb; +int mdbmkfault; + +#define MAXBRK 10 +struct brk { + int inst; + int addr; +} brk_tab[MAXBRK]; + +/* + * Mini debugger for kernel. + */ +int gethex(u_int *val, u_int dotval) +{ + u_int c; + + *val = 0; + while((c = cngetc()) != '\e' && c != '\n') { + if(c >= '0' && c <= '9') { + *val = (*val << 4) + c - '0'; + cnputc(c); + } + else if(c >= 'a' && c <= 'f') { + *val = (*val << 4) + c - 'a' + 10; + cnputc(c); + } + else if(c == '\b') { + *val = *val >> 4; + printf("\b \b"); + } + else if(c == ',') { + cnputc(c); + return(c); + } + else if(c == '.') { + *val = dotval;; + cnputc(c); + } + } + return(c); +} + +void dump(u_int *addr, u_int size) +{ + int cnt; + + cnt = 0; + + size = (size + 3) / 4; + while(size--) { + if((cnt++ & 3) == 0) + printf("\n%08x: ",(int)addr); + printf("%08x ",*addr++); + } +} + +void print_regs() +{ + printf("\n"); + printf("T0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", + mdbpcb.pcb_regs[T0],mdbpcb.pcb_regs[T1], + mdbpcb.pcb_regs[T2],mdbpcb.pcb_regs[T3], + mdbpcb.pcb_regs[T4],mdbpcb.pcb_regs[T5], + mdbpcb.pcb_regs[T6],mdbpcb.pcb_regs[T7]); + printf("T8-9 %08x %08x A0-4 %08x %08x %08x %08x\n", + mdbpcb.pcb_regs[T8],mdbpcb.pcb_regs[T9], + mdbpcb.pcb_regs[A0],mdbpcb.pcb_regs[A1], + mdbpcb.pcb_regs[A2],mdbpcb.pcb_regs[A3]); + printf("S0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", + mdbpcb.pcb_regs[S0],mdbpcb.pcb_regs[S1], + mdbpcb.pcb_regs[S2],mdbpcb.pcb_regs[S3], + mdbpcb.pcb_regs[S4],mdbpcb.pcb_regs[S5], + mdbpcb.pcb_regs[S6],mdbpcb.pcb_regs[S7]); + printf(" S8 %08x V0-1 %08x %08x GP %08x SP %08x\n", + mdbpcb.pcb_regs[S8],mdbpcb.pcb_regs[V0], + mdbpcb.pcb_regs[V1],mdbpcb.pcb_regs[GP], + mdbpcb.pcb_regs[SP]); + printf(" AT %08x PC %08x RA %08x SR %08x", + mdbpcb.pcb_regs[AST],mdbpcb.pcb_regs[PC], + mdbpcb.pcb_regs[RA],mdbpcb.pcb_regs[SR]); +} + +set_break(va) +{ + int i; + + va = va & ~3; + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr == 0) { + brk_tab[i].addr = va; + brk_tab[i].inst = *(u_int *)va; + return; + } + } + printf(" Break table full!!"); +} + +del_break(va) +{ + int i; + + va = va & ~3; + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr == va) { + brk_tab[i].addr = 0; + return; + } + } + printf(" Break to remove not found!!"); +} + +break_insert() +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr != 0) { + brk_tab[i].inst = *(u_int *)brk_tab[i].addr; + *(u_int *)brk_tab[i].addr = BREAK_BRKPT; + MachFlushDCache(brk_tab[i].addr,4); + MachFlushICache(brk_tab[i].addr,4); + } + } +} + +break_restore() +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr != 0) { + *(u_int *)brk_tab[i].addr = brk_tab[i].inst; + MachFlushDCache(brk_tab[i].addr,4); + MachFlushICache(brk_tab[i].addr,4); + } + } +} + +break_find(va) +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr == va) { + return(i); + } + } + return(-1); +} + +prt_break() +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr != 0) { + printf("\n %08x\t", brk_tab[i].addr); + mdbprintins(brk_tab[i].inst, brk_tab[i].addr); + } + } +} +mdb(causeReg, vadr, p, kernelmode) +{ + int c; + int newaddr; + int size; + int cause; +static int ssandrun; /* Single step and run flag (when cont at brk) */ + + splhigh(); + cause = (causeReg & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; + newaddr = (int)(mdbpcb.pcb_regs[PC]); + switch(cause) { + case T_BREAK: + if(*(int *)newaddr == BREAK_SOVER) { + break_restore(); + mdbpcb.pcb_regs[PC] += 4; + printf("\nStop break (panic)\n# "); + printf(" %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + printf("\n# "); + break; + } + if(*(int *)newaddr == BREAK_BRKPT) { + break_restore(); + printf("\rBRK %08x\t",newaddr); + if(mdbprintins(*(int *)newaddr, newaddr)) { + newaddr += 4; + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + } + printf("\n# "); + break; + } + if(mdbclrsstep(causeReg)) { + if(ssandrun) { /* Step over bp before free run */ + ssandrun = 0; + break_insert(); + return(TRUE); + } + printf("\r %08x\t",newaddr); + if(mdbprintins(*(int *)newaddr, newaddr)) { + newaddr += 4; + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + } + printf("\n# "); + } + break; + + default: + printf("\n-- %s --\n# ",trap_type[cause]); + } + ssandrun = 0; + break_restore(); + + while(c = cngetc()) { + switch(c) { + case 'T': + trapDump("Debugger"); + break; + case 'b': + printf("break-"); + c = cngetc(); + switch(c) { + case 's': + printf("set at "); + c = gethex(&newaddr, newaddr); + if(c != '\e') { + set_break(newaddr); + } + break; + + case 'd': + printf("delete at "); + c = gethex(&newaddr, newaddr); + if(c != '\e') { + del_break(newaddr); + } + break; + + case 'p': + printf("print"); + prt_break(); + break; + } + break; + + case 'r': + print_regs(); + break; + + case 'I': + printf("Instruction at "); + c = gethex(&newaddr, newaddr); + while(c != '\e') { + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + newaddr += 4; + c = cngetc(); + } + break; + + case 'c': + printf("continue"); + if(break_find((int)(mdbpcb.pcb_regs[PC])) >= 0) { + ssandrun = 1; + mdbsetsstep(); + } + else { + break_insert(); + } + return(TRUE); + + case 's': + set_break(mdbpcb.pcb_regs[PC] + 8); + return(TRUE); + case ' ': + mdbsetsstep(); + return(TRUE); + + case 'd': + printf("dump "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size,256); + } + else { + size = 16; + } + if(c == '\n' && newaddr != 0) { + dump((u_int *)newaddr, size); + newaddr += size; + } + break; + + case 'm': + printf("mod "); + c = gethex(&newaddr, newaddr); + while(c == ',') { + c = gethex(&size, 0); + if(c != '\e') + *((u_int *)newaddr)++ = size; + } + break; + + case 'i': + printf("in-"); + c = cngetc(); + switch(c) { + case 'b': + printf("byte "); + c = gethex(&newaddr, newaddr); + if(c == '\n') { + printf("= %02x", + *(u_char *)newaddr); + } + break; + case 'h': + printf("halfword "); + c = gethex(&newaddr, newaddr); + if(c == '\n') { + printf("= %04x", + *(u_short *)newaddr); + } + break; + case 'w': + printf("word "); + c = gethex(&newaddr, newaddr); + if(c == '\n') { + printf("= %08x", + *(u_int *)newaddr); + } + break; + } + break; + + case 'o': + printf("out-"); + c = cngetc(); + switch(c) { + case 'b': + printf("byte "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size, 0); + if(c == '\n') { + *(u_char *)newaddr = size; + } + } + break; + case 'h': + printf("halfword "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size, 0); + if(c == '\n') { + *(u_short *)newaddr = size; + } + } + break; + case 'w': + printf("word "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size, 0); + if(c == '\n') { + *(u_int *)newaddr = size; + } + } + break; + } + break; + + case 't': + printf("tlb-dump\n"); + arc_dump_tlb(0,23); + (void)cngetc(); + arc_dump_tlb(24,47); + break; + + case 'f': + printf("flush-"); + c = cngetc(); + switch(c) { + case 't': + printf("tlb"); + MachTLBFlush(); + break; + + case 'c': + printf("cache"); + MachFlushCache(); + break; + } + break; + + default: + cnputc('\a'); + break; + } + printf("\n# "); + } +} + +u_int mdb_ss_addr; +u_int mdb_ss_instr; + +mdbsetsstep() +{ + register u_int va; + register int *locr0 = mdbpcb.pcb_regs; + int i; + + /* compute next address after current location */ + if(mdbpeek(locr0[PC]) != 0) { + va = MachEmulateBranch(locr0, locr0[PC], 0, mdbpeek(locr0[PC])); + } + else { + va = locr0[PC] + 4; + } + if (mdb_ss_addr) { + printf("mdbsetsstep: breakpoint already set at %x (va %x)\n", + mdb_ss_addr, va); + return; + } + mdb_ss_addr = va; + + if ((int)va < 0) { + /* kernel address */ + mdb_ss_instr = mdbpeek(va); + mdbpoke((caddr_t)va, BREAK_SSTEP); + MachFlushDCache(va,4); + MachFlushICache(va,4); + return; + } +} + +mdbclrsstep(cr) + int cr; +{ + register u_int pc, va; + u_int instr; + + /* fix pc if break instruction is in the delay slot */ + pc = mdbpcb.pcb_regs[PC]; + if (cr < 0) + pc += 4; + + /* check to be sure its the one we are expecting */ + va = mdb_ss_addr; + if (!va || va != pc) + return(FALSE); + + /* read break instruction */ + instr = mdbpeek(va); + if (instr != BREAK_SSTEP) + return(FALSE); + + if ((int)va < 0) { + /* kernel address */ + mdbpoke((caddr_t)va, mdb_ss_instr); + MachFlushDCache(va,4); + MachFlushICache(va,4); + mdb_ss_addr = 0; + return(TRUE); + } + + printf("can't clear break at %x\n", va); + mdb_ss_addr = 0; + return(FALSE); +} + +void +mdbreadc(lp) + char *lp; +{ + int c; + + c = cngetc(); + if (c == '\r') + c = '\n'; + *lp = c; +} + +void +mdbwrite(lp, len) + char *lp; + int len; +{ + while (len-- > 0) + cnputc(*lp++); +} + +/* ARGSUSED */ +mdbprintins(ins, mdbdot) +{ + InstFmt i; + int delay = 0; + + i.word = ins; + + switch (i.JType.op) { + case OP_SPECIAL: + if (i.word == 0) { + printf("nop"); + break; + } + if (i.RType.func == OP_ADDU && i.RType.rt == 0) { + printf("move\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + } + printf("%s", spec_name[i.RType.func]); + switch (i.RType.func) { + case OP_SLL: + case OP_SRL: + case OP_SRA: + case OP_DSLL: + case OP_DSRL: + case OP_DSRA: + case OP_DSLL32: + case OP_DSRL32: + case OP_DSRA32: + printf("\t%s,%s,%d", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + i.RType.shamt); + break; + + case OP_SLLV: + case OP_SRLV: + case OP_SRAV: + case OP_DSLLV: + case OP_DSRLV: + case OP_DSRAV: + printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + reg_name[i.RType.rs]); + break; + + case OP_MFHI: + case OP_MFLO: + printf("\t%s", reg_name[i.RType.rd]); + break; + + case OP_JR: + case OP_JALR: + delay = 1; + /* FALLTHROUGH */ + case OP_MTLO: + case OP_MTHI: + printf("\t%s", reg_name[i.RType.rs]); + break; + + case OP_MULT: + case OP_MULTU: + case OP_DMULT: + case OP_DMULTU: + case OP_DIV: + case OP_DIVU: + case OP_DDIV: + case OP_DDIVU: + printf("\t%s,%s", + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + break; + + case OP_SYSCALL: + case OP_SYNC: + break; + + case OP_BREAK: + printf("\t%d", (i.RType.rs << 5) | i.RType.rt); + break; + + default: + printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + }; + break; + + case OP_BCOND: + printf("%s\t%s,", bcond_name[i.IType.rt], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BLEZ: + case OP_BLEZL: + case OP_BGTZ: + case OP_BGTZL: + printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BEQ: + case OP_BEQL: + if (i.IType.rs == 0 && i.IType.rt == 0) { + printf("b\t"); + goto pr_displ; + } + /* FALLTHROUGH */ + case OP_BNE: + case OP_BNEL: + printf("%s\t%s,%s,", op_name[i.IType.op], + reg_name[i.IType.rs], + reg_name[i.IType.rt]); + pr_displ: + delay = 1; + printf("0x%08x", mdbdot + 4 + ((short)i.IType.imm << 2)); + break; + + case OP_COP0: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + printf("bc0%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + printf("mtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMT: + printf("dmtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_MF: + printf("mfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMF: + printf("dmfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + default: + printf("%s", c0_opname[i.FRType.func]); + }; + break; + + case OP_COP1: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + printf("bc1%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + printf("mtc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_MF: + printf("mfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CT: + printf("ctc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CF: + printf("cfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + default: + printf("%s.%s\tf%d,f%d,f%d", + cop1_name[i.FRType.func], + fmt_name[i.FRType.fmt], + i.FRType.fd, i.FRType.fs, i.FRType.ft); + }; + break; + + case OP_J: + case OP_JAL: + printf("%s\t", op_name[i.JType.op]); + printf("0x%8x",(mdbdot & 0xF0000000) | (i.JType.target << 2)); + delay = 1; + break; + + case OP_LWC1: + case OP_SWC1: + printf("%s\tf%d,", op_name[i.IType.op], + i.IType.rt); + goto loadstore; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rt]); + loadstore: + printf("%d(%s)", (short)i.IType.imm, + reg_name[i.IType.rs]); + break; + + case OP_ORI: + case OP_XORI: + if (i.IType.rs == 0) { + printf("li\t%s,0x%x", + reg_name[i.IType.rt], + i.IType.imm); + break; + } + /* FALLTHROUGH */ + case OP_ANDI: + printf("%s\t%s,%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + i.IType.imm); + break; + + case OP_LUI: + printf("%s\t%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + i.IType.imm); + break; + + case OP_ADDI: + case OP_DADDI: + case OP_ADDIU: + case OP_DADDIU: + if (i.IType.rs == 0) { + printf("li\t%s,%d", + reg_name[i.IType.rt], + (short)i.IType.imm); + break; + } + /* FALLTHROUGH */ + default: + printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + (short)i.IType.imm); + } + return(delay); +} + +#define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ + +#if 0 +/* + * Print a stack backtrace. + */ +void +mdbstacktrace(printlocals) + int printlocals; +{ + u_int pc, sp, ra, va, subr; + int a0, a1, a2, a3; + u_int instr, mask; + InstFmt i; + int more, stksize; + extern MachKernGenException(); + extern MachUserGenException(); + extern MachKernIntr(); + extern MachUserIntr(); + extern setsoftclock(); + + /* get initial values from the exception frame */ + sp = mdbpcb.pcb_regs[SP]; + pc = mdbpcb.pcb_regs[PC]; + ra = mdbpcb.pcb_regs[RA]; + a0 = mdbpcb.pcb_regs[A0]; + a1 = mdbpcb.pcb_regs[A1]; + a2 = mdbpcb.pcb_regs[A2]; + a3 = mdbpcb.pcb_regs[A3]; + +loop: + /* check for current PC in the kernel interrupt handler code */ + if (pc >= (u_int)MachKernIntr && pc < (u_int)MachUserIntr) { + /* NOTE: the offsets depend on the code in locore.s */ + printf("interupt\n"); + a0 = mdbchkget(sp + 36, DSP); + a1 = mdbchkget(sp + 40, DSP); + a2 = mdbchkget(sp + 44, DSP); + a3 = mdbchkget(sp + 48, DSP); + pc = mdbchkget(sp + 20, DSP); + ra = mdbchkget(sp + 92, DSP); + sp = mdbchkget(sp + 100, DSP); + } + + /* check for current PC in the exception handler code */ + if (pc >= 0x80000000 && pc < (u_int)setsoftclock) { + ra = 0; + subr = 0; + goto done; + } + /* + * Find the beginning of the current subroutine by scanning backwards + * from the current PC for the end of the previous subroutine. + */ + va = pc - sizeof(int); + while ((instr = mdbchkget(va, ISP)) != MIPS_JR_RA) + va -= sizeof(int); + va += 2 * sizeof(int); /* skip back over branch & delay slot */ + /* skip over nulls which might separate .o files */ + while ((instr = mdbchkget(va, ISP)) == 0) + va += sizeof(int); + subr = va; + + /* scan forwards to find stack size and any saved registers */ + stksize = 0; + more = 3; + mask = 0; + for (; more; va += sizeof(int), more = (more == 3) ? 3 : more - 1) { + /* stop if hit our current position */ + if (va >= pc) + break; + instr = mdbchkget(va, ISP); + i.word = instr; + switch (i.JType.op) { + case OP_SPECIAL: + switch (i.RType.func) { + case OP_JR: + case OP_JALR: + more = 2; /* stop after next instruction */ + break; + + case OP_SYSCALL: + case OP_BREAK: + more = 1; /* stop now */ + }; + break; + + case OP_BCOND: + case OP_J: + case OP_JAL: + case OP_BEQ: + case OP_BNE: + case OP_BLEZ: + case OP_BGTZ: + more = 2; /* stop after next instruction */ + break; + + case OP_COP0: + case OP_COP1: + case OP_COP2: + case OP_COP3: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + more = 2; /* stop after next instruction */ + }; + break; + + case OP_SW: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= 1 << i.IType.rt; + switch (i.IType.rt) { + case 4: /* a0 */ + a0 = mdbchkget(sp + (short)i.IType.imm, DSP); + break; + + case 5: /* a1 */ + a1 = mdbchkget(sp + (short)i.IType.imm, DSP); + break; + + case 6: /* a2 */ + a2 = mdbchkget(sp + (short)i.IType.imm, DSP); + break; + + case 7: /* a3 */ + a3 = mdbchkget(sp + (short)i.IType.imm, DSP); + break; + + case 31: /* ra */ + ra = mdbchkget(sp + (short)i.IType.imm, DSP); + } + break; + + case OP_ADDI: + case OP_ADDIU: + /* look for stack pointer adjustment */ + if (i.IType.rs != 29 && i.IType.rt != 29) + break; + stksize = (short)i.IType.imm; + } + } + +done: + printf("%x+%x ", subr, pc - subr); /* XXX */ + printf("(%x,%x,%x,%x)\n", a0, a1, a2, a3); + + if (ra) { + pc = ra; + sp -= stksize; + goto loop; + } +} +#endif + +/* + * Very simple memory allocator for mdb. + */ +char * +mdbmalloc(size) + int size; +{ + static char buffer[4096]; + static char *bufp = buffer; + char *p; + + /* round size up to sizeof(int) */ + size = (size + sizeof(int) - 1) & ~(sizeof(int) - 1); + p = bufp; + bufp = p + size; + return (p); +} + +/* + * Dump TLB contents. + */ +void arc_dump_tlb(int first,int last) +{ + int tlbno; + struct tlb tlb; + + tlbno = first; + + while(tlbno <= last) { + MachTLBRead(tlbno, &tlb); + if(tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V) { + printf("TLB %2d vad 0x%08x ", tlbno, tlb.tlb_hi); + } + else { + printf("TLB*%2d vad 0x%08x ", tlbno, tlb.tlb_hi); + } + printf("0=0x%08x ", pfn_to_vad(tlb.tlb_lo0)); + printf("%c", tlb.tlb_lo0 & PG_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo0 & PG_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo0 >> 3) & 7); + printf("1=0x%08x ", pfn_to_vad(tlb.tlb_lo1)); + printf("%c", tlb.tlb_lo1 & PG_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo1 & PG_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo1 >> 3) & 7); + printf(" sz=%x\n", tlb.tlb_mask); + + tlbno++; + } +} diff --git a/sys/arch/arc/arc/pmap.c b/sys/arch/arc/arc/pmap.c new file mode 100644 index 00000000000..f5baee426c6 --- /dev/null +++ b/sys/arch/arc/arc/pmap.c @@ -0,0 +1,1633 @@ +/* $OpenBSD: pmap.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: @(#)pmap.c 8.4 (Berkeley) 1/26/94 + * $Id: pmap.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + +/* + * Manages physical address maps. + * + * In addition to hardware address maps, this + * module is called upon to provide software-use-only + * maps which may or may not be stored in the same + * form as hardware maps. These pseudo-maps are + * used to store intermediate results from copy + * operations to and from address spaces. + * + * Since the information managed by this module is + * also stored by the logical address mapping module, + * this module may throw away valid virtual-to-physical + * mappings at almost any time. However, invalidations + * of virtual-to-physical mappings must be done as + * requested. + * + * In order to cope with hardware architectures which + * make virtual-to-physical map invalidates expensive, + * this module may delay invalidate or reduced protection + * operations until such time as they are actually + * necessary. This module is given full information as + * to which processors are currently using which maps, + * and to when physical maps must be made correct. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/user.h> +#include <sys/buf.h> +#ifdef SYSVSHM +#include <sys/shm.h> +#endif + +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_pageout.h> + +#include <machine/cpu.h> +#include <machine/pte.h> + +extern vm_page_t vm_page_alloc1 __P((void)); +extern void vm_page_free1 __P((vm_page_t)); + +/* + * For each vm_page_t, there is a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry_t, the list is pv_table. + * XXX really should do this as a part of the higher level code. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + int pv_flags; /* Some flags for the mapping */ +} *pv_entry_t; +#define PV_UNCACHED 0x0001 /* Page is mapped unchached */ + +/* + * Local pte bits used only here + */ +#define PG_RO 0x40000000 +#define PG_WIRED 0x80000000 + +pv_entry_t pv_table; /* array of entries, one per page */ +int pmap_remove_pv(); + +#define pa_index(pa) atop((pa) - first_phys_addr) +#define pa_to_pvh(pa) (&pv_table[pa_index(pa)]) + +#ifdef DEBUG +struct { + int kernel; /* entering kernel mapping */ + int user; /* entering user mapping */ + int ptpneeded; /* needed to allocate a PT page */ + int pwchange; /* no mapping change, just wiring or protection */ + int wchange; /* no mapping change, just wiring */ + int mchange; /* was mapped but mapping to different page */ + int managed; /* a managed page */ + int firstpv; /* first mapping for this PA */ + int secondpv; /* second mapping for this PA */ + int ci; /* cache inhibited */ + int unmanaged; /* not a managed page */ + int flushes; /* cache flushes */ + int cachehit; /* new entry forced valid entry out */ +} enter_stats; +struct { + int calls; + int removes; + int flushes; + int pidflushes; /* HW pid stolen */ + int pvfirst; + int pvsearch; +} remove_stats; + +int pmapdebug = 0; +#define PDB_FOLLOW 0x0001 +#define PDB_INIT 0x0002 +#define PDB_ENTER 0x0004 +#define PDB_REMOVE 0x0008 +#define PDB_CREATE 0x0010 +#define PDB_PTPAGE 0x0020 +#define PDB_PVENTRY 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_TLBPID 0x0400 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +#endif /* DEBUG */ + +struct pmap kernel_pmap_store; + +vm_offset_t avail_start; /* PA of first available physical page */ +vm_offset_t avail_end; /* PA of last available physical page */ +vm_size_t mem_size; /* memory size in bytes */ +vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/ +vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ +#ifdef ATTR +char *pmap_attributes; /* reference and modify bits */ +#endif +struct segtab *free_segtab; /* free list kept locally */ +u_int tlbpid_gen = 1; /* TLB PID generation count */ +int tlbpid_cnt = 2; /* next available TLB PID */ +pt_entry_t *Sysmap; /* kernel pte table */ +u_int Sysmapsize; /* number of pte's in Sysmap */ + +/* + * Bootstrap the system enough to run with virtual memory. + * firstaddr is the first unused kseg0 address (not page aligned). + */ +void +pmap_bootstrap(firstaddr) + vm_offset_t firstaddr; +{ + register int i; + register pt_entry_t *spte; + vm_offset_t start = firstaddr; + extern int maxmem, physmem; + +#define valloc(name, type, num) \ + (name) = (type *)firstaddr; firstaddr = (vm_offset_t)((name)+(num)) + /* + * Allocate a PTE table for the kernel. + * The '1024' comes from PAGER_MAP_SIZE in vm_pager_init(). + * This should be kept in sync. + * We also reserve space for kmem_alloc_pageable() for vm_fork(). + */ + Sysmapsize = (VM_KMEM_SIZE + VM_MBUF_SIZE + VM_PHYS_SIZE + + nbuf * MAXBSIZE + 16 * NCARGS) / NBPG + 1024 + 256; +#ifdef SYSVSHM + Sysmapsize += shminfo.shmall; +#endif + valloc(Sysmap, pt_entry_t, Sysmapsize); +#ifdef ATTR + valloc(pmap_attributes, char, physmem); +#endif + /* + * Allocate memory for pv_table. + * This will allocate more entries than we really need. + * We could do this in pmap_init when we know the actual + * phys_start and phys_end but its better to use kseg0 addresses + * rather than kernel virtual addresses mapped through the TLB. + */ + i = maxmem - pica_btop(CACHED_TO_PHYS(firstaddr)); + valloc(pv_table, struct pv_entry, i); + + /* + * Clear allocated memory. + */ + firstaddr = pica_round_page(firstaddr); + bzero((caddr_t)start, firstaddr - start); + + avail_start = CACHED_TO_PHYS(firstaddr); + avail_end = pica_ptob(maxmem); + mem_size = avail_end - avail_start; + + virtual_avail = VM_MIN_KERNEL_ADDRESS; + virtual_end = VM_MIN_KERNEL_ADDRESS + Sysmapsize * NBPG; + /* XXX need to decide how to set cnt.v_page_size */ + + simple_lock_init(&pmap_kernel()->pm_lock); + pmap_kernel()->pm_count = 1; + + /* + * The R4?00 stores only one copy of the Global bit in the + * translation lookaside buffer for each 2 page entry. + * Thus invalid entrys must have the Global bit set so + * when Entry LO and Entry HI G bits are anded together + * they will produce a global bit to store in the tlb. + */ + for(i = 0, spte = Sysmap; i < Sysmapsize; i++, spte++) + spte->pt_entry = PG_G; +} + +/* + * Bootstrap memory allocator. This function allows for early dynamic + * memory allocation until the virtual memory system has been bootstrapped. + * After that point, either kmem_alloc or malloc should be used. This + * function works by stealing pages from the (to be) managed page pool, + * stealing virtual address space, then mapping the pages and zeroing them. + * + * It should be used from pmap_bootstrap till vm_page_startup, afterwards + * it cannot be used, and will generate a panic if tried. Note that this + * memory will never be freed, and in essence it is wired down. + */ +void * +pmap_bootstrap_alloc(size) + int size; +{ + vm_offset_t val; + extern boolean_t vm_page_startup_initialized; + + if (vm_page_startup_initialized) + panic("pmap_bootstrap_alloc: called after startup initialized"); + + val = PHYS_TO_CACHED(avail_start); + size = round_page(size); + avail_start += size; + + blkclr((caddr_t)val, size); + return ((void *)val); +} + +/* + * Initialize the pmap module. + * Called by vm_init, to initialize any structures that the pmap + * system needs to map virtual memory. + */ +void +pmap_init(phys_start, phys_end) + vm_offset_t phys_start, phys_end; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_INIT)) + printf("pmap_init(%x, %x)\n", phys_start, phys_end); +#endif +} + +/* + * Create and return a physical map. + * + * If the size specified for the map + * is zero, the map is an actual physical + * map, and may be referenced by the + * hardware. + * + * If the size specified is non-zero, + * the map will be used in software only, and + * is bounded by that size. + */ +pmap_t +pmap_create(size) + vm_size_t size; +{ + register pmap_t pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_create(%x)\n", size); +#endif + /* + * Software use map does not need a pmap + */ + if (size) + return (NULL); + + /* XXX: is it ok to wait here? */ + pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); +#ifdef notifwewait + if (pmap == NULL) + panic("pmap_create: cannot allocate a pmap"); +#endif + bzero(pmap, sizeof(*pmap)); + pmap_pinit(pmap); + return (pmap); +} + +/* + * Initialize a preallocated and zeroed pmap structure, + * such as one in a vmspace structure. + */ +void +pmap_pinit(pmap) + register struct pmap *pmap; +{ + register int i; + int s; + extern struct vmspace vmspace0; + extern struct user *proc0paddr; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_pinit(%x)\n", pmap); +#endif + simple_lock_init(&pmap->pm_lock); + pmap->pm_count = 1; + if (free_segtab) { + s = splimp(); + pmap->pm_segtab = free_segtab; + free_segtab = *(struct segtab **)free_segtab; + pmap->pm_segtab->seg_tab[0] = NULL; + splx(s); + } else { + register struct segtab *stp; + vm_page_t mem; + void pmap_zero_page(); + + mem = vm_page_alloc1(); + pmap_zero_page(VM_PAGE_TO_PHYS(mem)); + pmap->pm_segtab = stp = (struct segtab *) + PHYS_TO_CACHED(VM_PAGE_TO_PHYS(mem)); + i = NBPG / sizeof(struct segtab); + s = splimp(); + while (--i != 0) { + stp++; + *(struct segtab **)stp = free_segtab; + free_segtab = stp; + } + splx(s); + } +#ifdef DIAGNOSTIC + for (i = 0; i < PMAP_SEGTABSIZE; i++) + if (pmap->pm_segtab->seg_tab[i] != 0) + panic("pmap_pinit: pm_segtab != 0"); +#endif + if (pmap == &vmspace0.vm_pmap) { + /* + * The initial process has already been allocated a TLBPID + * in mach_init(). + */ + pmap->pm_tlbpid = 1; + pmap->pm_tlbgen = tlbpid_gen; + proc0paddr->u_pcb.pcb_segtab = (void *)pmap->pm_segtab; + } else { + pmap->pm_tlbpid = 0; + pmap->pm_tlbgen = 0; + } +} + +/* + * Retire the given physical map from service. + * Should only be called if the map contains + * no valid mappings. + */ +void +pmap_destroy(pmap) + register pmap_t pmap; +{ + int count; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_destroy(%x)\n", pmap); +#endif + if (pmap == NULL) + return; + + simple_lock(&pmap->pm_lock); + count = --pmap->pm_count; + simple_unlock(&pmap->pm_lock); + if (count == 0) { + pmap_release(pmap); + free((caddr_t)pmap, M_VMPMAP); + } +} + +/* + * Release any resources held by the given physical map. + * Called when a pmap initialized by pmap_pinit is being released. + * Should only be called if the map contains no valid mappings. + */ +void +pmap_release(pmap) + register pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_release(%x)\n", pmap); +#endif + + if (pmap->pm_segtab) { + register pt_entry_t *pte; + register int i; + int s; +#ifdef DIAGNOSTIC + register int j; +#endif + + for (i = 0; i < PMAP_SEGTABSIZE; i++) { + /* get pointer to segment map */ + pte = pmap->pm_segtab->seg_tab[i]; + if (!pte) + continue; +#ifdef DIAGNOSTIC + for (j = 0; j < NPTEPG; j++) { + if ((pte+j)->pt_entry) + panic("pmap_release: segmap not empty"); + } +#endif + MachHitFlushDCache(pte, PAGE_SIZE); + vm_page_free1( + PHYS_TO_VM_PAGE(CACHED_TO_PHYS(pte))); + pmap->pm_segtab->seg_tab[i] = NULL; + } + s = splimp(); + *(struct segtab **)pmap->pm_segtab = free_segtab; + free_segtab = pmap->pm_segtab; + splx(s); + pmap->pm_segtab = NULL; + } +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%x)\n", pmap); +#endif + if (pmap != NULL) { + simple_lock(&pmap->pm_lock); + pmap->pm_count++; + simple_unlock(&pmap->pm_lock); + } +} + +/* + * Remove the given range of addresses from the specified map. + * + * It is assumed that the start and end are properly + * rounded to the page size. + */ +void +pmap_remove(pmap, sva, eva) + register pmap_t pmap; + vm_offset_t sva, eva; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + unsigned entry; + int flush; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); + remove_stats.calls++; +#endif + if (pmap == NULL) + return; + + if (!pmap->pm_segtab) { + register pt_entry_t *pte; + + /* remove entries from kernel pmap */ +#ifdef DIAGNOSTIC + if (sva < VM_MIN_KERNEL_ADDRESS || eva > virtual_end) + panic("pmap_remove: kva not in range"); +#endif + pte = kvtopte(sva); + for (; sva < eva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + if (entry & PG_WIRED) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + if(pmap_remove_pv(pmap, sva, pfn_to_vad(entry))) { + MachFlushDCache(sva, PAGE_SIZE); + } +#ifdef ATTR + pmap_attributes[atop(pfn_to_vad(entry))] = 0; +#endif + /* + * Flush the TLB for the given address. + */ + pte->pt_entry = PG_NV | PG_G; /* See above about G bit */ + MachTLBFlushAddr(sva); +#ifdef DEBUG + remove_stats.flushes++; + +#endif + } + return; + } + +#ifdef DIAGNOSTIC + if (eva > VM_MAXUSER_ADDRESS) + panic("pmap_remove: uva not in range"); +#endif + while (sva < eva) { + nssva = pica_trunc_seg(sva) + NBSEG; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!(pte = pmap_segmap(pmap, sva))) { + sva = nssva; + continue; + } + /* + * Invalidate every valid mapping within this segment. + */ + pte += uvtopte(sva); + for (; sva < nssva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + if (entry & PG_WIRED) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + if(pmap_remove_pv(pmap, sva, pfn_to_vad(entry))) { + MachFlushDCache(sva, PAGE_SIZE); + } +#ifdef ATTR + pmap_attributes[atop(pfn_to_vad(entry))] = 0; +#endif + pte->pt_entry = PG_NV; + /* + * Flush the TLB for the given address. + */ + if (pmap->pm_tlbgen == tlbpid_gen) { + MachTLBFlushAddr(sva | (pmap->pm_tlbpid << + VMTLB_PID_SHIFT)); +#ifdef DEBUG + remove_stats.flushes++; +#endif + } + } + } +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(pa, prot) + vm_offset_t pa; + vm_prot_t prot; +{ + register pv_entry_t pv; + register vm_offset_t va; + int s; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || + prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE)) + printf("pmap_page_protect(%x, %x)\n", pa, prot); +#endif + if (!IS_VM_PHYSADDR(pa)) + return; + + switch (prot) { + case VM_PROT_READ|VM_PROT_WRITE: + case VM_PROT_ALL: + break; + + /* copy_on_write */ + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Loop over all current mappings setting/clearing as appropos. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + extern vm_offset_t pager_sva, pager_eva; + + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (va >= pager_sva && va < pager_eva) + continue; + pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE, + prot); + } + } + splx(s); + break; + + /* remove_all */ + default: + pv = pa_to_pvh(pa); + s = splimp(); + while (pv->pv_pmap != NULL) { + pmap_remove(pv->pv_pmap, pv->pv_va, + pv->pv_va + PAGE_SIZE); + } + splx(s); + } +} + +/* + * Set the physical protection on the + * specified range of this map as requested. + */ +void +pmap_protect(pmap, sva, eva, prot) + register pmap_t pmap; + vm_offset_t sva, eva; + vm_prot_t prot; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + register unsigned entry; + u_int p; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot); +#endif + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + + p = (prot & VM_PROT_WRITE) ? PG_M : PG_RO; + + if (!pmap->pm_segtab) { + /* + * Change entries in kernel pmap. + * This will trap if the page is writeable (in order to set + * the dirty bit) even if the dirty bit is already set. The + * optimization isn't worth the effort since this code isn't + * executed much. The common case is to make a user page + * read-only. + */ +#ifdef DIAGNOSTIC + if (sva < VM_MIN_KERNEL_ADDRESS || eva > virtual_end) + panic("pmap_protect: kva not in range"); +#endif + pte = kvtopte(sva); + for (; sva < eva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + entry = (entry & ~(PG_M | PG_RO)) | p; + pte->pt_entry = entry; + /* + * Update the TLB if the given address is in the cache. + */ + MachTLBUpdate(sva, entry); + } + return; + } + +#ifdef DIAGNOSTIC + if (eva > VM_MAXUSER_ADDRESS) + panic("pmap_protect: uva not in range"); +#endif + while (sva < eva) { + nssva = pica_trunc_seg(sva) + NBSEG; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!(pte = pmap_segmap(pmap, sva))) { + sva = nssva; + continue; + } + /* + * Change protection on every valid mapping within this segment. + */ + pte += (sva >> PGSHIFT) & (NPTEPG - 1); + for (; sva < nssva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + entry = (entry & ~(PG_M | PG_RO)) | p; + pte->pt_entry = entry; + /* + * Update the TLB if the given address is in the cache. + */ + if (pmap->pm_tlbgen == tlbpid_gen) + MachTLBUpdate(sva | (pmap->pm_tlbpid << + VMTLB_PID_SHIFT), entry); + } + } +} + +/* + * Return RO protection of page. + */ +int +pmap_is_page_ro(pmap, va, entry) + pmap_t pmap; + vm_offset_t va; + int entry; +{ + return(entry & PG_RO); +} + +/* + * pmap_page_cache: + * + * Change all mappings of a page to cached/uncached. + */ +void +pmap_page_cache(pa,mode) + vm_offset_t pa; +{ + register pv_entry_t pv; + register pt_entry_t *pte; + register vm_offset_t va; + register unsigned entry; + register unsigned newmode; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_page_uncache(%x)\n", pa); +#endif + if (!IS_VM_PHYSADDR(pa)) + return; + + newmode = mode & PV_UNCACHED ? PG_UNCACHED : PG_CACHED; + pv = pa_to_pvh(pa); + s = splimp(); + while (pv) { + pv->pv_flags = (pv->pv_flags & ~PV_UNCACHED) | mode; + if (!pv->pv_pmap->pm_segtab) { + /* + * Change entries in kernel pmap. + */ + pte = kvtopte(pv->pv_va); + entry = pte->pt_entry; + if (entry & PG_V) { + entry = (entry & ~PG_CACHEMODE) | newmode; + pte->pt_entry = entry; + MachTLBUpdate(pv->pv_va, entry); + } + } + else { + if (pte = pmap_segmap(pv->pv_pmap, pv->pv_va)) { + pte += (pv->pv_va >> PGSHIFT) & (NPTEPG - 1); + entry = pte->pt_entry; + if (entry & PG_V) { + entry = (entry & ~PG_CACHEMODE) | newmode; + pte->pt_entry = entry; + if (pv->pv_pmap->pm_tlbgen == tlbpid_gen) + MachTLBUpdate(pv->pv_va | (pv->pv_pmap->pm_tlbpid << + VMTLB_PID_SHIFT), entry); + } + } + } + pv = pv->pv_next; + } + + splx(s); +} + +/* + * Insert the given physical page (p) at + * the specified virtual address (v) in the + * target physical map with the protection requested. + * + * If specified, the page will be wired down, meaning + * that the related pte can not be reclaimed. + * + * NB: This is the only routine which MAY NOT lazy-evaluate + * or lose information. That is, this routine must actually + * insert this page into the given map NOW. + */ +void +pmap_enter(pmap, va, pa, prot, wired) + register pmap_t pmap; + vm_offset_t va; + register vm_offset_t pa; + vm_prot_t prot; + boolean_t wired; +{ + register pt_entry_t *pte; + register u_int npte; + register int i, j; + vm_page_t mem; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%x, %x, %x, %x, %x)\n", + pmap, va, pa, prot, wired); +#endif +#ifdef DIAGNOSTIC + if (!pmap) + panic("pmap_enter: pmap"); + if (!pmap->pm_segtab) { + enter_stats.kernel++; + if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) + panic("pmap_enter: kva"); + } else { + enter_stats.user++; + if (va >= VM_MAXUSER_ADDRESS) + panic("pmap_enter: uva"); + } + if (pa & 0x80000000) + panic("pmap_enter: pa"); + if (!(prot & VM_PROT_READ)) + panic("pmap_enter: prot"); +#endif + + if (IS_VM_PHYSADDR(pa)) { + register pv_entry_t pv, npv; + int s; + + if (!(prot & VM_PROT_WRITE)) + npte = PG_ROPAGE; + else { + register vm_page_t mem; + + mem = PHYS_TO_VM_PAGE(pa); + if ((int)va < 0) { + /* + * Don't bother to trap on kernel writes, + * just record page as dirty. + */ + npte = PG_RWPAGE; + mem->flags &= ~PG_CLEAN; + } else +#ifdef ATTR + if ((pmap_attributes[atop(pa)] & + PMAP_ATTR_MOD) || !(mem->flags & PG_CLEAN)) +#else + if (!(mem->flags & PG_CLEAN)) +#endif + npte = PG_RWPAGE; + else + npte = PG_CWPAGE; + } + +#ifdef DEBUG + enter_stats.managed++; +#endif + /* + * Enter the pmap and virtual address into the + * physical to virtual map table. + */ + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("pmap_enter: pv %x: was %x/%x/%x\n", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next); +#endif + if (pv->pv_pmap == NULL) { + /* + * No entries yet, use header as the first entry + */ +#ifdef DEBUG + if (pmapdebug & PDB_PVENTRY) + printf("pmap_enter: first pv: pmap %x va %x\n", + pmap, va); + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_flags = 0; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + } else { + if (!(pv->pv_flags & PV_UNCACHED)) { + /* + * There is at least one other VA mapping this page. + * Check if they are cache index compatible. If not + * remove all mappings, flush the cache and set page + * to be mapped uncached. Caching will be restored + * when pages are mapped compatible again. NOT! + */ + for (npv = pv; npv; npv = npv->pv_next) { + /* + * Check cache aliasing incompatibility + */ + if((npv->pv_va & machCacheAliasMask) != (va & machCacheAliasMask)) { + printf("pmap_enter: creating uncached mapping 0x%x, 0x%x.\n",npv->pv_va, va); + pmap_page_cache(pa,PV_UNCACHED); + MachFlushDCache(pv->pv_va, PAGE_SIZE); + npte = (npte & ~PG_CACHEMODE) | PG_UNCACHED; + break; + } + } + } + else { + npte = (npte & ~PG_CACHEMODE) | PG_UNCACHED; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + * + * Note: the entry may already be in the table if + * we are only changing the protection bits. + */ + for (npv = pv; npv; npv = npv->pv_next) { + if (pmap == npv->pv_pmap && va == npv->pv_va) { +#ifdef DIAGNOSTIC + unsigned entry; + + if (!pmap->pm_segtab) + entry = kvtopte(va)->pt_entry; + else { + pte = pmap_segmap(pmap, va); + if (pte) { + pte += (va >> PGSHIFT) & + (NPTEPG - 1); + entry = pte->pt_entry; + } else + entry = 0; + } + if (!(entry & PG_V) || + pfn_to_vad(entry) != pa) + printf( + "pmap_enter: found va %x pa %x in pv_table but != %x\n", + va, pa, entry); +#endif + goto fnd; + } + } +#ifdef DEBUG + if (pmapdebug & PDB_PVENTRY) + printf("pmap_enter: new pv: pmap %x va %x\n", + pmap, va); +#endif + /* can this cause us to recurse forever? */ + npv = (pv_entry_t) + malloc(sizeof *npv, M_VMPVENT, M_NOWAIT); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + npv->pv_flags = pv->pv_flags; + pv->pv_next = npv; +#ifdef DEBUG + if (!npv->pv_next) + enter_stats.secondpv++; +#endif + fnd: + ; + } + splx(s); + } else { + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ +#ifdef DEBUG + enter_stats.unmanaged++; +#endif + npte = (prot & VM_PROT_WRITE) ? (PG_IOPAGE & ~PG_G) : (PG_IOPAGE& ~(PG_G | PG_M)); + } + + /* + * The only time we need to flush the cache is if we + * execute from a physical address and then change the data. + * This is the best place to do this. + * pmap_protect() and pmap_remove() are mostly used to switch + * between R/W and R/O pages. + * NOTE: we only support cache flush for read only text. + */ + if (prot == (VM_PROT_READ | VM_PROT_EXECUTE)) + MachFlushICache(PHYS_TO_CACHED(pa), PAGE_SIZE); + + if (!pmap->pm_segtab) { + /* enter entries into kernel pmap */ + pte = kvtopte(va); + npte |= vad_to_pfn(pa) | PG_ROPAGE | PG_G; + if (wired) { + pmap->pm_stats.wired_count++; + npte |= PG_WIRED; + } + if (!(pte->pt_entry & PG_V)) { + pmap->pm_stats.resident_count++; + } else { +#ifdef DIAGNOSTIC + if (pte->pt_entry & PG_WIRED) + panic("pmap_enter: kernel wired"); +#endif + } + /* + * Update the same virtual address entry. + */ + j = MachTLBUpdate(va, npte); + pte->pt_entry = npte; + return; + } + + if (!(pte = pmap_segmap(pmap, va))) { + mem = vm_page_alloc1(); + pmap_zero_page(VM_PAGE_TO_PHYS(mem)); + pmap_segmap(pmap, va) = pte = (pt_entry_t *) + PHYS_TO_CACHED(VM_PAGE_TO_PHYS(mem)); +#ifdef DIAGNOSTIC + for (i = 0; i < NPTEPG; i++) { + if ((pte+i)->pt_entry) + panic("pmap_enter: new segmap not empty"); + } +#endif + } + pte += (va >> PGSHIFT) & (NPTEPG - 1); + + /* + * Now validate mapping with desired protection/wiring. + * Assume uniform modified and referenced status for all + * MIPS pages in a MACH page. + */ + npte |= vad_to_pfn(pa); + if (wired) { + pmap->pm_stats.wired_count++; + npte |= PG_WIRED; + } +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) { + printf("pmap_enter: new pte %x", npte); + if (pmap->pm_tlbgen == tlbpid_gen) + printf(" tlbpid %d", pmap->pm_tlbpid); + printf("\n"); + } +#endif + if (!(pte->pt_entry & PG_V)) { + pmap->pm_stats.resident_count++; + } + pte->pt_entry = npte; + if (pmap->pm_tlbgen == tlbpid_gen) + j = MachTLBUpdate(va | (pmap->pm_tlbpid << + VMTLB_PID_SHIFT), npte); +} + +/* + * Routine: pmap_change_wiring + * Function: Change the wiring attribute for a map/virtual-address + * pair. + * In/out conditions: + * The mapping must already exist in the pmap. + */ +void +pmap_change_wiring(pmap, va, wired) + register pmap_t pmap; + vm_offset_t va; + boolean_t wired; +{ + register pt_entry_t *pte; + u_int p; + register int i; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_WIRING)) + printf("pmap_change_wiring(%x, %x, %x)\n", pmap, va, wired); +#endif + if (pmap == NULL) + return; + + p = wired ? PG_WIRED : 0; + + /* + * Don't need to flush the TLB since PG_WIRED is only in software. + */ + if (!pmap->pm_segtab) { + /* change entries in kernel pmap */ +#ifdef DIAGNOSTIC + if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) + panic("pmap_change_wiring"); +#endif + pte = kvtopte(va); + } else { + if (!(pte = pmap_segmap(pmap, va))) + return; + pte += (va >> PGSHIFT) & (NPTEPG - 1); + } + + if (!(pte->pt_entry & PG_WIRED) && p) + pmap->pm_stats.wired_count++; + else if ((pte->pt_entry & PG_WIRED) && !p) + pmap->pm_stats.wired_count--; + + if (pte->pt_entry & PG_V) + pte->pt_entry = (pte->pt_entry & ~PG_WIRED) | p; +} + +/* + * Routine: pmap_extract + * Function: + * Extract the physical page address associated + * with the given map/virtual_address pair. + */ +vm_offset_t +pmap_extract(pmap, va) + register pmap_t pmap; + vm_offset_t va; +{ + register vm_offset_t pa; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract(%x, %x) -> ", pmap, va); +#endif + + if (!pmap->pm_segtab) { +#ifdef DIAGNOSTIC + if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) + panic("pmap_extract"); +#endif + pa = pfn_to_vad(kvtopte(va)->pt_entry); + } else { + register pt_entry_t *pte; + + if (!(pte = pmap_segmap(pmap, va))) + pa = 0; + else { + pte += (va >> PGSHIFT) & (NPTEPG - 1); + pa = pfn_to_vad(pte->pt_entry); + } + } + if (pa) + pa |= va & PGOFSET; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract: pa %x\n", pa); +#endif + return (pa); +} + +/* + * Copy the range specified by src_addr/len + * from the source map to the range dst_addr/len + * in the destination map. + * + * This routine is only advisory and need not do anything. + */ +void +pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) + pmap_t dst_pmap; + pmap_t src_pmap; + vm_offset_t dst_addr; + vm_size_t len; + vm_offset_t src_addr; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy(%x, %x, %x, %x, %x)\n", + dst_pmap, src_pmap, dst_addr, len, src_addr); +#endif +} + +/* + * Require that all active physical maps contain no + * incorrect entries NOW. [This update includes + * forcing updates of any address map caching.] + * + * Generally used to insure that a thread about + * to run will see a semantically correct world. + */ +void +pmap_update() +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_update()\n"); +#endif +} + +/* + * Routine: pmap_collect + * Function: + * Garbage collects the physical map system for + * pages which are no longer used. + * Success need not be guaranteed -- that is, there + * may well be pages which are not referenced, but + * others may be collected. + * Usage: + * Called by the pageout daemon when pages are scarce. + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_collect(%x)\n", pmap); +#endif +} + +/* + * pmap_zero_page zeros the specified (machine independent) + * page. + */ +void +pmap_zero_page(phys) + vm_offset_t phys; +{ + register int *p, *end; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)\n", phys); +#endif +/*XXX FIXME Not very sophisticated */ + MachFlushCache(); + p = (int *)PHYS_TO_CACHED(phys); + end = p + PAGE_SIZE / sizeof(int); + do { + p[0] = 0; + p[1] = 0; + p[2] = 0; + p[3] = 0; + p += 4; + } while (p != end); +/*XXX FIXME Not very sophisticated */ + MachFlushCache(); +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page. + */ +void +pmap_copy_page(src, dst) + vm_offset_t src, dst; +{ + register int *s, *d, *end; + register int tmp0, tmp1, tmp2, tmp3; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)\n", src, dst); +#endif +/*XXX FIXME Not very sophisticated */ + MachFlushCache(); + s = (int *)PHYS_TO_CACHED(src); + d = (int *)PHYS_TO_CACHED(dst); + end = s + PAGE_SIZE / sizeof(int); + do { + tmp0 = s[0]; + tmp1 = s[1]; + tmp2 = s[2]; + tmp3 = s[3]; + d[0] = tmp0; + d[1] = tmp1; + d[2] = tmp2; + d[3] = tmp3; + s += 4; + d += 4; + } while (s != end); +/*XXX FIXME Not very sophisticated */ + MachFlushCache(); +} + +/* + * Routine: pmap_pageable + * Function: + * Make the specified pages (by pmap, offset) + * pageable (or not) as requested. + * + * A page which is not pageable may not take + * a fault; therefore, its page table entry + * must remain valid for the duration. + * + * This routine is merely advisory; pmap_enter + * will specify that these pages are to be wired + * down (or not) as appropriate. + */ +void +pmap_pageable(pmap, sva, eva, pageable) + pmap_t pmap; + vm_offset_t sva, eva; + boolean_t pageable; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_pageable(%x, %x, %x, %x)\n", + pmap, sva, eva, pageable); +#endif +} + +/* + * Clear the modify bits on the specified physical page. + */ +void +pmap_clear_modify(pa) + vm_offset_t pa; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_modify(%x)\n", pa); +#endif +#ifdef ATTR + pmap_attributes[atop(pa)] &= ~PMAP_ATTR_MOD; +#endif +} + +/* + * pmap_clear_reference: + * + * Clear the reference bit on the specified physical page. + */ +void +pmap_clear_reference(pa) + vm_offset_t pa; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_reference(%x)\n", pa); +#endif +#ifdef ATTR + pmap_attributes[atop(pa)] &= ~PMAP_ATTR_REF; +#endif +} + +/* + * pmap_is_referenced: + * + * Return whether or not the specified physical page is referenced + * by any physical maps. + */ +boolean_t +pmap_is_referenced(pa) + vm_offset_t pa; +{ +#ifdef ATTR + return (pmap_attributes[atop(pa)] & PMAP_ATTR_REF); +#else + return (FALSE); +#endif +} + +/* + * pmap_is_modified: + * + * Return whether or not the specified physical page is modified + * by any physical maps. + */ +boolean_t +pmap_is_modified(pa) + vm_offset_t pa; +{ +#ifdef ATTR + return (pmap_attributes[atop(pa)] & PMAP_ATTR_MOD); +#else + return (FALSE); +#endif +} + +vm_offset_t +pmap_phys_address(ppn) + int ppn; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_phys_address(%x)\n", ppn); +#endif + return (pica_ptob(ppn)); +} + +/* + * Miscellaneous support routines + */ + +/* + * Allocate a hardware PID and return it. + * It takes almost as much or more time to search the TLB for a + * specific PID and flush those entries as it does to flush the entire TLB. + * Therefore, when we allocate a new PID, we just take the next number. When + * we run out of numbers, we flush the TLB, increment the generation count + * and start over. PID zero is reserved for kernel use. + * This is called only by switch(). + */ +int +pmap_alloc_tlbpid(p) + register struct proc *p; +{ + register pmap_t pmap; + register int id; + + pmap = &p->p_vmspace->vm_pmap; + if (pmap->pm_tlbgen != tlbpid_gen) { + id = tlbpid_cnt; + if (id == VMNUM_PIDS) { + MachTLBFlush(); + /* reserve tlbpid_gen == 0 to alway mean invalid */ + if (++tlbpid_gen == 0) + tlbpid_gen = 1; + id = 1; + } + tlbpid_cnt = id + 1; + pmap->pm_tlbpid = id; + pmap->pm_tlbgen = tlbpid_gen; + } else + id = pmap->pm_tlbpid; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_TLBPID)) { + if (curproc) + printf("pmap_alloc_tlbpid: curproc %d '%s' ", + curproc->p_pid, curproc->p_comm); + else + printf("pmap_alloc_tlbpid: curproc <none> "); + printf("segtab %x tlbpid %d pid %d '%s'\n", + pmap->pm_segtab, id, p->p_pid, p->p_comm); + } +#endif + return (id); +} + +/* + * Remove a physical to virtual address translation. + * Returns TRUE if it was the last mapping and cached, else FALSE. + */ +int +pmap_remove_pv(pmap, va, pa) + pmap_t pmap; + vm_offset_t va, pa; +{ + register pv_entry_t pv, npv; + int s, last; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PVENTRY)) + printf("pmap_remove_pv(%x, %x, %x)\n", pmap, va, pa); +#endif + /* + * Remove page from the PV table (raise IPL since we + * may be called at interrupt time). + */ + if (!IS_VM_PHYSADDR(pa)) + return(TRUE); + pv = pa_to_pvh(pa); + s = splimp(); + /* + * If it is the first entry on the list, it is actually + * in the header and we must copy the following entry up + * to the header. Otherwise we must search the list for + * the entry. In either case we free the now unused entry. + */ + if (pmap == pv->pv_pmap && va == pv->pv_va) { + last = (pv->pv_flags & PV_UNCACHED) ? FALSE : TRUE; + npv = pv->pv_next; + if (npv) { + *pv = *npv; + free((caddr_t)npv, M_VMPVENT); + } else + pv->pv_pmap = NULL; +#ifdef DEBUG + remove_stats.pvfirst++; +#endif + } else { + last = FALSE; + for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) { +#ifdef DEBUG + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + goto fnd; + } +#ifdef DIAGNOSTIC + printf("pmap_remove_pv(%x, %x, %x) not found\n", pmap, va, pa); + panic("pmap_remove_pv"); +#endif + fnd: + pv->pv_next = npv->pv_next; + free((caddr_t)npv, M_VMPVENT); + } + splx(s); + return(last); +} + +/* + * vm_page_alloc1: + * + * Allocate and return a memory cell with no associated object. + */ +vm_page_t +vm_page_alloc1() +{ + register vm_page_t mem; + int spl; + + spl = splimp(); /* XXX */ + simple_lock(&vm_page_queue_free_lock); + if (vm_page_queue_free.tqh_first == NULL) { + simple_unlock(&vm_page_queue_free_lock); + splx(spl); + return (NULL); + } + + mem = vm_page_queue_free.tqh_first; + TAILQ_REMOVE(&vm_page_queue_free, mem, pageq); + + cnt.v_free_count--; + simple_unlock(&vm_page_queue_free_lock); + splx(spl); + + mem->flags = PG_BUSY | PG_CLEAN | PG_FAKE; + mem->wire_count = 0; + + /* + * Decide if we should poke the pageout daemon. + * We do this if the free count is less than the low + * water mark, or if the free count is less than the high + * water mark (but above the low water mark) and the inactive + * count is less than its target. + * + * We don't have the counts locked ... if they change a little, + * it doesn't really matter. + */ + + if (cnt.v_free_count < cnt.v_free_min || + (cnt.v_free_count < cnt.v_free_target && + cnt.v_inactive_count < cnt.v_inactive_target)) + thread_wakeup((void *)&vm_pages_needed); + return (mem); +} + +/* + * vm_page_free1: + * + * Returns the given page to the free list, + * disassociating it with any VM object. + * + * Object and page must be locked prior to entry. + */ +void +vm_page_free1(mem) + register vm_page_t mem; +{ + + if (mem->flags & PG_ACTIVE) { + TAILQ_REMOVE(&vm_page_queue_active, mem, pageq); + mem->flags &= ~PG_ACTIVE; + cnt.v_active_count--; + } + + if (mem->flags & PG_INACTIVE) { + TAILQ_REMOVE(&vm_page_queue_inactive, mem, pageq); + mem->flags &= ~PG_INACTIVE; + cnt.v_inactive_count--; + } + + if (!(mem->flags & PG_FICTITIOUS)) { + int spl; + + spl = splimp(); + simple_lock(&vm_page_queue_free_lock); + TAILQ_INSERT_TAIL(&vm_page_queue_free, mem, pageq); + + cnt.v_free_count++; + simple_unlock(&vm_page_queue_free_lock); + splx(spl); + } +} + +/* + * Find first virtual address >= *vap that doesn't cause + * a cache alias conflict. + */ +void +pmap_prefer(foff, vap) + register vm_offset_t foff; + register vm_offset_t *vap; +{ + register vm_offset_t va = *vap; + register long m, d; + + m = 0x10000; /* Max aliased cache size */ + + d = foff - va; + d &= (m-1); + *vap = va + d; +} + diff --git a/sys/arch/arc/arc/process_machdep.c b/sys/arch/arc/arc/process_machdep.c new file mode 100644 index 00000000000..6941e7e4ad4 --- /dev/null +++ b/sys/arch/arc/arc/process_machdep.c @@ -0,0 +1,114 @@ +/* $OpenBSD: process_machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* + * Copyright (c) 1994 Adam Glass + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * 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. + * + * From: + * Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: process_machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + +/* + * This file may seem a bit stylized, but that so that it's easier to port. + * Functions to be implemented here are: + * + * process_read_regs(proc, regs) + * Get the current user-visible register set from the process + * and copy it into the regs structure (<machine/reg.h>). + * The process is stopped at the time read_regs is called. + * + * process_write_regs(proc, regs) + * Update the current register set from the passed in regs + * structure. Take care to avoid clobbering special CPU + * registers or privileged bits in the PSL. + * The process is stopped at the time write_regs is called. + * + * process_sstep(proc) + * Arrange for the process to trap after executing a single instruction. + * + * process_set_pc(proc) + * Set the process's program counter. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/vnode.h> +#include <sys/ptrace.h> +#include <machine/psl.h> +#include <machine/reg.h> + +int +process_read_regs(p, regs) + struct proc *p; + struct reg *regs; +{ + bcopy((caddr_t)p->p_md.md_regs, (caddr_t)regs, sizeof(struct reg)); + return (0); +} + +int +process_write_regs(p, regs) + struct proc *p; + struct reg *regs; +{ + bcopy((caddr_t)regs, (caddr_t)p->p_md.md_regs, sizeof(struct reg)); +/*XXX Clear to user set bits!! */ + return (0); +} + +int +process_sstep(p, sstep) + struct proc *p; +{ + if(sstep) + cpu_singlestep(p); + return (0); +} + +int +process_set_pc(p, addr) + struct proc *p; + caddr_t addr; +{ + p->p_md.md_regs[PC] = (int)addr; + return (0); +} + diff --git a/sys/arch/arc/arc/swapgeneric.c b/sys/arch/arc/arc/swapgeneric.c new file mode 100644 index 00000000000..ebba79bfcfb --- /dev/null +++ b/sys/arch/arc/arc/swapgeneric.c @@ -0,0 +1,195 @@ +/* $OpenBSD: swapgeneric.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* $NetBSD: swapgeneric.c,v 1.3 1995/03/24 15:03:02 cgd Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)swapgeneric.c 5.5 (Berkeley) 5/9/91 + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/systm.h> +#include <sys/reboot.h> +#include <sys/device.h> +#include <sys/disklabel.h> + +#include <machine/pte.h> + +/* + * Generic configuration; all in one + */ +dev_t rootdev = NODEV; +dev_t argdev = NODEV; +dev_t dumpdev = NODEV; +int nswap; +struct swdevt swdevt[] = { + { NODEV, 1, 0 }, + { NODEV, 0, 0 }, +}; +long dumplo; +int dmmin, dmmax, dmtext; + +#include "sd.h" +#if NSD > 0 +extern struct cfdriver sd_cd; +#endif +#include "fdc.h" +#if NFDC > 0 +extern struct cfdriver fd_cd; +#endif + +struct genericconf { + struct cfdriver *gc_driver; + char *gc_name; + dev_t gc_major; +} genericconf[] = { +#if NSD > 0 + { &sd_cd, "sd", 0 }, +#endif +#if NFDC > 0 + { &fd_cd, "fd", 7 }, +#endif + { 0 } +}; + +extern int ffs_mountroot(); +int (*mountroot)() = ffs_mountroot; + +setconf() +{ + register struct genericconf *gc; + int unit, swaponroot = 0; + + if (rootdev != NODEV) + goto doswap; + + if (genericconf[0].gc_driver == 0) + goto verybad; + + if (boothowto & RB_ASKNAME) { + char name[128]; +retry: + printf("root device? "); + gets(name); + + if (strcmp(name, "halt") == 0) + boot(RB_HALT); + + for (gc = genericconf; gc->gc_driver; gc++) + if (gc->gc_name[0] == name[0] && + gc->gc_name[1] == name[1]) + goto gotit; + goto bad; +gotit: + if (name[3] == '*') { + name[3] = name[4]; + swaponroot++; + } + if (name[2] >= '0' && name[2] <= '7' && name[3] == 0) { + unit = name[2] - '0'; + goto found; + } + printf("bad/missing unit number\n"); +bad: + printf("use:\n"); + for (gc = genericconf; gc->gc_driver; gc++) + printf("\t%s%%d\n", gc->gc_name); + printf("\thalt\n"); + goto retry; + } + unit = 0; + for (gc = genericconf; gc->gc_driver; gc++) { + if (gc->gc_driver->cd_ndevs > unit && + gc->gc_driver->cd_devs[unit]) { + printf("root on %s0\n", gc->gc_name); + goto found; + } + } +verybad: + printf("no suitable root\n"); + boot(RB_HALT); + +found: + rootdev = makedev(gc->gc_major, unit * MAXPARTITIONS); +doswap: + swdevt[0].sw_dev = argdev = dumpdev = + makedev(major(rootdev), minor(rootdev) + 1); + /* swap size and dumplo set during autoconfigure */ + if (swaponroot) + rootdev = dumpdev; +} + +gets(cp) + char *cp; +{ + register char *lp; + register c; + + lp = cp; + for (;;) { + c = cngetc() & 0177; + switch (c) { + case '\n': + case '\r': + cnputc(c); + *lp++ = '\0'; + return; + case '\b': + case '\177': + if (lp > cp) { + printf("\b \b"); + lp--; + } + continue; + case '#': + cnputc(c); + lp--; + if (lp < cp) + lp = cp; + continue; + case '@': + case 'u'&037: + cnputc(c); + cnputc('\n'); + lp = cp; + continue; + default: + cnputc(c); + *lp++ = c; + } + } +} diff --git a/sys/arch/arc/arc/sys_machdep.c b/sys/arch/arc/arc/sys_machdep.c new file mode 100644 index 00000000000..54a5ef1b15a --- /dev/null +++ b/sys/arch/arc/arc/sys_machdep.c @@ -0,0 +1,130 @@ +/* $OpenBSD: sys_machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* $NetBSD: sys_machdep.c,v 1.6 1994/10/26 21:10:42 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)sys_machdep.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/file.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/mtio.h> +#include <sys/buf.h> +#include <sys/trace.h> + +#include <sys/mount.h> +#include <sys/syscallargs.h> + +#ifdef TRACE +int nvualarm; + +vtrace(p, uap, retval) + struct proc *p; + register struct vtrace_args /* { + syscallarg(int) request; + syscallarg(int) value; + } */ *uap; + register_t *retval; +{ + int vdoualarm(); + + switch (SCARG(uap, request)) { + + case VTR_DISABLE: /* disable a trace point */ + case VTR_ENABLE: /* enable a trace point */ + if (SCARG(uap, value) < 0 || SCARG(uap, value) >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[SCARG(uap, value)]; + traceflags[SCARG(uap, value)] = SCARG(uap, request); + break; + + case VTR_VALUE: /* return a trace point setting */ + if (SCARG(uap, value) < 0 || SCARG(uap, value) >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[SCARG(uap, value)]; + break; + + case VTR_UALARM: /* set a real-time ualarm, less than 1 min */ + if (SCARG(uap, value) <= 0 || SCARG(uap, value) > 60 * hz || + nvualarm > 5) + return (EINVAL); + nvualarm++; + timeout(vdoualarm, (caddr_t)p->p_pid, SCARG(uap, value)); + break; + + case VTR_STAMP: + trace(TR_STAMP, SCARG(uap, value), p->p_pid); + break; + } + return (0); +} + +vdoualarm(arg) + int arg; +{ + register struct proc *p; + + p = pfind(arg); + if (p) + psignal(p, 16); + nvualarm--; +} +#endif + +sys_sysarch(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sys_sysarch_args /* { + syscallarg(int) op; + syscallarg(char *) parms; + } */ *uap = v; + int error = 0; + + switch(SCARG(uap, op)) { + default: + error = EINVAL; + break; + } + return(error); +} diff --git a/sys/arch/arc/arc/trap.c b/sys/arch/arc/arc/trap.c new file mode 100644 index 00000000000..99b6ba53a6f --- /dev/null +++ b/sys/arch/arc/arc/trap.c @@ -0,0 +1,1561 @@ +/* $OpenBSD: trap.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: trap.c 1.32 91/04/06 + * + * from: @(#)trap.c 8.5 (Berkeley) 1/11/94 + * $Id: trap.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/signalvar.h> +#include <sys/syscall.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/device.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif +#include <net/netisr.h> + +#include <machine/trap.h> +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> +#include <machine/pte.h> +#include <machine/pmap.h> +#include <machine/mips_opcode.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> + +#include <arc/pica/pica.h> + +#include <sys/cdefs.h> +#include <sys/syslog.h> + +struct proc *machFPCurProcPtr; /* pointer to last proc to use FP */ + +extern void MachKernGenException(); +extern void MachUserGenException(); +extern void MachKernIntr(); +extern void MachUserIntr(); +extern void MachTLBModException(); +extern void MachTLBInvalidException(); +extern unsigned MachEmulateBranch(); + +void (*machExceptionTable[])() = { +/* + * The kernel exception handlers. + */ + MachKernIntr, /* external interrupt */ + MachKernGenException, /* TLB modification */ + MachTLBInvalidException, /* TLB miss (load or instr. fetch) */ + MachTLBInvalidException, /* TLB miss (store) */ + MachKernGenException, /* address error (load or I-fetch) */ + MachKernGenException, /* address error (store) */ + MachKernGenException, /* bus error (I-fetch) */ + MachKernGenException, /* bus error (load or store) */ + MachKernGenException, /* system call */ + MachKernGenException, /* breakpoint */ + MachKernGenException, /* reserved instruction */ + MachKernGenException, /* coprocessor unusable */ + MachKernGenException, /* arithmetic overflow */ + MachKernGenException, /* trap exception */ + MachKernGenException, /* viritual coherence exception inst */ + MachKernGenException, /* floating point exception */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* watch exception */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* reserved */ + MachKernGenException, /* viritual coherence exception data */ +/* + * The user exception handlers. + */ + MachUserIntr, /* 0 */ + MachUserGenException, /* 1 */ + MachUserGenException, /* 2 */ + MachUserGenException, /* 3 */ + MachUserGenException, /* 4 */ + MachUserGenException, /* 5 */ + MachUserGenException, /* 6 */ + MachUserGenException, /* 7 */ + MachUserGenException, /* 8 */ + MachUserGenException, /* 9 */ + MachUserGenException, /* 10 */ + MachUserGenException, /* 11 */ + MachUserGenException, /* 12 */ + MachUserGenException, /* 13 */ + MachUserGenException, /* 14 */ + MachUserGenException, /* 15 */ + MachUserGenException, /* 16 */ + MachUserGenException, /* 17 */ + MachUserGenException, /* 18 */ + MachUserGenException, /* 19 */ + MachUserGenException, /* 20 */ + MachUserGenException, /* 21 */ + MachUserGenException, /* 22 */ + MachUserGenException, /* 23 */ + MachUserGenException, /* 24 */ + MachUserGenException, /* 25 */ + MachUserGenException, /* 26 */ + MachUserGenException, /* 27 */ + MachUserGenException, /* 28 */ + MachUserGenException, /* 29 */ + MachUserGenException, /* 20 */ + MachUserGenException, /* 31 */ +}; + +char *trap_type[] = { + "external interrupt", + "TLB modification", + "TLB miss (load or instr. fetch)", + "TLB miss (store)", + "address error (load or I-fetch)", + "address error (store)", + "bus error (I-fetch)", + "bus error (load or store)", + "system call", + "breakpoint", + "reserved instruction", + "coprocessor unusable", + "arithmetic overflow", + "trap", + "viritual coherency instruction", + "floating point", + "reserved 16", + "reserved 17", + "reserved 18", + "reserved 19", + "reserved 20", + "reserved 21", + "reserved 22", + "watch", + "reserved 24", + "reserved 25", + "reserved 26", + "reserved 27", + "reserved 28", + "reserved 29", + "reserved 30", + "viritual coherency data", +}; + +struct { + int int_mask; + int (*int_hand)(); +} cpu_int_tab[8]; + +int cpu_int_mask; /* External cpu interrupt mask */ + +#ifdef DEBUG +#define TRAPSIZE 10 +struct trapdebug { /* trap history buffer for debugging */ + u_int status; + u_int cause; + u_int vadr; + u_int pc; + u_int ra; + u_int sp; + u_int code; +} trapdebug[TRAPSIZE], *trp = trapdebug; +#endif /* DEBUG */ + +#ifdef DEBUG /* stack trace code, also useful for DDB one day */ +extern void stacktrace(); +extern void logstacktrace(); + +/* extern functions printed by name in stack backtraces */ +extern void idle(), cpu_switch(), splx(), wbflush(); +extern void MachTLBMiss(); +#endif /* DEBUG */ + +static void arc_errintr(); +extern const struct callback *callv; +extern volatile struct chiptime *Mach_clock_addr; +extern u_long intrcnt[]; + +/* + * Handle an exception. + * Called from MachKernGenException() or MachUserGenException() + * when a processor trap occurs. + * In the case of a kernel trap, we return the pc where to resume if + * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc. + */ +unsigned +trap(statusReg, causeReg, vadr, pc, args) + unsigned statusReg; /* status register at time of the exception */ + unsigned causeReg; /* cause register at time of exception */ + unsigned vadr; /* address (if any) the fault occured on */ + unsigned pc; /* program counter where to continue */ +{ + register int type, i; + unsigned ucode = 0; + register struct proc *p = curproc; + u_quad_t sticks; + vm_prot_t ftype; + extern unsigned onfault_table[]; + +#ifdef DEBUG + trp->status = statusReg; + trp->cause = causeReg; + trp->vadr = vadr; + trp->pc = pc; + trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] : + p->p_md.md_regs[RA]; + trp->sp = (int)&args; + trp->code = 0; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; +#endif + + cnt.v_trap++; + type = (causeReg & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; + if (USERMODE(statusReg)) { + type |= T_USER; + sticks = p->p_sticks; + } + + /* + * Enable hardware interrupts if they were on before. + * We only respond to software interrupts when returning to user mode. + */ + if (statusReg & SR_INT_ENAB) + splx((statusReg & HARD_INT_MASK) | SR_INT_ENAB); + + switch (type) { + case T_TLB_MOD: + /* check for kernel address */ + if ((int)vadr < 0) { + register pt_entry_t *pte; + register unsigned entry; + register vm_offset_t pa; + + pte = kvtopte(vadr); + entry = pte->pt_entry; +#ifdef DIAGNOSTIC + if (!(entry & PG_V) || (entry & PG_M)) + panic("trap: ktlbmod: invalid pte"); +#endif + if (pmap_is_page_ro(pmap_kernel(), pica_trunc_page(vadr), entry)) { + /* write to read only page in the kernel */ + ftype = VM_PROT_WRITE; + goto kernel_fault; + } + entry |= PG_M; + pte->pt_entry = entry; + vadr &= ~PGOFSET; + MachTLBUpdate(vadr, entry); + pa = pfn_to_vad(entry); +#ifdef ATTR + pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD; +#else + if (!IS_VM_PHYSADDR(pa)) + panic("trap: ktlbmod: unmanaged page"); + PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; +#endif + return (pc); + } + /* FALLTHROUGH */ + + case T_TLB_MOD+T_USER: + { + register pt_entry_t *pte; + register unsigned entry; + register vm_offset_t pa; + pmap_t pmap = &p->p_vmspace->vm_pmap; + + if (!(pte = pmap_segmap(pmap, vadr))) + panic("trap: utlbmod: invalid segmap"); + pte += (vadr >> PGSHIFT) & (NPTEPG - 1); + entry = pte->pt_entry; +#ifdef DIAGNOSTIC + if (!(entry & PG_V) || (entry & PG_M)) { + panic("trap: utlbmod: invalid pte"); + } +#endif + if (pmap_is_page_ro(pmap, pica_trunc_page(vadr), entry)) { + /* write to read only page */ + ftype = VM_PROT_WRITE; + goto dofault; + } + entry |= PG_M; + pte->pt_entry = entry; + vadr = (vadr & ~PGOFSET) | + (pmap->pm_tlbpid << VMTLB_PID_SHIFT); + MachTLBUpdate(vadr, entry); + pa = pfn_to_vad(entry); +#ifdef ATTR + pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD; +#else + if (!IS_VM_PHYSADDR(pa)) { + panic("trap: utlbmod: unmanaged page"); + } + PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; +#endif + if (!USERMODE(statusReg)) + return (pc); + goto out; + } + + case T_TLB_LD_MISS: + case T_TLB_ST_MISS: + ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; + /* check for kernel address */ + if ((int)vadr < 0) { + register vm_offset_t va; + int rv; + + kernel_fault: + va = trunc_page((vm_offset_t)vadr); + rv = vm_fault(kernel_map, va, ftype, FALSE); + if (rv == KERN_SUCCESS) + return (pc); + if (i = ((struct pcb *)UADDR)->pcb_onfault) { + ((struct pcb *)UADDR)->pcb_onfault = 0; + return (onfault_table[i]); + } + goto err; + } + /* + * It is an error for the kernel to access user space except + * through the copyin/copyout routines. + */ + if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 0) + goto err; + /* check for fuswintr() or suswintr() getting a page fault */ + if (i == 4) + return (onfault_table[i]); + goto dofault; + + case T_TLB_LD_MISS+T_USER: + ftype = VM_PROT_READ; + goto dofault; + + case T_TLB_ST_MISS+T_USER: + ftype = VM_PROT_WRITE; + dofault: + { + register vm_offset_t va; + register struct vmspace *vm; + register vm_map_t map; + int rv; + + vm = p->p_vmspace; + map = &vm->vm_map; + va = trunc_page((vm_offset_t)vadr); + rv = vm_fault(map, va, ftype, FALSE); +#ifdef VMFAULT_TRACE + printf("vm_fault(%x (pmap %x), %x (%x), %x, %d) -> %x at pc %x\n", + map, &vm->vm_pmap, va, vadr, ftype, FALSE, rv, pc); +#endif + /* + * If this was a stack access we keep track of the maximum + * accessed stack size. Also, if vm_fault gets a protection + * failure it is due to accessing the stack region outside + * the current limit and we need to reflect that as an access + * error. + */ + if ((caddr_t)va >= vm->vm_maxsaddr) { + if (rv == KERN_SUCCESS) { + unsigned nss; + + nss = clrnd(btoc(USRSTACK-(unsigned)va)); + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + } else if (rv == KERN_PROTECTION_FAILURE) + rv = KERN_INVALID_ADDRESS; + } + if (rv == KERN_SUCCESS) { + if (!USERMODE(statusReg)) + return (pc); + goto out; + } + if (!USERMODE(statusReg)) { + if (i = ((struct pcb *)UADDR)->pcb_onfault) { + ((struct pcb *)UADDR)->pcb_onfault = 0; + return (onfault_table[i]); + } + goto err; + } + ucode = vadr; + i = SIGSEGV; + break; + } + + case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ + case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ + case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ + case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ + i = SIGBUS; + break; + + case T_SYSCALL+T_USER: + { + register int *locr0 = p->p_md.md_regs; + register struct sysent *callp; + unsigned int code; + int numsys; + struct args { + int i[8]; + } args; + int rval[2]; + + cnt.v_syscall++; + /* compute next PC after syscall instruction */ + if ((int)causeReg < 0) + locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0); + else + locr0[PC] += 4; + callp = p->p_emul->e_sysent; + numsys = p->p_emul->e_nsysent; + code = locr0[V0]; + switch (code) { + case SYS_syscall: + /* + * Code is first argument, followed by actual args. + */ + code = locr0[A0]; + if (code >= numsys) + callp += p->p_emul->e_nosys; /* (illegal) */ + else + callp += code; + i = callp->sy_argsize / sizeof(int); + args.i[0] = locr0[A1]; + args.i[1] = locr0[A2]; + args.i[2] = locr0[A3]; + if (i > 3) { + i = copyin((caddr_t)(locr0[SP] + + 4 * sizeof(int)), + (caddr_t)&args.i[3], + (u_int)(i - 3) * sizeof(int)); + if (i) { + locr0[V0] = i; + locr0[A3] = 1; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, + callp->sy_argsize, + args.i); +#endif + goto done; + } + } + break; + + case SYS___syscall: + /* + * Like syscall, but code is a quad, so as to maintain + * quad alignment for the rest of the arguments. + */ + code = locr0[A0 + _QUAD_LOWWORD]; + if (code >= numsys) + callp += p->p_emul->e_nosys; /* (illegal) */ + else + callp += code; + i = callp->sy_argsize / sizeof(int); + args.i[0] = locr0[A2]; + args.i[1] = locr0[A3]; + if (i > 2) { + i = copyin((caddr_t)(locr0[SP] + + 4 * sizeof(int)), + (caddr_t)&args.i[2], + (u_int)(i - 2) * sizeof(int)); + if (i) { + locr0[V0] = i; + locr0[A3] = 1; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, + callp->sy_argsize, + args.i); +#endif + goto done; + } + } + break; + + default: + if (code >= numsys) + callp += p->p_emul->e_nosys; /* (illegal) */ + else + callp += code; + i = callp->sy_narg; + args.i[0] = locr0[A0]; + args.i[1] = locr0[A1]; + args.i[2] = locr0[A2]; + args.i[3] = locr0[A3]; + if (i > 4) { + i = copyin((caddr_t)(locr0[SP] + + 4 * sizeof(int)), + (caddr_t)&args.i[4], + (u_int)(i - 4) * sizeof(int)); + if (i) { + locr0[V0] = i; + locr0[A3] = 1; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, + callp->sy_argsize, + args.i); +#endif + goto done; + } + } + } +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_argsize, args.i); +#endif + rval[0] = 0; + rval[1] = locr0[V1]; +#ifdef DEBUG + if (trp == trapdebug) + trapdebug[TRAPSIZE - 1].code = code; + else + trp[-1].code = code; +#endif + i = (*callp->sy_call)(p, &args, rval); + /* + * Reinitialize proc pointer `p' as it may be different + * if this is a child returning from fork syscall. + */ + p = curproc; + locr0 = p->p_md.md_regs; +#ifdef DEBUG + { int s; + s = splhigh(); + trp->status = statusReg; + trp->cause = causeReg; + trp->vadr = locr0[SP]; + trp->pc = locr0[PC]; + trp->ra = locr0[RA]; + trp->code = -code; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; + splx(s); + } +#endif + switch (i) { + case 0: + locr0[V0] = rval[0]; + locr0[V1] = rval[1]; + locr0[A3] = 0; + break; + + case ERESTART: + locr0[PC] = pc; + break; + + case EJUSTRETURN: + break; /* nothing to do */ + + default: + locr0[V0] = i; + locr0[A3] = 1; + } + if(code == SYS_ptrace) + MachFlushCache(); + done: +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, i, rval); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, i, rval[0]); +#endif + goto out; + } + + case T_BREAK+T_USER: + { + register unsigned va, instr; + struct uio uio; + struct iovec iov; + + /* compute address of break instruction */ + va = pc; + if ((int)causeReg < 0) + va += 4; + + /* read break instruction */ + instr = fuiword((caddr_t)va); +#if 0 + printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n", + p->p_comm, p->p_pid, instr, pc, + p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */ +#endif + if (p->p_md.md_ss_addr != va || instr != BREAK_SSTEP) { + i = SIGTRAP; + break; + } + + /* + * Restore original instruction and clear BP + */ + iov.iov_base = (caddr_t)&p->p_md.md_ss_instr; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)va; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_WRITE; + uio.uio_procp = curproc; + i = procfs_domem(p, p, NULL, &uio); + MachFlushCache(); + + if (i < 0) + printf("Warning: can't restore instruction at %x: %x\n", + p->p_md.md_ss_addr, p->p_md.md_ss_instr); + + p->p_md.md_ss_addr = 0; + i = SIGTRAP; + break; + } + + case T_RES_INST+T_USER: + i = SIGILL; + break; + + case T_COP_UNUSABLE+T_USER: + if ((causeReg & CR_COP_ERR) != 0x10000000) { + i = SIGILL; /* only FPU instructions allowed */ + break; + } + MachSwitchFPState(machFPCurProcPtr, p->p_md.md_regs); + machFPCurProcPtr = p; + p->p_md.md_regs[PS] |= SR_COP_1_BIT; + p->p_md.md_flags |= MDP_FPUSED; + goto out; + + case T_FPE: +#ifdef DEBUG + trapDump("fpintr"); +#else + printf("FPU Trap: PC %x CR %x SR %x\n", + pc, causeReg, statusReg); + goto err; +#endif + + case T_FPE+T_USER: + MachFPTrap(statusReg, causeReg, pc); + goto out; + + case T_OVFLOW+T_USER: + i = SIGFPE; + break; + + case T_ADDR_ERR_LD: /* misaligned access */ + case T_ADDR_ERR_ST: /* misaligned access */ + case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ + if (i = ((struct pcb *)UADDR)->pcb_onfault) { + ((struct pcb *)UADDR)->pcb_onfault = 0; + return (onfault_table[i]); + } + /* FALLTHROUGH */ + + default: + err: +#ifdef DEBUG + { + extern struct pcb mdbpcb; + + if (USERMODE(statusReg)) + mdbpcb = p->p_addr->u_pcb; + else { + mdbpcb.pcb_regs[ZERO] = 0; + mdbpcb.pcb_regs[AST] = ((int *)&args)[2]; + mdbpcb.pcb_regs[V0] = ((int *)&args)[3]; + mdbpcb.pcb_regs[V1] = ((int *)&args)[4]; + mdbpcb.pcb_regs[A0] = ((int *)&args)[5]; + mdbpcb.pcb_regs[A1] = ((int *)&args)[6]; + mdbpcb.pcb_regs[A2] = ((int *)&args)[7]; + mdbpcb.pcb_regs[A3] = ((int *)&args)[8]; + mdbpcb.pcb_regs[T0] = ((int *)&args)[9]; + mdbpcb.pcb_regs[T1] = ((int *)&args)[10]; + mdbpcb.pcb_regs[T2] = ((int *)&args)[11]; + mdbpcb.pcb_regs[T3] = ((int *)&args)[12]; + mdbpcb.pcb_regs[T4] = ((int *)&args)[13]; + mdbpcb.pcb_regs[T5] = ((int *)&args)[14]; + mdbpcb.pcb_regs[T6] = ((int *)&args)[15]; + mdbpcb.pcb_regs[T7] = ((int *)&args)[16]; + mdbpcb.pcb_regs[T8] = ((int *)&args)[17]; + mdbpcb.pcb_regs[T9] = ((int *)&args)[18]; + mdbpcb.pcb_regs[RA] = ((int *)&args)[19]; + mdbpcb.pcb_regs[MULLO] = ((int *)&args)[21]; + mdbpcb.pcb_regs[MULHI] = ((int *)&args)[22]; + mdbpcb.pcb_regs[PC] = pc; + mdbpcb.pcb_regs[SR] = statusReg; + bzero((caddr_t)&mdbpcb.pcb_regs[F0], 33 * sizeof(int)); + } + if (mdb(causeReg, vadr, p, !USERMODE(statusReg))) + return (mdbpcb.pcb_regs[PC]); + } +#else +#ifdef DEBUG + stacktrace(); + trapDump("trap"); +#endif +#endif + panic("trap"); + } + p->p_md.md_regs[PC] = pc; + p->p_md.md_regs[CAUSE] = causeReg; + p->p_md.md_regs[BADVADDR] = vadr; + trapsignal(p, i, ucode); +out: + /* + * Note: we should only get here if returning to user mode. + */ + /* take pending signals */ + while ((i = CURSIG(p)) != 0) + postsig(i); + p->p_priority = p->p_usrpri; + astpending = 0; + if (want_resched) { + int s; + + /* + * Since we are curproc, clock will normally just change + * our priority without moving us from one queue to another + * (since the running process is not on a queue.) + * If that happened after we put ourselves on the run queue + * but before we switched, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + splx(s); + while ((i = CURSIG(p)) != 0) + postsig(i); + } + + /* + * If profiling, charge system time to the trapped pc. + */ + if (p->p_flag & P_PROFIL) { + extern int psratio; + + addupc_task(p, pc, (int)(p->p_sticks - sticks) * psratio); + } + + curpriority = p->p_priority; + return (pc); +} + +/* + * Handle an interrupt. + * Called from MachKernIntr() or MachUserIntr() + * Note: curproc might be NULL. + */ +interrupt(statusReg, causeReg, pc, what, args) + unsigned statusReg; /* status register at time of the exception */ + unsigned causeReg; /* cause register at time of exception */ + unsigned pc; /* program counter where to continue */ +{ + register unsigned mask; + register int i; + struct clockframe cf; + +#ifdef DEBUG + trp->status = statusReg; + trp->cause = causeReg; + trp->vadr = 0; + trp->pc = pc; + trp->ra = 0; + trp->sp = (int)&args; + trp->code = 0; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; +#endif + + cnt.v_intr++; + mask = causeReg & statusReg; /* pending interrupts & enable mask */ + + /* + * Check off all enabled interrupts. Called interrupt routine + * returns mask of interrupts to reenable. + */ + for(i = 0; i < 5; i++) { + if(cpu_int_tab[i].int_mask & mask) { + causeReg &= (*cpu_int_tab[i].int_hand)(mask, pc, statusReg, causeReg); + } + } + /* + * Reenable all non served hardware levels. + */ + splx((statusReg & ~causeReg & HARD_INT_MASK) | SR_INT_ENAB); + + + if (mask & SOFT_INT_MASK_0) { + clearsoftclock(); + cnt.v_soft++; + softclock(); + } + /* + * Process network interrupt if we trapped or will very soon + */ + if ((mask & SOFT_INT_MASK_1) || + netisr && (statusReg & SOFT_INT_MASK_1)) { + clearsoftnet(); + cnt.v_soft++; + intrcnt[1]++; +#ifdef INET + if (netisr & (1 << NETISR_ARP)) { + netisr &= ~(1 << NETISR_ARP); + arpintr(); + } + if (netisr & (1 << NETISR_IP)) { + netisr &= ~(1 << NETISR_IP); + ipintr(); + } +#endif +#ifdef NS + if (netisr & (1 << NETISR_NS)) { + netisr &= ~(1 << NETISR_NS); + nsintr(); + } +#endif +#ifdef ISO + if (netisr & (1 << NETISR_ISO)) { + netisr &= ~(1 << NETISR_ISO); + clnlintr(); + } +#endif +#include "ppp.h" +#if NPPP > 0 + if(netisr & (1 << NETISR_PPP)) { + netisr &= ~(1 << NETISR_PPP); + pppintr(); + } +#endif + } + if (mask & SOFT_INT_MASK_0) { + clearsoftclock(); + intrcnt[0]++; + cnt.v_soft++; + softclock(); + } +} + + +set_intr(mask, int_hand, prio) + int mask; + int (*int_hand)(); + int prio; +{ + if(prio > 4) + panic("set_intr: to high priority"); + + if(cpu_int_tab[prio].int_mask != 0) + panic("set_intr: int already set"); + + cpu_int_tab[prio].int_hand = int_hand; + cpu_int_tab[prio].int_mask = mask; + cpu_int_mask |= mask >> 10; + + /* + * Update external interrupt mask but don't enable clock. + */ + out32(PICA_SYS_EXT_IMASK, cpu_int_mask & (~INT_MASK_4 >> 10)); +} + +/* + * This is called from MachUserIntr() if astpending is set. + * This is very similar to the tail of trap(). + */ +softintr(statusReg, pc) + unsigned statusReg; /* status register at time of the exception */ + unsigned pc; /* program counter where to continue */ +{ + register struct proc *p = curproc; + int sig; + + cnt.v_soft++; + /* take pending signals */ + while ((sig = CURSIG(p)) != 0) + postsig(sig); + p->p_priority = p->p_usrpri; + astpending = 0; + if (p->p_flag & P_OWEUPC) { + p->p_flag &= ~P_OWEUPC; + ADDUPROF(p); + } + if (want_resched) { + int s; + + /* + * Since we are curproc, clock will normally just change + * our priority without moving us from one queue to another + * (since the running process is not on a queue.) + * If that happened after we put ourselves on the run queue + * but before we switched, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + splx(s); + while ((sig = CURSIG(p)) != 0) + postsig(sig); + } + curpriority = p->p_priority; +} + +#ifdef DEBUG +trapDump(msg) + char *msg; +{ + register int i; + int s; + + s = splhigh(); + printf("trapDump(%s)\n", msg); + for (i = 0; i < TRAPSIZE; i++) { + if (trp == trapdebug) + trp = &trapdebug[TRAPSIZE - 1]; + else + trp--; + if (trp->cause == 0) + break; + printf("%s: ADR %x PC %x CR %x SR %x\n", + trap_type[(trp->cause & CR_EXC_CODE) >> + CR_EXC_CODE_SHIFT], + trp->vadr, trp->pc, trp->cause, trp->status); + printf(" RA %x SP %x code %d\n", trp->ra, trp->sp, trp->code); + } + splx(s); +} +#endif + +/* + *---------------------------------------------------------------------- + * + * MemErrorInterrupts -- + * arc_errintr - for the ACER PICA_61 + * + * Handler an interrupt for the control register. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +arc_errintr() +{ +#if 0 + volatile u_short *sysCSRPtr = + (u_short *)PHYS_TO_UNCACHED(KN01_SYS_CSR); + u_short csr; + + csr = *sysCSRPtr; + + if (csr & KN01_CSR_MERR) { + printf("Memory error at 0x%x\n", + *(unsigned *)PHYS_TO_UNCACHED(KN01_SYS_ERRADR)); + panic("Mem error interrupt"); + } + *sysCSRPtr = (csr & ~KN01_CSR_MBZ) | 0xff; +#endif +} + + +/* + * Return the resulting PC as if the branch was executed. + */ +unsigned +MachEmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch) + unsigned *regsPtr; + unsigned instPC; + unsigned fpcCSR; + int allowNonBranch; +{ + InstFmt inst; + unsigned retAddr; + int condition; + +#define GetBranchDest(InstPtr, inst) \ + ((unsigned)InstPtr + 4 + ((short)inst.IType.imm << 2)) + + + if(allowNonBranch == 0) { + inst = *(InstFmt *)instPC; + } + else { + inst = *(InstFmt *)&allowNonBranch; + } +#if 0 + printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC, + inst.word, fpcCSR); /* XXX */ +#endif + switch ((int)inst.JType.op) { + case OP_SPECIAL: + switch ((int)inst.RType.func) { + case OP_JR: + case OP_JALR: + retAddr = regsPtr[inst.RType.rs]; + break; + + default: + if (!allowNonBranch) + panic("MachEmulateBranch: Non-branch"); + retAddr = instPC + 4; + break; + } + break; + + case OP_BCOND: + switch ((int)inst.IType.rt) { + case OP_BLTZ: + case OP_BLTZL: + case OP_BLTZAL: + case OP_BLTZALL: + if ((int)(regsPtr[inst.RType.rs]) < 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BGEZ: + case OP_BGEZL: + case OP_BGEZAL: + case OP_BGEZALL: + if ((int)(regsPtr[inst.RType.rs]) >= 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + default: + panic("MachEmulateBranch: Bad branch cond"); + } + break; + + case OP_J: + case OP_JAL: + retAddr = (inst.JType.target << 2) | + ((unsigned)instPC & 0xF0000000); + break; + + case OP_BEQ: + case OP_BEQL: + if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt]) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BNE: + case OP_BNEL: + if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt]) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BLEZ: + case OP_BLEZL: + if ((int)(regsPtr[inst.RType.rs]) <= 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BGTZ: + case OP_BGTZL: + if ((int)(regsPtr[inst.RType.rs]) > 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_COP1: + switch (inst.RType.rs) { + case OP_BCx: + case OP_BCy: + if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) + condition = fpcCSR & FPC_COND_BIT; + else + condition = !(fpcCSR & FPC_COND_BIT); + if (condition) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + default: + if (!allowNonBranch) + panic("MachEmulateBranch: Bad coproc branch instruction"); + retAddr = instPC + 4; + } + break; + + default: + if (!allowNonBranch) + panic("MachEmulateBranch: Non-branch instruction"); + retAddr = instPC + 4; + } +#if 0 + printf("Target addr=%x\n", retAddr); /* XXX */ +#endif + return (retAddr); +} + +/* + * This routine is called by procxmt() to single step one instruction. + * We do this by storing a break instruction after the current instruction, + * resuming execution, and then restoring the old instruction. + */ +cpu_singlestep(p) + register struct proc *p; +{ + register unsigned va; + register int *locr0 = p->p_md.md_regs; + int i; + int bpinstr = BREAK_SSTEP; + int curinstr; + struct uio uio; + struct iovec iov; + + /* + * Fetch what's at the current location. + */ + iov.iov_base = (caddr_t)&curinstr; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)locr0[PC]; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_procp = curproc; + procfs_domem(curproc, p, NULL, &uio); + + /* compute next address after current location */ + if(curinstr != 0) { + va = MachEmulateBranch(locr0, locr0[PC], locr0[FSR], curinstr); + } + else { + va = locr0[PC] + 4; + } + if (p->p_md.md_ss_addr) { + printf("SS %s (%d): breakpoint already set at %x (va %x)\n", + p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */ + return (EFAULT); + } + p->p_md.md_ss_addr = va; + /* + * Fetch what's at the current location. + */ + iov.iov_base = (caddr_t)&p->p_md.md_ss_instr; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)va; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_procp = curproc; + procfs_domem(curproc, p, NULL, &uio); + + /* + * Store breakpoint instruction at the "next" location now. + */ + iov.iov_base = (caddr_t)&bpinstr; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)va; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_WRITE; + uio.uio_procp = curproc; + i = procfs_domem(curproc, p, NULL, &uio); + MachFlushCache(); + + if (i < 0) + return (EFAULT); +#if 0 + printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", + p->p_comm, p->p_pid, p->p_md.md_ss_addr, + p->p_md.md_ss_instr, locr0[PC], curinstr); /* XXX */ +#endif + return (0); +} + +#ifdef DEBUG +kdbpeek(addr) +{ + if (addr & 3) { + printf("kdbpeek: unaligned address %x\n", addr); + return (-1); + } + return (*(int *)addr); +} +#endif + +#ifdef DEBUG +#define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ + +/* forward */ +char *fn_name(unsigned addr); +void stacktrace_subr __P((int, int, int, int, void (*)(const char*, ...))); + +/* + * Print a stack backtrace. + */ +void +stacktrace(a0, a1, a2, a3) + int a0, a1, a2, a3; +{ + stacktrace_subr(a0, a1, a2, a3, printf); +} + +void +logstacktrace(a0, a1, a2, a3) + int a0, a1, a2, a3; +{ + stacktrace_subr(a0, a1, a2, a3, addlog); +} + +void +stacktrace_subr(a0, a1, a2, a3, printfn) + int a0, a1, a2, a3; + void (*printfn) __P((const char*, ...)); +{ + unsigned pc, sp, fp, ra, va, subr; + unsigned instr, mask; + InstFmt i; + int more, stksize; + int regs[3]; + extern setsoftclock(); + extern char start[], edata[]; + unsigned int frames = 0; + + cpu_getregs(regs); + + /* get initial values from the exception frame */ + sp = regs[0]; + pc = regs[1]; + ra = 0; + fp = regs[2]; + +/* Jump here when done with a frame, to start a new one */ +loop: + ra = 0; + +/* Jump here after a nonstandard (interrupt handler) frame */ +specialframe: + stksize = 0; + subr = 0; + if (frames++ > 100) { + (*printfn)("\nstackframe count exceeded\n"); + /* return breaks stackframe-size heuristics with gcc -O2 */ + goto finish; /*XXX*/ + } + + /* check for bad SP: could foul up next frame */ + if (sp & 3 || sp < 0x80000000) { + (*printfn)("SP 0x%x: not in kernel\n", sp); + ra = 0; + subr = 0; + goto done; + } + + /* Backtraces should contine through interrupts from kernel mode */ + if (pc >= (unsigned)MachKernIntr && pc < (unsigned)MachUserIntr) { + /* NOTE: the offsets depend on the code in locore.s */ + (*printfn)("MachKernIntr+%x: (%x, %x ,%x) -------\n", + pc-(unsigned)MachKernIntr, a0, a1, a2); + a0 = kdbpeek(sp + 36); + a1 = kdbpeek(sp + 40); + a2 = kdbpeek(sp + 44); + a3 = kdbpeek(sp + 48); + + pc = kdbpeek(sp + 20); /* exc_pc - pc at time of exception */ + ra = kdbpeek(sp + 92); /* ra at time of exception */ + sp = sp + 108; + goto specialframe; + } + + +# define Between(x, y, z) \ + ( ((x) <= (y)) && ((y) < (z)) ) +# define pcBetween(a,b) \ + Between((unsigned)a, pc, (unsigned)b) + + /* + * Check for current PC in exception handler code that don't + * have a preceding "j ra" at the tail of the preceding function. + * Depends on relative ordering of functions in locore. + */ + if (pcBetween(MachKernGenException, MachUserGenException)) + subr = (unsigned) MachKernGenException; + else if (pcBetween(MachUserGenException,MachKernIntr)) + subr = (unsigned) MachUserGenException; + else if (pcBetween(MachKernIntr, MachUserIntr)) + subr = (unsigned) MachKernIntr; + else if (pcBetween(MachUserIntr, MachTLBInvalidException)) + subr = (unsigned) MachUserIntr; + else if (pcBetween(splx, wbflush)) + subr = (unsigned) splx; + else if (pcBetween(cpu_switch, fuword)) + subr = (unsigned) cpu_switch; + else if (pcBetween(idle, cpu_switch)) { + subr = (unsigned) idle; + ra = 0; + goto done; + } + else if (pc >= (unsigned)MachTLBMiss && pc < (unsigned)setsoftclock) { + (*printfn)("<<locore>>"); + goto done; + } + + /* check for bad PC */ + if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) { + (*printfn)("PC 0x%x: not in kernel\n", pc); + ra = 0; + goto done; + } + + /* + * Find the beginning of the current subroutine by scanning backwards + * from the current PC for the end of the previous subroutine. + */ + if (!subr) { + va = pc - sizeof(int); + while ((instr = kdbpeek(va)) != MIPS_JR_RA) + va -= sizeof(int); + va += 2 * sizeof(int); /* skip back over branch & delay slot */ + /* skip over nulls which might separate .o files */ + while ((instr = kdbpeek(va)) == 0) + va += sizeof(int); + subr = va; + } + + /* + * Jump here for locore entry pointsn for which the preceding + * function doesn't end in "j ra" + */ +stackscan: + /* scan forwards to find stack size and any saved registers */ + stksize = 0; + more = 3; + mask = 0; + for (va = subr; more; va += sizeof(int), + more = (more == 3) ? 3 : more - 1) { + /* stop if hit our current position */ + if (va >= pc) + break; + instr = kdbpeek(va); + i.word = instr; + switch (i.JType.op) { + case OP_SPECIAL: + switch (i.RType.func) { + case OP_JR: + case OP_JALR: + more = 2; /* stop after next instruction */ + break; + + case OP_SYSCALL: + case OP_BREAK: + more = 1; /* stop now */ + }; + break; + + case OP_BCOND: + case OP_J: + case OP_JAL: + case OP_BEQ: + case OP_BNE: + case OP_BLEZ: + case OP_BGTZ: + more = 2; /* stop after next instruction */ + break; + + case OP_COP0: + case OP_COP1: + case OP_COP2: + case OP_COP3: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + more = 2; /* stop after next instruction */ + }; + break; + + case OP_SW: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= (1 << i.IType.rt); + switch (i.IType.rt) { + case 4: /* a0 */ + a0 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 5: /* a1 */ + a1 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 6: /* a2 */ + a2 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 7: /* a3 */ + a3 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 30: /* fp */ + fp = kdbpeek(sp + (short)i.IType.imm); + break; + + case 31: /* ra */ + ra = kdbpeek(sp + (short)i.IType.imm); + } + break; + + case OP_ADDI: + case OP_ADDIU: + /* look for stack pointer adjustment */ + if (i.IType.rs != 29 || i.IType.rt != 29) + break; + stksize = - ((short)i.IType.imm); + } + } + +done: + (*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", + fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); + + if (ra) { + if (pc == ra && stksize == 0) + (*printfn)("stacktrace: loop!\n"); + else { + pc = ra; + sp += stksize; + ra = 0; + goto loop; + } + } else { +finish: + if (curproc) + (*printfn)("User-level: pid %d\n", curproc->p_pid); + else + (*printfn)("User-level: curproc NULL\n"); + } +} + +/* + * Functions ``special'' enough to print by name + */ +#ifdef __STDC__ +#define Name(_fn) { (void*)_fn, # _fn } +#else +#define Name(_fn) { _fn, "_fn"} +#endif +static struct { void *addr; char *name;} names[] = { + Name(interrupt), + Name(trap), + Name(MachKernGenException), + Name(MachUserGenException), + Name(MachKernIntr), + Name(MachUserIntr), + Name(splx), + Name(idle), + Name(cpu_switch), + {0, 0} +}; + +/* + * Map a function address to a string name, if known; or a hex string. + */ +char * +fn_name(unsigned addr) +{ + static char buf[17]; + int i = 0; + + for (i = 0; names[i].name; i++) + if (names[i].addr == (void*)addr) + return (names[i].name); + sprintf(buf, "%x", addr); + return (buf); +} + +#endif /* DEBUG */ diff --git a/sys/arch/arc/arc/vm_machdep.c b/sys/arch/arc/arc/vm_machdep.c new file mode 100644 index 00000000000..a2875520867 --- /dev/null +++ b/sys/arch/arc/arc/vm_machdep.c @@ -0,0 +1,487 @@ +/* $OpenBSD: vm_machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: vm_machdep.c 1.21 91/04/06 + * + * from: @(#)vm_machdep.c 8.3 (Berkeley) 1/4/94 + * $Id: vm_machdep.c,v 1.1 1996/06/24 09:07:21 pefo Exp $ + */ + + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/user.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#if 0 +#include <vm/vm_object.h> +#endif + +#include <machine/pte.h> +#include <machine/cpu.h> + +vm_offset_t kmem_alloc_wait_align(); + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the kernel stack and pcb, making the child + * ready to run, and marking it so that it can return differently + * than the parent. Returns 1 in the child process, 0 in the parent. + * We currently double-map the user area so that the stack is at the same + * address in each process; in the future we will probably relocate + * the frame pointers on the stack after copying. + */ +cpu_fork(p1, p2) + register struct proc *p1, *p2; +{ + register struct user *up = p2->p_addr; + register pt_entry_t *pte; + register int i; + extern struct proc *machFPCurProcPtr; + + p2->p_md.md_regs = up->u_pcb.pcb_regs; + p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; + + /* + * Cache the PTEs for the user area in the machine dependent + * part of the proc struct so cpu_switch() can quickly map in + * the user struct and kernel stack. Note: if the virtual address + * translation changes (e.g. swapout) we have to update this. + */ + pte = kvtopte(up); + for (i = 0; i < UPAGES; i++) { + p2->p_md.md_upte[i] = pte->pt_entry & ~(PG_G | PG_RO | PG_WIRED); + pte++; + } + + /* + * Copy floating point state from the FP chip if this process + * has state stored there. + */ + if (p1 == machFPCurProcPtr) + MachSaveCurFPState(p1); + + /* + * Copy pcb and stack from proc p1 to p2. + * We do this as cheaply as possible, copying only the active + * part of the stack. The stack and pcb need to agree; + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + /* cache segtab for ULTBMiss() */ + p2->p_addr->u_pcb.pcb_segtab = (void *)p2->p_vmspace->vm_pmap.pm_segtab; + + /* + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ +#ifdef DIAGNOSTIC + if (p1 != curproc) + panic("cpu_fork: curproc"); +#endif + if (copykstack(up)) { + /* + * Return 1 in child. + */ + return (1); + } + return (0); +} + +/* + * Finish a swapin operation. + * We neded to update the cached PTEs for the user area in the + * machine dependent part of the proc structure. + */ +void +cpu_swapin(p) + register struct proc *p; +{ + register struct user *up = p->p_addr; + register pt_entry_t *pte; + register int i; + + /* + * Cache the PTEs for the user area in the machine dependent + * part of the proc struct so cpu_switch() can quickly map in + * the user struct and kernel stack. + */ + pte = kvtopte(up); + for (i = 0; i < UPAGES; i++) { + p->p_md.md_upte[i] = pte->pt_entry & ~(PG_G | PG_RO | PG_WIRED); + pte++; + } +} + +/* + * cpu_exit is called as the last action during exit. + * We release the address space and machine-dependent resources, + * including the memory for the user structure and kernel stack. + * Once finished, we call switch_exit, which switches to a temporary + * pcb and stack and never returns. We block memory allocation + * until switch_exit has made things safe again. + */ +void cpu_exit(p) + struct proc *p; +{ + extern struct proc *machFPCurProcPtr; + + if (machFPCurProcPtr == p) + machFPCurProcPtr = (struct proc *)0; + + vmspace_free(p->p_vmspace); + + (void) splhigh(); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); + switch_exit(); + /* NOTREACHED */ +} + +/* + * Dump the machine specific header information at the start of a core dump. + */ +cpu_coredump(p, vp, cred, core) + struct proc *p; + struct vnode *vp; + struct ucred *cred; + struct core *core; +{ + extern struct proc *machFPCurProcPtr; + + /* + * Copy floating point state from the FP chip if this process + * has state stored there. + */ + if (p == machFPCurProcPtr) + MachSaveCurFPState(p); + + return (vn_rdwr(UIO_WRITE, vp, (caddr_t)p->p_addr, ctob(UPAGES), + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, + p)); +} + +/* + * Move pages from one kernel virtual address to another. + * Both addresses are assumed to reside in the Sysmap, + * and size must be a multiple of CLSIZE. + */ +void +pagemove(from, to, size) + register caddr_t from, to; + size_t size; +{ + register pt_entry_t *fpte, *tpte; + + if (size % CLBYTES) + panic("pagemove"); + fpte = kvtopte(from); + tpte = kvtopte(to); + if(((int)from & machCacheAliasMask) != ((int)to & machCacheAliasMask)) { + MachHitFlushDCache(from, size); + } + while (size > 0) { + MachTLBFlushAddr(from); + MachTLBUpdate(to, *fpte); + *tpte++ = *fpte; + fpte->pt_entry = PG_NV | PG_G; + fpte++; + size -= NBPG; + from += NBPG; + to += NBPG; + } +} + +extern vm_map_t phys_map; + +/* + * Map an IO request into kernel virtual address space. Requests fall into + * one of five catagories: + * + * B_PHYS|B_UAREA: User u-area swap. + * Address is relative to start of u-area (p_addr). + * B_PHYS|B_PAGET: User page table swap. + * Address is a kernel VA in usrpt (Usrptmap). + * B_PHYS|B_DIRTY: Dirty page push. + * Address is a VA in proc2's address space. + * B_PHYS|B_PGIN: Kernel pagein of user pages. + * Address is VA in user's address space. + * B_PHYS: User "raw" IO request. + * Address is VA in user's address space. + * + * All requests are (re)mapped into kernel VA space via the phys_map + */ +void +vmapbuf(bp, len) + struct buf *bp; + vm_size_t len; +{ + register caddr_t addr; + register vm_size_t sz; + struct proc *p; + int off; + vm_offset_t kva; + register vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + addr = bp->b_saveaddr = bp->b_un.b_addr; + off = (int)addr & PGOFSET; + p = bp->b_proc; + sz = round_page(off + len); + kva = kmem_alloc_wait_align(phys_map, sz, (vm_size_t)addr & machCacheAliasMask); + bp->b_un.b_addr = (caddr_t) (kva + off); + sz = atop(sz); + while (sz--) { + pa = pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), + (vm_offset_t)addr); + if (pa == 0) + panic("vmapbuf: null page frame"); + pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa), + VM_PROT_READ|VM_PROT_WRITE, TRUE); + addr += PAGE_SIZE; + kva += PAGE_SIZE; + } +} + +/* + * Free the io map PTEs associated with this IO operation. + * We also invalidate the TLB entries and restore the original b_addr. + */ +void +vunmapbuf(bp, len) + struct buf *bp; + vm_size_t len; +{ + register caddr_t addr = bp->b_un.b_addr; + register vm_size_t sz; + vm_offset_t kva; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + sz = round_page(len + ((int)addr & PGOFSET)); + kva = (vm_offset_t)((int)addr & ~PGOFSET); + kmem_free_wakeup(phys_map, kva, sz); + bp->b_un.b_addr = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} + + +/* + * SAVE_HINT: + * + * Saves the specified entry as the hint for + * future lookups. Performs necessary interlocks. + */ +#define SAVE_HINT(map,value) \ + simple_lock(&(map)->hint_lock); \ + (map)->hint = (value); \ + simple_unlock(&(map)->hint_lock); + + +/* + * kmem_alloc_upage: + * + * Allocate pageable memory to the kernel's address map. + * map must be "kernel_map" below. + * (Currently only used when allocating U pages). + */ +vm_offset_t +kmem_alloc_upage(map, size) + vm_map_t map; + register vm_size_t size; +{ + vm_offset_t addr; + register int result; + + + size = round_page(size); + + addr = vm_map_min(map); + result = vm_map_find_U(map, NULL, (vm_offset_t) 0, + &addr, size, TRUE); + if (result != KERN_SUCCESS) { + return(0); + } + + return(addr); +} + +/* + * vm_map_find finds an unallocated region in the target address + * map with the given length aligned on U viritual address. + * The search is defined to be first-fit from the specified address; + * the region found is returned in the same parameter. + * + */ +int +vm_map_find_U(map, object, offset, addr, length, find_space) + vm_map_t map; + vm_object_t object; + vm_offset_t offset; + vm_offset_t *addr; /* IN/OUT */ + vm_size_t length; + boolean_t find_space; +{ + register vm_offset_t start; + int result; + + start = *addr; + vm_map_lock(map); + if (find_space) { + if (vm_map_findspace_align(map, start, length, addr, 0)) { + vm_map_unlock(map); + return (KERN_NO_SPACE); + } + start = *addr; + } + result = vm_map_insert(map, object, offset, start, start + length); + vm_map_unlock(map); + return (result); +} + +/* + * Find sufficient space for `length' bytes in the given map, starting at + * `start'. The map must be locked. Returns 0 on success, 1 on no space. + */ +int +vm_map_findspace_align(map, start, length, addr, align) + register vm_map_t map; + register vm_offset_t start; + vm_size_t length; + vm_offset_t *addr; + vm_size_t align; +{ + register vm_map_entry_t entry, next; + register vm_offset_t end; + + if (start < map->min_offset) + start = map->min_offset; + if (start > map->max_offset) + return (1); + + /* + * Look for the first possible address; if there's already + * something at this address, we have to start after it. + */ + if (start == map->min_offset) { + if ((entry = map->first_free) != &map->header) + start = entry->end; + } else { + vm_map_entry_t tmp; + if (vm_map_lookup_entry(map, start, &tmp)) + start = tmp->end; + entry = tmp; + } + + /* + * Look through the rest of the map, trying to fit a new region in + * the gap between existing regions, or after the very last region. + */ + for (;; start = (entry = next)->end) { + /* + * Find the end of the proposed new region. Be sure we didn't + * go beyond the end of the map, or wrap around the address; + * if so, we lose. Otherwise, if this is the last entry, or + * if the proposed new region fits before the next entry, we + * win. + */ + start = ((start + NBPG -1) & ~(NBPG - 1)); /* Paranoia */ + if((start & machCacheAliasMask) <= align) { + start += align - (start & machCacheAliasMask); + } + else { + start = ((start + machCacheAliasMask) & ~machCacheAliasMask); + start += align; + } + + end = start + length; + if (end > map->max_offset || end < start) + return (1); + next = entry->next; + if (next == &map->header || next->start >= end) + break; + } + SAVE_HINT(map, entry); + *addr = start; + return (0); +} + +/* + * kmem_alloc_wait_align + * + * Allocates pageable memory from a sub-map of the kernel. If the submap + * has no room, the caller sleeps waiting for more memory in the submap. + * + */ +vm_offset_t +kmem_alloc_wait_align(map, size, align) + vm_map_t map; + vm_size_t size; + vm_size_t align; +{ + vm_offset_t addr; + + size = round_page(size); + + for (;;) { + /* + * To make this work for more than one map, + * use the map's lock to lock out sleepers/wakers. + */ + vm_map_lock(map); + if (vm_map_findspace_align(map, 0, size, &addr, align) == 0) + break; + /* no space now; see if we can ever get space */ + if (vm_map_max(map) - vm_map_min(map) < size) { + vm_map_unlock(map); + return (0); + } + assert_wait(map, TRUE); + vm_map_unlock(map); + thread_block(); + } + vm_map_insert(map, NULL, (vm_offset_t)0, addr, addr + size); + vm_map_unlock(map); + return (addr); +} diff --git a/sys/arch/arc/compile/.cvsignore b/sys/arch/arc/compile/.cvsignore new file mode 100644 index 00000000000..db5b0e04a3a --- /dev/null +++ b/sys/arch/arc/compile/.cvsignore @@ -0,0 +1 @@ +GENERIC diff --git a/sys/arch/arc/compile/.keep_me b/sys/arch/arc/compile/.keep_me new file mode 100644 index 00000000000..75270197a54 --- /dev/null +++ b/sys/arch/arc/compile/.keep_me @@ -0,0 +1 @@ +This file must remain so that 'cvs checkout' makes the compile directory. diff --git a/sys/arch/arc/conf/GENERIC b/sys/arch/arc/conf/GENERIC new file mode 100644 index 00000000000..21cfe44324b --- /dev/null +++ b/sys/arch/arc/conf/GENERIC @@ -0,0 +1,97 @@ +# +# Generic configuration file for MIPS R4400 PICA system +# + +machine arc + +maxusers 8 + +# does not really do anything anymore, but this replaces "ident GENERIC" +options GENERIC + +# Need to set locally +options TIMEZONE="8*60" # minutes west of GMT (for) +options DST=1 # use daylight savings rules + +# Standard system options +options SWAPPAGER # swap pager (anonymous and swap space) +options VNODEPAGER # vnode pager (mapped files) +options DEVPAGER # device pager (mapped devices) +options DIAGNOSTIC # extra kernel debugging checks +options DEBUG # extra kernel debugging support +options "COMPAT_43" # compatibility with 4.3BSD binaries +#options KTRACE # system call tracing support +options "NKMEMCLUSTERS=1024" # 4K pages in kernel malloc pool +#options KGDB # support for kernel gdb +#options "KGDBRATE=19200" # kernel gdb port rate (default 9600) +#options "KGDBDEV=15*256+0" # device for kernel gdb + +# System V options +options SYSVMSG # System V-like message queues +options SYSVSEM # System V-like semaphores +options SYSVSHM # System V-like memory sharing +options SHMMAXPGS=1024 # 1024 pages is the default +options NATIVE_ELF + +# Filesystem options +options FIFO # POSIX fifo support (in all filesystems) +options FFS,QUOTA # fast filesystem with user and group quotas +options MFS # memory-based filesystem +options NFSCLIENT # Sun NFS-compatible filesystem (client) +options NFSSERVER # Sun NFS-compatible filesystem (server) +options KERNFS # kernel data-structure filesystem +options MSDOSFS # Ability to read write MS-Dos filsystem +options CD9660 # ISO 9660 + Rock Ridge file system +options FDESC # user file descriptor filesystem +#options UMAPFS # uid/gid remapping filesystem +#options NULLFS # null layer filesystem +#options LFS # Log-based filesystem (still experimental) +#options PORTAL # portal filesystem (still experimental) + +# Networking options +options INET # Internet protocols +options "TCP_COMPAT_42" # compatibility with 4.2BSD TCP/IP +options GATEWAY # IP packet forwarding +#options MULTICAST # Multicast support +#options MROUTING # Multicast routing support +#options ISO # OSI networking +#options TPIP +#options EON + +config bsd swap generic + +mainbus0 at root +cpu* at mainbus0 + +pica* at mainbus0 +clock0 at pica? +pc0 at pica? +pms0 at pica? +ace0 at pica? +ace1 at pica? +lpt0 at pica? +sn0 at pica? + +fdc0 at pica? +fd* at fdc? drive ? + +asc0 at pica? +scsibus* at asc? + +sd* at scsibus? target ? lun ? +st* at scsibus? target ? lun ? +cd* at scsibus? target ? lun ? +ch* at scsibus? target ? lun ? +ss* at scsibus? target ? lun ? +uk* at scsibus? target ? lun ? + +isabr* at mainbus0 + +isa* at isabr? + +pseudo-device sl 2 # serial-line IP ports +pseudo-device ppp 2 # serial-line PPP ports +pseudo-device pty 64 # pseudo ptys +pseudo-device bpfilter 16 # packet filter ports +pseudo-device loop +pseudo-device vnd 4 # virtual disk diff --git a/sys/arch/arc/conf/Makefile.arc b/sys/arch/arc/conf/Makefile.arc new file mode 100644 index 00000000000..d78ad52e462 --- /dev/null +++ b/sys/arch/arc/conf/Makefile.arc @@ -0,0 +1,183 @@ +# $OpenBSD: Makefile.arc,v 1.1 1996/06/24 09:07:20 pefo Exp $ + +# @(#)Makefile.arc 8.2 (Berkeley) 2/16/94 +# +# Makefile for 4.4 BSD +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/arch/MACHINE/conf/``machineid'' +# after which you should do +# config machineid +# Machine generic makefile changes should be made in +# /sys/arch/MACHINE/conf/Makefile.``machinetype'' +# after which config should be rerun for all machines of that type. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE +# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING +# +# -DTRACE compile in kernel tracing hooks +# -DQUOTA compile in file system quotas + + +# DEBUG is set to -g by config if debugging is requested (config -g). +# PROF is set to -pg by config if profiling is requested (config -p). +AS?= as +CC?= cc +CPP?= cpp +LD= ld.ok # XXX TEMPORARY +STRIP?= strip -d +TOUCH?= touch -f -c + +# source tree is located via $S relative to the compilation directory +S= ../../../.. +ARC= ../.. + +INCLUDES= -I. -I$S/arch -I$S +CPPFLAGS= ${INCLUDES} ${IDENT} -D_KERNEL -Darc +CFLAGS= ${DEBUG} -O2 -Werror -mno-abicalls -mips2 -mcpu=r4000 +AFLAGS= -x assembler-with-cpp -traditional-cpp -D_LOCORE + +### find out what to use for libkern +.include "$S/lib/libkern/Makefile.inc" +.ifndef PROF +LIBKERN= ${KERNLIB} +.else +LIBKERN= ${KERNLIB_PROF} +.endif + +### find out what to use for libcompat +.include "$S/compat/common/Makefile.inc" +.ifndef PROF +LIBCOMPAT= ${COMPATLIB} +.else +LIBCOMPAT= ${COMPATLIB_PROF} +.endif + +# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP} +# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix, +# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file +# is marked as config-dependent. + +USRLAND_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +USRLAND_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +NORMAL_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +DRIVER_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +DRIVER_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $< +NORMAL_S_C= ${AS} ${COPTS} ${PARAM} $< -o $@ + +%OBJS + +%CFILES + +%SFILES + +# load lines for config "xxx" will be emitted as: +# xxx: ${SYSTEM_DEP} swapxxx.o +# ${SYSTEM_LD_HEAD} +# ${SYSTEM_LD} swapxxx.o +# ${SYSTEM_LD_TAIL} + +SYSTEM_OBJ= locore.o fp.o ${OBJS} param.o ioconf.o ${LIBKERN} \ + ${LIBCOMPAT} +# +SYSTEM_DEP= Makefile ${SYSTEM_OBJ} +SYSTEM_LD_HEAD= rm -f $@ +SYSTEM_LD= -@if [ X${DEBUG} = X-g ]; \ + then strip=-X; \ + else strip=-x; \ + fi; \ + echo ${LD} $$strip -N -o $@ -e start -Ttext 80080000 \ + '$${SYSTEM_OBJ}' vers.o; \ + ${LD} $$strip -N -o $@ -e start -Ttext 80080000 \ + ${SYSTEM_OBJ} vers.o +# +SYSTEM_LD_TAIL= chmod 755 $@; \ + elf2ecoff $@ $@.ecoff; \ + size $@ + +%LOAD + +newvers: + sh $S/conf/newvers.sh + ${CC} $(CFLAGS) -c vers.c + +clean:: + rm -f eddep bsd bsd.gdb tags *.o locore.i [a-z]*.s \ + Errs errs linterrs makelinks genassym + +lint: /tmp param.c + @lint -hbxn -DGENERIC -Dvolatile= ${COPTS} ${PARAM} -UKGDB \ + ${ARC}/arc/Locore.c ${CFILES} ${ARC}/arc/swapgeneric.c \ + ioconf.c param.c + +symbols.sort: ${ARC}/arc/symbols.raw + grep -v '^#' ${ARC}/arc/symbols.raw \ + | sed 's/^ //' | sort -u > symbols.sort + +locore.o: ${ARC}/arc/locore.S ${ARC}/include/asm.h \ + ${ARC}/include/cpu.h ${ARC}/include/reg.h assym.h + ${NORMAL_S} -mips3 ${ARC}/arc/locore.S + +fp.o: ${ARC}/arc/fp.S ${ARC}/include/asm.h \ + ${ARC}/include/cpu.h ${ARC}/include/reg.h assym.h + ${NORMAL_S} -mips3 ${ARC}/arc/fp.S + +# the following are necessary because the files depend on the types of +# cpu's included in the system configuration +clock.o machdep.o autoconf.o conf.o: Makefile + +# depend on network configuration +uipc_domain.o uipc_proto.o vfs_conf.o: Makefile +if_tun.o if_loop.o if_ethersubr.o: Makefile +in_proto.o: Makefile + +assym.h: genassym + ./genassym >assym.h + +genassym: genassym.o + ${CC} -o $@ genassym.o + +genassym.o: ${ARC}/arc/genassym.c + ${CC} ${INCLUDES} ${IDENT} -D_KERNEL -Darc -c $< + +links: + egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ + sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink + echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ + sort -u | comm -23 - dontlink | \ + sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks + sh makelinks && rm -f dontlink + +tags: + @echo "see $S/kern/Makefile for tags" + +ioconf.o: ioconf.c + ${NORMAL_C} + +param.c: $S/conf/param.c + rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${NORMAL_C_C} + +newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP} + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c + +depend:: .depend +.depend: ${SRCS} assym.h param.c + mkdep ${AFLAGS} ${CPPFLAGS} ${ARC}/arc/locore.s + mkdep -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES} + mkdep -a ${AFLAGS} ${CPPFLAGS} ${SFILES} + mkdep -a ${CFLAGS} ${CPPFLAGS} ${PARAM} ${ARC}/arc/genassym.c + +%RULES + diff --git a/sys/arch/arc/conf/PICA b/sys/arch/arc/conf/PICA new file mode 100644 index 00000000000..9251c84728d --- /dev/null +++ b/sys/arch/arc/conf/PICA @@ -0,0 +1,108 @@ +# +# Generic configuration file for MIPS R4400 PICA system +# + +machine arc + +maxusers 8 + +# does not really do anything anymore, but this replaces "ident GENERIC" +# options GENERIC + +# Need to set locally +options TIMEZONE="8*60" # minutes west of GMT (for) +options DST=1 # use daylight savings rules + +# Standard system options +options SWAPPAGER # swap pager (anonymous and swap space) +options VNODEPAGER # vnode pager (mapped files) +options DEVPAGER # device pager (mapped devices) +options DIAGNOSTIC # extra kernel debugging checks +options DEBUG # extra kernel debugging support +options "COMPAT_43" # compatibility with 4.3BSD binaries +#options KTRACE # system call tracing support +options "NKMEMCLUSTERS=1024" # 4K pages in kernel malloc pool +#options KGDB # support for kernel gdb +#options "KGDBRATE=19200" # kernel gdb port rate (default 9600) +#options "KGDBDEV=15*256+0" # device for kernel gdb + +# System V options +options SYSVMSG # System V-like message queues +options SYSVSEM # System V-like semaphores +options SYSVSHM # System V-like memory sharing +options SHMMAXPGS=1024 # 1024 pages is the default +options NATIVE_ELF + +# Filesystem options +options FIFO # POSIX fifo support (in all filesystems) +options FFS,QUOTA # fast filesystem with user and group quotas +options MFS # memory-based filesystem +options NFSCLIENT # Sun NFS-compatible filesystem (client) +options NFSSERVER # Sun NFS-compatible filesystem (server) +options KERNFS # kernel data-structure filesystem +options MSDOSFS # Ability to read write MS-Dos filsystem +options CD9660 # ISO 9660 + Rock Ridge file system +options FDESC # user file descriptor filesystem +#options UMAPFS # uid/gid remapping filesystem +#options NULLFS # null layer filesystem +#options LFS # Log-based filesystem (still experimental) +#options PORTAL # portal filesystem (still experimental) + +# Networking options +options INET # Internet protocols +options "TCP_COMPAT_42" # compatibility with 4.2BSD TCP/IP +options GATEWAY # IP packet forwarding +#options MULTICAST # Multicast support +#options MROUTING # Multicast routing support +#options ISO # OSI networking +#options TPIP +#options EON + +config bsd root on sd0 swap on sd0 and sd1 + +mainbus0 at root +cpu* at mainbus0 + +# +# PICA Bus +# +pica* at mainbus0 + +clock0 at pica? +pc0 at pica? +pms0 at pica? +ace0 at pica? +ace1 at pica? +lpt0 at pica? +sn0 at pica? + +fdc0 at pica? +fd* at fdc? drive ? + +asc0 at pica? +scsibus* at asc? + +sd* at scsibus? target ? lun ? +st* at scsibus? target ? lun ? +cd* at scsibus? target ? lun ? +ch* at scsibus? target ? lun ? +ss* at scsibus? target ? lun ? +uk* at scsibus? target ? lun ? + +# +# ISA Bus. +# +isabr* at mainbus0 + +isa* at isabr? + +ace2 at isa? port 0x3f8 irq 4 +ace3 at isa? port 0x2f8 irq 3 + + +pseudo-device sl 2 # serial-line IP ports +pseudo-device ppp 2 # serial-line PPP ports +pseudo-device pty 64 # pseudo ptys +pseudo-device bpfilter 16 # packet filter ports +pseudo-device loop +pseudo-device vnd 4 # virtual disk diff --git a/sys/arch/arc/conf/files.arc b/sys/arch/arc/conf/files.arc new file mode 100644 index 00000000000..3d57f328b3c --- /dev/null +++ b/sys/arch/arc/conf/files.arc @@ -0,0 +1,124 @@ +# $OpenBSD: files.arc,v 1.1 1996/06/24 09:07:20 pefo Exp $ +# +# maxpartitions must be first item in files.${ARCH} +# +maxpartitions 8 + +maxusers 2 8 64 + +# Required files + + +file arch/arc/arc/autoconf.c +file arch/arc/arc/conf.c +file arch/arc/arc/cpu_exec.c +file arch/arc/arc/disksubr.c +file arch/arc/dev/dma.c +file arch/arc/arc/machdep.c +file arch/arc/arc/minidebug.c +file arch/arc/arc/mem.c +file arch/arc/arc/pmap.c +file arch/arc/arc/process_machdep.c +file arch/arc/arc/sys_machdep.c +file arch/arc/arc/trap.c +file arch/arc/arc/vm_machdep.c + +# +# Machine-independent ATAPI drivers +# + +include "../../../dev/atapi/files.atapi" + + +# +# System BUS types +# + +define mainbus {} +device mainbus +attach mainbus at root +file arch/arc/arc/mainbus.c mainbus + +# Our CPU configurator +device cpu +attach cpu at mainbus # not optional +file arch/arc/arc/cpu.c cpu + +# +# PICA bus autoconfiguration devices +# +device pica {} +attach pica at mainbus # { slot = -1, offset = -1 } +file arch/arc/pica/picabus.c pica + +# Real time clock, must have one.. +device clock +attach clock at pica +file arch/arc/arc/clock.c clock +file arch/arc/arc/clock_mc.c clock + +# Ethernet chip +device sn +attach sn at pica: ifnet, ether +file arch/arc/dev/if_sn.c sn needs-count + +# Use machine independent SCSI driver routines +include "../../../scsi/files.scsi" +major {sd = 0} +major {cd = 3} + +# Machine dependent SCSI interface driver +device asc: scsi +attach asc at pica +file arch/arc/dev/asc.c asc needs-count + +# Console driver on PC-style graphics +device pc: tty +attach pc at pica +device pms: tty +attach pms at pica +file arch/arc/dev/pccons.c pc needs-count + +# Floppy disk controller +device fdc {drive = -1} +attach fdc at pica +device fd: disk +attach fd at fdc +file arch/arc/dev/fd.c fdc needs-flag +major {fd = 7} + + +# +# ISA +# +device isabr {} : isabus +attach isabr at mainbus +file arch/arc/isa/isabus.c isabr +file arch/arc/isa/isadma.c isadma needs-flag + +# +# Stock ISA bus support +# +define pcmcia {} # XXX dummy decl... +define pci {} # XXX dummy decl... + +include "../../../dev/isa/files.isa" + +# Serial driver for both ISA and LOCAL bus. +device ace: tty +attach ace at isa with ace_isa +attach ace at commulti with ace_commulti +attach ace at pica with ace_pica +file arch/arc/dev/ace.c ace & (ace_isa | ace_commulti | ace_pica) needs-flag + +# + +file dev/cons.c +file dev/cninit.c +file netinet/in_cksum.c +file netns/ns_cksum.c ns + +file compat/ultrix/ultrix_misc.c compat_ultrix +file compat/ultrix/ultrix_syscalls.c compat_ultrix +file compat/ultrix/ultrix_sysent.c compat_ultrix + diff --git a/sys/arch/arc/dev/ace.c b/sys/arch/arc/dev/ace.c new file mode 100644 index 00000000000..a285e748ff7 --- /dev/null +++ b/sys/arch/arc/dev/ace.c @@ -0,0 +1,1783 @@ +/* $OpenBSD: ace.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995, 1996 + * Charles M. Hannum. All rights reserved. + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * 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. + * + * @(#)com.c 7.5 (Berkeley) 5/16/91 + */ + +/* + * ACE driver, based on HP dca driver + * uses National Semiconductor NS16450/NS16550AF UART + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/types.h> +#include <sys/device.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/comreg.h> +#include <dev/isa/comvar.h> +#include <dev/ic/ns16550reg.h> +#ifdef COM_HAYESP +#include <dev/ic/hayespreg.h> +#endif +#define com_lcr com_cfcr + +#include "com.h" + + +#define COM_IBUFSIZE (2 * 512) +#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4) + +struct com_softc { + struct device sc_dev; + void *sc_ih; + bus_chipset_tag_t sc_bc; + struct tty *sc_tty; + + int sc_overflows; + int sc_floods; + int sc_errors; + + int sc_halt; + + int sc_iobase; +#ifdef COM_HAYESP + int sc_hayespbase; +#endif + + bus_io_handle_t sc_ioh; + bus_io_handle_t sc_hayespioh; + + u_char sc_hwflags; +#define COM_HW_NOIEN 0x01 +#define COM_HW_FIFO 0x02 +#define COM_HW_HAYESP 0x04 +#define COM_HW_ABSENT_PENDING 0x08 /* reattached, awaiting close/reopen */ +#define COM_HW_ABSENT 0x10 /* configure actually failed, or removed */ +#define COM_HW_REATTACH 0x20 /* reattaching */ +#define COM_HW_CONSOLE 0x40 + u_char sc_swflags; +#define COM_SW_SOFTCAR 0x01 +#define COM_SW_CLOCAL 0x02 +#define COM_SW_CRTSCTS 0x04 +#define COM_SW_MDMBUF 0x08 + u_char sc_msr, sc_mcr, sc_lcr, sc_ier; + u_char sc_dtr; + + u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; + u_char sc_ibufs[2][COM_IBUFSIZE]; +}; + +#ifdef COM_HAYESP +int comprobeHAYESP __P((bus_io_handle_t hayespioh, struct com_softc *sc)); +#endif +void comdiag __P((void *)); +int comspeed __P((long)); +int comparam __P((struct tty *, struct termios *)); +void comstart __P((struct tty *)); +void compoll __P((void *)); + +/* XXX: These belong elsewhere */ +cdev_decl(com); +bdev_decl(com); + +struct consdev; +void comcnprobe __P((struct consdev *)); +void comcninit __P((struct consdev *)); +int comcngetc __P((dev_t)); +void comcnputc __P((dev_t, int)); +void comcnpollc __P((dev_t, int)); + +static u_char tiocm_xxx2mcr __P((int)); + +/* + * XXX the following two cfattach structs should be different, and possibly + * XXX elsewhere. + */ +int comprobe __P((struct device *, void *, void *)); +void comattach __P((struct device *, struct device *, void *)); +void com_absent_notify __P((struct com_softc *sc)); +void comstart_pending __P((void *)); + +#if NACE_ISA +struct cfattach ace_isa_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif + +#if NACE_COMMULTI +struct cfattach ace_commulti_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif + +#if NACE_PICA +#undef CONADDR /* This is stupid but using devs before config .. */ +#define CONADDR 0xe0006000 + +struct cfattach ace_pica_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif + + +struct cfdriver ace_cd = { + NULL, "com", DV_TTY +}; + +void cominit __P((bus_chipset_tag_t, bus_io_handle_t, int)); + +#ifndef CONSPEED +#define CONSPEED B9600 +#endif + +#ifdef COMCONSOLE +int comdefaultrate = CONSPEED; /* XXX why set default? */ +#else +int comdefaultrate = TTYDEF_SPEED; +#endif +int comconsaddr; +int comconsinit; +int comconsattached; +bus_chipset_tag_t comconsbc; +bus_io_handle_t comconsioh; +tcflag_t comconscflag = TTYDEF_CFLAG; + +int commajor; +int comsopen = 0; +int comevents = 0; + +#ifdef KGDB +#include <machine/remote-sl.h> +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + +#define COMUNIT(x) (minor(x)) + +/* Macros to clear/set/test flags. */ +#define SET(t, f) (t) |= (f) +#define CLR(t, f) (t) &= ~(f) +#define ISSET(t, f) ((t) & (f)) + +#if NACE_PCMCIA +#include <dev/pcmcia/pcmciavar.h> + +int com_pcmcia_match __P((struct device *, void *, void *)); +void com_pcmcia_attach __P((struct device *, struct device *, void *)); +int com_pcmcia_detach __P((struct device *)); + +struct cfattach ace_pcmcia_ca = { + sizeof(struct com_softc), com_pcmcia_match, comattach, + com_pcmcia_detach +}; + +int com_pcmcia_mod __P((struct pcmcia_link *pc_link, struct device *self, + struct pcmcia_conf *pc_cf, struct cfdata *cf)); + +/* additional setup needed for pcmcia devices */ +/* modify config entry */ +int +com_pcmcia_mod(pc_link, self, pc_cf, cf) + struct pcmcia_link *pc_link; + struct device *self; + struct pcmcia_conf *pc_cf; + struct cfdata *cf; +{ + int err; + struct pcmciadevs *dev = pc_link->device; + struct ed_softc *sc = (void *)self; + if (!(err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self, + pc_cf, cf))) { + pc_cf->memwin = 0; + if (pc_cf->cfgtype == 0) + pc_cf->cfgtype = CFGENTRYID; /* determine from ioaddr */ + } + return err; +} + +int com_pcmcia_isa_attach __P((struct device *, void *, void *, + struct pcmcia_link *)); +int com_pcmcia_remove __P((struct pcmcia_link *, struct device *)); + +static struct pcmcia_com { + struct pcmcia_device pcd; +} pcmcia_com = { + {"PCMCIA Modem card", com_pcmcia_mod, com_pcmcia_isa_attach, + NULL, com_pcmcia_remove} +}; + + +struct pcmciadevs pcmcia_com_devs[] = { + { "com", 0, + NULL, "*MODEM*", NULL, NULL, + NULL, (void *)&pcmcia_com + }, + { "com", 0, + NULL, NULL, "*MODEM*", NULL, + NULL, (void *)&pcmcia_com + }, + { "com", 0, + NULL, NULL, NULL, "*MODEM*", + NULL, (void *)&pcmcia_com + }, + {NULL} +}; +#define ncom_pcmcia_devs sizeof(pcmcia_com_devs)/sizeof(pcmcia_com_devs[0]) + +int +com_pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + return pcmcia_slave_match(parent, match, aux, pcmcia_com_devs, + ncom_pcmcia_devs); +} + +int +com_pcmcia_isa_attach(parent, match, aux, pc_link) + struct device *parent; + void *match; + void *aux; + struct pcmcia_link *pc_link; +{ + struct isa_attach_args *ia = aux; + struct com_softc *sc = match; + + int rval; + if (rval = comprobe(parent, sc->sc_dev.dv_cfdata, ia)) { + if (ISSET(pc_link->flags, PCMCIA_REATTACH)) { +#ifdef COM_DEBUG + printf("comreattach, hwflags=%x\n", sc->sc_hwflags); +#endif + sc->sc_hwflags = COM_HW_REATTACH | + (sc->sc_hwflags & (COM_HW_ABSENT_PENDING|COM_HW_CONSOLE)); + } else + sc->sc_hwflags = 0; + } + return rval; +} + + +/* + * Called by config_detach attempts, shortly after com_pcmcia_remove + * was called. + */ +int +com_pcmcia_detach(self) + struct device *self; +{ + struct com_softc *sc = (void *)self; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) { + /* don't let it really be detached, it is still open */ + return EBUSY; + } + return 0; /* OK! */ +} + +/* + * called by pcmcia framework to accept/reject remove attempts. + * If we return 0, then the detach will proceed. + */ +int +com_pcmcia_remove(pc_link, self) + struct pcmcia_link *pc_link; + struct device *self; +{ + struct com_softc *sc = (void *)self; + struct tty *tp; + int s; + + if (!sc->sc_tty) + goto ok; + tp = sc->sc_tty; + + /* not in use ? if so, return "OK" */ + if (!ISSET(tp->t_state, TS_ISOPEN) && + !ISSET(tp->t_state, TS_WOPEN)) { + ttyfree(sc->sc_tty); + sc->sc_tty = NULL; + ok: + isa_intr_disestablish(sc->sc_bc, sc->sc_ih); + sc->sc_ih = NULL; + SET(sc->sc_hwflags, COM_HW_ABSENT); + return 0; /* OK! */ + } + /* + * Not easily removed. Put device into a dead state, clean state + * as best we can. notify all waiters. + */ + SET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING); +#ifdef COM_DEBUG + printf("pending detach flags %x\n", sc->sc_hwflags); +#endif + + s = spltty(); + com_absent_notify(sc); + splx(s); + + return 0; +} + +#if 0 +void +com_pcmcia_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pcmcia_attach_args *paa = aux; + + printf("com_pcmcia_attach %p %p %p\n", parent, self, aux); + delay(2000000); + if (!pcmcia_configure(parent, self, paa->paa_link)) { + struct com_softc *sc = (void *)self; + sc->sc_hwflags |= COM_HW_ABSENT; + printf(": not attached\n"); + } +} +#endif +#endif + +/* + * must be called at spltty() or higher. + */ +void +com_absent_notify(sc) + struct com_softc *sc; +{ + struct tty *tp = sc->sc_tty; + + if (tp) { + CLR(tp->t_state, TS_CARR_ON|TS_BUSY); + ttyflush(tp, FREAD|FWRITE); + } +} + +int +comspeed(speed) + long speed; +{ +#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ + + int x, err; + + if (speed == 0) + return 0; + if (speed < 0) + return -1; + x = divrnd((COM_FREQ / 16), speed); + if (x <= 0) + return -1; + err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000; + if (err < 0) + err = -err; + if (err > COM_TOLERANCE) + return -1; + return x; + +#undef divrnd(n, q) +} + +int +comprobe1(bc, ioh, iobase) + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + int iobase; +{ + int i, k; + + /* force access to id reg */ + bus_io_write_1(bc, ioh, com_lcr, 0); + bus_io_write_1(bc, ioh, com_iir, 0); + for (i = 0; i < 32; i++) { + k = bus_io_read_1(bc, ioh, com_iir); + if (k & 0x38) { + bus_io_read_1(bc, ioh, com_data); /* cleanup */ + } else + break; + } + if (i >= 32) + return 0; + + return 1; +} + +#ifdef COM_HAYESP +int +comprobeHAYESP(hayespioh, sc) + bus_io_handle_t hayespioh; + struct com_softc *sc; +{ + char val, dips; + int combaselist[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; + bus_chipset_tag_t bc = sc->sc_bc; + + /* + * Hayes ESP cards have two iobases. One is for compatibility with + * 16550 serial chips, and at the same ISA PC base addresses. The + * other is for ESP-specific enhanced features, and lies at a + * different addressing range entirely (0x140, 0x180, 0x280, or 0x300). + */ + + /* Test for ESP signature */ + if ((bus_io_read_1(bc, hayespioh, 0) & 0xf3) == 0) + return 0; + + /* + * ESP is present at ESP enhanced base address; unknown com port + */ + + /* Get the dip-switch configurations */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_GETDIPS); + dips = bus_io_read_1(bc, hayespioh, HAYESP_STATUS1); + + /* Determine which com port this ESP card services: bits 0,1 of */ + /* dips is the port # (0-3); combaselist[val] is the com_iobase */ + if (sc->sc_iobase != combaselist[dips & 0x03]) + return 0; + + printf(": ESP"); + + /* Check ESP Self Test bits. */ + /* Check for ESP version 2.0: bits 4,5,6 == 010 */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_GETTEST); + val = bus_io_read_1(bc, hayespioh, HAYESP_STATUS1); /* Clear reg 1 */ + val = bus_io_read_1(bc, hayespioh, HAYESP_STATUS2); + if ((val & 0x70) < 0x20) { + printf("-old (%o)", val & 0x70); + /* we do not support the necessary features */ + return 0; + } + + /* Check for ability to emulate 16550: bit 8 == 1 */ + if ((dips & 0x80) == 0) { + printf(" slave"); + /* XXX Does slave really mean no 16550 support?? */ + return 0; + } + + /* + * If we made it this far, we are a full-featured ESP v2.0 (or + * better), at the correct com port address. + */ + + SET(sc->sc_hwflags, COM_HW_HAYESP); + printf(", 1024 byte fifo\n"); + return 1; +} +#endif + +int +comprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + int iobase, needioh; + int rv = 1; + +#if NACE_ISA || NACE_PCMCIA +#define IS_ISA(parent) \ + (!strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") || \ + !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pcmcia")) +#elif NACE_ISA +#define IS_ISA(parent) \ + !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") +#endif +#if NACE_PICA +#define IS_PICA(parent) \ + !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pica") +#endif + /* + * XXX should be broken out into functions for isa probe and + * XXX for commulti probe, with a helper function that contains + * XXX most of the interesting stuff. + */ +#if NACE_ISA || NACE_PCMCIA + if (IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + bc = ia->ia_bc; + iobase = ia->ia_iobase; + needioh = 1; + } else +#endif +#if NACE_PICA + if(IS_PICA(parent)) { + struct confargs *ca = aux; + if(!BUS_MATCHNAME(ca, "com")) + return(0); + iobase = (long)BUS_CVTADDR(ca); + bc = 0; + needioh = 1; + } else +#endif +#if NACE_COMMULTI + if (1) { + struct cfdata *cf = match; + struct commulti_attach_args *ca = aux; + + if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ca->ca_slave) + return (0); + + bc = ca->ca_bc; + iobase = ca->ca_iobase; + ioh = ca->ca_ioh; + needioh = 0; + } else +#endif + return(0); /* This cannot happen */ + + /* if it's in use as console, it's there. */ + if (iobase == comconsaddr && !comconsattached) + goto out; + + if (needioh && bus_io_map(bc, iobase, COM_NPORTS, &ioh)) { + rv = 0; + goto out; + } + rv = comprobe1(bc, ioh, iobase); + if (needioh) + bus_io_unmap(bc, ioh, COM_NPORTS); + +out: +#if NACE_ISA || NACE_PCMCIA + if (rv && IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + ia->ia_iosize = COM_NPORTS; + ia->ia_msize = 0; + } +#endif + return (rv); +} + +void +comattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct com_softc *sc = (void *)self; + int iobase, irq; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; +#ifdef COM_HAYESP + int hayesp_ports[] = { 0x140, 0x180, 0x280, 0x300, 0 }; + int *hayespp; +#endif + + /* + * XXX should be broken out into functions for isa attach and + * XXX for commulti attach, with a helper function that contains + * XXX most of the interesting stuff. + */ + if (ISSET(sc->sc_hwflags, COM_HW_REATTACH)) { + int s; + s = spltty(); + com_absent_notify(sc); + splx(s); + } else + sc->sc_hwflags = 0; + sc->sc_swflags = 0; +#if NACE_ISA || NACE_PCMCIA + if (IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + /* + * We're living on an isa. + */ + iobase = ia->ia_iobase; + bc = ia->ia_bc; + if (iobase != comconsaddr) { + if (bus_io_map(bc, iobase, COM_NPORTS, &ioh)) + panic("comattach: io mapping failed"); + } else + ioh = comconsioh; + irq = ia->ia_irq; + } else +#endif +#if NACE_PICA + if(IS_PICA(parent)) { + struct confargs *ca = aux; + iobase = (long)BUS_CVTADDR(ca); + bc = 0; + irq = 0; + ioh = iobase; + } else +#endif +#if NACE_COMMULTI + if (1) { + struct commulti_attach_args *ca = aux; + + /* + * We're living on a commulti. + */ + iobase = ca->ca_iobase; + bc = ca->ca_bc; + ioh = ca->ca_ioh; + irq = IRQUNK; + + if (ca->ca_noien) + SET(sc->sc_hwflags, COM_HW_NOIEN); + } else +#endif + panic("comattach: impossible"); + + sc->sc_bc = bc; + sc->sc_ioh = ioh; + sc->sc_iobase = iobase; + + if (iobase == comconsaddr) { + comconsattached = 1; + + /* + * Need to reset baud rate, etc. of next print so reset + * comconsinit. Also make sure console is always "hardwired". + */ + delay(1000); /* wait for output to finish */ + comconsinit = 0; + SET(sc->sc_hwflags, COM_HW_CONSOLE); + SET(sc->sc_swflags, COM_SW_SOFTCAR); + } + +#ifdef COM_HAYESP + /* Look for a Hayes ESP board. */ + for (hayespp = hayesp_ports; *hayespp != 0; hayespp++) { + bus_io_handle_t hayespioh; + +#define HAYESP_NPORTS 8 /* XXX XXX XXX ??? ??? ??? */ + if (bus_io_map(bc, *hayespp, HAYESP_NPORTS, &hayespioh)) + continue; + if (comprobeHAYESP(hayespioh, sc)) { + sc->sc_hayespbase = *hayespp; + sc->sc_hayespioh = hayespioh; + break; + } + bus_io_unmap(bc, hayespioh, HAYESP_NPORTS); + } + /* No ESP; look for other things. */ + if (*hayespp == 0) { +#endif + + /* look for a NS 16550AF UART with FIFOs */ + bus_io_write_1(bc, ioh, com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + delay(100); + if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_FIFO_MASK) == + IIR_FIFO_MASK) + if (ISSET(bus_io_read_1(bc, ioh, com_fifo), FIFO_TRIGGER_14) == + FIFO_TRIGGER_14) { + SET(sc->sc_hwflags, COM_HW_FIFO); + printf(": ns16550a, working fifo\n"); + } else + printf(": ns16550, broken fifo\n"); + else + printf(": ns8250 or ns16450, no fifo\n"); + bus_io_write_1(bc, ioh, com_fifo, 0); +#ifdef COM_HAYESP + } +#endif + + /* disable interrupts */ + bus_io_write_1(bc, ioh, com_ier, 0); + bus_io_write_1(bc, ioh, com_mcr, 0); + + if (irq != IRQUNK) { +#if NACE_ISA || NACE_PCMCIA + if (IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + sc->sc_ih = isa_intr_establish(ia->ia_ic, irq, + IST_EDGE, IPL_TTY, comintr, sc, + sc->sc_dev.dv_xname); + } else +#endif +#if NACE_PICA + if (IS_PICA(parent)) { + struct confargs *ca = aux; + BUS_INTR_ESTABLISH(ca, comintr, (void *)(long)sc); + } else +#endif + panic("comattach: IRQ but can't have one"); + } + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + kgdb_dev = -1; /* can't debug over console port */ + else { + cominit(bc, ioh, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("%s: ", sc->sc_dev.dv_xname); + kgdb_connect(1); + } else + printf("%s: kgdb enabled\n", + sc->sc_dev.dv_xname); + } + } +#endif + + /* XXX maybe move up some? */ + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + printf("%s: console\n", sc->sc_dev.dv_xname); +} + +int +comopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = COMUNIT(dev); + struct com_softc *sc; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + struct tty *tp; + int s; + int error = 0; + + if (unit >= com_cd.cd_ndevs) + return ENXIO; + sc = com_cd.cd_devs[unit]; + if (!sc || ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) + return ENXIO; + + if (!sc->sc_tty) { + tp = sc->sc_tty = ttymalloc(); + tty_attach(tp); + } else + tp = sc->sc_tty; + + tp->t_oproc = comstart; + tp->t_param = comparam; + tp->t_dev = dev; + if (!ISSET(tp->t_state, TS_ISOPEN)) { + SET(tp->t_state, TS_WOPEN); + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + tp->t_cflag = comconscflag; + else + tp->t_cflag = TTYDEF_CFLAG; + if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) + SET(tp->t_cflag, CLOCAL); + if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) + SET(tp->t_cflag, CRTSCTS); + if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) + SET(tp->t_cflag, MDMBUF); + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = comdefaultrate; + + s = spltty(); + + comparam(tp, &tp->t_termios); + ttsetwater(tp); + + if (comsopen++ == 0) + timeout(compoll, NULL, 1); + + sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; + sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER; + sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE; + + bc = sc->sc_bc; + ioh = sc->sc_ioh; +#ifdef COM_HAYESP + /* Setup the ESP board */ + if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) { + bus_io_handle_t hayespioh = sc->sc_hayespioh; + + bus_io_write_1(bc, ioh, com_fifo, + FIFO_DMA_MODE|FIFO_ENABLE| + FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_8); + + /* Set 16550 compatibility mode */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETMODE); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_MODE_FIFO|HAYESP_MODE_RTS| + HAYESP_MODE_SCALE); + + /* Set RTS/CTS flow control */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETFLOWTYPE); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, HAYESP_FLOW_RTS); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, HAYESP_FLOW_CTS); + + /* Set flow control levels */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETRXFLOW); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_HIBYTE(HAYESP_RXHIWMARK)); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_LOBYTE(HAYESP_RXHIWMARK)); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_HIBYTE(HAYESP_RXLOWMARK)); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_LOBYTE(HAYESP_RXLOWMARK)); + } else +#endif + if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) + /* Set the FIFO threshold based on the receive speed. */ + bus_io_write_1(bc, ioh, com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | + (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); + /* flush any pending I/O */ + while (ISSET(bus_io_read_1(bc, ioh, com_lsr), LSR_RXRDY)) + (void) bus_io_read_1(bc, ioh, com_data); + /* you turn me on, baby */ + sc->sc_mcr = MCR_DTR | MCR_RTS; + if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN)) + SET(sc->sc_mcr, MCR_IENABLE); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + sc->sc_ier = IER_ERXRDY | IER_ERLS | IER_EMSC; + bus_io_write_1(bc, ioh, com_ier, sc->sc_ier); + + sc->sc_msr = bus_io_read_1(bc, ioh, com_msr); + if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) || + ISSET(sc->sc_msr, MSR_DCD) || ISSET(tp->t_cflag, MDMBUF)) + SET(tp->t_state, TS_CARR_ON); + else + CLR(tp->t_state, TS_CARR_ON); + } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) + return EBUSY; + else + s = spltty(); + + /* wait for carrier if necessary */ + if (!ISSET(flag, O_NONBLOCK)) + while (!ISSET(tp->t_cflag, CLOCAL) && + !ISSET(tp->t_state, TS_CARR_ON)) { + SET(tp->t_state, TS_WOPEN); + error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, + ttopen, 0); + if (error) { + /* XXX should turn off chip if we're the + only waiter */ + splx(s); + return error; + } + } + splx(s); + + return (*linesw[tp->t_line].l_open)(dev, tp); +} + +int +comclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = COMUNIT(dev); + struct com_softc *sc = com_cd.cd_devs[unit]; + struct tty *tp = sc->sc_tty; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int s; + + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return 0; + + (*linesw[tp->t_line].l_close)(tp, flag); + s = spltty(); + if (!ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + /* can't do any of this stuff .... */ + CLR(sc->sc_lcr, LCR_SBREAK); + bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr); + bus_io_write_1(bc, ioh, com_ier, 0); + if (ISSET(tp->t_cflag, HUPCL) && + !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) { + /* XXX perhaps only clear DTR */ + bus_io_write_1(bc, ioh, com_mcr, 0); + } + } + CLR(tp->t_state, TS_BUSY | TS_FLUSH); + if (--comsopen == 0) + untimeout(compoll, NULL); + splx(s); + ttyclose(tp); +#ifdef COM_DEBUG + /* mark it ready for more use if reattached earlier */ + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) { + printf("comclose pending cleared\n"); + } +#endif + CLR(sc->sc_hwflags, COM_HW_ABSENT_PENDING); + +#ifdef notyet /* XXXX */ + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { + ttyfree(tp); + sc->sc_tty = 0; + } +#endif + return 0; +} + +int +comread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +comwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +struct tty * +comtty(dev) + dev_t dev; +{ + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return (tp); +} + +static u_char +tiocm_xxx2mcr(data) + int data; +{ + u_char m = 0; + + if (ISSET(data, TIOCM_DTR)) + SET(m, MCR_DTR); + if (ISSET(data, TIOCM_RTS)) + SET(m, MCR_RTS); + return m; +} + +int +comioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int unit = COMUNIT(dev); + struct com_softc *sc = com_cd.cd_devs[unit]; + struct tty *tp = sc->sc_tty; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int error; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return error; + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return error; + + switch (cmd) { + case TIOCSBRK: + SET(sc->sc_lcr, LCR_SBREAK); + bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr); + break; + case TIOCCBRK: + CLR(sc->sc_lcr, LCR_SBREAK); + bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr); + break; + case TIOCSDTR: + SET(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCCDTR: + CLR(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCMSET: + CLR(sc->sc_mcr, MCR_DTR | MCR_RTS); + case TIOCMBIS: + SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data)); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCMBIC: + CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data)); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCMGET: { + u_char m; + int bits = 0; + + m = sc->sc_mcr; + if (ISSET(m, MCR_DTR)) + SET(bits, TIOCM_DTR); + if (ISSET(m, MCR_RTS)) + SET(bits, TIOCM_RTS); + m = sc->sc_msr; + if (ISSET(m, MSR_DCD)) + SET(bits, TIOCM_CD); + if (ISSET(m, MSR_CTS)) + SET(bits, TIOCM_CTS); + if (ISSET(m, MSR_DSR)) + SET(bits, TIOCM_DSR); + if (ISSET(m, MSR_RI | MSR_TERI)) + SET(bits, TIOCM_RI); + if (bus_io_read_1(bc, ioh, com_ier)) + SET(bits, TIOCM_LE); + *(int *)data = bits; + break; + } + case TIOCGFLAGS: { + int driverbits, userbits = 0; + + driverbits = sc->sc_swflags; + if (ISSET(driverbits, COM_SW_SOFTCAR)) + SET(userbits, TIOCFLAG_SOFTCAR); + if (ISSET(driverbits, COM_SW_CLOCAL)) + SET(userbits, TIOCFLAG_CLOCAL); + if (ISSET(driverbits, COM_SW_CRTSCTS)) + SET(userbits, TIOCFLAG_CRTSCTS); + if (ISSET(driverbits, COM_SW_MDMBUF)) + SET(userbits, TIOCFLAG_MDMBUF); + + *(int *)data = userbits; + break; + } + case TIOCSFLAGS: { + int userbits, driverbits = 0; + + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return(EPERM); + + userbits = *(int *)data; + if (ISSET(userbits, TIOCFLAG_SOFTCAR) || + ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + SET(driverbits, COM_SW_SOFTCAR); + if (ISSET(userbits, TIOCFLAG_CLOCAL)) + SET(driverbits, COM_SW_CLOCAL); + if (ISSET(userbits, TIOCFLAG_CRTSCTS)) + SET(driverbits, COM_SW_CRTSCTS); + if (ISSET(userbits, TIOCFLAG_MDMBUF)) + SET(driverbits, COM_SW_MDMBUF); + + sc->sc_swflags = driverbits; + break; + } + default: + return ENOTTY; + } + + return 0; +} + +int +comparam(tp, t) + struct tty *tp; + struct termios *t; +{ + struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)]; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int ospeed = comspeed(t->c_ospeed); + u_char lcr; + tcflag_t oldcflag; + int s; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + /* check requested parameters */ + if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) + return EINVAL; + + lcr = ISSET(sc->sc_lcr, LCR_SBREAK); + + switch (ISSET(t->c_cflag, CSIZE)) { + case CS5: + SET(lcr, LCR_5BITS); + break; + case CS6: + SET(lcr, LCR_6BITS); + break; + case CS7: + SET(lcr, LCR_7BITS); + break; + case CS8: + SET(lcr, LCR_8BITS); + break; + } + if (ISSET(t->c_cflag, PARENB)) { + SET(lcr, LCR_PENAB); + if (!ISSET(t->c_cflag, PARODD)) + SET(lcr, LCR_PEVEN); + } + if (ISSET(t->c_cflag, CSTOPB)) + SET(lcr, LCR_STOPB); + + sc->sc_lcr = lcr; + + s = spltty(); + + if (ospeed == 0) { + CLR(sc->sc_mcr, MCR_DTR); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + + /* + * Set the FIFO threshold based on the receive speed, if we are + * changing it. + */ +#if 1 + if (tp->t_ispeed != t->c_ispeed) { +#else + if (1) { +#endif + if (ospeed != 0) { + /* + * Make sure the transmit FIFO is empty before + * proceeding. If we don't do this, some revisions + * of the UART will hang. Interestingly enough, + * even if we do this will the last character is + * still being pushed out, they don't hang. This + * seems good enough. + */ + while (ISSET(tp->t_state, TS_BUSY)) { + int error; + + ++sc->sc_halt; + error = ttysleep(tp, &tp->t_outq, + TTOPRI | PCATCH, "comprm", 0); + --sc->sc_halt; + if (error) { + splx(s); + comstart(tp); + return (error); + } + } + + bus_io_write_1(bc, ioh, com_lcr, lcr | LCR_DLAB); + bus_io_write_1(bc, ioh, com_dlbl, ospeed); + bus_io_write_1(bc, ioh, com_dlbh, ospeed >> 8); + bus_io_write_1(bc, ioh, com_lcr, lcr); + SET(sc->sc_mcr, MCR_DTR); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } else + bus_io_write_1(bc, ioh, com_lcr, lcr); + + if (!ISSET(sc->sc_hwflags, COM_HW_HAYESP) && + ISSET(sc->sc_hwflags, COM_HW_FIFO)) + bus_io_write_1(bc, ioh, com_fifo, + FIFO_ENABLE | + (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); + } else + bus_io_write_1(bc, ioh, com_lcr, lcr); + + /* When not using CRTSCTS, RTS follows DTR. */ + if (!ISSET(t->c_cflag, CRTSCTS)) { + if (ISSET(sc->sc_mcr, MCR_DTR)) { + if (!ISSET(sc->sc_mcr, MCR_RTS)) { + SET(sc->sc_mcr, MCR_RTS); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + } else { + if (ISSET(sc->sc_mcr, MCR_RTS)) { + CLR(sc->sc_mcr, MCR_RTS); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + } + sc->sc_dtr = MCR_DTR | MCR_RTS; + } else + sc->sc_dtr = MCR_DTR; + + /* and copy to tty */ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + oldcflag = tp->t_cflag; + tp->t_cflag = t->c_cflag; + + /* + * If DCD is off and MDMBUF is changed, ask the tty layer if we should + * stop the device. + */ + if (!ISSET(sc->sc_msr, MSR_DCD) && + !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) && + ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) && + (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { + CLR(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + + /* Just to be sure... */ + splx(s); + comstart(tp); + return 0; +} + +void +comstart_pending(arg) + void *arg; +{ + struct com_softc *sc = arg; + int s; + + s = spltty(); + com_absent_notify(sc); + splx(s); +} + +void +comstart(tp) + struct tty *tp; +{ + struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)]; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int s; + + s = spltty(); + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + /* + * not quite good enough: if caller is ttywait() it will + * go to sleep immediately, so hang out a bit and then + * prod caller again. + */ + com_absent_notify(sc); + timeout(comstart_pending, sc, 1); + goto out; + } + if (ISSET(tp->t_state, TS_BUSY)) + goto out; + if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || + sc->sc_halt > 0) + goto stopped; + if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS)) + goto stopped; + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup(&tp->t_outq); + } + if (tp->t_outq.c_cc == 0) + goto stopped; + selwakeup(&tp->t_wsel); + } + SET(tp->t_state, TS_BUSY); + + if (!ISSET(sc->sc_ier, IER_ETXRDY)) { + SET(sc->sc_ier, IER_ETXRDY); + bus_io_write_1(bc, ioh, com_ier, sc->sc_ier); + } +#ifdef COM_HAYESP + if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) { + u_char buffer[1024], *cp = buffer; + int n = q_to_b(&tp->t_outq, cp, sizeof buffer); + do + bus_io_write_1(bc, ioh, com_data, *cp++); + while (--n); + } + else +#endif + if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) { + u_char buffer[16], *cp = buffer; + int n = q_to_b(&tp->t_outq, cp, sizeof buffer); + do { + bus_io_write_1(bc, ioh, com_data, *cp++); + } while (--n); + } else + bus_io_write_1(bc, ioh, com_data, getc(&tp->t_outq)); +out: + splx(s); + return; +stopped: + if (ISSET(sc->sc_ier, IER_ETXRDY)) { + CLR(sc->sc_ier, IER_ETXRDY); + bus_io_write_1(bc, ioh, com_ier, sc->sc_ier); + } + splx(s); +} + +/* + * Stop output on a line. + */ +int +comstop(tp, flag) + struct tty *tp; + int flag; +{ + int s; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY)) + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + splx(s); + return 0; +} + +void +comdiag(arg) + void *arg; +{ + struct com_softc *sc = arg; + int overflows, floods; + int s; + + s = spltty(); + sc->sc_errors = 0; + overflows = sc->sc_overflows; + sc->sc_overflows = 0; + floods = sc->sc_floods; + sc->sc_floods = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", + sc->sc_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +void +compoll(arg) + void *arg; +{ + int unit; + struct com_softc *sc; + struct tty *tp; + register u_char *ibufp; + u_char *ibufend; + register int c; + int s; + static int lsrmap[8] = { + 0, TTY_PE, + TTY_FE, TTY_PE|TTY_FE, + TTY_FE, TTY_PE|TTY_FE, + TTY_FE, TTY_PE|TTY_FE + }; + + s = spltty(); + if (comevents == 0) { + splx(s); + goto out; + } + comevents = 0; + splx(s); + + for (unit = 0; unit < com_cd.cd_ndevs; unit++) { + sc = com_cd.cd_devs[unit]; + if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf) + continue; + + tp = sc->sc_tty; + + s = spltty(); + + ibufp = sc->sc_ibuf; + ibufend = sc->sc_ibufp; + + if (ibufp == ibufend) { + splx(s); + continue; + } + + sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? + sc->sc_ibufs[1] : sc->sc_ibufs[0]; + sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER; + sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE; + + if (tp == 0 || !ISSET(tp->t_state, TS_ISOPEN)) { + splx(s); + continue; + } + + if (ISSET(tp->t_cflag, CRTSCTS) && + !ISSET(sc->sc_mcr, MCR_RTS)) { + /* XXX */ + SET(sc->sc_mcr, MCR_RTS); + bus_io_write_1(sc->sc_bc, sc->sc_ioh, com_mcr, + sc->sc_mcr); + } + + splx(s); + + while (ibufp < ibufend) { + c = *ibufp++; + if (*ibufp & LSR_OE) { + sc->sc_overflows++; + if (sc->sc_errors++ == 0) + timeout(comdiag, sc, 60 * hz); + } + /* This is ugly, but fast. */ + c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2]; + (*linesw[tp->t_line].l_rint)(c, tp); + } + } + +out: + timeout(compoll, NULL, 1); +} + +int +comintr(arg) + void *arg; +{ + struct com_softc *sc = arg; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + struct tty *tp; + u_char lsr, data, msr, delta; +#ifdef COM_DEBUG + int n; + struct { + u_char iir, lsr, msr; + } iter[32]; +#endif + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT) || !sc->sc_tty) + return 0; /* can't do squat. */ + +#ifdef COM_DEBUG + n = 0; + if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (0); +#else + if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (0); +#endif + + tp = sc->sc_tty; + + for (;;) { +#ifdef COM_DEBUG + iter[n].lsr = +#endif + lsr = bus_io_read_1(bc, ioh, com_lsr); + + if (ISSET(lsr, LSR_RXRDY)) { + register u_char *p = sc->sc_ibufp; + + comevents = 1; + do { + data = bus_io_read_1(bc, ioh, com_data); + if (ISSET(lsr, LSR_BI)) { +#ifdef notdef + printf("break %02x %02x %02x %02x\n", + sc->sc_msr, sc->sc_mcr, sc->sc_lcr, + sc->sc_dtr); +#endif +#ifdef DDB + if (ISSET(sc->sc_hwflags, + COM_HW_CONSOLE)) { + Debugger(); + goto next; + } +#endif + } + if (p >= sc->sc_ibufend) { + sc->sc_floods++; + if (sc->sc_errors++ == 0) + timeout(comdiag, sc, 60 * hz); + } else { + *p++ = data; + *p++ = lsr; + if (p == sc->sc_ibufhigh && + ISSET(tp->t_cflag, CRTSCTS)) { + /* XXX */ + CLR(sc->sc_mcr, MCR_RTS); + bus_io_write_1(bc, ioh, com_mcr, + sc->sc_mcr); + } + } + next: +#ifdef COM_DEBUG + if (++n >= 32) + goto ohfudge; + iter[n].lsr = +#endif + lsr = bus_io_read_1(bc, ioh, com_lsr); + } while (ISSET(lsr, LSR_RXRDY)); + + sc->sc_ibufp = p; + } +#ifdef COM_DEBUG + else if (ISSET(lsr, LSR_BI|LSR_FE|LSR_PE|LSR_OE)) + printf("weird lsr %02x\n", lsr); +#endif + +#ifdef COM_DEBUG + iter[n].msr = +#endif + msr = bus_io_read_1(bc, ioh, com_msr); + + if (msr != sc->sc_msr) { + delta = msr ^ sc->sc_msr; + sc->sc_msr = msr; + if (ISSET(delta, MSR_DCD) && + !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) && + (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD)) == 0) { + CLR(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + if (ISSET(delta & msr, MSR_CTS) && + ISSET(tp->t_cflag, CRTSCTS)) { + /* the line is up and we want to do rts/cts flow control */ + (*linesw[tp->t_line].l_start)(tp); + } + } + + if (ISSET(lsr, LSR_TXRDY) && ISSET(tp->t_state, TS_BUSY)) { + CLR(tp->t_state, TS_BUSY | TS_FLUSH); + if (sc->sc_halt > 0) + wakeup(&tp->t_outq); + (*linesw[tp->t_line].l_start)(tp); + } + +#ifdef COM_DEBUG + if (++n >= 32) + goto ohfudge; + if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (1); +#else + if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (1); +#endif + } +#ifdef COM_DEBUG +ohfudge: + printf("comintr: too many iterations"); + for (n = 0; n < 32; n++) { + if ((n % 4) == 0) + printf("\ncomintr: iter[%02d]", n); + printf(" %02x %02x %02x", iter[n].iir, iter[n].lsr, iter[n].msr); + } + printf("\n"); + printf("comintr: msr %02x mcr %02x lcr %02x ier %02x\n", + sc->sc_msr, sc->sc_mcr, sc->sc_lcr, sc->sc_ier); + printf("comintr: state %08x cc %d\n", sc->sc_tty->t_state, + sc->sc_tty->t_outq.c_cc); +#endif +} + +/* + * Following are all routines needed for COM to act as console + */ +#include <dev/cons.h> + +void +comcnprobe(cp) + struct consdev *cp; +{ + /* XXX NEEDS TO BE FIXED XXX */ + bus_chipset_tag_t bc = 0; + bus_io_handle_t ioh; + int found; + +#if 0 + if (bus_io_map(bc, CONADDR, COM_NPORTS, &ioh)) { + cp->cn_pri = CN_DEAD; + return; + } +#else + ioh = CONADDR; +#endif + found = comprobe1(bc, ioh, CONADDR); + bus_io_unmap(bc, ioh, COM_NPORTS); + if (!found) { + cp->cn_pri = CN_DEAD; + return; + } + + /* locate the major number */ + for (commajor = 0; commajor < nchrdev; commajor++) + if (cdevsw[commajor].d_open == comopen) + break; + + /* initialize required fields */ + cp->cn_dev = makedev(commajor, CONUNIT); +#ifdef COMCONSOLE + cp->cn_pri = CN_REMOTE; /* Force a serial port console */ +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +comcninit(cp) + struct consdev *cp; +{ + +#if 0 + XXX NEEDS TO BE FIXED XXX + comconsbc = ???; +#endif + if (bus_io_map(comconsbc, CONADDR, COM_NPORTS, &comconsioh)) + panic("comcninit: mapping failed"); + + cominit(comconsbc, comconsioh, comdefaultrate); + comconsaddr = CONADDR; + comconsinit = 0; +} + +void +cominit(bc, ioh, rate) + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + int rate; +{ + int s = splhigh(); + u_char stat; + + bus_io_write_1(bc, ioh, com_lcr, LCR_DLAB); + rate = comspeed(comdefaultrate); + bus_io_write_1(bc, ioh, com_dlbl, rate); + bus_io_write_1(bc, ioh, com_dlbh, rate >> 8); + bus_io_write_1(bc, ioh, com_lcr, LCR_8BITS); + bus_io_write_1(bc, ioh, com_ier, IER_ERXRDY | IER_ETXRDY); + bus_io_write_1(bc, ioh, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4); + stat = bus_io_read_1(bc, ioh, com_iir); + splx(s); +} + +int +comcngetc(dev) + dev_t dev; +{ + int s = splhigh(); + bus_chipset_tag_t bc = comconsbc; + bus_io_handle_t ioh = comconsioh; + u_char stat, c; + + while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_RXRDY)) + ; + c = bus_io_read_1(bc, ioh, com_data); + stat = bus_io_read_1(bc, ioh, com_iir); + splx(s); + return c; +} + +/* + * Console kernel output character routine. + */ +void +comcnputc(dev, c) + dev_t dev; + int c; +{ + int s = splhigh(); + bus_chipset_tag_t bc = comconsbc; + bus_io_handle_t ioh = comconsioh; + u_char stat; + register int timo; + +#ifdef KGDB + if (dev != kgdb_dev) +#endif + if (comconsinit == 0) { + cominit(bc, ioh, comdefaultrate); + comconsinit = 1; + } + /* wait for any pending transmission to finish */ + timo = 50000; + while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_TXRDY) && --timo) + ; + bus_io_write_1(bc, ioh, com_data, c); + /* wait for this transmission to complete */ + timo = 1500000; + while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_TXRDY) && --timo) + ; + /* clear any interrupts generated by this transmission */ + stat = bus_io_read_1(bc, ioh, com_iir); + splx(s); +} + +void +comcnpollc(dev, on) + dev_t dev; + int on; +{ + +} diff --git a/sys/arch/arc/dev/asc.c b/sys/arch/arc/dev/asc.c new file mode 100644 index 00000000000..0a8af5464b9 --- /dev/null +++ b/sys/arch/arc/dev/asc.c @@ -0,0 +1,2074 @@ +/* $OpenBSD: asc.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* $NetBSD: asc.c,v 1.10 1994/12/05 19:11:12 dean Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * @(#)asc.c 8.3 (Berkeley) 7/3/94 + */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * HISTORY + * Log: scsi_53C94_hdw.c,v + * Revision 2.5 91/02/05 17:45:07 mrt + * Added author notices + * [91/02/04 11:18:43 mrt] + * + * Changed to use new Mach copyright + * [91/02/02 12:17:20 mrt] + * + * Revision 2.4 91/01/08 15:48:24 rpd + * Added continuation argument to thread_block. + * [90/12/27 rpd] + * + * Revision 2.3 90/12/05 23:34:48 af + * Recovered from pmax merge.. and from the destruction of a disk. + * [90/12/03 23:40:40 af] + * + * Revision 2.1.1.1 90/11/01 03:39:09 af + * Created, from the DEC specs: + * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" + * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. + * And from the NCR data sheets + * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" + * [90/09/03 af] + */ + +/* + * File: scsi_53C94_hdw.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Bottom layer of the SCSI driver: chip-dependent functions + * + * This file contains the code that is specific to the NCR 53C94 + * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start + * operation, and interrupt routine. + */ + +/* + * This layer works based on small simple 'scripts' that are installed + * at the start of the command and drive the chip to completion. + * The idea comes from the specs of the NCR 53C700 'script' processor. + * + * There are various reasons for this, mainly + * - Performance: identify the common (successful) path, and follow it; + * at interrupt time no code is needed to find the current status + * - Code size: it should be easy to compact common operations + * - Adaptability: the code skeleton should adapt to different chips without + * terrible complications. + * - Error handling: and it is easy to modify the actions performed + * by the scripts to cope with strange but well identified sequences + * + */ + +#include <asc.h> +#if NASC > 0 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/dkstat.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/errno.h> +#include <sys/device.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> + +#include <arc/dev/dma.h> +#include <arc/dev/scsi.h> +#include <arc/dev/ascreg.h> + +#include <arc/pica/pica.h> +#include <arc/arc/arctype.h> + + +#define readback(a) { register int foo; foo = (a); } +extern int cputype; + +/* + * In 4ns ticks. + */ +int asc_to_scsi_period[] = { + 32, + 33, + 34, + 35, + 5, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, +}; + +/* + * Internal forward declarations. + */ +static void asc_reset(); +static void asc_startcmd(); + +#ifdef DEBUG +int asc_debug = 1; +int asc_debug_cmd; +int asc_debug_bn; +int asc_debug_sz; +#define NLOG 16 +struct asc_log { + u_int status; + u_char state; + u_char msg; + int target; + int resid; +} asc_log[NLOG], *asc_logp = asc_log; +#define PACK(unit, status, ss, ir) \ + ((unit << 24) | (status << 16) | (ss << 8) | ir) +#endif + +/* + * Scripts are entries in a state machine table. + * A script has four parts: a pre-condition, an action, a command to the chip, + * and an index into asc_scripts for the next state. The first triggers error + * handling if not satisfied and in our case it is formed by the + * values of the interrupt register and status register, this + * basically captures the phase of the bus and the TC and BS + * bits. The action part is just a function pointer, and the + * command is what the 53C94 should be told to do at the end + * of the action processing. This command is only issued and the + * script proceeds if the action routine returns TRUE. + * See asc_intr() for how and where this is all done. + */ +typedef struct script { + int condition; /* expected state at interrupt time */ + int (*action)(); /* extra operations */ + int command; /* command to the chip */ + struct script *next; /* index into asc_scripts for next state */ +} script_t; + +/* Matching on the condition value */ +#define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8)) + +/* forward decls of script actions */ +static int script_nop(); /* when nothing needed */ +static int asc_end(); /* all come to an end */ +static int asc_get_status(); /* get status from target */ +static int asc_dma_in(); /* start reading data from target */ +static int asc_last_dma_in(); /* cleanup after all data is read */ +static int asc_resume_in(); /* resume data in after a message */ +static int asc_resume_dma_in(); /* resume DMA after a disconnect */ +static int asc_dma_out(); /* send data to target via dma */ +static int asc_last_dma_out(); /* cleanup after all data is written */ +static int asc_resume_out(); /* resume data out after a message */ +static int asc_resume_dma_out(); /* resume DMA after a disconnect */ +static int asc_sendsync(); /* negotiate sync xfer */ +static int asc_replysync(); /* negotiate sync xfer */ +static int asc_msg_in(); /* process a message byte */ +static int asc_disconnect(); /* process an expected disconnect */ + +/* Define the index into asc_scripts for various state transitions */ +#define SCRIPT_DATA_IN 0 +#define SCRIPT_CONTINUE_IN 2 +#define SCRIPT_DATA_OUT 3 +#define SCRIPT_CONTINUE_OUT 5 +#define SCRIPT_SIMPLE 6 +#define SCRIPT_GET_STATUS 7 +#define SCRIPT_DONE 8 +#define SCRIPT_MSG_IN 9 +#define SCRIPT_REPLY_SYNC 11 +#define SCRIPT_TRY_SYNC 12 +#define SCRIPT_DISCONNECT 15 +#define SCRIPT_RESEL 16 +#define SCRIPT_RESUME_IN 17 +#define SCRIPT_RESUME_DMA_IN 18 +#define SCRIPT_RESUME_OUT 19 +#define SCRIPT_RESUME_DMA_OUT 20 +#define SCRIPT_RESUME_NO_DATA 21 + +/* + * Scripts + */ +script_t asc_scripts[] = { + /* start data in */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ + asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ + asc_last_dma_in, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, + + /* continue data in after a chunk is finished */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ + asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + + /* start data out */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ + asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ + asc_last_dma_out, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, + + /* continue data out after a chunk is finished */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ + asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + + /* simple command with no data transfer */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ + script_nop, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, + + /* get status and finish command */ + {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ + asc_get_status, ASC_CMD_MSG_ACPT, + &asc_scripts[SCRIPT_DONE]}, + {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ + asc_end, ASC_CMD_NOP, + &asc_scripts[SCRIPT_DONE]}, + + /* message in */ + {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ + asc_msg_in, ASC_CMD_MSG_ACPT, + &asc_scripts[SCRIPT_MSG_IN + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ + script_nop, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_MSG_IN]}, + + /* send synchonous negotiation reply */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ + asc_replysync, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_REPLY_SYNC]}, + + /* try to negotiate synchonous transfer parameters */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ + asc_sendsync, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_TRY_SYNC + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ + script_nop, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_MSG_IN]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ + script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_RESUME_NO_DATA]}, + + /* handle a disconnect */ + {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ + asc_disconnect, ASC_CMD_ENABLE_SEL, + &asc_scripts[SCRIPT_RESEL]}, + + /* reselect sequence: this is just a placeholder so match fails */ + {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ + script_nop, ASC_CMD_MSG_ACPT, + &asc_scripts[SCRIPT_RESEL]}, + + /* resume data in after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ + asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + + /* resume partial DMA data in after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ + asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + + /* resume data out after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ + asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + + /* resume partial DMA data out after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ + asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + + /* resume after a message when there is no more data */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ + script_nop, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, +}; + +/* + * State kept for each active SCSI device. + */ +typedef struct scsi_state { + script_t *script; /* saved script while processing error */ + struct scsi_generic cmd;/* storage for scsi command */ + int statusByte; /* status byte returned during STATUS_PHASE */ + u_int dmaBufSize; /* DMA buffer size */ + int dmalen; /* amount to transfer in this chunk */ + int dmaresid; /* amount not transfered if chunk suspended */ + int cmdlen; /* length of command in cmd */ + int buflen; /* total remaining amount of data to transfer */ + vm_offset_t buf; /* current pointer within scsicmd->buf */ + int flags; /* see below */ + int msglen; /* number of message bytes to read */ + int msgcnt; /* number of message bytes received */ + u_char sync_period; /* DMA synchronous period */ + u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ + u_char msg_out; /* next MSG_OUT byte to send */ + u_char msg_in[16]; /* buffer for multibyte messages */ +} State; + +/* state flags */ +#define DISCONN 0x001 /* true if currently disconnected from bus */ +#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */ +#define DMA_IN 0x004 /* true if reading from SCSI device */ +#define DMA_OUT 0x010 /* true if writing to SCSI device */ +#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */ +#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */ +#define PARITY_ERR 0x080 /* true if parity error seen */ +#define CHECK_SENSE 0x100 /* true if doing sense command */ + +/* + * State kept for each active SCSI host interface (53C94). + */ +struct asc_softc { + struct device sc_dev; /* use as a device */ + asc_regmap_t *regs; /* chip address */ + dma_softc_t __dma; /* stupid macro..... */ + dma_softc_t *dma; /* dma control structure */ + int sc_id; /* SCSI ID of this interface */ + int myidmask; /* ~(1 << myid) */ + int state; /* current SCSI connection state */ + int target; /* target SCSI ID if busy */ + script_t *script; /* next expected interrupt & action */ + struct scsi_xfer *cmdq[ASC_NCMD];/* Pointer to queued commands */ + struct scsi_xfer *cmd[ASC_NCMD];/* Pointer to current active command */ + State st[ASC_NCMD]; /* state info for each active command */ + int min_period; /* Min transfer period clk/byte */ + int max_period; /* Max transfer period clk/byte */ + int ccf; /* CCF, whatever that really is? */ + int timeout_250; /* 250ms timeout */ + int tb_ticks; /* 4ns. ticks/tb channel ticks */ + struct scsi_link sc_link; /* scsi link struct */ +}; + +#define ASC_STATE_IDLE 0 /* idle state */ +#define ASC_STATE_BUSY 1 /* selecting or currently connected */ +#define ASC_STATE_TARGET 2 /* currently selected as target */ +#define ASC_STATE_RESEL 3 /* currently waiting for reselect */ + +typedef struct asc_softc *asc_softc_t; + +/* + * Autoconfiguration data for config. + */ +int ascmatch __P((struct device *, void *, void *)); +void ascattach __P((struct device *, struct device *, void *)); +int ascprint(void *, char *); + +int asc_doprobe __P((void *, int, int, struct device *)); + +struct cfattach asc_ca = { + sizeof(struct asc_softc), ascmatch, ascattach +}; +struct cfdriver asc_cd = { + NULL, "asc", DV_DULL, NULL, 0 +}; + +/* + * Glue to the machine dependent scsi + */ +int asc_scsi_cmd __P((struct scsi_xfer *)); +void asc_minphys __P((struct buf *)); + +struct scsi_adapter asc_switch = { + asc_scsi_cmd, +/*XXX*/ asc_minphys, /* no max transfer size, DMA driver negotiates */ + NULL, + NULL, +}; + +struct scsi_device asc_dev = { +/*XXX*/ NULL, /* Use default error handler */ +/*XXX*/ NULL, /* have a queue, served by this */ +/*XXX*/ NULL, /* have no async handler */ +/*XXX*/ NULL, /* Use default 'done' routine */ +}; + +static int asc_probe(); +static void asc_start(); +static int asc_intr(); + +/* + * Match driver based on name + */ +int +ascmatch(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + struct cfdata *cf = match; + struct confargs *ca = aux; + + if(!BUS_MATCHNAME(ca, "asc")) + return(0); + return(1); +} + +void +ascattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + register struct confargs *ca = aux; + register asc_softc_t asc = (void *)self; + register asc_regmap_t *regs; + int id, s, i; + int bufsiz; + + /* + * Initialize hw descriptor, cache some pointers + */ + asc->regs = (asc_regmap_t *)BUS_CVTADDR(ca); + + /* + * Set up machine dependencies. + * 1) how to do dma + * 2) timing based on chip clock frequency + */ + switch (cputype) { + case ACER_PICA_61: + bufsiz = 63 * 1024; /*XXX check if code handles 0 as 64k */ + asc->dma = &asc->__dma; + asc_dma_init(asc->dma); + break; + default: + bufsiz = 64 * 1024; + }; + /* + * Now for timing. The pica has a 25Mhz + */ + switch (cputype) { + case ACER_PICA_61: + asc->min_period = ASC_MIN_PERIOD25; + asc->max_period = ASC_MAX_PERIOD25; + asc->ccf = ASC_CCF(25); + asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf); + asc->tb_ticks = 10; + break; + default: + asc->min_period = ASC_MIN_PERIOD12; + asc->max_period = ASC_MAX_PERIOD12; + asc->ccf = ASC_CCF(13); + asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf); + asc->tb_ticks = 20; + break; + }; + + asc->state = ASC_STATE_IDLE; + asc->target = -1; + + regs = asc->regs; + + /* + * Reset chip, fully. Note that interrupts are already enabled. + */ + s = splbio(); + + /* preserve our ID for now */ + asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; + asc->myidmask = ~(1 << asc->sc_id); + + asc_reset(asc, regs); + + /* + * Our SCSI id on the bus. + * The user can set this via the prom on 3maxen/picaen. + * If this changes it is easy to fix: make a default that + * can be changed as boot arg. + */ +#ifdef unneeded + regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | + (scsi_initiator_id[unit] & 0x7); + asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; +#endif + id = asc->sc_id; + splx(s); + + /* + * Give each target its DMA buffer region. + * The buffer address is the same for all targets, + * the allocated dma viritual scatter/gather space. + */ + for (i = 0; i < ASC_NCMD; i++) { + asc->st[i].dmaBufSize = bufsiz; + } + + /* + * Set up interrupt handler. + */ + BUS_INTR_ESTABLISH(ca, asc_intr, (void *)asc); + + printf(": NCR53C94, target %d\n", id); + + /* + * Fill in the prototype scsi link. + */ + asc->sc_link.adapter_softc = asc; + asc->sc_link.adapter_target = asc->sc_id; + asc->sc_link.adapter = &asc_switch; + asc->sc_link.device = &asc_dev; + asc->sc_link.openings = 2; + + /* + * Now try to attach all the sub devices. + */ + config_found(self, &asc->sc_link, ascprint); +} + +int +ascprint(aux, name) + void *aux; + char *name; +{ + return -1; +} + +/* + * Driver breaks down request transfer size. + */ +void +asc_minphys(bp) + struct buf *bp; +{ +} + +/* + * Start activity on a SCSI device. + * We maintain information on each device separately since devices can + * connect/disconnect during an operation. + */ +int +asc_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct asc_softc *asc = sc_link->adapter_softc; + State *state = &asc->st[sc_link->target]; + + int flags, s; + + flags = xs->flags; + + /* + * Flush caches for any data buffer + */ + if(xs->datalen != 0) { + MachHitFlushDCache(xs->data, xs->datalen); + } + /* + * The hack on the next few lines are to avoid buffers + * mapped to UADDR. Realloc to the kva uarea address. + */ + if((u_int)(xs->data) >= UADDR) { + xs->data = ((u_int)(xs->data) & ~UADDR) + (u_char *)(curproc->p_addr); + } + + /* + * Check if another command is already in progress. + * We may have to change this if we allow SCSI devices with + * separate LUNs. + */ + s = splbio(); + if (asc->cmd[sc_link->target]) { + if (asc->cmdq[sc_link->target]) { + splx(s); + printf("asc_scsi_cmd: called when target busy"); + xs->error = XS_DRIVER_STUFFUP; + return TRY_AGAIN_LATER; + } + asc->cmdq[sc_link->target] = xs; + splx(s); + return SUCCESSFULLY_QUEUED; + } + asc->cmd[sc_link->target] = xs; + + /* + * Going to launch. + * Make a local copy of the command and some pointers. + */ + asc_startcmd(asc, sc_link->target); + + /* + * If in startup, interrupts not usable yet. + */ + if(flags & SCSI_POLL) { + return(asc_poll(asc,sc_link->target)); + } + splx(s); + return SUCCESSFULLY_QUEUED; +} + +int +asc_poll(asc, target) + struct asc_softc *asc; + int target; +{ + struct scsi_xfer *scsicmd = asc->cmd[target]; + int count = scsicmd->timeout * 10; + + while(count) { + if(asc->regs->asc_status &ASC_CSR_INT) { + asc_intr(asc); + } + if(scsicmd->flags & ITSDONE) + break; + DELAY(5); + count--; + } + if(count == 0) { + scsicmd->error = XS_TIMEOUT; + asc_end(asc, 0, 0, 0); + } + return COMPLETE; +} + +static void +asc_reset(asc, regs) + asc_softc_t asc; + asc_regmap_t *regs; +{ + + /* + * Reset chip and wait till done + */ + regs->asc_cmd = ASC_CMD_RESET; + wbflush(); DELAY(25); + + /* spec says this is needed after reset */ + regs->asc_cmd = ASC_CMD_NOP; + wbflush(); DELAY(25); + + /* + * Set up various chip parameters + */ + regs->asc_ccf = asc->ccf; + wbflush(); DELAY(25); + regs->asc_sel_timo = asc->timeout_250; + /* restore our ID */ + regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK; + /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */ + regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL; + regs->asc_cnfg3 = 0; + /* zero anything else */ + ASC_TC_PUT(regs, 0); + regs->asc_syn_p = asc->min_period; + regs->asc_syn_o = 0; /* async for now */ + wbflush(); +} + +/* + * Start a SCSI command on a target. + */ +static void +asc_startcmd(asc, target) + asc_softc_t asc; + int target; +{ + asc_regmap_t *regs; + State *state; + struct scsi_xfer *scsicmd; + int i, len; + + /* + * See if another target is currently selected on this SCSI bus. + */ + if (asc->target >= 0) + return; + + regs = asc->regs; + + /* + * If a reselection is in progress, it is Ok to ignore it since + * the ASC will automatically cancel the command and flush + * the FIFO if the ASC is reselected before the command starts. + * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if + * a reselect occurs before starting the command. + */ + + asc->state = ASC_STATE_BUSY; + asc->target = target; + + /* cache some pointers */ + scsicmd = asc->cmd[target]; + state = &asc->st[target]; + + /* + * Init the chip and target state. + */ + state->flags = state->flags & (DID_SYNC | CHECK_SENSE); + state->script = (script_t *)0; + state->msg_out = SCSI_NO_OP; + + /* + * Set up for DMA of command output. Also need to flush cache. + */ + if(!(state->flags & CHECK_SENSE)) { + bcopy(scsicmd->cmd, &state->cmd, scsicmd->cmdlen); + state->cmdlen = scsicmd->cmdlen; + state->buf = (vm_offset_t)scsicmd->data; + state->buflen = scsicmd->datalen; + } + len = state->cmdlen; + state->dmalen = len; + +#ifdef DEBUG + if (asc_debug > 1) { + printf("asc_startcmd: %s target %d cmd %x len %d\n", + asc->sc_dev.dv_xname, target, + state->cmd.opcode, state->buflen); + } +#endif + + /* check for simple SCSI command with no data transfer */ + if(state->flags & CHECK_SENSE) { + asc->script = &asc_scripts[SCRIPT_DATA_IN]; + state->flags |= DMA_IN; + } + else if (scsicmd->flags & SCSI_DATA_OUT) { + asc->script = &asc_scripts[SCRIPT_DATA_OUT]; + state->flags |= DMA_OUT; + } + else if (scsicmd->flags & SCSI_DATA_IN) { + asc->script = &asc_scripts[SCRIPT_DATA_IN]; + state->flags |= DMA_IN; + } + else if (state->buflen == 0) { + /* check for sync negotiation */ + if ((scsicmd->flags & /* SCSICMD_USE_SYNC */ 0) && + !(state->flags & DID_SYNC)) { + asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; + state->flags |= TRY_SYNC; + } else + asc->script = &asc_scripts[SCRIPT_SIMPLE]; + state->buf = (vm_offset_t)0; + } + +#ifdef DEBUG + asc_debug_cmd = state->cmd.opcode; + if (state->cmd.opcode == SCSI_READ_EXT) { + asc_debug_bn = (state->cmd.bytes[1] << 24) | + (state->cmd.bytes[2] << 16) | + (state->cmd.bytes[3] << 8) | + state->cmd.bytes[4]; + asc_debug_sz = (state->cmd.bytes[6] << 8) | state->cmd.bytes[7]; + } + asc_logp->status = PACK(asc->sc_dev.dv_unit, 0, 0, asc_debug_cmd); + asc_logp->target = asc->target; + asc_logp->state = asc->script - asc_scripts; + asc_logp->msg = SCSI_DIS_REC_IDENTIFY; + asc_logp->resid = scsicmd->datalen; + if (++asc_logp >= &asc_log[NLOG]) + asc_logp = asc_log; +#endif + + /* preload the FIFO with the message and command to be sent */ + regs->asc_fifo = SCSI_DIS_REC_IDENTIFY | (scsicmd->sc_link->lun & 0x07); + + for( i = 0; i < len; i++ ) { + regs->asc_fifo = ((caddr_t)&state->cmd)[i]; + } + ASC_TC_PUT(regs, 0); + readback(regs->asc_cmd); + regs->asc_cmd = ASC_CMD_DMA; + readback(regs->asc_cmd); + + regs->asc_dbus_id = target; + readback(regs->asc_dbus_id); + regs->asc_syn_p = state->sync_period; + readback(regs->asc_syn_p); + regs->asc_syn_o = state->sync_offset; + readback(regs->asc_syn_o); + +/*XXX PEFO */ +/* we are not using sync transfer now, need to check this if we will */ + + if (state->flags & TRY_SYNC) + regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; + else + regs->asc_cmd = ASC_CMD_SEL_ATN; + readback(regs->asc_cmd); +} + +/* + * Interrupt routine + * Take interrupts from the chip + * + * Implementation: + * Move along the current command's script if + * all is well, invoke error handler if not. + */ +int +asc_intr(sc) + void *sc; +{ + asc_softc_t asc = sc; + asc_regmap_t *regs = asc->regs; + State *state; + script_t *scpt; + int ss, ir, status; + + /* collect ephemeral information */ + status = regs->asc_status; + ss = regs->asc_ss; + + if ((status & ASC_CSR_INT) == 0) /* Make shure it's a real interrupt */ + return; + + ir = regs->asc_intr; /* this resets the previous two */ + scpt = asc->script; + +#ifdef DEBUG + asc_logp->status = PACK(asc->sc_dev.dv_unit, status, ss, ir); + asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; + asc_logp->state = scpt - asc_scripts; + asc_logp->msg = -1; + asc_logp->resid = 0; + if (++asc_logp >= &asc_log[NLOG]) + asc_logp = asc_log; + if (asc_debug > 2) + printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", + status, ss, ir, scpt - asc_scripts, scpt->condition); +#endif + + /* check the expected state */ + if (SCRIPT_MATCH(ir, status) == scpt->condition) { + /* + * Perform the appropriate operation, then proceed. + */ + if ((*scpt->action)(asc, status, ss, ir)) { + regs->asc_cmd = scpt->command; + readback(regs->asc_cmd); + asc->script = scpt->next; + } + goto done; + } + + /* + * Check for parity error. + * Hardware will automatically set ATN + * to request the device for a MSG_OUT phase. + */ + if (status & ASC_CSR_PE) { + printf("%s: SCSI device %d: incomming parity error seen\n", + asc->sc_dev.dv_xname, asc->target); + asc->st[asc->target].flags |= PARITY_ERR; + } + + /* + * Check for gross error. + * Probably a bug in a device driver. + */ + if (status & ASC_CSR_GE) { + printf("%s: SCSI device %d: gross error\n", + asc->sc_dev.dv_xname, asc->target); + goto abort; + } + + /* check for message in or out */ + if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { + register int len, fifo; + + state = &asc->st[asc->target]; + switch (ASC_PHASE(status)) { + case ASC_PHASE_DATAI: + case ASC_PHASE_DATAO: + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); + goto abort; + + case ASC_PHASE_MSG_IN: + break; + + case ASC_PHASE_MSG_OUT: + /* + * Check for parity error. + * Hardware will automatically set ATN + * to request the device for a MSG_OUT phase. + */ + if (state->flags & PARITY_ERR) { + state->flags &= ~PARITY_ERR; + state->msg_out = SCSI_MESSAGE_PARITY_ERROR; + /* reset message in counter */ + state->msglen = 0; + } else + state->msg_out = SCSI_NO_OP; + regs->asc_fifo = state->msg_out; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + goto done; + + case ASC_PHASE_STATUS: + /* probably an error in the SCSI command */ + asc->script = &asc_scripts[SCRIPT_GET_STATUS]; + regs->asc_cmd = ASC_CMD_I_COMPLETE; + readback(regs->asc_cmd); + goto done; + + default: + goto abort; + } + + if (state->script) + goto abort; + + /* + * OK, message coming in clean up whatever is going on. + * Get number of bytes left to transfered from byte counter + * counter decrements when data is trf on the SCSI bus + */ + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + /* flush any data in the FIFO */ + if (fifo && !(state->flags & DMA_IN_PROGRESS)) { +printf("asc_intr: fifo flush %d len %d fifo %x\n", fifo, len, regs->asc_fifo); + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + DELAY(2); + } + else if (fifo && state->flags & DMA_IN_PROGRESS) { + if (state->flags & DMA_OUT) { + len += fifo; /* Bytes dma'ed but not sent */ + } + else if (state->flags & DMA_IN) { + u_char *cp; + + printf("asc_intr: IN: dmalen %d len %d fifo %d\n", + state->dmalen, len, fifo); /* XXX */ + } + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + DELAY(2); + } + if (len && (state->flags & DMA_IN_PROGRESS)) { + /* save number of bytes still to be sent or received */ + state->dmaresid = len; + state->flags &= ~DMA_IN_PROGRESS; + ASC_TC_PUT(regs, 0); +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + /* setup state to resume to */ + if (state->flags & DMA_IN) { + /* + * Since the ASC_CNFG3_SRB bit of the + * cnfg3 register bit is not set, + * we just transferred an extra byte. + * Since we can't resume on an odd byte + * boundary, we copy the valid data out + * and resume DMA at the start address. + */ + if (len & 1) { + printf("asc_intr: msg in len %d (fifo %d)\n", + len, fifo); /* XXX */ + len = state->dmalen - len; + goto do_in; + } + state->script = + &asc_scripts[SCRIPT_RESUME_DMA_IN]; + } else if (state->flags & DMA_OUT) + state->script = + &asc_scripts[SCRIPT_RESUME_DMA_OUT]; + else + state->script = asc->script; + } else if (state->flags & DMA_IN) { + if (len) { +#ifdef DEBUG + printf("asc_intr: 1: bn %d len %d (fifo %d)\n", + asc_debug_bn, len, fifo); /* XXX */ +#endif + goto abort; + } + /* setup state to resume to */ + if (state->flags & DMA_IN_PROGRESS) { + len = state->dmalen; + state->flags &= ~DMA_IN_PROGRESS; + do_in: + DMA_END(asc->dma); + state->buf += len; + state->buflen -= len; + } + if (state->buflen) + state->script = + &asc_scripts[SCRIPT_RESUME_IN]; + else + state->script = + &asc_scripts[SCRIPT_RESUME_NO_DATA]; + } else if (state->flags & DMA_OUT) { + if (len) { + printf("asc_intr: 2: len %d (fifo %d)\n", len, + fifo); /* XXX */ +/* XXX THEO */ +#if 1 + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + DELAY(2); + len = 0; +#else + goto abort; +#endif + } + /* + * If this is the last chunk, the next expected + * state is to get status. + */ + if (state->flags & DMA_IN_PROGRESS) { + state->flags &= ~DMA_IN_PROGRESS; + DMA_END(asc->dma); + len = state->dmalen; + state->buf += len; + state->buflen -= len; + } + if (state->buflen) + state->script = + &asc_scripts[SCRIPT_RESUME_OUT]; + else + state->script = + &asc_scripts[SCRIPT_RESUME_NO_DATA]; + } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) + state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA]; + else + state->script = asc->script; + + /* setup to receive a message */ + asc->script = &asc_scripts[SCRIPT_MSG_IN]; + state->msglen = 0; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + goto done; + } + + /* check for SCSI bus reset */ + if (ir & ASC_INT_RESET) { + register int i; + + printf("%s: SCSI bus reset!!\n", asc->sc_dev.dv_xname); + /* need to flush any pending commands */ + for (i = 0; i < ASC_NCMD; i++) { + if (!asc->cmd[i]) + continue; + asc->cmd[i]->error = XS_DRIVER_STUFFUP; + asc_end(asc, 0, 0, 0); + } + /* rearbitrate synchronous offset */ + for (i = 0; i < ASC_NCMD; i++) { + asc->st[i].sync_offset = 0; + asc->st[i].flags = 0; + } + asc->target = -1; + return; + } + + /* check for command errors */ + if (ir & ASC_INT_ILL) + goto abort; + + /* check for disconnect */ + if (ir & ASC_INT_DISC) { + state = &asc->st[asc->target]; + switch (asc->script - asc_scripts) { + case SCRIPT_DONE: + case SCRIPT_DISCONNECT: + /* + * Disconnects can happen normally when the + * command is complete with the phase being + * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN. + * The SCRIPT_MATCH() only checks for one phase + * so we can wind up here. + * Perform the appropriate operation, then proceed. + */ + if ((*scpt->action)(asc, status, ss, ir)) { + regs->asc_cmd = scpt->command; + readback(regs->asc_cmd); + asc->script = scpt->next; + } + goto done; + + case SCRIPT_TRY_SYNC: + case SCRIPT_SIMPLE: + case SCRIPT_DATA_IN: + case SCRIPT_DATA_OUT: /* one of the starting scripts */ + if (ASC_SS(ss) == 0) { + /* device did not respond */ + if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + } + asc->cmd[asc->target]->error = XS_DRIVER_STUFFUP; + asc_end(asc, status, ss, ir); + return; + } + /* FALLTHROUGH */ + + default: + printf("%s: SCSI device %d: unexpected disconnect\n", + asc->sc_dev.dv_xname, asc->target); +#ifdef DEBUG + asc_DumpLog("asc_disc"); +#endif + /* + * On rare occasions my RZ24 does a disconnect during + * data in phase and the following seems to keep it + * happy. + * XXX Should a scsi disk ever do this?? + */ + asc->script = &asc_scripts[SCRIPT_RESEL]; + asc->state = ASC_STATE_RESEL; + state->flags |= DISCONN; + regs->asc_cmd = ASC_CMD_ENABLE_SEL; + readback(regs->asc_cmd); + return; + } + } + + /* check for reselect */ + if (ir & ASC_INT_RESEL) { + unsigned fifo, id, msg; + + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + if (fifo < 2) + goto abort; + /* read unencoded SCSI ID and convert to binary */ + msg = regs->asc_fifo & asc->myidmask; + for (id = 0; (msg & 1) == 0; id++) + msg >>= 1; + /* read identify message */ + msg = regs->asc_fifo; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].msg = msg; + else + asc_logp[-1].msg = msg; +#endif + asc->state = ASC_STATE_BUSY; + asc->target = id; + state = &asc->st[id]; + asc->script = state->script; + state->script = (script_t *)0; + if (!(state->flags & DISCONN)) + goto abort; + state->flags &= ~DISCONN; + regs->asc_syn_p = state->sync_period; + regs->asc_syn_o = state->sync_offset; + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + goto done; + } + + /* check if we are being selected as a target */ + if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) + goto abort; + + /* + * 'ir' must be just ASC_INT_FC. + * This is normal if canceling an ASC_ENABLE_SEL. + */ + +done: + wbflush(); + /* + * If the next interrupt comes in immediatly the interrupt + * dispatcher (which we are returning to) will catch it + * before returning to the interrupted code. + */ + return; + +abort: +#ifdef DEBUG + asc_DumpLog("asc_intr"); +#endif +#if 0 + panic("asc_intr"); +#else + boot(4); /* XXX */ +#endif +} + +/* + * All the many little things that the interrupt + * routine might switch to. + */ + +/* ARGSUSED */ +static int +script_nop(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + return (1); +} + +/* ARGSUSED */ +static int +asc_get_status(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register int data; + + /* + * Get the last two bytes in the FIFO. + */ + if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { + printf("asc_get_status: cmdreg %x, fifo cnt %d\n", + regs->asc_cmd, data); /* XXX */ +#ifdef DEBUG + asc_DumpLog("get_status"); /* XXX */ +#endif + if (data < 2) { + asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(asc->regs->asc_cmd); + return (0); + } + do { + data = regs->asc_fifo; + } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); + } + + /* save the status byte */ + asc->st[asc->target].statusByte = data = regs->asc_fifo; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].msg = data; + else + asc_logp[-1].msg = data; +#endif + + /* get the (presumed) command_complete message */ + if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) + return (1); + +#ifdef DEBUG + printf("asc_get_status: status %x cmd %x\n", + asc->st[asc->target].statusByte, data); + asc_DumpLog("asc_get_status"); +#endif + return (0); +} + +/* ARGSUSED */ +static int +asc_end(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + struct scsi_xfer *scsicmd; + struct scsi_link *sc_link; + State *state; + int i, target; + + asc->state = ASC_STATE_IDLE; + target = asc->target; + asc->target = -1; + scsicmd = asc->cmd[target]; + sc_link = scsicmd->sc_link; + asc->cmd[target] = (struct scsi_xfer *)0; + state = &asc->st[target]; + +#ifdef DEBUG + if (asc_debug > 1) { + printf("asc_end: %s target %d cmd %x err %d resid %d\n", + asc->sc_dev.dv_xname, target, + state->cmd.opcode, scsicmd->error, state->buflen); + } +#endif +#ifdef DIAGNOSTIC + if (target < 0 || !scsicmd) + panic("asc_end"); +#endif + + /* look for disconnected devices */ + for (i = 0; i < ASC_NCMD; i++) { + if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) + continue; + asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; + readback(asc->regs->asc_cmd); + asc->state = ASC_STATE_RESEL; + asc->script = &asc_scripts[SCRIPT_RESEL]; + break; + } + + if(scsicmd->error == XS_NOERROR && !(state->flags & CHECK_SENSE)) { + if((state->statusByte & ST_MASK) == SCSI_CHECK) { + struct scsi_sense *ss = (void *)&state->cmd; + /* Save return values */ + scsicmd->resid = state->buflen; + scsicmd->status = state->statusByte; + /* Set up sense request command */ + bzero(ss, sizeof(*ss)); + ss->opcode = REQUEST_SENSE; + ss->byte2 = sc_link->lun << 5; + ss->length = sizeof(struct scsi_sense_data); + state->cmdlen = sizeof(*ss); + state->buf = (vm_offset_t)&scsicmd->sense; + state->buflen = sizeof(struct scsi_sense_data); + state->flags |= CHECK_SENSE; + MachHitFlushDCache(state->buf, state->buflen); + asc->cmd[target] = scsicmd; + asc_startcmd(asc, target); + return(0); + } + } + + if(scsicmd->error == XS_NOERROR && (state->flags & CHECK_SENSE)) { + scsicmd->error = XS_SENSE; + } + else { + scsicmd->resid = state->buflen; + } + state->flags &= ~CHECK_SENSE; + + /* + * Look for another device that is ready. + * May want to keep last one started and increment for fairness + * rather than always starting at zero. + */ + for (i = 0; i < ASC_NCMD; i++) { + if (asc->cmd[i] == 0 && asc->cmdq[i] != 0) { + asc->cmd[i] = asc->cmdq[i]; + asc->cmdq[i] = 0; + } + } + for (i = 0; i < ASC_NCMD; i++) { + /* don't restart a disconnected command */ + if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) + continue; + asc_startcmd(asc, i); + break; + } + + /* signal device driver that the command is done */ + scsicmd->flags |= ITSDONE; + scsi_done(scsicmd); + + return (0); +} + +/* ARGSUSED */ +static int +asc_dma_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len; + + /* check for previous chunk in buffer */ + if (state->flags & DMA_IN_PROGRESS) { + /* + * Only count bytes that have been copied to memory. + * There may be some bytes in the FIFO if synchonous transfers + * are in progress. + */ + DMA_END(asc->dma); + ASC_TC_GET(regs, len); + len = state->dmalen - len; + state->buf += len; + state->buflen -= len; + } + + /* setup to start reading the next chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; + DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_last_dma_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, fifo; + + DMA_END(asc->dma); + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); +#endif + if (fifo) { + /* device must be trying to send more than we expect */ + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + } + state->flags &= ~DMA_IN_PROGRESS; + len = state->dmalen - len; + state->buflen -= len; + + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len; + + /* setup to start reading the next chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_in: buflen %d, len %d\n", state->buflen, + len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_dma_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, off; + + /* setup to finish reading the current chunk */ + len = state->dmaresid; + off = state->dmalen - len; + if ((off & 1) && state->sync_offset) { + printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", + state->dmalen, len, off); /* XXX */ + regs->asc_res_fifo = ((u_char *)state->buf)[off]; +/*XXX Need to flush cache ? */ + } + DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_FROM_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", + state->dmalen, state->buflen, len, off); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (state->dmalen != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_dma_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, fifo; + + if (state->flags & DMA_IN_PROGRESS) { + /* check to be sure previous chunk was finished */ + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + if (len || fifo) + printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); /* XXX */ + len += fifo; + len = state->dmalen - len; + state->buf += len; + state->buflen -= len; + } + + /* setup for this chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; + DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_last_dma_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, fifo; + + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); +#endif + if (fifo) { + len += fifo; + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + } + state->flags &= ~DMA_IN_PROGRESS; + len = state->dmalen - len; + state->buflen -= len; + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len; + + /* setup for this chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_out: buflen %d, len %d\n", state->buflen, + len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_dma_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, off; + + /* setup to finish writing this chunk */ + len = state->dmaresid; + off = state->dmalen - len; + if (off & 1) { + printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", + state->dmalen, len, off); /* XXX */ + regs->asc_fifo = ((u_char *)state->buf)[off]; +/*XXX Need to flush Cache ? */ + off++; + len--; + } + DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_TO_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", + state->dmalen, state->buflen, len, off); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (state->dmalen != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_sendsync(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + + /* send the extended synchronous negotiation message */ + regs->asc_fifo = SCSI_EXTENDED_MSG; + wbflush(); + regs->asc_fifo = 3; + wbflush(); + regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; + wbflush(); + regs->asc_fifo = SCSI_MIN_PERIOD; + wbflush(); + regs->asc_fifo = ASC_MAX_OFFSET; + /* state to resume after we see the sync reply message */ + state->script = asc->script + 2; + state->msglen = 0; + return (1); +} + +/* ARGSUSED */ +static int +asc_replysync(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_replysync: %x %x\n", + asc_to_scsi_period[state->sync_period] * asc->tb_ticks, + state->sync_offset); +#endif + /* send synchronous transfer in response to a request */ + regs->asc_fifo = SCSI_EXTENDED_MSG; + wbflush(); + regs->asc_fifo = 3; + wbflush(); + regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; + wbflush(); + regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; + wbflush(); + regs->asc_fifo = state->sync_offset; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + + /* return to the appropriate script */ + if (!state->script) { +#ifdef DEBUG + asc_DumpLog("asc_replsync"); +#endif + panic("asc_replysync"); + } + asc->script = state->script; + state->script = (script_t *)0; + return (0); +} + +/* ARGSUSED */ +static int +asc_msg_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int msg; + int i; + + /* read one message byte */ + msg = regs->asc_fifo; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].msg = msg; + else + asc_logp[-1].msg = msg; +#endif + + /* check for multi-byte message */ + if (state->msglen != 0) { + /* first byte is the message length */ + if (state->msglen < 0) { + state->msglen = msg; + return (1); + } + if (state->msgcnt >= state->msglen) + goto abort; + state->msg_in[state->msgcnt++] = msg; + + /* did we just read the last byte of the message? */ + if (state->msgcnt != state->msglen) + return (1); + + /* process an extended message */ +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_msg_in: msg %x %x %x\n", + state->msg_in[0], + state->msg_in[1], + state->msg_in[2]); +#endif + switch (state->msg_in[0]) { + case SCSI_SYNCHRONOUS_XFER: + state->flags |= DID_SYNC; + state->sync_offset = state->msg_in[2]; + + /* convert SCSI period to ASC period */ + i = state->msg_in[1] / asc->tb_ticks; + if (i < asc->min_period) + i = asc->min_period; + else if (i >= asc->max_period) { + /* can't do sync transfer, period too long */ + printf("%s: SCSI device %d: sync xfer period too long (%d)\n", + asc->sc_dev.dv_xname, asc->target, i); + i = asc->max_period; + state->sync_offset = 0; + } + if ((i * asc->tb_ticks) != state->msg_in[1]) + i++; + state->sync_period = i & 0x1F; + + /* + * If this is a request, check minimums and + * send back an acknowledge. + */ + if (!(state->flags & TRY_SYNC)) { + regs->asc_cmd = ASC_CMD_SET_ATN; + readback(regs->asc_cmd); + + if (state->sync_period < asc->min_period) + state->sync_period = + asc->min_period; + if (state->sync_offset > ASC_MAX_OFFSET) + state->sync_offset = + ASC_MAX_OFFSET; + asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; + regs->asc_syn_p = state->sync_period; + readback(regs->asc_syn_p); + regs->asc_syn_o = state->sync_offset; + readback(regs->asc_syn_o); + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + return (0); + } + + regs->asc_syn_p = state->sync_period; + readback(regs->asc_syn_p); + regs->asc_syn_o = state->sync_offset; + readback(regs->asc_syn_o); + goto done; + + default: + printf("%s: SCSI device %d: rejecting extended message 0x%x\n", + asc->sc_dev.dv_xname, asc->target, + state->msg_in[0]); + goto reject; + } + } + + /* process first byte of a message */ +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_msg_in: msg %x\n", msg); +#endif + switch (msg) { +#if 0 + case SCSI_MESSAGE_REJECT: + printf(" did not like SYNCH xfer "); /* XXX */ + state->flags |= DID_SYNC; + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + status = asc_wait(regs, ASC_CSR_INT); + ir = regs->asc_intr; + /* some just break out here, some dont */ + if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { + regs->asc_fifo = SCSI_ABORT; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + status = asc_wait(regs, ASC_CSR_INT); + ir = regs->asc_intr; + } + if (ir & ASC_INT_DISC) { + asc_end(asc, status, 0, ir); + return (0); + } + goto status; +#endif /* 0 */ + + case SCSI_EXTENDED_MSG: /* read an extended message */ + /* setup to read message length next */ + state->msglen = -1; + state->msgcnt = 0; + return (1); + + case SCSI_NO_OP: + break; + + case SCSI_SAVE_DATA_POINTER: + /* expect another message */ + return (1); + + case SCSI_RESTORE_POINTERS: + /* + * Need to do the following if resuming synchonous data in + * on an odd byte boundary. + regs->asc_cnfg2 |= ASC_CNFG2_RFB; + */ + break; + + case SCSI_DISCONNECT: + if (state->flags & DISCONN) + goto abort; + state->flags |= DISCONN; + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_DISCONNECT]; + return (0); + + default: + printf("%s: SCSI device %d: rejecting message 0x%x\n", + asc->sc_dev.dv_xname, asc->target, msg); + reject: + /* request a message out before acknowledging this message */ + state->msg_out = SCSI_MESSAGE_REJECT; + regs->asc_cmd = ASC_CMD_SET_ATN; + readback(regs->asc_cmd); + } + +done: + /* return to original script */ + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + if (!state->script) { + abort: +#ifdef DEBUG + asc_DumpLog("asc_msg_in"); +#endif + panic("asc_msg_in"); + } + asc->script = state->script; + state->script = (script_t *)0; + return (0); +} + +/* ARGSUSED */ +static int +asc_disconnect(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register State *state = &asc->st[asc->target]; + +#ifdef DIAGNOSTIC + if (!(state->flags & DISCONN)) { + printf("asc_disconnect: device %d: DISCONN not set!\n", + asc->target); + } +#endif /* DIAGNOSTIC */ + asc->target = -1; + asc->state = ASC_STATE_RESEL; + return (1); +} + +#ifdef DEBUG +/* + * Dump the log buffer. + */ +asc_DumpLog(str) + char *str; +{ + register struct asc_log *lp; + register u_int status; + + printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, + asc_debug_bn, asc_debug_sz); + lp = asc_logp; + do { + status = lp->status; + printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", + status >> 24, + lp->target, + (status >> 16) & 0xFF, + (status >> 8) & 0xFF, + status & 0XFF, + lp->state, + asc_scripts[lp->state].condition, + lp->msg, lp->resid); + if (++lp >= &asc_log[NLOG]) + lp = asc_log; + } while (lp != asc_logp); +} +#endif /* DEBUG */ + +#endif /* NASC > 0 */ diff --git a/sys/arch/arc/dev/ascreg.h b/sys/arch/arc/dev/ascreg.h new file mode 100644 index 00000000000..c6ff2fb236b --- /dev/null +++ b/sys/arch/arc/dev/ascreg.h @@ -0,0 +1,322 @@ +/* $OpenBSD: ascreg.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * from: @(#)ascreg.h 8.1 (Berkeley) 6/10/93 + * $Id: ascreg.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ + */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * HISTORY + * Log: scsi_53C94.h,v + * Revision 2.4 91/02/05 17:44:59 mrt + * Added author notices + * [91/02/04 11:18:32 mrt] + * + * Changed to use new Mach copyright + * [91/02/02 12:17:11 mrt] + * + * Revision 2.3 90/12/05 23:34:46 af + * Documented max DMA xfer size. + * [90/12/03 23:39:36 af] + * + * Revision 2.1.1.1 90/11/01 03:38:54 af + * Created, from the DEC specs: + * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" + * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. + * And from the NCR data sheets + * "NCR 53C94, 53C95, 53C96 Advanced SCSI Controller" + * [90/09/03 af] + */ + +/* + * File: scsi_53C94.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Defines for the NCR 53C94 ASC (SCSI interface) + * Some gotcha came from the "86C01/53C94 DMA lab work" written + * by Ken Stewart (NCR MED Logic Products Applications Engineer) + * courtesy of NCR. Thanks Ken ! + */ + +#define ASC_OFFSET_53C94 0x0 /* from module base */ + +#define ASC_NCMD 7 /* Number of simultaneous cmds */ + +/* + * Synch xfer parameters, and timing conversions + */ +#define SCSI_MIN_PERIOD 50 /* in 4 nsecs units */ +#define ASC_MIN_PERIOD40 8 /* in CLKS/BYTE, 1 CLK = 25nsecs */ +#define ASC_MIN_PERIOD25 5 /* in CLKS/BYTE, 1 CLK = 40nsecs */ +#define ASC_MIN_PERIOD12 3 /* in CLKS/BYTE, 1 CLK = 80nsecs */ +#define ASC_MAX_PERIOD40 56 /* in CLKS/BYTE, 1 CLK = 25nsecs */ +#define ASC_MAX_PERIOD25 35 /* in CLKS/BYTE, 1 CLK = 40nsecs */ +#define ASC_MAX_PERIOD12 18 /* in CLKS/BYTE, 1 CLK = 80nsecs */ +#define ASC_MAX_OFFSET 15 /* pure number */ +/* + * Register map, padded as needed + */ + +typedef volatile struct { + u_char asc_tc_lsb; /* rw: Transfer Counter LSB */ + u_char asc_tc_msb; /* rw: Transfer Counter MSB */ + u_char asc_fifo; /* rw: FIFO top */ + u_char asc_cmd; /* rw: Command */ + u_char asc_status; /* r: Status */ +#define asc_dbus_id asc_status /* w: Destination Bus ID */ + u_char asc_intr; /* r: Interrupt */ +#define asc_sel_timo asc_intr /* w: (re)select timeout */ + u_char asc_ss; /* r: Sequence Step */ +#define asc_syn_p asc_ss /* w: synchronous period */ + u_char asc_flags; /* r: FIFO flags + seq step */ +#define asc_syn_o asc_flags /* w: synchronous offset */ + u_char asc_cnfg1; /* rw: Configuration 1 */ + u_char asc_ccf; /* w: Clock Conv. Factor */ + u_char asc_test; /* w: Test Mode */ + u_char asc_cnfg2; /* rw: Configuration 2 */ + u_char asc_cnfg3; /* rw: Configuration 3 */ + u_char asc_res_fifo; /* w: Reserve FIFO byte */ +} asc_regmap_t; + +/* + * Transfer Count: access macros + * That a NOP is required after loading the dma counter + * I learned on the NCR test code. Sic. + */ + +#define ASC_TC_MAX 0x10000 + +#define ASC_TC_GET(ptr, val) \ + val = (ptr)->asc_tc_lsb | ((ptr)->asc_tc_msb << 8) +#define ASC_TC_PUT(ptr, val) \ + (ptr)->asc_tc_lsb = (val); \ + (ptr)->asc_tc_msb = (val) >> 8; \ + (ptr)->asc_cmd = ASC_CMD_NOP | ASC_CMD_DMA; + +/* + * Command register (command codes) + */ + +#define ASC_CMD_DMA 0x80 + /* Miscellaneous */ +#define ASC_CMD_NOP 0x00 +#define ASC_CMD_FLUSH 0x01 +#define ASC_CMD_RESET 0x02 +#define ASC_CMD_BUS_RESET 0x03 + /* Initiator state */ +#define ASC_CMD_XFER_INFO 0x10 +#define ASC_CMD_I_COMPLETE 0x11 +#define ASC_CMD_MSG_ACPT 0x12 +#define ASC_CMD_XFER_PAD 0x18 +#define ASC_CMD_SET_ATN 0x1a +#define ASC_CMD_CLR_ATN 0x1b + /* Target state */ +#define ASC_CMD_SND_MSG 0x20 +#define ASC_CMD_SND_STATUS 0x21 +#define ASC_CMD_SND_DATA 0x22 +#define ASC_CMD_DISC_SEQ 0x23 +#define ASC_CMD_TERM 0x24 +#define ASC_CMD_T_COMPLETE 0x25 +#define ASC_CMD_DISC 0x27 +#define ASC_CMD_RCV_MSG 0x28 +#define ASC_CMD_RCV_CDB 0x29 +#define ASC_CMD_RCV_DATA 0x2a +#define ASC_CMD_RCV_CMD 0x2b +#define ASC_CMD_ABRT_DMA 0x04 + /* Disconnected state */ +#define ASC_CMD_RESELECT 0x40 +#define ASC_CMD_SEL 0x41 +#define ASC_CMD_SEL_ATN 0x42 +#define ASC_CMD_SEL_ATN_STOP 0x43 +#define ASC_CMD_ENABLE_SEL 0x44 +#define ASC_CMD_DISABLE_SEL 0x45 +#define ASC_CMD_SEL_ATN3 0x46 + +/* + * Status register, and phase encoding + */ + +#define ASC_CSR_INT 0x80 +#define ASC_CSR_GE 0x40 +#define ASC_CSR_PE 0x20 +#define ASC_CSR_TC 0x10 +#define ASC_CSR_VGC 0x08 +#define ASC_CSR_MSG 0x04 +#define ASC_CSR_CD 0x02 +#define ASC_CSR_IO 0x01 + +#define ASC_PHASE(csr) ((csr) & 0x7) +#define ASC_PHASE_DATAO 0x0 +#define ASC_PHASE_DATAI 0x1 +#define ASC_PHASE_COMMAND 0x2 +#define ASC_PHASE_STATUS 0x3 + /* 4..5 ANSI reserved */ +#define ASC_PHASE_MSG_OUT 0x6 +#define ASC_PHASE_MSG_IN 0x7 + +/* + * Destination Bus ID + */ + +#define ASC_DEST_ID_MASK 0x07 + +/* + * Interrupt register + */ + +#define ASC_INT_RESET 0x80 +#define ASC_INT_ILL 0x40 +#define ASC_INT_DISC 0x20 +#define ASC_INT_BS 0x10 +#define ASC_INT_FC 0x08 +#define ASC_INT_RESEL 0x04 +#define ASC_INT_SEL_ATN 0x02 +#define ASC_INT_SEL 0x01 + +/* + * Timeout register: + * + * val = (timeout * CLK_freq) / (8192 * CCF); + */ + +#define ASC_TIMEOUT_250(clk, ccf) (((clk) * 31) / (ccf)) + +/* + * Sequence Step register + */ + +#define ASC_SS_RESERVED 0xf0 +#define ASC_SS_SOM 0x08 +#define ASC_SS_MASK 0x07 +#define ASC_SS(ss) ((ss) & ASC_SS_MASK) + +/* + * Synchronous Transfer Period + */ + +#define ASC_STP_MASK 0x1f +#define ASC_STP_MIN 0x05 /* 5 clk per byte */ +#define ASC_STP_MAX 0x04 /* after ovfl, 35 clk/byte */ + +/* + * FIFO flags + */ + +#define ASC_FLAGS_SEQ_STEP 0xe0 +#define ASC_FLAGS_FIFO_CNT 0x1f + +/* + * Synchronous offset + */ + +#define ASC_SYNO_MASK 0x0f /* 0 -> asyn */ + +/* + * Configuration 1 + */ + +#define ASC_CNFG1_SLOW 0x80 +#define ASC_CNFG1_SRD 0x40 +#define ASC_CNFG1_P_TEST 0x20 +#define ASC_CNFG1_P_CHECK 0x10 +#define ASC_CNFG1_TEST 0x08 +#define ASC_CNFG1_MY_BUS_ID 0x07 + +/* + * CCF register + */ + +#define ASC_CCF(clk) ((((clk) - 1) / 5) + 1) + +/* + * Test register + */ + +#define ASC_TEST_XXXX 0xf8 +#define ASC_TEST_HI_Z 0x04 +#define ASC_TEST_I 0x02 +#define ASC_TEST_T 0x01 + +/* + * Configuration 2 + */ + +#define ASC_CNFG2_RFB 0x80 +#define ASC_CNFG2_EPL 0x40 +#define ASC_CNFG2_EBC 0x20 +#define ASC_CNFG2_DREQ_HIZ 0x10 +#define ASC_CNFG2_SCSI2 0x08 +#define ASC_CNFG2_BPA 0x04 +#define ASC_CNFG2_RPE 0x02 +#define ASC_CNFG2_DPE 0x01 + +/* + * Configuration 3 + */ + +#define ASC_CNFG3_RESERVED 0xf8 +#define ASC_CNFG3_SRB 0x04 +#define ASC_CNFG3_ALT_DMA 0x02 +#define ASC_CNFG3_T8 0x01 + +#define ST_MASK 0x3e diff --git a/sys/arch/arc/dev/dma.c b/sys/arch/arc/dev/dma.c new file mode 100644 index 00000000000..20d068480e5 --- /dev/null +++ b/sys/arch/arc/dev/dma.c @@ -0,0 +1,395 @@ +/* $OpenBSD: dma.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * from: @(#)rz.c 8.1 (Berkeley) 7/29/93 + * $Id: dma.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ + */ + +/* + * PICA system dma driver. Handles resource allocation and + * logical (viritual) address remaping. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/syslog.h> +#include <sys/device.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> +#include <machine/pte.h> +#include <machine/pio.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <arc/pica/pica.h> +#include <arc/dev/dma.h> + + +extern vm_map_t phys_map; + +#define dma_pte_to_pa(x) (((x) - first_dma_pte) * PICA_DMA_PAGE_SIZE) + +dma_pte_t *free_dma_pte; /* Pointer to free dma pte list */ +dma_pte_t *first_dma_pte; /* Pointer to first dma pte */ + +/* + * Initialize the dma mapping register area and pool. + */ +void +picaDmaInit() +{ + int map = PICA_TL_BASE; + + MachFlushCache(); /* Make shure no map entries are cached */ + + bzero((char *)map, PICA_TL_SIZE); + free_dma_pte = (dma_pte_t *)map; + first_dma_pte = (dma_pte_t *)map; + free_dma_pte->queue.next = NULL; + free_dma_pte->queue.size = PICA_TL_SIZE / sizeof(dma_pte_t); + + out32(PICA_SYS_TL_BASE, UNCACHED_TO_PHYS(map)); + out32(PICA_SYS_TL_LIMIT, PICA_TL_SIZE); + out32(PICA_SYS_TL_IVALID, 0); +} + +/* + * Allocate an array of 'size' dma pte entrys. + * Return address to first pte. + */ +void +picaDmaTLBAlloc(dma_softc_t *dma) +{ + dma_pte_t *list; + dma_pte_t *found; + int size; + int s; + + found = NULL; + size = dma->pte_size; + do { + list = (dma_pte_t *)&free_dma_pte; + s = splhigh(); + while(list) { + if(list->queue.next->queue.size >= size) { + found = list->queue.next; + break; + } + } +/*XXX Wait for release wakeup */ + } while(found == NULL); + if(found->queue.size == size) { + list->queue.next = found->queue.next; + } + else { + list->queue.next = found + size; + list = found + size; + list->queue.next = found->queue.next; + list->queue.size = found->queue.size - size; + } + splx(s); + dma->pte_base = found; + dma->dma_va = dma_pte_to_pa(found); +} + +/* + * Free an array of dma pte entrys. + */ +void +picaDmaTLBFree(dma_softc_t *dma) +{ + dma_pte_t *list; + dma_pte_t *entry; + int size; + int s; + + s = splhigh(); + entry = dma->pte_base; + size = dma->pte_size; + entry->queue.next = NULL; + entry->queue.size = size; + if(free_dma_pte == NULL || entry < free_dma_pte) { + list = entry; + list->queue.next = free_dma_pte; + free_dma_pte = entry; + } + else { + list = free_dma_pte; + while(list < entry && list->queue.next != NULL) { + if(list + list->queue.size == entry) { + list->queue.size += size; + break; + } + else if(list->queue.next == NULL) { + list->queue.next = entry; + break; + } + else + list = list->queue.next; + } + } + if(list->queue.next != NULL) { + if(list + list->queue.size == list->queue.next) { + list->queue.size += list->queue.next->queue.size; + list->queue.next = list->queue.next->queue.next; + } + } + splx(s); +/*XXX Wakeup waiting */ +} + +/* + * Map up a viritual address space in dma space given by + * the dma control structure and invalidate dma TLB cache. + */ + +picaDmaTLBMap(dma_softc_t *sc) +{ + vm_offset_t pa; + vm_offset_t va; + dma_pte_t *dma_pte; + int nbytes; + + va = sc->next_va - sc->dma_va; + dma_pte = sc->pte_base + (va / PICA_DMA_PAGE_SIZE); + nbytes = dma_page_round(sc->next_size + dma_page_offs(va)); + va = sc->req_va; + while(nbytes > 0) { + if(va < VM_MIN_KERNEL_ADDRESS) { + pa = CACHED_TO_PHYS(va); + } + else { + pa = pmap_extract(vm_map_pmap(phys_map), va); + } + pa &= PICA_DMA_PAGE_NUM; + if(pa == 0) + panic("picaDmaTLBMap: null page frame"); + dma_pte->entry.lo_addr = pa; + dma_pte->entry.hi_addr = 0; + dma_pte++; + va += PICA_DMA_PAGE_SIZE; + nbytes -= PICA_DMA_PAGE_SIZE; + } +} + +/* + * Start local dma channel. + */ +void +picaDmaStart(sc, addr, size, datain) + struct dma_softc *sc; + char *addr; + size_t size; + int datain; +{ + int mode; + pDmaReg regs = sc->dma_reg; + + /* Halt DMA */ + regs->dma_enab = 0; + regs->dma_mode = 0; + + /* Remap request space va into dma space va */ + + sc->req_va = (int)addr; + sc->next_va = sc->dma_va + dma_page_offs(addr); + sc->next_size = size; + + /* Map up the request viritual dma space */ + picaDmaTLBMap(sc); + out32(PICA_SYS_TL_IVALID, 0); /* Flush dma map cache */ + + /* Load new transfer parameters */ + regs->dma_addr = sc->next_va; + regs->dma_count = sc->next_size; + regs->dma_mode = sc->mode & PICA_DMA_MODE; + + sc->sc_active = 1; + if(datain == DMA_FROM_DEV) { + sc->mode &= ~DMA_DIR_WRITE; + regs->dma_enab = PICA_DMA_ENAB_RUN | PICA_DMA_ENAB_READ; + } + else { + sc->mode |= DMA_DIR_WRITE; + regs->dma_enab = PICA_DMA_ENAB_RUN | PICA_DMA_ENAB_WRITE; + } + wbflush(); +} + +/* + * Set up DMA mapper for external dma. + * Used by ISA dma and SONIC + */ +void +picaDmaMap(sc, addr, size, offset) + struct dma_softc *sc; + char *addr; + size_t size; + int offset; +{ + /* Remap request space va into dma space va */ + + sc->req_va = (int)addr; + sc->next_va = sc->dma_va + dma_page_offs(addr) + offset; + sc->next_size = size; + + /* Map up the request viritual dma space */ + picaDmaTLBMap(sc); +} + +/* + * Prepare for new dma by flushing + */ +void +picaDmaFlush(sc, addr, size, datain) + struct dma_softc *sc; + char *addr; + size_t size; + int datain; +{ + out32(PICA_SYS_TL_IVALID, 0); /* Flush dma map cache */ +} + +/* + * Stop/Reset a DMA channel + */ +void +picaDmaReset(dma_softc_t *sc) +{ + pDmaReg regs = sc->dma_reg; + + /* Halt DMA */ + regs->dma_enab = 0; + regs->dma_mode = 0; + sc->sc_active = 0; +} + +/* + * End dma operation, return byte count left. + */ +int +picaDmaEnd(dma_softc_t *sc) +{ + pDmaReg regs = sc->dma_reg; + int res; + + res = regs->dma_count = sc->next_size; + + /* Halt DMA */ + regs->dma_enab = 0; + regs->dma_mode = 0; + sc->sc_active = 0; + + return res; +} + +/* + * Null call rathole! + */ +void +picaDmaNull(dma_softc_t *sc) +{ + pDmaReg regs = sc->dma_reg; + + printf("picaDmaNull called\n"); +} + +/* + * dma_init.. + * Called from asc to set up dma + */ +void +asc_dma_init(dma_softc_t *sc) +{ + sc->reset = picaDmaReset; + sc->enintr = picaDmaNull; + sc->start = picaDmaStart; + sc->map = picaDmaMap; + sc->isintr = (int(*)())picaDmaNull; + sc->intr = (int(*)())picaDmaNull; + sc->end = picaDmaEnd; + + sc->dma_reg = (pDmaReg)PICA_SYS_DMA0_REGS; + sc->pte_size = 32; + sc->mode = PICA_DMA_MODE_160NS | PICA_DMA_MODE_16; + picaDmaTLBAlloc(sc); +} +/* + * dma_init.. + * Called from fdc to set up dma + */ +void +fdc_dma_init(dma_softc_t *sc) +{ + sc->reset = picaDmaReset; + sc->enintr = picaDmaNull; + sc->start = picaDmaStart; + sc->map = picaDmaMap; + sc->isintr = (int(*)())picaDmaNull; + sc->intr = (int(*)())picaDmaNull; + sc->end = picaDmaEnd; + + sc->dma_reg = (pDmaReg)PICA_SYS_DMA1_REGS; + sc->pte_size = 32; + sc->mode = PICA_DMA_MODE_160NS | PICA_DMA_MODE_8; + picaDmaTLBAlloc(sc); +} +/* + * dma_init.. + * Called from sonic to set up dma + */ +void +sn_dma_init(dma_softc_t *sc, int pages) +{ + sc->reset = picaDmaNull; + sc->enintr = picaDmaNull; + sc->start = picaDmaFlush; + sc->map = picaDmaMap; + sc->isintr = (int(*)())picaDmaNull; + sc->intr = (int(*)())picaDmaNull; + sc->end = (int(*)())picaDmaNull; + + sc->dma_reg = (pDmaReg)NULL; + sc->pte_size = pages; + sc->mode = 0; + picaDmaTLBAlloc(sc); +} diff --git a/sys/arch/arc/dev/dma.h b/sys/arch/arc/dev/dma.h new file mode 100644 index 00000000000..949154ca697 --- /dev/null +++ b/sys/arch/arc/dev/dma.h @@ -0,0 +1,151 @@ +/* $OpenBSD: dma.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * from: @(#)dma.h 8.1 (Berkeley) 6/10/93 + * $Id: dma.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ + */ + +/* + * The PICA system has four dma channels capable of scatter/gather + * and full memory addressing. The maximum transfer length is 1Mb. + * Dma snopes the L2 cache so no precaution is required. However + * if L1 cache is cached 'write back' the processor is responible + * for flushing/invalidating it. + * + * The dma mapper has up to 4096 page descriptors. + */ + +#define PICA_TL_BASE 0xa0008000 /* Base of tl register area */ +#define PICA_TL_SIZE 0x00008000 /* Size of tl register area */ + +/* + * Hardware dma registers. + */ +typedef volatile struct { + int dma_mode; + int pad1; + int dma_enab; + int pad2; + int dma_count; + int pad3; + vm_offset_t dma_addr; + int pad4; +} DmaReg, *pDmaReg; + +#define PICA_DMA_MODE_40NS 0x00 /* Device dma timing */ +#define PICA_DMA_MODE_80NS 0x01 /* Device dma timing */ +#define PICA_DMA_MODE_120NS 0x02 /* Device dma timing */ +#define PICA_DMA_MODE_160NS 0x03 /* Device dma timing */ +#define PICA_DMA_MODE_200NS 0x04 /* Device dma timing */ +#define PICA_DMA_MODE_240NS 0x05 /* Device dma timing */ +#define PICA_DMA_MODE_280NS 0x06 /* Device dma timing */ +#define PICA_DMA_MODE_320NS 0x07 /* Device dma timing */ +#define PICA_DMA_MODE_8 0x08 /* Device 8 bit */ +#define PICA_DMA_MODE_16 0x10 /* Device 16 bit */ +#define PICA_DMA_MODE_32 0x18 /* Device 32 bit */ +#define PICA_DMA_MODE_INT 0x20 /* Interrupt when done */ +#define PICA_DMA_MODE_BURST 0x40 /* Burst mode (Rev 2 only) */ +#define PICA_DMA_MODE_FAST 0x80 /* Fast dma cycle (Rev 2 only) */ +#define PICA_DMA_MODE 0xff /* Mode register bits */ +#define DMA_DIR_WRITE 0x100 /* Software direction status */ +#define DMA_DIR_READ 0x000 /* Software direction status */ + +#define PICA_DMA_ENAB_RUN 0x01 /* Enable dma */ +#define PICA_DMA_ENAB_READ 0x00 /* Read from device */ +#define PICA_DMA_ENAB_WRITE 0x02 /* Write to device */ +#define PICA_DMA_ENAB_TC_IE 0x100 /* Terminal count int enable */ +#define PICA_DMA_ENAB_ME_IE 0x200 /* Memory error int enable */ +#define PICA_DMA_ENAB_TL_IE 0x400 /* Translation limit int enable */ + +#define PICA_DMA_COUNT_MASK 0x00fffff /* Byte count mask */ +#define PICA_DMA_PAGE_NUM 0xffff000 /* Address page number */ +#define PICA_DMA_PAGE_OFFS 0x0000fff /* Address page offset */ +#define PICA_DMA_PAGE_SIZE 0x0001000 /* Address page size */ + + +/* + * Dma TLB entry + */ + +typedef union dma_pte { + struct { + vm_offset_t lo_addr; /* Low part of translation addr */ + vm_offset_t hi_addr; /* High part of translation addr */ + } entry; + struct bbb { + union dma_pte *next; /* Next free translation entry */ + int size; /* Number of consecutive free entrys */ + } queue; +} dma_pte_t; + +/* + * Structure used to control dma. + */ + +typedef struct dma_softc { + struct device sc_dev; /* use as a device */ + struct esp_softc *sc_esp; + vm_offset_t dma_va; /* Viritual address for transfer */ + int req_va; /* Original request va */ + vm_offset_t next_va; /* Value to program into dma regs */ + int next_size; /* Value to program into dma regs */ + int mode; /* Mode register value and direction */ + dma_pte_t *pte_base; /* Pointer to dma tlb array */ + int pte_size; /* Size of pte allocated pte array */ + pDmaReg dma_reg; /* Pointer to dma registers */ + int sc_active; /* Active flag */ + char **sc_dmaaddr; /* Pointer to dma address in dev */ + int *sc_dmalen; /* Pointer to len counter in dev */ + void (*reset)(struct dma_softc *); /* Reset routine pointer */ + void (*enintr)(struct dma_softc *); /* Int enab routine pointer */ + void (*map)(struct dma_softc *, char *, size_t, int); + /* Map a dma viritual area */ + void (*start)(struct dma_softc *, caddr_t, size_t, int); + /* Start routine pointer */ + int (*isintr)(struct dma_softc *); /* Int check routine pointer */ + int (*intr)(struct dma_softc *); /* Interrupt routine pointer */ + int (*end)(struct dma_softc *); /* Interrupt routine pointer */ +} dma_softc_t; + +#define DMA_TO_DEV 0 +#define DMA_FROM_DEV 1 + +#define dma_page_offs(x) ((int)(x) & PICA_DMA_PAGE_OFFS) +#define dma_page_round(x) (((int)(x) + PICA_DMA_PAGE_OFFS) & PICA_DMA_PAGE_NUM) + +#define DMA_RESET(r) ((r->reset)(r)) +#define DMA_START(a, b, c, d) ((a->start)(a, b, c, d)) +#define DMA_MAP(a, b, c, d) ((a->map)(a, b, c, d)) +#define DMA_INTR(r) ((r->intr)(r)) +#define DMA_DRAIN(r) +#define DMA_END(r) ((r->end)(r)) diff --git a/sys/arch/arc/dev/fd.c b/sys/arch/arc/dev/fd.c new file mode 100644 index 00000000000..aee3df4d52d --- /dev/null +++ b/sys/arch/arc/dev/fd.c @@ -0,0 +1,1139 @@ +/* $OpenBSD: fd.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* $NetBSD: fd.c,v 1.78 1995/07/04 07:23:09 mycroft Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995 Charles Hannum. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Don Ahn. + * + * 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. + * + * @(#)fd.c 7.4 (Berkeley) 5/25/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/dkstat.h> +#include <sys/disk.h> +#include <sys/buf.h> +#include <sys/uio.h> +#include <sys/syslog.h> +#include <sys/queue.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> + +#include <arc/dev/fdreg.h> +#include <arc/dev/dma.h> + + +#define FDUNIT(dev) (minor(dev) / 8) +#define FDTYPE(dev) (minor(dev) % 8) + +#define b_cylin b_resid + +enum fdc_state { + DEVIDLE = 0, + MOTORWAIT, + DOSEEK, + SEEKWAIT, + SEEKTIMEDOUT, + SEEKCOMPLETE, + DOIO, + IOCOMPLETE, + IOTIMEDOUT, + DORESET, + RESETCOMPLETE, + RESETTIMEDOUT, + DORECAL, + RECALWAIT, + RECALTIMEDOUT, + RECALCOMPLETE, +}; + +/* software state, per controller */ +struct fdc_softc { + struct device sc_dev; /* boilerplate */ + + struct dma_softc __dma; + struct dma_softc *dma; + + int sc_iobase; + + struct fd_softc *sc_fd[4]; /* pointers to children */ + TAILQ_HEAD(drivehead, fd_softc) sc_drives; + enum fdc_state sc_state; + int sc_errors; /* number of retries so far */ + u_char sc_status[7]; /* copy of registers */ +}; + +/* controller driver configuration */ +int fdcprobe __P((struct device *, void *, void *)); +void fdcattach __P((struct device *, struct device *, void *)); + +struct cfattach fdc_ca = { + sizeof(struct fdc_softc), fdcprobe, fdcattach +}; +struct cfdriver fdc_cd = { + NULL, "fdc", DV_DULL, NULL, 0 +}; + +/* + * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how + * we tell them apart. + */ +struct fd_type { + int sectrac; /* sectors per track */ + int heads; /* number of heads */ + int seccyl; /* sectors per cylinder */ + int secsize; /* size code for sectors */ + int datalen; /* data len when secsize = 0 */ + int steprate; /* step rate and head unload time */ + int gap1; /* gap len between sectors */ + int gap2; /* formatting gap */ + int tracks; /* total num of tracks */ + int size; /* size of disk in sectors */ + int step; /* steps per cylinder */ + int rate; /* transfer speed code */ + char *name; +}; + +/* The order of entries in the following table is important -- BEWARE! */ +struct fd_type fd_types[] = { + { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */ + { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */ + { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */ + { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */ + { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */ + { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */ + { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */ +}; + +/* software state, per disk (with up to 4 disks per ctlr) */ +struct fd_softc { + struct device sc_dev; + struct disk sc_dk; + + struct fd_type *sc_deftype; /* default type descriptor */ + struct fd_type *sc_type; /* current type descriptor */ + + daddr_t sc_blkno; /* starting block number */ + int sc_bcount; /* byte count left */ + int sc_skip; /* bytes already transferred */ + int sc_nblks; /* number of blocks currently tranferring */ + int sc_nbytes; /* number of bytes currently tranferring */ + + int sc_drive; /* physical unit number */ + int sc_flags; +#define FD_OPEN 0x01 /* it's open */ +#define FD_MOTOR 0x02 /* motor should be on */ +#define FD_MOTOR_WAIT 0x04 /* motor coming up */ + int sc_cylin; /* where we think the head is */ + + void *sc_sdhook; /* saved shutdown hook for drive. */ + + TAILQ_ENTRY(fd_softc) sc_drivechain; + int sc_ops; /* I/O ops since last switch */ + struct buf sc_q; /* head of buf chain */ +}; + +/* floppy driver configuration */ +int fdprobe __P((struct device *, void *, void *)); +void fdattach __P((struct device *, struct device *, void *)); + +struct cfattach fd_ca = { + sizeof(struct fd_softc), fdprobe, fdattach +}; +struct cfdriver fd_cd = { + NULL, "fd", DV_DISK, NULL, 0 +}; + +void fdgetdisklabel __P((struct fd_softc *)); +int fd_get_parms __P((struct fd_softc *)); +void fdstrategy __P((struct buf *)); +void fdstart __P((struct fd_softc *)); + +struct dkdriver fddkdriver = { fdstrategy }; + +struct fd_type *fd_nvtotype __P((char *, int, int)); +void fd_set_motor __P((struct fdc_softc *fdc, int reset)); +void fd_motor_off __P((void *arg)); +void fd_motor_on __P((void *arg)); +int fdcresult __P((struct fdc_softc *fdc)); +int out_fdc __P((int iobase, u_char x)); +void fdcstart __P((struct fdc_softc *fdc)); +void fdcstatus __P((struct device *dv, int n, char *s)); +void fdctimeout __P((void *arg)); +void fdcpseudointr __P((void *arg)); +int fdcintr __P((void *)); +void fdcretry __P((struct fdc_softc *fdc)); +void fdfinish __P((struct fd_softc *fd, struct buf *bp)); + +int +fdcprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + register struct confargs *ca = aux; + int iobase = (long)BUS_CVTADDR(ca); + + if (!BUS_MATCHNAME(ca, "fdc")) + return (0); + + /* reset */ + outb(iobase + fdout, 0); + delay(100); + outb(iobase + fdout, FDO_FRST); + + /* see if it can handle a command */ + if (out_fdc(iobase, NE7CMD_SPECIFY) < 0) + return 0; + out_fdc(iobase, 0xdf); + out_fdc(iobase, 2); + + return 1; +} + +/* + * Arguments passed between fdcattach and fdprobe. + */ +struct fdc_attach_args { + int fa_drive; + struct fd_type *fa_deftype; +}; + +/* + * Print the location of a disk drive (called just before attaching the + * the drive). If `fdc' is not NULL, the drive was found but was not + * in the system config file; print the drive name as well. + * Return QUIET (config_find ignores this if the device was configured) to + * avoid printing `fdN not configured' messages. + */ +int +fdprint(aux, fdc) + void *aux; + char *fdc; +{ + register struct fdc_attach_args *fa = aux; + + if (!fdc) + printf(" drive %d", fa->fa_drive); + return QUIET; +} + +void +fdcattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct fdc_softc *fdc = (void *)self; + struct confargs *ca = aux; + struct fdc_attach_args fa; + int type; + + fdc->sc_iobase = (long)BUS_CVTADDR(ca); + fdc->sc_state = DEVIDLE; + TAILQ_INIT(&fdc->sc_drives); + + fdc->dma = &fdc->__dma; + fdc_dma_init(fdc->dma); + + printf("\n"); + + BUS_INTR_ESTABLISH(ca, fdcintr, fdc); + + /* + * No way yet to determine default disk types. + * we assume 1.44 3.5" type for the moment. + */ + type = 0; + + /* physical limit: two drives per controller. */ + for (fa.fa_drive = 0; fa.fa_drive < 2; fa.fa_drive++) { + if (type >= 0 && fa.fa_drive < 2) + fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname, + type, fa.fa_drive); + else + fa.fa_deftype = NULL; /* unknown */ + (void)config_found(self, (void *)&fa, fdprint); + } +} + +int +fdprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct fdc_softc *fdc = (void *)parent; + struct cfdata *cf = match; + struct fdc_attach_args *fa = aux; + int drive = fa->fa_drive; + int iobase = fdc->sc_iobase; + int n; + + if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive) + return 0; + + /* select drive and turn on motor */ + outb(iobase + fdout, drive | FDO_FRST | FDO_MOEN(drive)); + /* wait for motor to spin up */ + delay(500000); + out_fdc(iobase, NE7CMD_RECAL); + out_fdc(iobase, drive); + /* wait for recalibrate */ + delay(2000000); + out_fdc(iobase, NE7CMD_SENSEI); + n = fdcresult(fdc); +#ifdef FD_DEBUG + { + int i; + printf("fdprobe: status"); + for (i = 0; i < n; i++) + printf(" %x", fdc->sc_status[i]); + printf("\n"); + } +#endif + if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) + return 0; + /* turn off motor */ + outb(iobase + fdout, FDO_FRST); + + return 1; +} + +/* + * Controller is working, and drive responded. Attach it. + */ +void +fdattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct fdc_softc *fdc = (void *)parent; + struct fd_softc *fd = (void *)self; + struct fdc_attach_args *fa = aux; + struct fd_type *type = fa->fa_deftype; + int drive = fa->fa_drive; + + /* XXX Allow `flags' to override device type? */ + + if (type) + printf(": %s %d cyl, %d head, %d sec\n", type->name, + type->tracks, type->heads, type->sectrac); + else + printf(": density unknown\n"); + + fd->sc_cylin = -1; + fd->sc_drive = drive; + fd->sc_deftype = type; + fdc->sc_fd[drive] = fd; + fd->sc_dk.dk_name = fd->sc_dev.dv_xname; + fd->sc_dk.dk_driver = &fddkdriver; + /* XXX Need to do some more fiddling with sc_dk. */ + dk_establish(&fd->sc_dk, &fd->sc_dev); + + /* Needed to power off if the motor is on when we halt. */ + fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); +} + +/* + * Translate nvram type into internal data structure. Return NULL for + * none/unknown/unusable. + */ +struct fd_type * +fd_nvtotype(fdc, nvraminfo, drive) + char *fdc; + int nvraminfo, drive; +{ + int type; + + type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; +#if 0 + switch (type) { + case NVRAM_DISKETTE_NONE: + return NULL; + case NVRAM_DISKETTE_12M: + return &fd_types[1]; + case NVRAM_DISKETTE_TYPE5: + case NVRAM_DISKETTE_TYPE6: + /* XXX We really ought to handle 2.88MB format. */ + case NVRAM_DISKETTE_144M: + return &fd_types[0]; + case NVRAM_DISKETTE_360K: + return &fd_types[3]; + case NVRAM_DISKETTE_720K: + return &fd_types[4]; + default: + printf("%s: drive %d: unknown device type 0x%x\n", + fdc, drive, type); + return NULL; + } +#else + return &fd_types[0]; /* Use only 1.44 for now */ +#endif +} + +inline struct fd_type * +fd_dev_to_type(fd, dev) + struct fd_softc *fd; + dev_t dev; +{ + int type = FDTYPE(dev); + + if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) + return NULL; + return type ? &fd_types[type - 1] : fd->sc_deftype; +} + +void +fdstrategy(bp) + register struct buf *bp; /* IO operation to perform */ +{ + struct fd_softc *fd; + int unit = FDUNIT(bp->b_dev); + int sz; + int s; + + /* Valid unit, controller, and request? */ + if (unit >= fd_cd.cd_ndevs || + (fd = fd_cd.cd_devs[unit]) == 0 || + bp->b_blkno < 0 || + (bp->b_bcount % FDC_BSIZE) != 0) { + bp->b_error = EINVAL; + goto bad; + } + + /* If it's a null transfer, return immediately. */ + if (bp->b_bcount == 0) + goto done; + + sz = howmany(bp->b_bcount, FDC_BSIZE); + + if (bp->b_blkno + sz > fd->sc_type->size) { + sz = fd->sc_type->size - bp->b_blkno; + if (sz == 0) { + /* If exactly at end of disk, return EOF. */ + bp->b_resid = bp->b_bcount; + goto done; + } + if (sz < 0) { + /* If past end of disk, return EINVAL. */ + bp->b_error = EINVAL; + goto bad; + } + /* Otherwise, truncate request. */ + bp->b_bcount = sz << DEV_BSHIFT; + } + + bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; + +#ifdef FD_DEBUG + printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n", + bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, sz); +#endif + + /* Queue transfer on drive, activate drive and controller if idle. */ + s = splbio(); + disksort(&fd->sc_q, bp); + untimeout(fd_motor_off, fd); /* a good idea */ + if (!fd->sc_q.b_active) + fdstart(fd); +#ifdef DIAGNOSTIC + else { + struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; + if (fdc->sc_state == DEVIDLE) { + printf("fdstrategy: controller inactive\n"); + fdcstart(fdc); + } + } +#endif + splx(s); + return; + +bad: + bp->b_flags |= B_ERROR; +done: + /* Toss transfer; we're done early. */ + biodone(bp); +} + +void +fdstart(fd) + struct fd_softc *fd; +{ + struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; + int active = fdc->sc_drives.tqh_first != 0; + + /* Link into controller queue. */ + fd->sc_q.b_active = 1; + TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); + + /* If controller not already active, start it. */ + if (!active) + fdcstart(fdc); +} + +void +fdfinish(fd, bp) + struct fd_softc *fd; + struct buf *bp; +{ + struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; + + /* + * Move this drive to the end of the queue to give others a `fair' + * chance. We only force a switch if N operations are completed while + * another drive is waiting to be serviced, since there is a long motor + * startup delay whenever we switch. + */ + if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { + fd->sc_ops = 0; + TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); + if (bp->b_actf) { + TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); + } else + fd->sc_q.b_active = 0; + } + bp->b_resid = fd->sc_bcount; + fd->sc_skip = 0; + fd->sc_q.b_actf = bp->b_actf; + biodone(bp); + /* turn off motor 5s from now */ + timeout(fd_motor_off, fd, 10 * hz); + fdc->sc_state = DEVIDLE; +} + +int +fdread(dev, uio) + dev_t dev; + struct uio *uio; +{ + + return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); +} + +int +fdwrite(dev, uio) + dev_t dev; + struct uio *uio; +{ + + return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); +} + +void +fd_set_motor(fdc, reset) + struct fdc_softc *fdc; + int reset; +{ + struct fd_softc *fd; + u_char status; + int n; + + if (fd = fdc->sc_drives.tqh_first) + status = fd->sc_drive; + else + status = 0; + if (!reset) + status |= FDO_FRST | FDO_FDMAEN; + for (n = 0; n < 4; n++) + if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) + status |= FDO_MOEN(n); + outb(fdc->sc_iobase + fdout, status); +} + +void +fd_motor_off(arg) + void *arg; +{ + struct fd_softc *fd = arg; + int s; + + s = splbio(); + fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); + fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); + splx(s); +} + +void +fd_motor_on(arg) + void *arg; +{ + struct fd_softc *fd = arg; + struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; + int s; + + s = splbio(); + fd->sc_flags &= ~FD_MOTOR_WAIT; + if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) + (void) fdcintr(fdc); + splx(s); +} + +int +fdcresult(fdc) + struct fdc_softc *fdc; +{ + int iobase = fdc->sc_iobase; + u_char i; + int j = 400000, /* Empirical, should do at 150 Mhz to */ + n = 0; + + for (; j; --j) { + i = inb(iobase + fdsts) & (NE7_DIO | NE7_RQM | NE7_CB); + if (i == NE7_RQM) { + return n; + } + if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { + if (n >= sizeof(fdc->sc_status)) { + log(LOG_ERR, "fdcresult: overrun\n"); + return -1; + } + fdc->sc_status[n++] = inb(iobase + fddata); + } + } + log(LOG_ERR, "fdcresult: timeout\n"); + return -1; +} + +int +out_fdc(iobase, x) + int iobase; + u_char x; +{ + int i = 100000; + + while ((inb(iobase + fdsts) & NE7_DIO) && i-- > 0); + if (i <= 0) + return -1; + while ((inb(iobase + fdsts) & NE7_RQM) == 0 && i-- > 0); + if (i <= 0) + return -1; + outb(iobase + fddata, x); + return 0; +} + +int +fdopen(dev, flags) + dev_t dev; + int flags; +{ + int unit; + struct fd_softc *fd; + struct fd_type *type; + + unit = FDUNIT(dev); + if (unit >= fd_cd.cd_ndevs) + return ENXIO; + fd = fd_cd.cd_devs[unit]; + if (fd == 0) + return ENXIO; + type = fd_dev_to_type(fd, dev); + if (type == NULL) + return ENXIO; + + if ((fd->sc_flags & FD_OPEN) != 0 && + fd->sc_type != type) + return EBUSY; + + fd->sc_type = type; + fd->sc_cylin = -1; + fd->sc_flags |= FD_OPEN; + + return 0; +} + +int +fdclose(dev, flags) + dev_t dev; + int flags; +{ + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; + + fd->sc_flags &= ~FD_OPEN; + return 0; +} + +void +fdcstart(fdc) + struct fdc_softc *fdc; +{ + +#ifdef DIAGNOSTIC + /* only got here if controller's drive queue was inactive; should + be in idle state */ + if (fdc->sc_state != DEVIDLE) { + printf("fdcstart: not idle\n"); + return; + } +#endif + (void) fdcintr(fdc); +} + +void +fdcstatus(dv, n, s) + struct device *dv; + int n; + char *s; +{ + struct fdc_softc *fdc = (void *)dv->dv_parent; + int iobase = fdc->sc_iobase; + + if (n == 0) { + out_fdc(fdc->sc_iobase, NE7CMD_SENSEI); + (void) fdcresult(fdc); + n = 2; + } + + printf("%s: %s", dv->dv_xname, s); + + switch (n) { + case 0: + printf("\n"); + break; + case 2: + printf(" (st0 %b cyl %d)\n", + fdc->sc_status[0], NE7_ST0BITS, + fdc->sc_status[1]); + break; + case 7: + printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", + fdc->sc_status[0], NE7_ST0BITS, + fdc->sc_status[1], NE7_ST1BITS, + fdc->sc_status[2], NE7_ST2BITS, + fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); + break; +#ifdef DIAGNOSTIC + default: + printf("\nfdcstatus: weird size"); + break; +#endif + } +} + +void +fdctimeout(arg) + void *arg; +{ + struct fdc_softc *fdc = arg; + struct fd_softc *fd = fdc->sc_drives.tqh_first; + int s; + + s = splbio(); + fdcstatus(&fd->sc_dev, 0, "timeout"); + + if (fd->sc_q.b_actf) + fdc->sc_state++; + else + fdc->sc_state = DEVIDLE; + + (void) fdcintr(fdc); + splx(s); +} + +void +fdcpseudointr(arg) + void *arg; +{ + int s; + + /* Just ensure it has the right spl. */ + s = splbio(); + (void) fdcintr(arg); + splx(s); +} + +int +fdcintr(arg) + void *arg; +{ + struct fdc_softc *fdc = arg; +#define st0 fdc->sc_status[0] +#define cyl fdc->sc_status[1] + struct fd_softc *fd; + struct buf *bp; + int iobase = fdc->sc_iobase; + int read, head, trac, sec, i, s, nblks; + struct fd_type *type; + +loop: + /* Is there a drive for the controller to do a transfer with? */ + fd = fdc->sc_drives.tqh_first; + if (fd == NULL) { + fdc->sc_state = DEVIDLE; + return 1; + } + + /* Is there a transfer to this drive? If not, deactivate drive. */ + bp = fd->sc_q.b_actf; + if (bp == NULL) { + fd->sc_ops = 0; + TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); + fd->sc_q.b_active = 0; + goto loop; + } + + switch (fdc->sc_state) { + case DEVIDLE: + fdc->sc_errors = 0; + fd->sc_skip = 0; + fd->sc_bcount = bp->b_bcount; + fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); + untimeout(fd_motor_off, fd); + if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { + fdc->sc_state = MOTORWAIT; + return 1; + } + if ((fd->sc_flags & FD_MOTOR) == 0) { + /* Turn on the motor, being careful about pairing. */ + struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; + if (ofd && ofd->sc_flags & FD_MOTOR) { + untimeout(fd_motor_off, ofd); + ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); + } + fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; + fd_set_motor(fdc, 0); + fdc->sc_state = MOTORWAIT; + /* Allow .5s for motor to stabilize. */ + timeout(fd_motor_on, fd, hz / 2); + return 1; + } + /* Make sure the right drive is selected. */ + fd_set_motor(fdc, 0); + + /* fall through */ + case DOSEEK: + doseek: + if (fd->sc_cylin == bp->b_cylin) + goto doio; + + out_fdc(iobase, NE7CMD_SPECIFY);/* specify command */ + out_fdc(iobase, fd->sc_type->steprate); + out_fdc(iobase, 6); /* XXX head load time == 6ms */ + + out_fdc(iobase, NE7CMD_SEEK); /* seek function */ + out_fdc(iobase, fd->sc_drive); /* drive number */ + out_fdc(iobase, bp->b_cylin * fd->sc_type->step); + + fd->sc_cylin = -1; + fdc->sc_state = SEEKWAIT; + timeout(fdctimeout, fdc, 4 * hz); + return 1; + + case DOIO: + doio: + type = fd->sc_type; + sec = fd->sc_blkno % type->seccyl; + nblks = type->seccyl - sec; + nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); + nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); + fd->sc_nblks = nblks; + fd->sc_nbytes = nblks * FDC_BSIZE; + head = sec / type->sectrac; + sec -= head * type->sectrac; +#ifdef DIAGNOSTIC + {int block; + block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; + if (block != fd->sc_blkno) { + printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno); +#ifdef DDB + Debugger(); +#endif + }} +#endif + MachFlushDCache(bp->b_data + fd->sc_skip, fd->sc_nbytes); + read = bp->b_flags & B_READ ? DMA_FROM_DEV : DMA_TO_DEV; + DMA_START(fdc->dma, bp->b_data + fd->sc_skip, fd->sc_nbytes, read); + outb(iobase + fdctl, type->rate); +#ifdef FD_DEBUG + printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", + read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head, + sec, nblks); +#endif + if (read) + out_fdc(iobase, NE7CMD_READ); /* READ */ + else + out_fdc(iobase, NE7CMD_WRITE); /* WRITE */ + out_fdc(iobase, (head << 2) | fd->sc_drive); + out_fdc(iobase, fd->sc_cylin); /* track */ + out_fdc(iobase, head); + out_fdc(iobase, sec + 1); /* sector +1 */ + out_fdc(iobase, type->secsize); /* sector size */ + out_fdc(iobase, type->sectrac); /* sectors/track */ + out_fdc(iobase, type->gap1); /* gap1 size */ + out_fdc(iobase, type->datalen); /* data length */ + fdc->sc_state = IOCOMPLETE; + /* allow 2 seconds for operation */ + timeout(fdctimeout, fdc, 2 * hz); + return 1; /* will return later */ + + case SEEKWAIT: + untimeout(fdctimeout, fdc); + fdc->sc_state = SEEKCOMPLETE; + /* allow 1/50 second for heads to settle */ + timeout(fdcpseudointr, fdc, hz / 50); + return 1; + + case SEEKCOMPLETE: + /* Make sure seek really happened. */ + out_fdc(iobase, NE7CMD_SENSEI); + if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || + cyl != bp->b_cylin * fd->sc_type->step) { +#ifdef FD_DEBUG + fdcstatus(&fd->sc_dev, 2, "seek failed"); +#endif + fdcretry(fdc); + goto loop; + } + fd->sc_cylin = bp->b_cylin; + goto doio; + + case IOTIMEDOUT: + DMA_RESET(fdc->dma); + + case SEEKTIMEDOUT: + case RECALTIMEDOUT: + case RESETTIMEDOUT: + fdcretry(fdc); + goto loop; + + case IOCOMPLETE: /* IO DONE, post-analyze */ + untimeout(fdctimeout, fdc); + if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { + DMA_RESET(fdc->dma); +#ifdef FD_DEBUG + fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? + "read failed" : "write failed"); + printf("blkno %d nblks %d\n", + fd->sc_blkno, fd->sc_nblks); +#endif + fdcretry(fdc); + goto loop; + } + DMA_END(fdc->dma); + read = bp->b_flags & B_READ; + if (fdc->sc_errors) { + diskerr(bp, "fd", "soft error", LOG_PRINTF, + fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); + printf("\n"); + fdc->sc_errors = 0; + } + fd->sc_blkno += fd->sc_nblks; + fd->sc_skip += fd->sc_nbytes; + fd->sc_bcount -= fd->sc_nbytes; + if (fd->sc_bcount > 0) { + bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl; + goto doseek; + } + fdfinish(fd, bp); + goto loop; + + case DORESET: + /* try a reset, keep motor on */ + fd_set_motor(fdc, 1); + delay(100); + fd_set_motor(fdc, 0); + fdc->sc_state = RESETCOMPLETE; + timeout(fdctimeout, fdc, hz / 2); + return 1; /* will return later */ + + case RESETCOMPLETE: + untimeout(fdctimeout, fdc); + /* clear the controller output buffer */ + for (i = 0; i < 4; i++) { + out_fdc(iobase, NE7CMD_SENSEI); + (void) fdcresult(fdc); + } + + /* fall through */ + case DORECAL: + out_fdc(iobase, NE7CMD_RECAL); /* recalibrate function */ + out_fdc(iobase, fd->sc_drive); + fdc->sc_state = RECALWAIT; + timeout(fdctimeout, fdc, 5 * hz); + return 1; /* will return later */ + + case RECALWAIT: + untimeout(fdctimeout, fdc); + fdc->sc_state = RECALCOMPLETE; + /* allow 1/30 second for heads to settle */ + timeout(fdcpseudointr, fdc, hz / 30); + return 1; /* will return later */ + + case RECALCOMPLETE: + out_fdc(iobase, NE7CMD_SENSEI); + if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { +#ifdef FD_DEBUG + fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); +#endif + fdcretry(fdc); + goto loop; + } + fd->sc_cylin = 0; + goto doseek; + + case MOTORWAIT: + if (fd->sc_flags & FD_MOTOR_WAIT) + return 1; /* time's not up yet */ + goto doseek; + + default: + fdcstatus(&fd->sc_dev, 0, "stray interrupt"); + return 1; + } +#ifdef DIAGNOSTIC + panic("fdcintr: impossible"); +#endif +#undef st0 +#undef cyl +} + +void +fdcretry(fdc) + struct fdc_softc *fdc; +{ + struct fd_softc *fd; + struct buf *bp; + + fd = fdc->sc_drives.tqh_first; + bp = fd->sc_q.b_actf; + + switch (fdc->sc_errors) { + case 0: + /* try again */ + fdc->sc_state = SEEKCOMPLETE; + break; + + case 1: case 2: case 3: + /* didn't work; try recalibrating */ + fdc->sc_state = DORECAL; + break; + + case 4: + /* still no go; reset the bastard */ + fdc->sc_state = DORESET; + break; + + default: + diskerr(bp, "fd", "hard error", LOG_PRINTF, + fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); + printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", + fdc->sc_status[0], NE7_ST0BITS, + fdc->sc_status[1], NE7_ST1BITS, + fdc->sc_status[2], NE7_ST2BITS, + fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); + + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + fdfinish(fd, bp); + } + fdc->sc_errors++; +} + +int +fdsize(dev) + dev_t dev; +{ + + /* Swapping to floppies would not make sense. */ + return -1; +} + +int +fddump(dev, blkno, va, size) + dev_t dev; + daddr_t blkno; + caddr_t va; + size_t size; +{ + + /* Not implemented. */ + return ENXIO; +} + +int +fdioctl(dev, cmd, addr, flag) + dev_t dev; + u_long cmd; + caddr_t addr; + int flag; +{ + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; + struct disklabel buffer; + int error; + + switch (cmd) { + case DIOCGDINFO: + bzero(&buffer, sizeof(buffer)); + + buffer.d_secpercyl = fd->sc_type->seccyl; + buffer.d_type = DTYPE_FLOPPY; + buffer.d_secsize = FDC_BSIZE; + + if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) + return EINVAL; + + *(struct disklabel *)addr = buffer; + return 0; + + case DIOCWLABEL: + if ((flag & FWRITE) == 0) + return EBADF; + /* XXX do something */ + return 0; + + case DIOCWDINFO: + if ((flag & FWRITE) == 0) + return EBADF; + + error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); + if (error) + return error; + + error = writedisklabel(dev, fdstrategy, &buffer, NULL); + return error; + + default: + return ENOTTY; + } + +#ifdef DIAGNOSTIC + panic("fdioctl: impossible"); +#endif +} diff --git a/sys/arch/arc/dev/fdreg.h b/sys/arch/arc/dev/fdreg.h new file mode 100644 index 00000000000..633ddf816de --- /dev/null +++ b/sys/arch/arc/dev/fdreg.h @@ -0,0 +1,67 @@ +/* $OpenBSD: fdreg.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* $NetBSD: fdreg.h,v 1.8 1995/06/28 04:30:57 cgd Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * 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. + * + * @(#)fdreg.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * AT floppy controller registers and bitfields + */ + +/* uses NEC765 controller */ +#include <dev/ic/nec765reg.h> + +/* registers */ +#define fdout 2 /* Digital Output Register (W) */ +#define FDO_FDSEL 0x03 /* floppy device select */ +#define FDO_FRST 0x04 /* floppy controller reset */ +#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */ +#define FDO_MOEN(n) ((1 << n) * 0x10) /* motor enable */ + +#define fdsts 4 /* NEC 765 Main Status Register (R) */ +#define fddata 5 /* NEC 765 Data Register (R/W) */ + +#define fdctl 7 /* Control Register (W) */ +#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */ +#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */ +#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */ +#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */ + +#define fdin 7 /* Digital Input Register (R) */ +#define FDI_DCHG 0x80 /* diskette has been changed */ + +#define FDC_BSIZE 512 +#define FDC_NPORT 8 +#define FDC_MAXIOSIZE NBPG /* XXX should be MAXBSIZE */ diff --git a/sys/arch/arc/dev/if_sn.c b/sys/arch/arc/dev/if_sn.c new file mode 100644 index 00000000000..dfe411a6551 --- /dev/null +++ b/sys/arch/arc/dev/if_sn.c @@ -0,0 +1,1300 @@ +/* $OpenBSD: if_sn.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* + * National Semiconductor SONIC Driver + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + * + * This driver has been substantially modified since Algorithmics donated + * it. + */ + +#include "sn.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/buf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <machine/autoconf.h> + +#include <net/if.h> +#include <net/netisr.h> +#include <net/route.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#endif + +#include <vm/vm.h> + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#include <arc/dev/dma.h> + +#define SONICDW 32 +typedef unsigned char uchar; + +#include <arc/dev/if_sn.h> +#define SWR(a, x) (a) = (x) +#define SRD(a) ((a) & 0xffff) + +#include <machine/cpu.h> + +/* + * Statistics collected over time + */ +struct sn_stats { + int ls_opacks; /* packets transmitted */ + int ls_ipacks; /* packets received */ + int ls_tdr; /* contents of tdr after collision */ + int ls_tdef; /* packets where had to wait */ + int ls_tone; /* packets with one retry */ + int ls_tmore; /* packets with more than one retry */ + int ls_tbuff; /* transmit buff errors */ + int ls_tuflo; /* " uflo " */ + int ls_tlcol; + int ls_tlcar; + int ls_trtry; + int ls_rbuff; /* receive buff errors */ + int ls_rfram; /* framing */ + int ls_roflo; /* overflow */ + int ls_rcrc; + int ls_rrng; /* rx ring sequence error */ + int ls_babl; /* chip babl error */ + int ls_cerr; /* collision error */ + int ls_miss; /* missed packet */ + int ls_merr; /* memory error */ + int ls_copies; /* copies due to out of range mbufs */ + int ls_maxmbufs; /* max mbufs on transmit */ + int ls_maxslots; /* max ring slots on transmit */ +}; + +struct sn_softc { + struct device sc_dev; + struct arpcom sc_ac; +#define sc_if sc_ac.ac_if /* network visible interface */ +#define sc_enaddr sc_ac.ac_enaddr /* hardware ethernet address */ + + struct sonic_reg *sc_csr; /* hardware pointer */ + dma_softc_t __dma; /* stupid macro ... */ + dma_softc_t *dma; /* dma mapper control */ + int sc_rxmark; /* position in rx ring for reading buffs */ + + int sc_rramark; /* index into rra of wp */ + + int sc_txhead; /* index of first TDA passed to chip */ + int sc_missed; /* missed packet counter */ + struct RXpkt *sc_lrxp; /* last RDA available to chip */ + struct sn_stats sc_sum; + short sc_iflags; +} sn_softc; + +int snmatch __P((struct device *, void *, void *)); +void snattach __P((struct device *, struct device *, void *)); + +struct cfattach sn_ca = { + sizeof(struct sn_softc), snmatch, snattach +}; +struct cfdriver sn_cd = { + NULL, "sn", DV_IFNET, NULL, 0 +}; + +#include <assert.h> +void +__assert(file, line, failedexpr) + const char *file, *failedexpr; + int line; +{ + (void)printf( + "assertion \"%s\" failed: file \"%s\", line %d\n", + failedexpr, file, line); +} + +void +m_check(m) + struct mbuf *m; +{ + if (m->m_flags & M_EXT) { + assert(m->m_len >= 0); + assert(m->m_len <= m->m_ext.ext_size); + assert(m->m_data >= &m->m_ext.ext_buf[0]); + assert(m->m_data <= &m->m_ext.ext_buf[m->m_ext.ext_size]); + assert(m->m_data + m->m_len <= &m->m_ext.ext_buf[m->m_ext.ext_size]); + } else if (m->m_flags & M_PKTHDR) { + assert(m->m_len >= 0); + assert(m->m_len <= MHLEN); + assert(m->m_data >= m->m_pktdat); + assert(m->m_data <= &m->m_pktdat[MHLEN]); + assert(m->m_data + m->m_len <= &m->m_pktdat[MHLEN]); + } else { + assert(m->m_len >= 0); + assert(m->m_len <= MLEN); + assert(m->m_data >= m->m_dat); + assert(m->m_data <= &m->m_dat[MLEN]); + assert(m->m_data + m->m_len <= &m->m_dat[MLEN]); + } +} + +void +m_checkm(m) + struct mbuf *m; +{ + while (m) { + m_check(m); + m = m->m_next; + } +} + +int ethdebug = 0; + +int snintr __P((struct sn_softc *)); +int snioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data)); +void snstart __P((struct ifnet *ifp)); +void snwatchdog __P((struct ifnet *ifp)); +void snreset __P((struct sn_softc *sc)); + +/* + * SONIC buffers need to be aligned 16 or 32 bit aligned. + * These macros calculate and verify alignment. + */ +#if SONICDW == 32 +#define SONICALIGN 4 +#else +#define SONICALIGN 2 +#endif +#define SOALIGN(array) (((int)array+SONICALIGN-1) & ~(SONICALIGN-1)) +#define SOALIGNED(p) (!(((uint)p)&(SONICALIGN-1))) + +#define UPPER(x) ((unsigned)(x) >> 16) +#define LOWER(x) ((unsigned)(x) & 0xffff) + +#define NRRA 32 /* # receive resource descriptors */ +#define RRAMASK 0x1f /* why it must be poer of two */ + +#define NRBA 16 /* # receive buffers < NRRA */ +#define NRDA NRBA /* # receive descriptors */ +#define NTDA 4 /* # transmit descriptors */ + +#define CDASIZE sizeof(struct CDA) +#define RRASIZE (NRRA*sizeof(struct RXrsrc)) +#define RDASIZE (NRDA*sizeof(struct RXpkt)) +#define TDASIZE (NTDA*sizeof(struct TXpkt)) + +#define FCSSIZE 4 /* size of FCS append te received packets */ + +/* + * maximum recieve packet size plus 2 byte pad to make each + * one aligned. 4 byte slop (required for eobc) + */ +#define RBASIZE (sizeof(struct ether_header) + ETHERMTU + FCSSIZE + 2 + 4) + +/* + * space requiered for descriptors + */ +#define DESC_SIZE (RRASIZE + CDASIZE + RDASIZE + TDASIZE + SONICALIGN - 1) + +/* + * This should really be 'allocated' but for now we + * 'hardwire' it. + */ +#define SONICBUF 0xa0010000 + +/* + * Nicely aligned pointers into the sonicbuffers + * p_ points at physical (K1_SEG) addresses. + * v_ is dma viritual address used by sonic. + */ +struct RXrsrc *p_rra; /* receiver resource descriptors */ +struct RXrsrc *v_rra; +struct RXpkt *p_rda; /* receiver desriptors */ +struct RXpkt *v_rda; +struct TXpkt *p_tda; /* transmitter descriptors */ +struct TXpkt *v_tda; +struct CDA *p_cda; /* CAM descriptors */ +struct CDA *v_cda; +char *p_rba; /* receive buffer area base */ +char *v_rba; + +/* Meta transmit descriptors */ +struct mtd { + struct mtd *mtd_link; + struct TXpkt *mtd_txp; + struct mbuf *mtd_mbuf; +} mtda[NTDA]; + +struct mtd *mtdfree; /* list of free meta transmit descriptors */ +struct mtd *mtdhead; /* head of descriptors assigned to chip */ +struct mtd *mtdtail; /* tail of descriptors assigned to chip */ +struct mtd *mtdnext; /* next descriptor to give to chip */ + +void mtd_free __P((struct mtd *)); +struct mtd *mtd_alloc __P((void)); + +int sngetaddr __P((struct sn_softc *sc)); +int sninit __P((struct sn_softc *sc)); +int snstop __P((struct sn_softc *sc)); +int sonicput __P((struct sn_softc *sc, struct mbuf *m0)); + +void camdump __P((struct sn_softc *sc)); + +int +snmatch(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct cfdata *cf = match; + struct confargs *ca = aux; + + /* XXX CHECK BUS */ + /* make sure that we're looking for this type of device. */ + if (!BUS_MATCHNAME(ca, "sonic")) + return (0); + + return (1); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +void +snattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct sn_softc *sc = (void *)self; + struct confargs *ca = aux; + struct ifnet *ifp = &sc->sc_if; + struct cfdata *cf = sc->sc_dev.dv_cfdata; + int p, pp; + + sc->sc_csr = (struct sonic_reg *)BUS_CVTADDR(ca); + + sc->dma = &sc->__dma; + sn_dma_init(sc->dma, FRAGMAX * NTDA + + (NRBA * RBASIZE / PICA_DMA_PAGE_SIZE) + 1 + + (DESC_SIZE * 2 / PICA_DMA_PAGE_SIZE) + 1); + +/* + * because the sonic is basicly 16bit device it 'concatenates' + * a higher buffer address to a 16 bit offset this will cause wrap + * around problems near the end of 64k !! + */ + p = SONICBUF; + pp = SONICBUF - (FRAGMAX * NTDA * PICA_DMA_PAGE_SIZE); + + if ((p ^ (p + TDASIZE)) & 0x10000) + p = (p + 0x10000) & ~0xffff; + p_tda = (struct TXpkt *) p; + v_tda = (struct TXpkt *)(p - pp + sc->dma->dma_va); + p += TDASIZE; + + if ((p ^ (p + RRASIZE + CDASIZE)) & 0x10000) + p = (p + 0x10000) & ~0xffff; + p_rra = (struct RXrsrc *) p; + v_rra = (struct RXrsrc *)(p - pp + sc->dma->dma_va); + p += RRASIZE; + + if ((p ^ (p + RDASIZE)) & 0x10000) + p = (p + 0x10000) & ~0xffff; + p_rda = (struct RXpkt *) p; + v_rda = (struct RXpkt *)(p - pp + sc->dma->dma_va); + p += RDASIZE; + + p_cda = (struct CDA *) p; + v_cda = (struct CDA *)(p - pp + sc->dma->dma_va); + p += CDASIZE; + + p += PICA_DMA_PAGE_SIZE - (p & (PICA_DMA_PAGE_SIZE -1)); + p_rba = (char *)p; + v_rba = (char *)(p - pp + sc->dma->dma_va); + p += NRBA * RBASIZE; + + DMA_MAP(sc->dma, (caddr_t)SONICBUF, p - SONICBUF, SONICBUF - pp); + +#if 0 + camdump(sc); +#endif + sngetaddr(sc); + printf(" address %s\n", ether_sprintf(sc->sc_enaddr)); + +#if 0 +printf("\nsonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n", + p_rra, p_cda, p_rda, p_tda, p_rba); +printf("sonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n", + v_rra, v_cda, v_rda, v_tda, v_rba); +printf("mapped to offset 0x%x size 0x%x\n", SONICBUF - pp, p - SONICBUF); +#endif + + BUS_INTR_ESTABLISH(ca, (intr_handler_t)snintr, (void *)sc); + + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_ioctl = snioctl; + ifp->if_start = snstart; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_watchdog = snwatchdog; +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + if_attach(ifp); + ether_ifattach(ifp); +} + +int +snioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct ifaddr *ifa; + struct sn_softc *sc = ifp->if_softc; + int s = splnet(), err = 0; + int temp; + int error; + + if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) { + splx(s); + return error; + } + + switch (cmd) { + + case SIOCSIFADDR: + ifa = (struct ifaddr *)data; + ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + (void)sninit(ifp->if_softc); + arp_ifinit(&sc->sc_ac, ifa); + break; +#endif + default: + (void)sninit(ifp->if_softc); + break; + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + ifp->if_flags & IFF_RUNNING) { + snstop(ifp->if_softc); + ifp->if_flags &= ~IFF_RUNNING; + } else if (ifp->if_flags & IFF_UP && + (ifp->if_flags & IFF_RUNNING) == 0) + (void)sninit(ifp->if_softc); + /* + * If the state of the promiscuous bit changes, the interface + * must be reset to effect the change. + */ + if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) && + (ifp->if_flags & IFF_RUNNING)) { + sc->sc_iflags = ifp->if_flags; + printf("change in flags\n"); + temp = sc->sc_if.if_flags & IFF_UP; + snreset(sc); + sc->sc_if.if_flags |= temp; + snstart(ifp); + } + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if(cmd == SIOCADDMULTI) + err = ether_addmulti((struct ifreq *)data, &sc->sc_ac); + else + err = ether_delmulti((struct ifreq *)data, &sc->sc_ac); + + if (err == ENETRESET) { + /* + * Multicast list has changed; set the hardware + * filter accordingly. But remember UP flag! + */ + temp = sc->sc_if.if_flags & IFF_UP; + snreset(sc); + sc->sc_if.if_flags |= temp; + err = 0; + } + break; + default: + err = EINVAL; + } + splx(s); + return (err); +} + +/* + * Encapsulate a packet of type family for the local net. + * Use trailer local net encapsulation if enough data in first + * packet leaves a multiple of 512 bytes of data in remainder. + */ +void +snstart(ifp) + struct ifnet *ifp; +{ + struct sn_softc *sc = ifp->if_softc; + struct mbuf *m; + int len; + + if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) + return; + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if (m == 0) + return; + + /* + * If there is nothing in the o/p queue, and there is room in + * the Tx ring, then send the packet directly. Otherwise append + * it to the o/p queue. + */ + if (!sonicput(sc, m)) { /* not enough space */ + IF_PREPEND(&sc->sc_if.if_snd, m); + } +#if NBPFILTER > 0 + /* + * If bpf is listening on this interface, let it + * see the packet before we commit it to the wire. + */ + if (sc->sc_if.if_bpf) + bpf_mtap(sc->sc_if.if_bpf, m); +#endif + + sc->sc_if.if_opackets++; /* # of pkts */ + sc->sc_sum.ls_opacks++; /* # of pkts */ +} + +/* + * This is called from sonicioctl() when /etc/ifconfig is run to set + * the address or switch the i/f on. + */ +void caminitialise __P((void)); +void camentry __P((int, u_char *ea)); +void camprogram __P((struct sn_softc *)); +void initialise_tda __P((struct sn_softc *)); +void initialise_rda __P((struct sn_softc *)); +void initialise_rra __P((struct sn_softc *)); + +/* + * reset and restart the SONIC. Called in case of fatal + * hardware/software errors. + */ +void +snreset(sc) + struct sn_softc *sc; +{ + snstop(sc); + sninit(sc); +} + +int +sninit(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + int s, error; + + if (sc->sc_if.if_flags & IFF_RUNNING) + /* already running */ + return (0); + + s = splnet(); + + csr->s_cr = CR_RST; /* s_dcr only accessable reset mode! */ + + /* config it */ + csr->s_dcr = DCR_LBR | DCR_SYNC | DCR_WAIT0 | DCR_DW32 | DCR_DMABLOCK | + DCR_RFT16 | DCR_TFT16; + csr->s_rcr = RCR_BRD | RCR_LBNONE; + csr->s_imr = IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_HBLEN | IMR_LCDEN; + + /* clear pending interrupts */ + csr->s_isr = 0x7fff; + + /* clear tally counters */ + csr->s_crct = -1; + csr->s_faet = -1; + csr->s_mpt = -1; + + initialise_tda(sc); + initialise_rda(sc); + initialise_rra(sc); + + /* enable the chip */ + csr->s_cr = 0; + wbflush(); + + /* program the CAM with our address */ + caminitialise(); + camentry(0, sc->sc_enaddr); + camprogram(sc); + + /* get it to read resource descriptors */ + csr->s_cr = CR_RRRA; + wbflush(); + while (csr->s_cr & CR_RRRA) + continue; + + /* enable rx */ + csr->s_cr = CR_RXEN; + wbflush(); + + /* flag interface as "running" */ + sc->sc_if.if_flags |= IFF_RUNNING; + + splx(s); + return (0); + +bad: + snstop(sc); + return (error); +} + +/* + * close down an interface and free its buffers + * Called on final close of device, or if sninit() fails + * part way through. + */ +int +snstop(sc) + struct sn_softc *sc; +{ + struct mtd *mtd; + int s = splnet(); + + /* stick chip in reset */ + sc->sc_csr->s_cr = CR_RST; + wbflush(); + + /* free all receive buffers (currently static so nothing to do) */ + + /* free all pending transmit mbufs */ + while (mtd = mtdhead) { + mtdhead = mtdhead->mtd_link; + if (mtd->mtd_mbuf) + m_freem(mtd->mtd_mbuf); + mtd->mtd_mbuf = 0; + mtd_free(mtd); + } + mtdnext = mtd_alloc(); + + sc->sc_if.if_timer = 0; + sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP); + + splx(s); + return (0); +} + +/* + * Called if any Tx packets remain unsent after 5 seconds, + * In all cases we just reset the chip, and any retransmission + * will be handled by higher level protocol timeouts. + */ +void +snwatchdog(ifp) + struct ifnet *ifp; +{ + struct sn_softc *sc = ifp->if_softc; + int temp; + + if (mtdhead && mtdhead->mtd_mbuf) { + /* something still pending for transmit */ + if (mtdhead->mtd_txp->status == 0) + log(LOG_ERR, "%s%d: Tx - timeout\n", + sc->sc_if.if_xname, sc->sc_if.if_softc); + else + log(LOG_ERR, "%s%d: Tx - lost interrupt\n", + sc->sc_if.if_xname, sc->sc_if.if_softc); + temp = sc->sc_if.if_flags & IFF_UP; + snreset(sc); + sc->sc_if.if_flags |= temp; + } +} +/* + * stuff packet into sonic (at splnet) +*/ +int +sonicput(sc, m0) + struct sn_softc *sc; + struct mbuf *m0; +{ + struct sonic_reg *csr = sc->sc_csr; + struct TXpkt *txp; + struct mtd *mtdnew; + struct mbuf *m; + int len = 0, fr = 0; + int i; + int fragoffset; /* Offset in viritual dma space for fragment */ + + /* grab the replacement mtd */ + if ((mtdnew = mtd_alloc()) == 0) + return (0); + + /* this packet goes to mdtnext fill in the TDA */ + mtdnext->mtd_mbuf = m0; + txp = mtdnext->mtd_txp; + SWR(txp->config, 0); + fragoffset = (txp - p_tda) * FRAGMAX * PICA_DMA_PAGE_SIZE; + + /* + * Now fill in the fragments. Each fragment maps to it's + * own dma page. Fragments crossing a dma page boundary + * are split up in two fragments. This is somewhat stupid + * because the dma mapper can do the work, but it helps + * keeping the fragments in order. (read lazy programmer). + */ + for (m = m0; m; m = m->m_next) { + unsigned va = (unsigned) mtod(m, caddr_t); + int resid = m->m_len; + + if(resid != 0) { + MachHitFlushDCache(va, resid); + DMA_MAP(sc->dma, (caddr_t)va, resid, fragoffset); + } + len += resid; + + while (resid) { + unsigned pa; + unsigned n; + + pa = sc->dma->dma_va + (va & PGOFSET) + fragoffset; + n = resid; + if (n > NBPG - (va & PGOFSET)) { + n = NBPG - (va & PGOFSET); + } + if (fr < FRAGMAX) { + SWR(txp->u[fr].frag_ptrlo, LOWER(pa)); + SWR(txp->u[fr].frag_ptrhi, UPPER(pa)); + SWR(txp->u[fr].frag_size, n); + } + fr++; + va += n; + resid -= n; + fragoffset += PICA_DMA_PAGE_SIZE; + } + } + /* + * pad out last fragment for minimum size + */ + if (len < ETHERMIN + sizeof(struct ether_header) && fr < FRAGMAX) { + int pad = ETHERMIN + sizeof(struct ether_header) - len; + static char zeros[64]; + unsigned pa; + + DMA_MAP(sc->dma, (caddr_t)zeros, pad, fragoffset); + pa = sc->dma->dma_va + ((unsigned)zeros & PGOFSET) + fragoffset; + SWR(txp->u[fr].frag_ptrlo, LOWER(pa)); + SWR(txp->u[fr].frag_ptrhi, UPPER(pa)); + SWR(txp->u[fr].frag_size, pad); + fr++; + len = ETHERMIN + sizeof(struct ether_header); + } + + DMA_START(sc->dma, (caddr_t)0, 0, 0); /* Flush dma tlb */ + + if (fr > FRAGMAX) { + mtd_free(mtdnew); + m_freem(m0); + log(LOG_ERR, "%s%d: tx too many fragments %d\n", + sc->sc_if.if_xname, sc->sc_if.if_softc, fr); + sc->sc_if.if_oerrors++; + return (len); + } + + SWR(txp->frag_count, fr); + SWR(txp->pkt_size, len); + + /* link onto the next mtd that will be used */ + SWR(txp->u[fr].tlink, LOWER(v_tda + (mtdnew->mtd_txp - p_tda)) | EOL); + + if (mtdhead == 0) { + /* no current transmit list start with this one */ + mtdtail = mtdhead = mtdnext; + csr->s_ctda = LOWER(v_tda + (txp - p_tda)); + } else { + /* + * have a transmit list append it to end note + * mtdnext is already physicaly linked to mtdtail in + * mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink + */ + SWR(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink, + SRD(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink) & ~EOL); + mtdtail = mtdnext; + } + mtdnext->mtd_link = mtdnew; + mtdnext = mtdnew; + + /* make sure chip is running */ + wbflush(); + csr->s_cr = CR_TXP; + wbflush(); + sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */ + return (len); +} + +/* + * Read out the ethernet address from the cam. It is stored + * there by the boot when doing a loopback test. Thus we don't + * have to fetch it from nv ram. + */ +int +sngetaddr(sc) + struct sn_softc *sc; +{ + unsigned i, x, y; + char *cp, *ea; + +#if 0 + sc->sc_csr->s_cr = CR_RST; + wbflush(); + sc->sc_csr->s_cep = 0; + i = sc->sc_csr->s_cap2; + wbflush(); + sc->sc_enaddr[5] = i >> 8; + sc->sc_enaddr[4] = i; + i = sc->sc_csr->s_cap1; + wbflush(); + sc->sc_enaddr[3] = i >> 8; + sc->sc_enaddr[2] = i; + i = sc->sc_csr->s_cap0; + wbflush(); + sc->sc_enaddr[1] = i >> 8; + sc->sc_enaddr[0] = i; + + sc->sc_csr->s_cr = 0; + wbflush(); +#else + sc->sc_enaddr[0] = 0x08; + sc->sc_enaddr[1] = 0x00; + sc->sc_enaddr[2] = 0x20; + sc->sc_enaddr[3] = 0xa0; + sc->sc_enaddr[4] = 0x66; + sc->sc_enaddr[5] = 0x54; +#endif + return (0); +} + +void sonictxint __P((struct sn_softc *)); +void sonicrxint __P((struct sn_softc *)); + +int sonic_read __P((struct sn_softc *, struct RXpkt *)); +struct mbuf *sonic_get __P((struct sn_softc *, struct ether_header *, int)); + +void +mtd_free(mtd) + struct mtd *mtd; +{ + mtd->mtd_link = mtdfree; + mtdfree = mtd; +} + +struct mtd * +mtd_alloc() +{ + struct mtd *mtd = mtdfree; + + if (mtd) { + mtdfree = mtd->mtd_link; + mtd->mtd_link = 0; + } + return (mtd); +} + +/* + * CAM support + */ +void +caminitialise() +{ + int i; + + for (i = 0; i < MAXCAM; i++) + SWR(p_cda->desc[i].cam_ep, i); + SWR(p_cda->enable, 0); +} + +void +camentry(entry, ea) + int entry; + u_char *ea; +{ + SWR(p_cda->desc[entry].cam_ep, entry); + SWR(p_cda->desc[entry].cam_ap2, (ea[5] << 8) | ea[4]); + SWR(p_cda->desc[entry].cam_ap1, (ea[3] << 8) | ea[2]); + SWR(p_cda->desc[entry].cam_ap0, (ea[1] << 8) | ea[0]); + SWR(p_cda->enable, SRD(p_cda->enable) | (1 << entry)); +} + +void +camprogram(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + int timeout; + int i; + + csr = sc->sc_csr; + csr->s_cdp = LOWER(v_cda); + csr->s_cdc = MAXCAM; + csr->s_cr = CR_LCAM; + wbflush(); + + timeout = 10000; + while (csr->s_cr & CR_LCAM && timeout--) + continue; + if (timeout == 0) { + /* XXX */ + panic("sonic: CAM initialisation failed\n"); + } + timeout = 10000; + while ((csr->s_isr & ISR_LCD) == 0 && timeout--) + continue; + + if (csr->s_isr & ISR_LCD) + csr->s_isr = ISR_LCD; + else + printf("sonic: CAM initialisation without interrupt\n"); +} + +#if 0 +void +camdump(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + int i; + + printf("CAM entries:\n"); + csr->s_cr = CR_RST; + wbflush(); + + for (i = 0; i < 16; i++) { + ushort ap2, ap1, ap0; + csr->s_cep = i; + wbflush(); + ap2 = csr->s_cap2; + ap1 = csr->s_cap1; + ap0 = csr->s_cap0; + printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0); + } + printf("CAM enable 0x%x\n", csr->s_cep); + + csr->s_cr = 0; + wbflush(); +} +#endif + +void +initialise_tda(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + struct mtd *mtd; + int i; + + csr = sc->sc_csr; + + mtdfree = mtdhead = mtdtail = (struct mtd *) 0; + + for (i = 0; i < NTDA; i++) { + mtd = &mtda[i]; + mtd->mtd_txp = &p_tda[i]; + mtd->mtd_mbuf = (struct mbuf *) 0; + mtd_free(mtd); + } + mtdnext = mtd_alloc(); + + csr->s_utda = UPPER(v_tda); +} + +void +initialise_rda(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + int i; + + csr = sc->sc_csr; + + /* link the RDA's together into a circular list */ + for (i = 0; i < (NRDA - 1); i++) { + SWR(p_rda[i].rlink, LOWER(&v_rda[i + 1])); + SWR(p_rda[i].in_use, 1); + } + SWR(p_rda[NRDA - 1].rlink, LOWER(&v_rda[0]) | EOL); + SWR(p_rda[NRDA - 1].in_use, 1); + + /* mark end of receive descriptor list */ + sc->sc_lrxp = &p_rda[NRDA - 1]; + + sc->sc_rxmark = 0; + + csr->s_urda = UPPER(&v_rda[0]); + csr->s_crda = LOWER(&v_rda[0]); + wbflush(); +} + +void +initialise_rra(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + int i; + + csr = sc->sc_csr; + + csr->s_eobc = RBASIZE / 2 - 2; /* must be >= MAXETHERPKT */ + csr->s_urra = UPPER(v_rra); + csr->s_rsa = LOWER(v_rra); + csr->s_rea = LOWER(&v_rra[NRRA]); + csr->s_rrp = LOWER(v_rra); + csr->s_rsc = 0; + + /* fill up SOME of the rra with buffers */ + for (i = 0; i < NRBA; i++) { + SWR(p_rra[i].buff_ptrhi, UPPER(&v_rba[i * RBASIZE])); + SWR(p_rra[i].buff_ptrlo, LOWER(&v_rba[i * RBASIZE])); + SWR(p_rra[i].buff_wchi, UPPER(RBASIZE / 2)); + SWR(p_rra[i].buff_wclo, LOWER(RBASIZE / 2)); + } + sc->sc_rramark = NRBA; + csr->s_rwp = LOWER(&v_rra[sc->sc_rramark]); + wbflush(); +} + +int +snintr(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + int isr; + + while (isr = (csr->s_isr & ISR_ALL)) { + /* scrub the interrupts that we are going to service */ + csr->s_isr = isr; + wbflush(); + + if (isr & (ISR_BR | ISR_LCD | ISR_PINT | ISR_TC)) + printf("sonic: unexpected interrupt status 0x%x\n", isr); + + if (isr & (ISR_TXDN | ISR_TXER)) + sonictxint(sc); + + if (isr & ISR_PKTRX) + sonicrxint(sc); + + if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) { + if (isr & ISR_HBL) + printf("sonic: no heartbeat\n"); + if (isr & ISR_RDE) + printf("sonic: receive descriptors exhausted\n"); + if (isr & ISR_RBE) + printf("sonic: receive buffers exhausted\n"); + if (isr & ISR_RBAE) + printf("sonic: receive buffer area exhausted\n"); + if (isr & ISR_RFO) + printf("sonic: receive FIFO overrun\n"); + } + if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) { +#ifdef notdef + if (isr & ISR_CRC) + sc->sc_crctally++; + if (isr & ISR_FAE) + sc->sc_faetally++; + if (isr & ISR_MP) + sc->sc_mptally++; +#endif + } + } + return (1); +} + +/* + * Transmit interrupt routine + */ +void +sonictxint(sc) + struct sn_softc *sc; +{ + struct TXpkt *txp; + struct sonic_reg *csr; + struct mtd *mtd; + + if (mtdhead == (struct mtd *) 0) + return; + + csr = sc->sc_csr; + + while (mtd = mtdhead) { + struct mbuf *m = mtd->mtd_mbuf; + + if (m == 0) + break; + + txp = mtd->mtd_txp; + + if (SRD(txp->status) == 0) /* it hasn't really gone yet */ + return; + + if (ethdebug) { + struct ether_header *eh = mtod(m, struct ether_header *); + printf("xmit status=0x%x len=%d type=0x%x from %s", + txp->status, + txp->pkt_size, + htons(eh->ether_type), + ether_sprintf(eh->ether_shost)); + printf(" (to %s)\n", ether_sprintf(eh->ether_dhost)); + } + m_freem(m); + mtd->mtd_mbuf = 0; + mtdhead = mtd->mtd_link; + + mtd_free(mtd); + + if ((SRD(txp->status) & TCR_PTX) == 0) { + printf("sonic: Tx packet status=0x%x\n", txp->status); + + if (mtdhead != mtdnext) { + printf("resubmitting remaining packets\n"); + csr->s_ctda = LOWER(mtdhead->mtd_txp); + csr->s_cr = CR_TXP; + wbflush(); + return; + } + } + } + /* mtdhead should be at mtdnext (go) */ + assert(mtdhead == mtdnext); + assert(mtdhead->mtd_link == 0); + mtdhead = 0; + + /* and start feeding any queued packets to chip */ + while (1) { + struct mbuf *m; + + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if (m == 0) /* nothing left to send */ + break; + if (!sonicput(sc, m)) { /* not enough space */ + IF_PREPEND(&sc->sc_if.if_snd, m); + break; + } + } +} + +/* + * Receive interrupt routine + */ +void +sonicrxint(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + struct RXpkt *rxp; + u_long addr; + int orra; + + rxp = &p_rda[sc->sc_rxmark]; + + while (SRD(rxp->in_use) == 0) { + unsigned status = SRD(rxp->status); + if ((status & RCR_LPKT) == 0) + printf("sonic: more than one packet in RBA!\n"); + assert(PSNSEQ(SRD(rxp->seq_no)) == 0); + + if (status & RCR_PRX) { + if (sonic_read(sc, rxp)) { + sc->sc_if.if_ipackets++; + sc->sc_sum.ls_ipacks++; + sc->sc_missed = 0; + } + } else + sc->sc_if.if_ierrors++; + + /* + * give receive buffer area back to chip XXX what buffer + * did the sonic use for this descriptor answer look at + * the rba sequence number !! + */ + orra = RBASEQ(SRD(rxp->seq_no)) & RRAMASK; + + assert(SRD(rxp->pkt_ptrhi) == SRD(p_rra[orra].buff_ptrhi)); + assert(SRD(rxp->pkt_ptrlo) == SRD(p_rra[orra].buff_ptrlo)); +if(SRD(rxp->pkt_ptrlo) != SRD(p_rra[orra].buff_ptrlo)) +printf("%x,%x\n",SRD(rxp->pkt_ptrlo),SRD(p_rra[orra].buff_ptrlo)); + assert(SRD(p_rra[orra].buff_wclo)); + + /* + * orra is now empty of packets and can be freed if + * sonic read didnt copy it out then we would have to + * wait !! + * (dont bother add it back in again straight away) + */ + p_rra[sc->sc_rramark] = p_rra[orra]; + + /* zap old rra for fun */ + p_rra[orra].buff_wchi = 0; + p_rra[orra].buff_wclo = 0; + + sc->sc_rramark = (sc->sc_rramark + 1) & RRAMASK; + csr->s_rwp = LOWER(&v_rra[sc->sc_rramark]); + wbflush(); + + /* + * give recieve descriptor back to chip simple + * list is circular + */ + SWR(rxp->in_use, 1); + SWR(rxp->rlink, SRD(rxp->rlink) | EOL); + SWR(sc->sc_lrxp->rlink, SRD(sc->sc_lrxp->rlink) & ~EOL); + sc->sc_lrxp = rxp; + + if (++sc->sc_rxmark >= NRDA) + sc->sc_rxmark = 0; + rxp = &p_rda[sc->sc_rxmark]; + } +} + +/* + * sonic_read -- pull packet off interface and forward to + * appropriate protocol handler + */ +int +sonic_read(sc, rxp) + struct sn_softc *sc; + struct RXpkt *rxp; +{ + struct ifnet *ifp = &sc->sc_if; + /*extern char *ether_sprintf();*/ + struct ether_header *et; + struct mbuf *m; + int len, off, i; + caddr_t pkt; + + /* + * Get input data length. + * Get pointer to ethernet header (in input buffer). + * Deal with trailer protocol: if type is PUP trailer + * get true type from first 16-bit word past data. + * Remember that type was trailer by setting off. + */ + + len = SRD(rxp->byte_count) - sizeof(struct ether_header) - FCSSIZE; + pkt = (caddr_t)((SRD(rxp->pkt_ptrhi) << 16) | SRD(rxp->pkt_ptrlo)); + pkt = pkt - v_rba + p_rba; + et = (struct ether_header *)pkt; + + if (ethdebug) { + printf("rcvd 0x%x status=0x%x, len=%d type=0x%x from %s", + et, rxp->status, len, htons(et->ether_type), + ether_sprintf(et->ether_shost)); + printf(" (to %s)\n", ether_sprintf(et->ether_dhost)); + } + if (len < ETHERMIN || len > ETHERMTU) { + printf("sonic: invalid packet length %d bytes\n", len); + return (0); + } + +#if NBPFILTER > 0 + /* + * Check if there's a bpf filter listening on this interface. + * If so, hand off the raw packet to enet, then discard things + * not destined for us (but be sure to keep broadcast/multicast). + */ + if (sc->sc_if.if_bpf) { + bpf_tap(sc->sc_if.if_bpf, pkt, + len + sizeof(struct ether_header)); + if ((ifp->if_flags & IFF_PROMISC) != 0 && + (et->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ + bcmp(et->ether_dhost, sc->sc_enaddr, + sizeof(et->ether_dhost)) != 0) + return; + } +#endif + m = sonic_get(sc, et, len); + if (m == NULL) + return (0); + ether_input(ifp, et, m); + return(1); +} + +#define sonicdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) + +/* + * munge the recieved packet into an mbuf chain + * because we are using stupif buffer management this + * is slow. +*/ +struct mbuf * +sonic_get(sc, eh, datalen) + struct sn_softc *sc; + struct ether_header *eh; + int datalen; +{ + struct mbuf *m; + struct mbuf *top = 0, **mp = ⊤ + int len; + char *spkt = sonicdataaddr(eh, 0, caddr_t); + char *epkt = spkt + datalen; + char *cp = spkt; + + epkt = cp + datalen; + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = &sc->sc_if; + m->m_pkthdr.len = datalen; + m->m_len = MHLEN; + + while (datalen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + m->m_len = MLEN; + } + len = min(datalen, epkt - cp); + if (len >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = len = min(len, MCLBYTES); + else + len = m->m_len; + } else { + /* + * Place initial small packet/header at end of mbuf. + */ + if (len < m->m_len) { + if (top == 0 && len + max_linkhdr <= m->m_len) + m->m_data += max_linkhdr; + m->m_len = len; + } else + len = m->m_len; + } + bcopy(cp, mtod(m, caddr_t), (unsigned) len); + cp += len; + *mp = m; + mp = &m->m_next; + datalen -= len; + if (cp == epkt) + cp = spkt; + } + return (top); +} diff --git a/sys/arch/arc/dev/if_sn.h b/sys/arch/arc/dev/if_sn.h new file mode 100644 index 00000000000..c2018fb43e5 --- /dev/null +++ b/sys/arch/arc/dev/if_sn.h @@ -0,0 +1,347 @@ +/* $OpenBSD: if_sn.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + */ + +/* + * if_sonic.h -- National Semiconductor DP83932BVF (SONIC) + */ + +/* + * Accessing SONIC data structures and registers as 32 bit values + * makes code endianess independent. The SONIC is however always in + * bigendian mode so it is necessary to ensure that data structures shared + * between the CPU and the SONIC are always in bigendian order. + */ + +/* + * Receive Resource Descriptor + * This structure describes the buffers into which packets + * will be received. Note that more than one packet may be + * packed into a single buffer if constraints permit. + */ +#if SONICDW == 32 +struct RXrsrc { + u_long buff_ptrlo; /* buffer address LO */ + u_long buff_ptrhi; /* buffer address HI */ + u_long buff_wclo; /* buffer size (16bit words) LO */ + u_long buff_wchi; /* buffer size (16bit words) HI */ +}; +#endif + +/* + * Receive Descriptor + * This structure holds information about packets received. + */ +#if SONICDW == 32 +struct RXpkt { + u_long status; /* + receive status */ + u_long byte_count; /* + packet byte count (including FCS) */ + u_long pkt_ptrlo; /* + packet data LO (in RBA) */ + u_long pkt_ptrhi; /* + packet data HI (in RBA) */ + u_long seq_no; /* + RBA sequence numbers */ + u_long rlink; /* link to next receive descriptor */ + u_long in_use; /* + packet available to SONIC */ + u_long pad; /* pad to multiple of 16 bytes */ +}; +#endif +#define RBASEQ(x) (((x)>>8)&0xff) +#define PSNSEQ(x) ((x) & 0xff) + +/* + * Transmit Descriptor + * This structure holds information about packets to be transmitted. + */ +#define FRAGMAX 31 /* maximum number of fragments in a packet */ +#if SONICDW == 32 +struct TXpkt { + u_long status; /* + transmitted packet status */ + u_long config; /* transmission configuration */ + u_long pkt_size; /* entire packet size in bytes */ + u_long frag_count; /* # fragments in packet */ + union { + struct { + u_long _frag_ptrlo; /* pointer to packet fragment LO */ + u_long _frag_ptrhi; /* pointer to packet fragment HI */ + u_long _frag_size; /* fragment size */ + } u_frag; + struct { + u_long _tlink; /* link to next transmit descriptor */ + } u_link; + } u[FRAGMAX+1]; /* +1 makes tcp->u[FRAGMAX].u_link.link valid! */ +}; +#endif + +#define frag_ptrlo u_frag._frag_ptrlo +#define frag_ptrhi u_frag._frag_ptrhi +#define frag_size u_frag._frag_size +#define tlink u_link._tlink + +#define EOL 0x0001 /* end of list marker for link fields */ + +#define MAXCAM 16 /* number of user entries in CAM */ +#if SONICDW == 32 +struct CDA { + struct { + u_long cam_ep; /* CAM Entry Pointer */ + u_long cam_ap0; /* CAM Address Port 0 xx-xx-xx-xx-YY-YY */ + u_long cam_ap1; /* CAM Address Port 1 xx-xx-YY-YY-xxxx */ + u_long cam_ap2; /* CAM Address Port 2 YY-YY-xx-xx-xx-xx */ + } desc[MAXCAM]; + u_long enable; /* mask enabling CAM entries */ +}; +#endif + +/* + * SONIC registers as seen by the processor + */ +struct sonic_reg { + volatile u_long s_cr; /* 00: Command */ + volatile u_long s_dcr; /* 01: Data Configuration */ + volatile u_long s_rcr; /* 02: Receive Control */ + volatile u_long s_tcr; /* 03: Transmit Control */ + volatile u_long s_imr; /* 04: Interrupt Mask */ + volatile u_long s_isr; /* 05: Interrupt Status */ + volatile u_long s_utda; /* 06: Upper Transmit Descriptor Address */ + volatile u_long s_ctda; /* 07: Current Transmit Descriptor Address */ + volatile u_long _s_tps; /* 08* Transmit Packet Size */ + volatile u_long _s_tfc; /* 09* Transmit Fragment Count */ + volatile u_long _s_tsa0; /* 0a* Transmit Start Address 0 */ + volatile u_long _s_tsa1; /* 0b* Transmit Start Address 1 */ + volatile u_long _s_tfs; /* 0c* Transmit Fragment Size */ + volatile u_long s_urda; /* 0d: Upper Receive Descriptor Address */ + volatile u_long s_crda; /* 0e: Current Receive Descriptor Address */ + volatile u_long _s_crba0; /* 0f* Current Receive Buffer Address 0 */ + volatile u_long _s_crba1; /* 10* Current Receive Buffer Address 1 */ + volatile u_long _s_rbwc0; /* 11* Remaining Buffer Word Count 0 */ + volatile u_long _s_rbwc1; /* 12* Remaining Buffer Word Count 1 */ + volatile u_long s_eobc; /* 13: End Of Buffer Word Count */ + volatile u_long s_urra; /* 14: Upper Receive Resource Address */ + volatile u_long s_rsa; /* 15: Resource Start Address */ + volatile u_long s_rea; /* 16: Resource End Address */ + volatile u_long s_rrp; /* 17: Resource Read Pointer */ + volatile u_long s_rwp; /* 18: Resource Write Pointer */ + volatile u_long _s_trba0; /* 19* Temporary Receive Buffer Address 0 */ + volatile u_long _s_trba1; /* 1a* Temporary Receive Buffer Address 1 */ + volatile u_long _s_tbwc0; /* 1b* Temporary Buffer Word Count 0 */ + volatile u_long _s_tbwc1; /* 1c* Temporary Buffer Word Count 1 */ + volatile u_long _s_addr0; /* 1d* Address Generator 0 */ + volatile u_long _s_addr1; /* 1e* Address Generator 1 */ + volatile u_long _s_llfa; /* 1f* Last Link Field Address */ + volatile u_long _s_ttda; /* 20* Temp Transmit Descriptor Address */ + volatile u_long s_cep; /* 21: CAM Entry Pointer */ + volatile u_long s_cap2; /* 22: CAM Address Port 2 */ + volatile u_long s_cap1; /* 23: CAM Address Port 1 */ + volatile u_long s_cap0; /* 24: CAM Address Port 0 */ + volatile u_long s_ce; /* 25: CAM Enable */ + volatile u_long s_cdp; /* 26: CAM Descriptor Pointer */ + volatile u_long s_cdc; /* 27: CAM Descriptor Count */ + volatile u_long s_sr; /* 28: Silicon Revision */ + volatile u_long s_wt0; /* 29: Watchdog Timer 0 */ + volatile u_long s_wt1; /* 2a: Watchdog Timer 1 */ + volatile u_long s_rsc; /* 2b: Receive Sequence Counter */ + volatile u_long s_crct; /* 2c: CRC Error Tally */ + volatile u_long s_faet; /* 2d: FAE Tally */ + volatile u_long s_mpt; /* 2e: Missed Packet Tally */ + volatile u_long _s_mdt; /* 2f* Maximum Deferral Timer */ + volatile u_long _s_rtc; /* 30* Receive Test Control */ + volatile u_long _s_ttc; /* 31* Transmit Test Control */ + volatile u_long _s_dtc; /* 32* DMA Test Control */ + volatile u_long _s_cc0; /* 33* CAM Comparison 0 */ + volatile u_long _s_cc1; /* 34* CAM Comparison 1 */ + volatile u_long _s_cc2; /* 35* CAM Comparison 2 */ + volatile u_long _s_cm; /* 36* CAM Match */ + volatile u_long :32; /* 37* reserved */ + volatile u_long :32; /* 38* reserved */ + volatile u_long _s_rbc; /* 39* Receiver Byte Count */ + volatile u_long :32; /* 3a* reserved */ + volatile u_long _s_tbo; /* 3b* Transmitter Backoff Counter */ + volatile u_long _s_trc; /* 3c* Transmitter Random Counter */ + volatile u_long _s_tbm; /* 3d* Transmitter Backoff Mask */ + volatile u_long :32; /* 3e* Reserved */ + volatile u_long s_dcr2; /* 3f Data Configuration 2 (AVF) */ +}; + +/* + * Register Interpretations + */ + +/* + * The command register is used for issuing commands to the SONIC. + * With the exception of CR_RST, the bit is reset when the operation + * completes. + */ +#define CR_LCAM 0x0200 /* load CAM with descriptor at s_cdp */ +#define CR_RRRA 0x0100 /* read next RRA descriptor at s_rrp */ +#define CR_RST 0x0080 /* software reset */ +#define CR_ST 0x0020 /* start timer */ +#define CR_STP 0x0010 /* stop timer */ +#define CR_RXEN 0x0008 /* receiver enable */ +#define CR_RXDIS 0x0004 /* receiver disable */ +#define CR_TXP 0x0002 /* transmit packets */ +#define CR_HTX 0x0001 /* halt transmission */ + +/* + * The data configuration register establishes the SONIC's bus cycle + * operation. This register can only be accessed when the SONIC is in + * reset mode (s_cr.CR_RST is set.) + */ +#define DCR_EXBUS 0x8000 /* extended bus mode (AVF) */ +#define DCR_LBR 0x2000 /* latched bus retry */ +#define DCR_PO1 0x1000 /* programmable output 1 */ +#define DCR_PO0 0x0800 /* programmable output 0 */ +#define DCR_STERM 0x0400 /* synchronous termination */ +#define DCR_USR1 0x0200 /* reflects USR1 input pin */ +#define DCR_USR0 0x0100 /* reflects USR0 input pin */ +#define DCR_WC1 0x0080 /* wait state control 1 */ +#define DCR_WC0 0x0040 /* wait state control 0 */ +#define DCR_DW 0x0020 /* data width select */ +#define DCR_BMS 0x0010 /* DMA block mode select */ +#define DCR_RFT1 0x0008 /* receive FIFO threshold control 1 */ +#define DCR_RFT0 0x0004 /* receive FIFO threshold control 0 */ +#define DCR_TFT1 0x0002 /* transmit FIFO threshold control 1 */ +#define DCR_TFT0 0x0001 /* transmit FIFO threshold control 0 */ + +/* data configuration register aliases */ +#define DCR_SYNC DCR_STERM /* synchronous (memory cycle 2 clocks) */ +#define DCR_ASYNC 0 /* asynchronous (memory cycle 3 clocks) */ + +#define DCR_WAIT0 0 /* 0 wait states added */ +#define DCR_WAIT1 DCR_WC0 /* 1 wait state added */ +#define DCR_WAIT2 DCR_WC1 /* 2 wait states added */ +#define DCR_WAIT3 (DCR_WC1|DCR_WC0) /* 3 wait states added */ + +#define DCR_DW16 0 /* use 16-bit DMA accesses */ +#define DCR_DW32 DCR_DW /* use 32-bit DMA accesses */ + +#define DCR_DMAEF 0 /* DMA until TX/RX FIFO has emptied/filled */ +#define DCR_DMABLOCK DCR_BMS /* DMA until RX/TX threshold crossed */ + +#define DCR_RFT4 0 /* receive threshold 4 bytes */ +#define DCR_RFT8 DCR_RFT0 /* receive threshold 8 bytes */ +#define DCR_RFT16 DCR_RFT1 /* receive threshold 16 bytes */ +#define DCR_RFT24 (DCR_RFT1|DCR_RFT0) /* receive threshold 24 bytes */ + +#define DCR_TFT8 0 /* transmit threshold 8 bytes */ +#define DCR_TFT16 DCR_TFT0 /* transmit threshold 16 bytes */ +#define DCR_TFT24 DCR_TFT1 /* transmit threshold 24 bytes */ +#define DCR_TFT28 (DCR_TFT1|DCR_TFT0) /* transmit threshold 28 bytes */ + +/* + * The receive control register is used to filter incoming packets and + * provides status information on packets received. + * The contents of the register are copied into the RXpkt.status field + * when a packet is received. RCR_MC - RCR_PRX are then reset. + */ +#define RCR_ERR 0x8000 /* accept packets with CRC errors */ +#define RCR_RNT 0x4000 /* accept runt (length < 64) packets */ +#define RCR_BRD 0x2000 /* accept broadcast packets */ +#define RCR_PRO 0x1000 /* accept all physical address packets */ +#define RCR_AMC 0x0800 /* accept all multicast packets */ +#define RCR_LB1 0x0400 /* loopback control 1 */ +#define RCR_LB0 0x0200 /* loopback control 0 */ +#define RCR_MC 0x0100 /* multicast packet received */ +#define RCR_BC 0x0080 /* broadcast packet received */ +#define RCR_LPKT 0x0040 /* last packet in RBA (RBWC < EOBC) */ +#define RCR_CRS 0x0020 /* carrier sense activity */ +#define RCR_COL 0x0010 /* collision activity */ +#define RCR_CRC 0x0008 /* CRC error */ +#define RCR_FAE 0x0004 /* frame alignment error */ +#define RCR_LBK 0x0002 /* loopback packet received */ +#define RCR_PRX 0x0001 /* packet received without errors */ + +/* receiver control register aliases */ +/* the loopback control bits provide the following options */ +#define RCR_LBNONE 0 /* no loopback - normal operation */ +#define RCR_LBMAC RCR_LB0 /* MAC loopback */ +#define RCR_LBENDEC RCR_LB1 /* ENDEC loopback */ +#define RCR_LBTRANS (RCR_LB1|RCR_LB0) /* transceiver loopback */ + +/* + * The transmit control register controls the SONIC's transmit operations. + * TCR_PINT - TCR_EXDIS are loaded from the TXpkt.config field at the + * start of transmission. TCR_EXD-TCR_PTX are cleared at the beginning + * of transmission and updated when the transmission is completed. + */ +#define TCR_PINT 0x8000 /* interrupt when transmission starts */ +#define TCR_POWC 0x4000 /* program out of window collision timer */ +#define TCR_CRCI 0x2000 /* transmit packet without 4 byte FCS */ +#define TCR_EXDIS 0x1000 /* disable excessive deferral timer */ +#define TCR_EXD 0x0400 /* excessive deferrals occurred (>3.2ms) */ +#define TCR_DEF 0x0200 /* deferred transmissions occurred */ +#define TCR_NCRS 0x0100 /* carrier not present during transmission */ +#define TCR_CRSL 0x0080 /* carrier lost during transmission */ +#define TCR_EXC 0x0040 /* excessive collisions (>16) detected */ +#define TCR_OWC 0x0020 /* out of window (bad) collision occurred */ +#define TCR_PMB 0x0008 /* packet monitored bad - the tansmitted + * packet had a bad source address or CRC */ +#define TCR_FU 0x0004 /* FIFO underrun (memory access failed) */ +#define TCR_BCM 0x0002 /* byte count mismatch (TXpkt.pkt_size + * != sum(TXpkt.frag_size) */ +#define TCR_PTX 0x0001 /* packet transmitted without errors */ + +/* transmit control register aliases */ +#define TCR_OWCSFD 0 /* start after start of frame delimiter */ +#define TCR_OWCPRE TCR_POWC /* start after first bit of preamble */ + + +/* + * The interrupt mask register masks the interrupts that + * are generated from the interrupt status register. + * All reserved bits should be written with 0. + */ +#define IMR_BREN 0x4000 /* bus retry occurred enable */ +#define IMR_HBLEN 0x2000 /* heartbeat lost enable */ +#define IMR_LCDEN 0x1000 /* load CAM done interrupt enable */ +#define IMR_PINTEN 0x0800 /* programmable interrupt enable */ +#define IMR_PRXEN 0x0400 /* packet received enable */ +#define IMR_PTXEN 0x0200 /* packet transmitted enable */ +#define IMR_TXEREN 0x0100 /* transmit error enable */ +#define IMR_TCEN 0x0080 /* timer complete enable */ +#define IMR_RDEEN 0x0040 /* receive descriptors exhausted enable */ +#define IMR_RBEEN 0x0020 /* receive buffers exhausted enable */ +#define IMR_RBAEEN 0x0010 /* receive buffer area exceeded enable */ +#define IMR_CRCEN 0x0008 /* CRC tally counter rollover enable */ +#define IMR_FAEEN 0x0004 /* FAE tally counter rollover enable */ +#define IMR_MPEN 0x0002 /* MP tally counter rollover enable */ +#define IMR_RFOEN 0x0001 /* receive FIFO overrun enable */ + + +/* + * The interrupt status register indicates the source of an interrupt when + * the INT pin goes active. The interrupt is acknowledged by writing + * the appropriate bit(s) in this register. + */ +#define ISR_ALL 0xffff /* all interrupts */ +#define ISR_BR 0x4000 /* bus retry occurred */ +#define ISR_HBL 0x2000 /* CD heartbeat lost */ +#define ISR_LCD 0x1000 /* load CAM command has completed */ +#define ISR_PINT 0x0800 /* programmed interrupt from TXpkt.config */ +#define ISR_PKTRX 0x0400 /* packet received */ +#define ISR_TXDN 0x0200 /* no remaining packets to be transmitted */ +#define ISR_TXER 0x0100 /* packet transmission caused error */ +#define ISR_TC 0x0080 /* timer complete */ +#define ISR_RDE 0x0040 /* receive descriptors exhausted */ +#define ISR_RBE 0x0020 /* receive buffers exhausted */ +#define ISR_RBAE 0x0010 /* receive buffer area exceeded */ +#define ISR_CRC 0x0008 /* CRC tally counter rollover */ +#define ISR_FAE 0x0004 /* FAE tally counter rollover */ +#define ISR_MP 0x0002 /* MP tally counter rollover */ +#define ISR_RFO 0x0001 /* receive FIFO overrun */ + +/* + * The second data configuration register allows additional user defined + * pins to be controlled. These bits are only available if s_dcr.DCR_EXBUS + * is set. + */ +#define DCR2_EXPO3 0x8000 /* EXUSR3 output */ +#define DCR2_EXPO2 0x4000 /* EXUSR2 output */ +#define DCR2_EXPO1 0x2000 /* EXUSR1 output */ +#define DCR2_EXPO0 0x1000 /* EXUSR0 output */ +#define DCR2_PHL 0x0010 /* extend HOLD signal by 1/2 clock */ +#define DCR2_LRDY 0x0008 /* set latched ready mode */ +#define DCR2_PCM 0x0004 /* packet compress on match */ +#define DCR2_PCNM 0x0002 /* packet compress on mismatch */ +#define DCR2_RJM 0x0001 /* reject on match */ diff --git a/sys/arch/arc/dev/lpt.c b/sys/arch/arc/dev/lpt.c new file mode 100644 index 00000000000..da3e62733ba --- /dev/null +++ b/sys/arch/arc/dev/lpt.c @@ -0,0 +1,676 @@ +/* $OpenBSD: lpt.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* $NetBSD: lpt.c,v 1.39 1996/05/12 23:53:06 mycroft Exp $ */ + +/* + * Copyright (c) 1993, 1994 Charles Hannum. + * Copyright (c) 1990 William F. Jolitz, TeleMuse + * All rights reserved. + * + * 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 software is a component of "386BSD" developed by + * William F. Jolitz, TeleMuse. + * 4. Neither the name of the developer nor the name "386BSD" + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ + * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS + * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. + * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT + * NOT MAKE USE OF THIS WORK. + * + * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED + * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN + * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES + * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING + * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND + * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE + * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS + * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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. + */ + +/* + * Device Driver for AT parallel printer port + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/kernel.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/syslog.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/lptreg.h> + +#include <lpt.h> + +#define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ +#define STEP hz/4 + +#define LPTPRI (PZERO+8) +#define LPT_BSIZE 1024 + +#if !defined(DEBUG) || !defined(notdef) +#define LPRINTF(a) +#else +#define LPRINTF if (lptdebug) printf a +int lptdebug = 1; +#endif + +struct lpt_softc { + struct device sc_dev; + void *sc_ih; + + size_t sc_count; + struct buf *sc_inbuf; + u_char *sc_cp; + int sc_spinmax; + int sc_iobase; + bus_chipset_tag_t sc_bc; + bus_io_handle_t sc_ioh; + int sc_irq; + u_char sc_state; +#define LPT_OPEN 0x01 /* device is open */ +#define LPT_OBUSY 0x02 /* printer is busy doing output */ +#define LPT_INIT 0x04 /* waiting to initialize for open */ + u_char sc_flags; +#define LPT_AUTOLF 0x20 /* automatic LF on CR */ +#define LPT_NOPRIME 0x40 /* don't prime on open */ +#define LPT_NOINTR 0x80 /* do not use interrupt */ + u_char sc_control; + u_char sc_laststatus; +}; + +/* XXX does not belong here */ +cdev_decl(lpt); + +int lptintr __P((void *)); + +#if NLPT_ISA +int lpt_isa_probe __P((struct device *, void *, void *)); +void lpt_isa_attach __P((struct device *, struct device *, void *)); +struct cfattach lpt_ca = { + sizeof(struct lpt_softc), lpt_isa_probe, lpt_isa_attach +}; +#endif + +#if NLPT_PICA +int lpt_pica_probe __P((struct device *, void *, void *)); +void lpt_pica_attach __P((struct device *, struct device *, void *)); +struct cfattach lpt_pica_ca = { + sizeof(struct lpt_softc), lpt_pica_probe, lpt_pica_attach +}; +#endif + +struct cfdriver lpt_cd = { + NULL, "lpt", DV_TTY +}; + +#define LPTUNIT(s) (minor(s) & 0x1f) +#define LPTFLAGS(s) (minor(s) & 0xe0) + +#define LPS_INVERT (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK) +#define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER) +#define NOT_READY() ((bus_io_read_1(bc, ioh, lpt_status) ^ LPS_INVERT) & LPS_MASK) +#define NOT_READY_ERR() not_ready(bus_io_read_1(bc, ioh, lpt_status), sc) +static int not_ready __P((u_char, struct lpt_softc *)); + +static void lptwakeup __P((void *arg)); +static int pushbytes __P((struct lpt_softc *)); + +int lpt_port_test __P((bus_chipset_tag_t, bus_io_handle_t, bus_io_addr_t, + bus_io_size_t, u_char, u_char)); + +/* + * Internal routine to lptprobe to do port tests of one byte value. + */ +int +lpt_port_test(bc, ioh, base, off, data, mask) + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + bus_io_addr_t base; + bus_io_size_t off; + u_char data, mask; +{ + int timeout; + u_char temp; + + data &= mask; + bus_io_write_1(bc, ioh, off, data); + timeout = 1000; + do { + delay(10); + temp = bus_io_read_1(bc, ioh, off) & mask; + } while (temp != data && --timeout); + LPRINTF(("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n", base + off, + data, temp, timeout)); + return (temp == data); +} + +/* + * Logic: + * 1) You should be able to write to and read back the same value + * to the data port. Do an alternating zeros, alternating ones, + * walking zero, and walking one test to check for stuck bits. + * + * 2) You should be able to write to and read back the same value + * to the control port lower 5 bits, the upper 3 bits are reserved + * per the IBM PC technical reference manauls and different boards + * do different things with them. Do an alternating zeros, alternating + * ones, walking zero, and walking one test to check for stuck bits. + * + * Some printers drag the strobe line down when the are powered off + * so this bit has been masked out of the control port test. + * + * XXX Some printers may not like a fast pulse on init or strobe, I + * don't know at this point, if that becomes a problem these bits + * should be turned off in the mask byte for the control port test. + * + * 3) Set the data and control ports to a value of 0 + */ +#if NLPT_ISA +int +lpt_isa_probe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct isa_attach_args *ia = aux; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + u_long base; + u_char mask, data; + int i, rv; + +#ifdef DEBUG +#define ABORT do {printf("lptprobe: mask %x data %x failed\n", mask, data); \ + goto out;} while (0) +#else +#define ABORT goto out +#endif + + bc = ia->ia_bc; + base = ia->ia_iobase; + if (bus_io_map(bc, base, LPT_NPORTS, &ioh)) + return 0; + + rv = 0; + mask = 0xff; + + data = 0x55; /* Alternating zeros */ + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + + data = 0xaa; /* Alternating ones */ + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + + for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */ + data = ~(1 << i); + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + } + + for (i = 0; i < CHAR_BIT; i++) { /* Walking one */ + data = (1 << i); + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + } + + bus_io_write_1(bc, ioh, lpt_data, 0); + bus_io_write_1(bc, ioh, lpt_control, 0); + + ia->ia_iosize = LPT_NPORTS; + ia->ia_msize = 0; + + rv = 1; + +out: + bus_io_unmap(bc, ioh, LPT_NPORTS); + return rv; +} +#endif + +#if NLPT_PICA +int +lpt_pica_probe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct confargs *ca = aux; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + u_long base; + u_char mask, data; + int i; + +#ifdef DEBUG +#define ABORT do {printf("lptprobe: mask %x data %x failed\n", mask, data); \ + return 0;} while (0) +#else +#define ABORT return 0 +#endif + + if(!BUS_MATCHNAME(ca, "lpt")) + return(0); + + bc = 0; + base = (int)BUS_CVTADDR(ca); + ioh = base; + + mask = 0xff; + + data = 0x55; /* Alternating zeros */ + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + + data = 0xaa; /* Alternating ones */ + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + + for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */ + data = ~(1 << i); + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + } + + for (i = 0; i < CHAR_BIT; i++) { /* Walking one */ + data = (1 << i); + if (!lpt_port_test(bc, ioh, base, lpt_data, data, mask)) + ABORT; + } + + bus_io_write_1(bc, ioh, lpt_data, 0); + bus_io_write_1(bc, ioh, lpt_control, 0); + + return 1; +} +#endif + +#if NLPT_ISA +void +lpt_isa_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct lpt_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + + if (ia->ia_irq != IRQUNK) + printf("\n"); + else + printf(": polled\n"); + + sc->sc_iobase = ia->ia_iobase; + sc->sc_irq = ia->ia_irq; + sc->sc_state = 0; + + bc = sc->sc_bc = ia->ia_bc; + if (bus_io_map(bc, sc->sc_iobase, LPT_NPORTS, &ioh)) + panic("lptattach: couldn't map I/O ports"); + sc->sc_ioh = ioh; + + bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT); + + if (ia->ia_irq != IRQUNK) + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_TTY, lptintr, sc, sc->sc_dev.dv_xname); +} +#endif + +#if NLPT_PICA +void +lpt_pica_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct lpt_softc *sc = (void *)self; + struct confargs *ca = aux; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + + printf("\n"); + + sc->sc_iobase = (int)BUS_CVTADDR(ca); + sc->sc_irq = 0; + sc->sc_state = 0; + + bc = sc->sc_bc = 0; + sc->sc_ioh = sc->sc_iobase; + + bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT); + + BUS_INTR_ESTABLISH(ca, lptintr, sc); +} +#endif + +/* + * Reset the printer, then wait until it's selected and not busy. + */ +int +lptopen(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + int unit = LPTUNIT(dev); + u_char flags = LPTFLAGS(dev); + struct lpt_softc *sc; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + u_char control; + int error; + int spin; + + if (unit >= lpt_cd.cd_ndevs) + return ENXIO; + sc = lpt_cd.cd_devs[unit]; + if (!sc) + return ENXIO; + + if (sc->sc_irq == IRQUNK && (flags & LPT_NOINTR) == 0) + return ENXIO; + +#ifdef DIAGNOSTIC + if (sc->sc_state) + printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname, + sc->sc_state); +#endif + + if (sc->sc_state) + return EBUSY; + + sc->sc_state = LPT_INIT; + sc->sc_flags = flags; + LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags)); + bc = sc->sc_bc; + ioh = sc->sc_ioh; + + if ((flags & LPT_NOPRIME) == 0) { + /* assert INIT for 100 usec to start up printer */ + bus_io_write_1(bc, ioh, lpt_control, LPC_SELECT); + delay(100); + } + + control = LPC_SELECT | LPC_NINIT; + bus_io_write_1(bc, ioh, lpt_control, control); + + /* wait till ready (printer running diagnostics) */ + for (spin = 0; NOT_READY_ERR(); spin += STEP) { + if (spin >= TIMEOUT) { + sc->sc_state = 0; + return EBUSY; + } + + /* wait 1/4 second, give up if we get a signal */ + error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP); + if (error != EWOULDBLOCK) { + sc->sc_state = 0; + return error; + } + } + + if ((flags & LPT_NOINTR) == 0) + control |= LPC_IENABLE; + if (flags & LPT_AUTOLF) + control |= LPC_AUTOLF; + sc->sc_control = control; + bus_io_write_1(bc, ioh, lpt_control, control); + + sc->sc_inbuf = geteblk(LPT_BSIZE); + sc->sc_count = 0; + sc->sc_state = LPT_OPEN; + + if ((sc->sc_flags & LPT_NOINTR) == 0) + lptwakeup(sc); + + LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname)); + return 0; +} + +int +not_ready(status, sc) + u_char status; + struct lpt_softc *sc; +{ + u_char new; + + status = (status ^ LPS_INVERT) & LPS_MASK; + new = status & ~sc->sc_laststatus; + sc->sc_laststatus = status; + + if (new & LPS_SELECT) + log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname); + else if (new & LPS_NOPAPER) + log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname); + else if (new & LPS_NERR) + log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname); + + return status; +} + +void +lptwakeup(arg) + void *arg; +{ + struct lpt_softc *sc = arg; + int s; + + s = spltty(); + lptintr(sc); + splx(s); + + timeout(lptwakeup, sc, STEP); +} + +/* + * Close the device, and free the local line buffer. + */ +int +lptclose(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + int unit = LPTUNIT(dev); + struct lpt_softc *sc = lpt_cd.cd_devs[unit]; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + + if (sc->sc_count) + (void) pushbytes(sc); + + if ((sc->sc_flags & LPT_NOINTR) == 0) + untimeout(lptwakeup, sc); + + bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT); + sc->sc_state = 0; + bus_io_write_1(bc, ioh, lpt_control, LPC_NINIT); + brelse(sc->sc_inbuf); + + LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname)); + return 0; +} + +int +pushbytes(sc) + struct lpt_softc *sc; +{ + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int error; + + if (sc->sc_flags & LPT_NOINTR) { + int spin, tic; + u_char control = sc->sc_control; + + while (sc->sc_count > 0) { + spin = 0; + while (NOT_READY()) { + if (++spin < sc->sc_spinmax) + continue; + tic = 0; + /* adapt busy-wait algorithm */ + sc->sc_spinmax++; + while (NOT_READY_ERR()) { + /* exponential backoff */ + tic = tic + tic + 1; + if (tic > TIMEOUT) + tic = TIMEOUT; + error = tsleep((caddr_t)sc, + LPTPRI | PCATCH, "lptpsh", tic); + if (error != EWOULDBLOCK) + return error; + } + break; + } + + bus_io_write_1(bc, ioh, lpt_data, *sc->sc_cp++); + bus_io_write_1(bc, ioh, lpt_control, control | LPC_STROBE); + sc->sc_count--; + bus_io_write_1(bc, ioh, lpt_control, control); + + /* adapt busy-wait algorithm */ + if (spin*2 + 16 < sc->sc_spinmax) + sc->sc_spinmax--; + } + } else { + int s; + + while (sc->sc_count > 0) { + /* if the printer is ready for a char, give it one */ + if ((sc->sc_state & LPT_OBUSY) == 0) { + LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname, + sc->sc_count)); + s = spltty(); + (void) lptintr(sc); + splx(s); + } + error = tsleep((caddr_t)sc, LPTPRI | PCATCH, + "lptwrite2", 0); + if (error) + return error; + } + } + return 0; +} + +/* + * Copy a line from user space to a local buffer, then call putc to get the + * chars moved to the output queue. + */ +int +lptwrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)]; + size_t n; + int error = 0; + + while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) { + uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio); + sc->sc_count = n; + error = pushbytes(sc); + if (error) { + /* + * Return accurate residual if interrupted or timed + * out. + */ + uio->uio_resid += sc->sc_count; + sc->sc_count = 0; + return error; + } + } + return 0; +} + +/* + * Handle printer interrupts which occur when the printer is ready to accept + * another char. + */ +int +lptintr(arg) + void *arg; +{ + struct lpt_softc *sc = arg; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + + if (((sc->sc_state & LPT_OPEN) == 0 && sc->sc_count == 0) || (sc->sc_flags & LPT_NOINTR)) + return 0; + + /* is printer online and ready for output */ + if (NOT_READY() && NOT_READY_ERR()) + return -1; + + if (sc->sc_count) { + u_char control = sc->sc_control; + /* send char */ + bus_io_write_1(bc, ioh, lpt_data, *sc->sc_cp++); + bus_io_write_1(bc, ioh, lpt_control, control | LPC_STROBE); + sc->sc_count--; + bus_io_write_1(bc, ioh, lpt_control, control); + sc->sc_state |= LPT_OBUSY; + } else + sc->sc_state &= ~LPT_OBUSY; + + if (sc->sc_count == 0) { + /* none, wake up the top half to get more */ + wakeup((caddr_t)sc); + } + + return 1; +} + +int +lptioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int error = 0; + + switch (cmd) { + default: + error = ENODEV; + } + + return error; +} diff --git a/sys/arch/arc/dev/pccons.c b/sys/arch/arc/dev/pccons.c new file mode 100644 index 00000000000..edc39878791 --- /dev/null +++ b/sys/arch/arc/dev/pccons.c @@ -0,0 +1,2094 @@ +/* $OpenBSD: pccons.c,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* $NetBSD: pccons.c,v 1.89 1995/05/04 19:35:20 cgd Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995 Charles Hannum. All rights reserved. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * Copyright (c) 1994 Charles Hannum. + * Copyright (c) 1992, 1993 Erik Forsberg. + * + * 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. + * + * @(#)pccons.c 5.11 (Berkeley) 5/21/91 + */ + +/* + * code to work keyboard & display for PC-style console + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/tty.h> +#include <sys/uio.h> +#include <sys/callout.h> +#include <sys/syslog.h> +#include <sys/vnode.h> +#include <sys/device.h> +#include <sys/file.h> + +#include <dev/cons.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> +#include <machine/display.h> +#include <machine/pccons.h> +#include <arc/pica/pica.h> + +#include <dev/isa/isavar.h> +#include <machine/kbdreg.h> + +#define XFREE86_BUG_COMPAT + +#ifndef BEEP_FREQ +#define BEEP_FREQ 1600 +#endif +#ifndef BEEP_TIME +#define BEEP_TIME (hz/5) +#endif + +#define PCBURST 128 + +static u_short *Crtat; /* pointer to backing store */ +static u_short *crtat; /* pointer to current char */ +static u_char async, kernel, polling; /* Really, you don't want to know. */ +static u_char lock_state = 0x00, /* all off */ + old_lock_state = 0xff, + typematic_rate = 0xff, /* don't update until set by user */ + old_typematic_rate = 0xff; +static u_short cursor_shape = 0xffff, /* don't update until set by user */ + old_cursor_shape = 0xffff; +static keymap_t scan_codes[KB_NUM_KEYS];/* keyboard translation table */ +int pc_xmode = 0; + +/* + * Keyboard output queue. + */ +int kb_oq_put = 0; +int kb_oq_get = 0; +u_char kb_oq[8]; + +#define PCUNIT(x) (minor(x)) + +static struct video_state { + int cx, cy; /* escape parameters */ + int row, col; /* current cursor position */ + int nrow, ncol, nchr; /* current screen geometry */ + u_char state; /* parser state */ +#define VSS_ESCAPE 1 +#define VSS_EBRACE 2 +#define VSS_EPARAM 3 + char so; /* in standout mode? */ + char color; /* color or mono display */ + char at; /* normal attributes */ + char so_at; /* standout attributes */ +} vs; + +struct pc_softc { + struct device sc_dev; + struct tty *sc_tty; +}; + +struct pms_softc { /* driver status information */ + struct device sc_dev; + + struct clist sc_q; + struct selinfo sc_rsel; + u_char sc_state; /* mouse driver state */ +#define PMS_OPEN 0x01 /* device is open */ +#define PMS_ASLP 0x02 /* waiting for mouse data */ + u_char sc_status; /* mouse button status */ + int sc_x, sc_y; /* accumulated motion in the X,Y axis */ +}; + +int pcprobe __P((struct device *, void *, void *)); +void pcattach __P((struct device *, struct device *, void *)); +int pcintr __P((void *)); + +struct cfattach pc_ca = { + sizeof(struct pc_softc), pcprobe, pcattach +}; +struct cfdriver pc_cd = { + NULL, "pc", DV_TTY, NULL, 0 +}; + +int pmsprobe __P((struct device *, void *, void *)); +void pmsattach __P((struct device *, struct device *, void *)); +int pmsintr __P((void *)); + +struct cfattach pms_ca = { + sizeof(struct pms_softc), pmsprobe, pmsattach +}; +struct cfdriver pms_cd = { + NULL, "pms", DV_TTY, NULL, 0 +}; + +#define PMSUNIT(dev) (minor(dev)) + +#define COL 80 +#define ROW 25 +#define CHR 2 + +static unsigned int addr_6845 = MONO_BASE; + +char *sget __P((void)); +void sput __P((u_char *, int)); + +void pcstart(); +int pcparam(); +char partab[]; + +extern pcopen(dev_t, int, int, struct proc *); + +#define KBD_DELAY \ + DELAY(10); + +static inline int +kbd_wait_output() +{ + u_int i; + + for (i = 100000; i; i--) + if ((inb(KBSTATP) & KBS_IBF) == 0) { + KBD_DELAY; + return 1; + } + return 0; +} + +static inline int +kbd_wait_input() +{ + u_int i; + + for (i = 100000; i; i--) + if ((inb(KBSTATP) & KBS_DIB) != 0) { + KBD_DELAY; + return 1; + } + return 0; +} + +static inline void +kbd_flush_input() +{ + u_char c; + + while (c = inb(KBSTATP) & 0x03) + if ((c & KBS_DIB) == KBS_DIB) { + /* XXX - delay is needed to prevent some keyboards from + wedging when the system boots */ + delay(6); + (void) inb(KBDATAP); + } +} + + +#if 1 +/* + * Get the current command byte. + */ +static u_char +kbc_get8042cmd() +{ + + if (!kbd_wait_output()) + return -1; + outb(KBCMDP, K_RDCMDBYTE); + if (!kbd_wait_input()) + return -1; + return inb(KBDATAP); +} +#endif + +/* + * Pass command byte to keyboard controller (8042). + */ +static int +kbc_put8042cmd(val) + u_char val; +{ + + if (!kbd_wait_output()) + return 0; + outb(KBCMDP, K_LDCMDBYTE); + if (!kbd_wait_output()) + return 0; + outb(KBOUTP, val); + return 1; +} + +/* + * Pass command to keyboard itself + */ +int +kbd_cmd(val, polling) + u_char val; + u_char polling; +{ + u_int retries = 3; + register u_int i; + + if(!polling) { + i = spltty(); + if(kb_oq_get == kb_oq_put) { + outb(KBOUTP, val); + } + kb_oq[kb_oq_put] = val; + kb_oq_put = (kb_oq_put + 1) & 7; + splx(i); + return(1); + } + else do { + if (!kbd_wait_output()) + return 0; + outb(KBOUTP, val); + for (i = 100000; i; i--) { + if (inb(KBSTATP) & KBS_DIB) { + register u_char c; + + KBD_DELAY; + c = inb(KBDATAP); + if (c == KBR_ACK || c == KBR_ECHO) { + return 1; + } + if (c == KBR_RESEND) { + break; + } +#ifdef DIAGNOSTIC + printf("kbd_cmd: input char %x lost\n", c); +#endif + } + } + } while (--retries); + return 0; +} + +void +set_cursor_shape() +{ + register int iobase = addr_6845; + + outb(iobase, 10); + outb(iobase+1, cursor_shape >> 8); + outb(iobase, 11); + outb(iobase+1, cursor_shape); + old_cursor_shape = cursor_shape; +} + +void +get_cursor_shape() +{ + register int iobase = addr_6845; + + outb(iobase, 10); + cursor_shape = inb(iobase+1) << 8; + outb(iobase, 11); + cursor_shape |= inb(iobase+1); + + /* + * real 6845's, as found on, MDA, Hercules or CGA cards, do + * not support reading the cursor shape registers. the 6845 + * tri-states it's data bus. This is _normally_ read by the + * cpu as either 0x00 or 0xff.. in which case we just use + * a line cursor. + */ + if (cursor_shape == 0x0000 || cursor_shape == 0xffff) + cursor_shape = 0x0b10; + else + cursor_shape &= 0x1f1f; +} + +void +do_async_update(poll) + u_char poll; +{ + int pos; + static int old_pos = -1; + + async = 0; + + if (lock_state != old_lock_state) { + old_lock_state = lock_state; + if (!kbd_cmd(KBC_MODEIND, poll) || + !kbd_cmd(lock_state, poll)) { + printf("pc: timeout updating leds\n"); + (void) kbd_cmd(KBC_ENABLE, poll); + } + } + if (typematic_rate != old_typematic_rate) { + old_typematic_rate = typematic_rate; + if (!kbd_cmd(KBC_TYPEMATIC, poll) || + !kbd_cmd(typematic_rate, poll)) { + printf("pc: timeout updating typematic rate\n"); + (void) kbd_cmd(KBC_ENABLE, poll); + } + } + + if (pc_xmode > 0) + return; + + pos = crtat - Crtat; + if (pos != old_pos) { + register int iobase = addr_6845; + outb(iobase, 14); + outb(iobase+1, pos >> 8); + outb(iobase, 15); + outb(iobase+1, pos); + old_pos = pos; + } + if (cursor_shape != old_cursor_shape) + set_cursor_shape(); +} + +void +async_update() +{ + + if (kernel || polling) { + if (async) + untimeout(do_async_update, NULL); + do_async_update(1); + } else { + if (async) + return; + async = 1; + timeout(do_async_update, NULL, 1); + } +} + +/* + * these are both bad jokes + */ +int +pcprobe(parent, cfdata, aux) + struct device *parent; + void *cfdata, *aux; +{ + struct confargs *ca = aux; + u_int i; + + /* Make shure we're looking for this type of device */ + if(!BUS_MATCHNAME(ca, "pc")) + return(0); + + /* Enable interrupts and keyboard, etc. */ + if (!kbc_put8042cmd(CMDBYTE)) { + printf("pcprobe: command error\n"); + return 0; + } + +#if 1 + /* Flush any garbage. */ + kbd_flush_input(); + /* Reset the keyboard. */ + if (!kbd_cmd(KBC_RESET, 1)) { + printf("pcprobe: reset error %d\n", 1); + goto lose; + } + for (i = 600000; i; i--) + if ((inb(KBSTATP) & KBS_DIB) != 0) { + KBD_DELAY; + break; + } + if (i == 0 || inb(KBDATAP) != KBR_RSTDONE) { + printf("pcprobe: reset error %d\n", 2); + goto lose; + } + /* + * Some keyboards seem to leave a second ack byte after the reset. + * This is kind of stupid, but we account for them anyway by just + * flushing the buffer. + */ + kbd_flush_input(); + /* Just to be sure. */ + if (!kbd_cmd(KBC_ENABLE, 1)) { + printf("pcprobe: reset error %d\n", 3); + goto lose; + } + + /* + * Some keyboard/8042 combinations do not seem to work if the keyboard + * is set to table 1; in fact, it would appear that some keyboards just + * ignore the command altogether. So by default, we use the AT scan + * codes and have the 8042 translate them. Unfortunately, this is + * known to not work on some PS/2 machines. We try desparately to deal + * with this by checking the (lack of a) translate bit in the 8042 and + * attempting to set the keyboard to XT mode. If this all fails, well, + * tough luck. + * + * XXX It would perhaps be a better choice to just use AT scan codes + * and not bother with this. + */ + if (kbc_get8042cmd() & KC8_TRANS) { + /* The 8042 is translating for us; use AT codes. */ + if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) { + printf("pcprobe: reset error %d\n", 4); + goto lose; + } + } else { + /* Stupid 8042; set keyboard to XT codes. */ + if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) { + printf("pcprobe: reset error %d\n", 5); + goto lose; + } + } + +lose: + /* + * Technically, we should probably fail the probe. But we'll be nice + * and allow keyboard-less machines to boot with the console. + */ +#endif + + return 1; +} + +void +pcattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct confargs *ca = aux; + struct pc_softc *sc = (void *)self; + + printf(": %s\n", vs.color ? "color" : "mono"); + do_async_update(1); + + BUS_INTR_ESTABLISH(ca, pcintr, (void *)(long)sc); +} + +int +pcopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct pc_softc *sc; + int unit = PCUNIT(dev); + struct tty *tp; + + if (unit >= pc_cd.cd_ndevs) + return ENXIO; + sc = pc_cd.cd_devs[unit]; + if (sc == 0) + return ENXIO; + + if (!sc->sc_tty) { + tp = sc->sc_tty = ttymalloc(); + } + else { + tp = sc->sc_tty; + } + + tp->t_oproc = pcstart; + tp->t_param = pcparam; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + pcparam(tp, &tp->t_termios); + ttsetwater(tp); + } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) + return EBUSY; + tp->t_state |= TS_CARR_ON; + + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +int +pcclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + (*linesw[tp->t_line].l_close)(tp, flag); + ttyclose(tp); +#ifdef notyet /* XXX */ + ttyfree(tp); +#endif + return(0); +} + +int +pcread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +pcwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +struct tty * +pctty(dev) + dev_t dev; +{ + struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return (tp); +} + +/* + * Got a console receive interrupt - + * the console processor wants to give us a character. + * Catch the character, and see who it goes to. + */ +int +pcintr(arg) + void *arg; +{ + struct pc_softc *sc = arg; + register struct tty *tp = sc->sc_tty; + u_char *cp; + + if ((inb(KBSTATP) & KBS_DIB) == 0) + return 0; + if (polling) + return 1; + do { + cp = sget(); + if (!tp || (tp->t_state & TS_ISOPEN) == 0) + return 1; + if (cp) + do + (*linesw[tp->t_line].l_rint)(*cp++, tp); + while (*cp); + } while (inb(KBSTATP) & KBS_DIB); + return 1; +} + +int +pcioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; + struct tty *tp = sc->sc_tty; + int error; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return error; + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return error; + + switch (cmd) { + case CONSOLE_X_MODE_ON: + pc_xmode_on(); + return 0; + case CONSOLE_X_MODE_OFF: + pc_xmode_off(); + return 0; + case CONSOLE_X_BELL: + /* + * If set, data is a pointer to a length 2 array of + * integers. data[0] is the pitch in Hz and data[1] + * is the duration in msec. + */ + if (data) + sysbeep(((int*)data)[0], + (((int*)data)[1] * hz) / 1000); + else + sysbeep(BEEP_FREQ, BEEP_TIME); + return 0; + case CONSOLE_SET_TYPEMATIC_RATE: { + u_char rate; + + if (!data) + return EINVAL; + rate = *((u_char *)data); + /* + * Check that it isn't too big (which would cause it to be + * confused with a command). + */ + if (rate & 0x80) + return EINVAL; + typematic_rate = rate; + async_update(); + return 0; + } + case CONSOLE_SET_KEYMAP: { + keymap_t *map = (keymap_t *) data; + int i; + + if (!data) + return EINVAL; + for (i = 0; i < KB_NUM_KEYS; i++) + if (map[i].unshift[KB_CODE_SIZE-1] || + map[i].shift[KB_CODE_SIZE-1] || + map[i].ctl[KB_CODE_SIZE-1] || + map[i].altgr[KB_CODE_SIZE-1] || + map[i].shift_altgr[KB_CODE_SIZE-1]) + return EINVAL; + + bcopy(data,scan_codes,sizeof(keymap_t[KB_NUM_KEYS])); + return 0; + } + case CONSOLE_GET_KEYMAP: + if (!data) + return EINVAL; + bcopy(scan_codes,data,sizeof(keymap_t[KB_NUM_KEYS])); + return 0; + + default: + return ENOTTY; + } + +#ifdef DIAGNOSTIC + panic("pcioctl: impossible"); +#endif +} + +void +pcstart(tp) + struct tty *tp; +{ + struct clist *cl; + int s, len, n; + u_char buf[PCBURST]; + + s = spltty(); + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + goto out; + tp->t_state |= TS_BUSY; + splx(s); + /* + * We need to do this outside spl since it could be fairly + * expensive and we don't want our serial ports to overflow. + */ + cl = &tp->t_outq; + len = q_to_b(cl, buf, PCBURST); + sput(buf, len); + s = spltty(); + tp->t_state &= ~TS_BUSY; + if (cl->c_cc) { + tp->t_state |= TS_TIMEOUT; + timeout(ttrstrt, tp, 1); + } + if (cl->c_cc <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup(cl); + } + selwakeup(&tp->t_wsel); + } +out: + splx(s); +} + +void +pcstop(tp, flag) + struct tty *tp; + int flag; +{ + +} + +void +pccnprobe(cp) + struct consdev *cp; +{ + int maj; + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == pcopen) + break; + + /* initialize required fields */ + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_INTERNAL; +} + +/* ARGSUSED */ +void +pccninit(cp) + struct consdev *cp; +{ + + /* + * For now, don't screw with it. + */ + /* crtat = 0; */ +} + +/* ARGSUSED */ +void +pccnputc(dev, c) + dev_t dev; + char c; +{ + u_char oldkernel = kernel; + + kernel = 1; + if (c == '\n') + sput("\r\n", 2); + else + sput(&c, 1); + kernel = oldkernel; +} + +/* ARGSUSED */ +pccngetc(dev) + dev_t dev; +{ + register char *cp; + + if (pc_xmode > 0) + return 0; + + do { + /* wait for byte */ + while ((inb(KBSTATP) & KBS_DIB) == 0); + /* see if it's worthwhile */ + cp = sget(); + } while (!cp); + if (*cp == '\r') + return '\n'; + return *cp; +} + +void +pccnpollc(dev, on) + dev_t dev; + int on; +{ + + polling = on; + if (!on) { + int unit; + struct pc_softc *sc; + int s; + + /* + * If disabling polling on a device that's been configured, + * make sure there are no bytes left in the FIFO, holding up + * the interrupt line. Otherwise we won't get any further + * interrupts. + */ + unit = PCUNIT(dev); + if (pc_cd.cd_ndevs > unit) { + sc = pc_cd.cd_devs[unit]; + if (sc != 0) { + s = spltty(); + pcintr(sc); + splx(s); + } + } + } +} + +/* + * Set line parameters. + */ +int +pcparam(tp, t) + struct tty *tp; + struct termios *t; +{ + + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + return 0; +} + +#define wrtchar(c, at) do {\ + char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; \ +} while (0) + +/* translate ANSI color codes to standard pc ones */ +static char fgansitopc[] = { + FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, + FG_MAGENTA, FG_CYAN, FG_LIGHTGREY +}; + +static char bgansitopc[] = { + BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, + BG_MAGENTA, BG_CYAN, BG_LIGHTGREY +}; + +static u_char iso2ibm437[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40, + 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0, + 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa, + 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8, + 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80, + 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, + 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f, + 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1, + 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87, + 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, + 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f, + 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0 +}; + +/* + * `pc3' termcap emulation. + */ +void +sput(cp, n) + u_char *cp; + int n; +{ + u_char c, scroll = 0; + + if (pc_xmode > 0) + return; + + if (crtat == 0) { + u_short volatile *cp; + u_short was; + unsigned cursorat; + + cp = (u_short *)CGA_BUF; + was = *cp; + *cp = (u_short) 0xA55A; + if (*cp != 0xA55A) { + cp = (u_short *)MONO_BUF; + addr_6845 = MONO_BASE; + vs.color = 0; + } else { + *cp = was; + addr_6845 = CGA_BASE; + vs.color = 1; + } + + /* Extract cursor location */ + outb(addr_6845, 14); + cursorat = inb(addr_6845+1) << 8; + outb(addr_6845, 15); + cursorat |= inb(addr_6845+1); + +#ifdef FAT_CURSOR + cursor_shape = 0x0012; +#else + get_cursor_shape(); +#endif + + Crtat = (u_short *)cp; + crtat = (u_short *)(cp + cursorat); + + vs.ncol = COL; + vs.nrow = ROW; + vs.nchr = COL * ROW; + vs.at = FG_LIGHTGREY | BG_BLACK; + + if (vs.color == 0) + vs.so_at = FG_BLACK | BG_LIGHTGREY; + else + vs.so_at = FG_YELLOW | BG_BLACK; + + fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat); + } + + while (n--) { + if (!(c = *cp++)) + continue; + + switch (c) { + case 0x1B: + if (vs.state >= VSS_ESCAPE) { + wrtchar(c, vs.so_at); + vs.state = 0; + goto maybe_scroll; + } else + vs.state = VSS_ESCAPE; + break; + + case '\t': { + int inccol = 8 - (vs.col & 7); + crtat += inccol; + vs.col += inccol; + } + maybe_scroll: + if (vs.col >= COL) { + vs.col -= COL; + scroll = 1; + } + break; + + case '\010': + if (crtat <= Crtat) + break; + --crtat; + if (--vs.col < 0) + vs.col += COL; /* non-destructive backspace */ + break; + + case '\r': + crtat -= vs.col; + vs.col = 0; + break; + + case '\n': + crtat += vs.ncol; + scroll = 1; + break; + + default: + bypass: + switch (vs.state) { + case 0: + if (c == '\a') + sysbeep(BEEP_FREQ, BEEP_TIME); + else { + /* + * If we're outputting multiple printed + * characters, just blast them to the + * screen until we reach the end of the + * buffer or a control character. This + * saves time by short-circuiting the + * switch. + * If we reach the end of the line, we + * break to do a scroll check. + */ + for (;;) { + if (c & 0x80) + c = iso2ibm437[c&0x7f]; + + if (vs.so) + wrtchar(c, vs.so_at); + else + wrtchar(c, vs.at); + if (vs.col >= vs.ncol) { + vs.col = 0; + scroll = 1; + break; + } + if (!n || (c = *cp) < ' ') + break; + n--, cp++; + } + } + break; + case VSS_ESCAPE: + if (c == '[') { /* Start ESC [ sequence */ + vs.cx = vs.cy = 0; + vs.state = VSS_EBRACE; + } else if (c == 'c') { /* Clear screen & home */ + fillw((vs.at << 8) | ' ', Crtat, + vs.nchr); + crtat = Crtat; + vs.col = 0; + vs.state = 0; + } else { /* Invalid, clear state */ + wrtchar(c, vs.so_at); + vs.state = 0; + goto maybe_scroll; + } + break; + default: /* VSS_EBRACE or VSS_EPARAM */ + switch (c) { + int pos; + case 'm': + if (!vs.cx) + vs.so = 0; + else + vs.so = 1; + vs.state = 0; + break; + case 'A': { /* back cx rows */ + int cx = vs.cx; + if (cx <= 0) + cx = 1; + else + cx %= vs.nrow; + pos = crtat - Crtat; + pos -= vs.ncol * cx; + if (pos < 0) + pos += vs.nchr; + crtat = Crtat + pos; + vs.state = 0; + break; + } + case 'B': { /* down cx rows */ + int cx = vs.cx; + if (cx <= 0) + cx = 1; + else + cx %= vs.nrow; + pos = crtat - Crtat; + pos += vs.ncol * cx; + if (pos >= vs.nchr) + pos -= vs.nchr; + crtat = Crtat + pos; + vs.state = 0; + break; + } + case 'C': { /* right cursor */ + int cx = vs.cx, + col = vs.col; + if (cx <= 0) + cx = 1; + else + cx %= vs.ncol; + pos = crtat - Crtat; + pos += cx; + col += cx; + if (col >= vs.ncol) { + pos -= vs.ncol; + col -= vs.ncol; + } + vs.col = col; + crtat = Crtat + pos; + vs.state = 0; + break; + } + case 'D': { /* left cursor */ + int cx = vs.cx, + col = vs.col; + if (cx <= 0) + cx = 1; + else + cx %= vs.ncol; + pos = crtat - Crtat; + pos -= cx; + col -= cx; + if (col < 0) { + pos += vs.ncol; + col += vs.ncol; + } + vs.col = col; + crtat = Crtat + pos; + vs.state = 0; + break; + } + case 'J': /* Clear ... */ + switch (vs.cx) { + case 0: + /* ... to end of display */ + fillw((vs.at << 8) | ' ', crtat, + Crtat + vs.nchr - crtat); + break; + case 1: + /* ... to next location */ + fillw((vs.at << 8) | ' ', Crtat, + crtat - Crtat + 1); + break; + case 2: + /* ... whole display */ + fillw((vs.at << 8) | ' ', Crtat, + vs.nchr); + break; + } + vs.state = 0; + break; + case 'K': /* Clear line ... */ + switch (vs.cx) { + case 0: + /* ... current to EOL */ + fillw((vs.at << 8) | ' ', crtat, + vs.ncol - vs.col); + break; + case 1: + /* ... beginning to next */ + fillw((vs.at << 8) | ' ', + crtat - vs.col, + vs.col + 1); + break; + case 2: + /* ... entire line */ + fillw((vs.at << 8) | ' ', + crtat - vs.col, vs.ncol); + break; + } + vs.state = 0; + break; + case 'f': /* in system V consoles */ + case 'H': { /* Cursor move */ + int cx = vs.cx, + cy = vs.cy; + if (!cx || !cy) { + crtat = Crtat; + vs.col = 0; + } else { + if (cx > vs.nrow) + cx = vs.nrow; + if (cy > vs.ncol) + cy = vs.ncol; + crtat = Crtat + + (cx - 1) * vs.ncol + cy - 1; + vs.col = cy - 1; + } + vs.state = 0; + break; + } + case 'M': { /* delete cx rows */ + u_short *crtAt = crtat - vs.col; + int cx = vs.cx, + row = (crtAt - Crtat) / vs.ncol, + nrow = vs.nrow - row; + if (cx <= 0) + cx = 1; + else if (cx > nrow) + cx = nrow; + if (cx < nrow) + bcopy(crtAt + vs.ncol * cx, + crtAt, vs.ncol * (nrow - + cx) * CHR); + fillw((vs.at << 8) | ' ', + crtAt + vs.ncol * (nrow - cx), + vs.ncol * cx); + vs.state = 0; + break; + } + case 'S': { /* scroll up cx lines */ + int cx = vs.cx; + if (cx <= 0) + cx = 1; + else if (cx > vs.nrow) + cx = vs.nrow; + if (cx < vs.nrow) + bcopy(Crtat + vs.ncol * cx, + Crtat, vs.ncol * (vs.nrow - + cx) * CHR); + fillw((vs.at << 8) | ' ', + Crtat + vs.ncol * (vs.nrow - cx), + vs.ncol * cx); + /* crtat -= vs.ncol * cx; /* XXX */ + vs.state = 0; + break; + } + case 'L': { /* insert cx rows */ + u_short *crtAt = crtat - vs.col; + int cx = vs.cx, + row = (crtAt - Crtat) / vs.ncol, + nrow = vs.nrow - row; + if (cx <= 0) + cx = 1; + else if (cx > nrow) + cx = nrow; + if (cx < nrow) + bcopy(crtAt, + crtAt + vs.ncol * cx, + vs.ncol * (nrow - cx) * + CHR); + fillw((vs.at << 8) | ' ', crtAt, + vs.ncol * cx); + vs.state = 0; + break; + } + case 'T': { /* scroll down cx lines */ + int cx = vs.cx; + if (cx <= 0) + cx = 1; + else if (cx > vs.nrow) + cx = vs.nrow; + if (cx < vs.nrow) + bcopy(Crtat, + Crtat + vs.ncol * cx, + vs.ncol * (vs.nrow - cx) * + CHR); + fillw((vs.at << 8) | ' ', Crtat, + vs.ncol * cx); + /* crtat += vs.ncol * cx; /* XXX */ + vs.state = 0; + break; + } + case ';': /* Switch params in cursor def */ + vs.state = VSS_EPARAM; + break; + case 'r': + vs.so_at = (vs.cx & FG_MASK) | + ((vs.cy << 4) & BG_MASK); + vs.state = 0; + break; + case 'x': /* set attributes */ + switch (vs.cx) { + case 0: + vs.at = FG_LIGHTGREY | BG_BLACK; + break; + case 1: + /* ansi background */ + if (!vs.color) + break; + vs.at &= FG_MASK; + vs.at |= bgansitopc[vs.cy & 7]; + break; + case 2: + /* ansi foreground */ + if (!vs.color) + break; + vs.at &= BG_MASK; + vs.at |= fgansitopc[vs.cy & 7]; + break; + case 3: + /* pc text attribute */ + if (vs.state >= VSS_EPARAM) + vs.at = vs.cy; + break; + } + vs.state = 0; + break; + + default: /* Only numbers valid here */ + if ((c >= '0') && (c <= '9')) { + if (vs.state >= VSS_EPARAM) { + vs.cy *= 10; + vs.cy += c - '0'; + } else { + vs.cx *= 10; + vs.cx += c - '0'; + } + } else + vs.state = 0; + break; + } + break; + } + } + if (scroll) { + scroll = 0; + /* scroll check */ + if (crtat >= Crtat + vs.nchr) { + if (!kernel) { + int s = spltty(); + if (lock_state & KB_SCROLL) + tsleep((caddr_t)&lock_state, + PUSER, "pcputc", 0); + splx(s); + } + bcopy(Crtat + vs.ncol, Crtat, + (vs.nchr - vs.ncol) * CHR); + fillw((vs.at << 8) | ' ', + Crtat + vs.nchr - vs.ncol, vs.ncol); + crtat -= vs.ncol; + } + } + } + async_update(); +} + +static keymap_t scan_codes[KB_NUM_KEYS] = { +/* type unshift shift control altgr shift_altgr scancode */ + KB_NONE, "", "", "", "", "", /* 0 unused */ + KB_ASCII, "\033", "\033", "\033", "", "", /* 1 ESCape */ + KB_ASCII, "1", "!", "!", "", "", /* 2 1 */ + KB_ASCII, "2", "@", "\000", "", "", /* 3 2 */ + KB_ASCII, "3", "#", "#", "", "", /* 4 3 */ + KB_ASCII, "4", "$", "$", "", "", /* 5 4 */ + KB_ASCII, "5", "%", "%", "", "", /* 6 5 */ + KB_ASCII, "6", "^", "\036", "", "", /* 7 6 */ + KB_ASCII, "7", "&", "&", "", "", /* 8 7 */ + KB_ASCII, "8", "*", "\010", "", "", /* 9 8 */ + KB_ASCII, "9", "(", "(", "", "", /* 10 9 */ + KB_ASCII, "0", ")", ")", "", "", /* 11 0 */ + KB_ASCII, "-", "_", "\037", "", "", /* 12 - */ + KB_ASCII, "=", "+", "+", "", "", /* 13 = */ + KB_ASCII, "\177", "\177", "\010", "", "", /* 14 backspace */ + KB_ASCII, "\t", "\t", "\t", "", "", /* 15 tab */ + KB_ASCII, "q", "Q", "\021", "", "", /* 16 q */ + KB_ASCII, "w", "W", "\027", "", "", /* 17 w */ + KB_ASCII, "e", "E", "\005", "", "", /* 18 e */ + KB_ASCII, "r", "R", "\022", "", "", /* 19 r */ + KB_ASCII, "t", "T", "\024", "", "", /* 20 t */ + KB_ASCII, "y", "Y", "\031", "", "", /* 21 y */ + KB_ASCII, "u", "U", "\025", "", "", /* 22 u */ + KB_ASCII, "i", "I", "\011", "", "", /* 23 i */ + KB_ASCII, "o", "O", "\017", "", "", /* 24 o */ + KB_ASCII, "p", "P", "\020", "", "", /* 25 p */ + KB_ASCII, "[", "{", "\033", "", "", /* 26 [ */ + KB_ASCII, "]", "}", "\035", "", "", /* 27 ] */ + KB_ASCII, "\r", "\r", "\n", "", "", /* 28 return */ + KB_CTL, "", "", "", "", "", /* 29 control */ + KB_ASCII, "a", "A", "\001", "", "", /* 30 a */ + KB_ASCII, "s", "S", "\023", "", "", /* 31 s */ + KB_ASCII, "d", "D", "\004", "", "", /* 32 d */ + KB_ASCII, "f", "F", "\006", "", "", /* 33 f */ + KB_ASCII, "g", "G", "\007", "", "", /* 34 g */ + KB_ASCII, "h", "H", "\010", "", "", /* 35 h */ + KB_ASCII, "j", "J", "\n", "", "", /* 36 j */ + KB_ASCII, "k", "K", "\013", "", "", /* 37 k */ + KB_ASCII, "l", "L", "\014", "", "", /* 38 l */ + KB_ASCII, ";", ":", ";", "", "", /* 39 ; */ + KB_ASCII, "'", "\"", "'", "", "", /* 40 ' */ + KB_ASCII, "`", "~", "`", "", "", /* 41 ` */ + KB_SHIFT, "", "", "", "", "", /* 42 shift */ + KB_ASCII, "\\", "|", "\034", "", "", /* 43 \ */ + KB_ASCII, "z", "Z", "\032", "", "", /* 44 z */ + KB_ASCII, "x", "X", "\030", "", "", /* 45 x */ + KB_ASCII, "c", "C", "\003", "", "", /* 46 c */ + KB_ASCII, "v", "V", "\026", "", "", /* 47 v */ + KB_ASCII, "b", "B", "\002", "", "", /* 48 b */ + KB_ASCII, "n", "N", "\016", "", "", /* 49 n */ + KB_ASCII, "m", "M", "\r", "", "", /* 50 m */ + KB_ASCII, ",", "<", "<", "", "", /* 51 , */ + KB_ASCII, ".", ">", ">", "", "", /* 52 . */ + KB_ASCII, "/", "?", "\037", "", "", /* 53 / */ + KB_SHIFT, "", "", "", "", "", /* 54 shift */ + KB_KP, "*", "*", "*", "", "", /* 55 kp * */ + KB_ALT, "", "", "", "", "", /* 56 alt */ + KB_ASCII, " ", " ", "\000", "", "", /* 57 space */ + KB_CAPS, "", "", "", "", "", /* 58 caps */ + KB_FUNC, "\033[M", "\033[Y", "\033[k", "", "", /* 59 f1 */ + KB_FUNC, "\033[N", "\033[Z", "\033[l", "", "", /* 60 f2 */ + KB_FUNC, "\033[O", "\033[a", "\033[m", "", "", /* 61 f3 */ + KB_FUNC, "\033[P", "\033[b", "\033[n", "", "", /* 62 f4 */ + KB_FUNC, "\033[Q", "\033[c", "\033[o", "", "", /* 63 f5 */ + KB_FUNC, "\033[R", "\033[d", "\033[p", "", "", /* 64 f6 */ + KB_FUNC, "\033[S", "\033[e", "\033[q", "", "", /* 65 f7 */ + KB_FUNC, "\033[T", "\033[f", "\033[r", "", "", /* 66 f8 */ + KB_FUNC, "\033[U", "\033[g", "\033[s", "", "", /* 67 f9 */ + KB_FUNC, "\033[V", "\033[h", "\033[t", "", "", /* 68 f10 */ + KB_NUM, "", "", "", "", "", /* 69 num lock */ + KB_SCROLL, "", "", "", "", "", /* 70 scroll lock */ + KB_KP, "7", "\033[H", "7", "", "", /* 71 kp 7 */ + KB_KP, "8", "\033[A", "8", "", "", /* 72 kp 8 */ + KB_KP, "9", "\033[I", "9", "", "", /* 73 kp 9 */ + KB_KP, "-", "-", "-", "", "", /* 74 kp - */ + KB_KP, "4", "\033[D", "4", "", "", /* 75 kp 4 */ + KB_KP, "5", "\033[E", "5", "", "", /* 76 kp 5 */ + KB_KP, "6", "\033[C", "6", "", "", /* 77 kp 6 */ + KB_KP, "+", "+", "+", "", "", /* 78 kp + */ + KB_KP, "1", "\033[F", "1", "", "", /* 79 kp 1 */ + KB_KP, "2", "\033[B", "2", "", "", /* 80 kp 2 */ + KB_KP, "3", "\033[G", "3", "", "", /* 81 kp 3 */ + KB_KP, "0", "\033[L", "0", "", "", /* 82 kp 0 */ + KB_KP, ",", "\177", ",", "", "", /* 83 kp , */ + KB_NONE, "", "", "", "", "", /* 84 0 */ + KB_NONE, "", "", "", "", "", /* 85 0 */ + KB_NONE, "", "", "", "", "", /* 86 0 */ + KB_FUNC, "\033[W", "\033[i", "\033[u", "", "", /* 87 f11 */ + KB_FUNC, "\033[X", "\033[j", "\033[v", "", "", /* 88 f12 */ + KB_NONE, "", "", "", "", "", /* 89 0 */ + KB_NONE, "", "", "", "", "", /* 90 0 */ + KB_NONE, "", "", "", "", "", /* 91 0 */ + KB_NONE, "", "", "", "", "", /* 92 0 */ + KB_NONE, "", "", "", "", "", /* 93 0 */ + KB_NONE, "", "", "", "", "", /* 94 0 */ + KB_NONE, "", "", "", "", "", /* 95 0 */ + KB_NONE, "", "", "", "", "", /* 96 0 */ + KB_NONE, "", "", "", "", "", /* 97 0 */ + KB_NONE, "", "", "", "", "", /* 98 0 */ + KB_NONE, "", "", "", "", "", /* 99 0 */ + KB_NONE, "", "", "", "", "", /* 100 */ + KB_NONE, "", "", "", "", "", /* 101 */ + KB_NONE, "", "", "", "", "", /* 102 */ + KB_NONE, "", "", "", "", "", /* 103 */ + KB_NONE, "", "", "", "", "", /* 104 */ + KB_NONE, "", "", "", "", "", /* 105 */ + KB_NONE, "", "", "", "", "", /* 106 */ + KB_NONE, "", "", "", "", "", /* 107 */ + KB_NONE, "", "", "", "", "", /* 108 */ + KB_NONE, "", "", "", "", "", /* 109 */ + KB_NONE, "", "", "", "", "", /* 110 */ + KB_NONE, "", "", "", "", "", /* 111 */ + KB_NONE, "", "", "", "", "", /* 112 */ + KB_NONE, "", "", "", "", "", /* 113 */ + KB_NONE, "", "", "", "", "", /* 114 */ + KB_NONE, "", "", "", "", "", /* 115 */ + KB_NONE, "", "", "", "", "", /* 116 */ + KB_NONE, "", "", "", "", "", /* 117 */ + KB_NONE, "", "", "", "", "", /* 118 */ + KB_NONE, "", "", "", "", "", /* 119 */ + KB_NONE, "", "", "", "", "", /* 120 */ + KB_NONE, "", "", "", "", "", /* 121 */ + KB_NONE, "", "", "", "", "", /* 122 */ + KB_NONE, "", "", "", "", "", /* 123 */ + KB_NONE, "", "", "", "", "", /* 124 */ + KB_NONE, "", "", "", "", "", /* 125 */ + KB_NONE, "", "", "", "", "", /* 126 */ + KB_NONE, "", "", "", "", "" /* 127 */ +}; + +/* + * Get characters from the keyboard. If none are present, return NULL. + */ +char * +sget() +{ + u_char dt; + static u_char extended = 0, shift_state = 0; + static u_char capchar[2]; + +top: + KBD_DELAY; + dt = inb(KBDATAP); + + switch (dt) { + case KBR_ACK: case KBR_ECHO: + kb_oq_get = (kb_oq_get + 1) & 7; + if(kb_oq_get != kb_oq_put) { + outb(KBOUTP, kb_oq[kb_oq_get]); + } + goto loop; + case KBR_RESEND: + outb(KBOUTP, kb_oq[kb_oq_get]); + goto loop; + } + + if (pc_xmode > 0) { +#if defined(DDB) && defined(XSERVER_DDB) + /* F12 enters the debugger while in X mode */ + if (dt == 88) + Debugger(); +#endif + capchar[0] = dt; + capchar[1] = 0; + /* + * Check for locking keys. + * + * XXX Setting the LEDs this way is a bit bogus. What if the + * keyboard has been remapped in X? + */ + switch (scan_codes[dt & 0x7f].type) { + case KB_NUM: + if (dt & 0x80) { + shift_state &= ~KB_NUM; + break; + } + if (shift_state & KB_NUM) + break; + shift_state |= KB_NUM; + lock_state ^= KB_NUM; + async_update(); + break; + case KB_CAPS: + if (dt & 0x80) { + shift_state &= ~KB_CAPS; + break; + } + if (shift_state & KB_CAPS) + break; + shift_state |= KB_CAPS; + lock_state ^= KB_CAPS; + async_update(); + break; + case KB_SCROLL: + if (dt & 0x80) { + shift_state &= ~KB_SCROLL; + break; + } + if (shift_state & KB_SCROLL) + break; + shift_state |= KB_SCROLL; + lock_state ^= KB_SCROLL; + if ((lock_state & KB_SCROLL) == 0) + wakeup((caddr_t)&lock_state); + async_update(); + break; + } + return capchar; + } + + switch (dt) { + case KBR_EXTENDED: + extended = 1; + goto loop; + } + +#ifdef DEBUG + /* + * Check for cntl-alt-esc. + */ + if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) { + mdbpanic(); + dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */ + } +#endif + + /* + * Check for make/break. + */ + if (dt & 0x80) { + /* + * break + */ + dt &= 0x7f; + switch (scan_codes[dt].type) { + case KB_NUM: + shift_state &= ~KB_NUM; + break; + case KB_CAPS: + shift_state &= ~KB_CAPS; + break; + case KB_SCROLL: + shift_state &= ~KB_SCROLL; + break; + case KB_SHIFT: + shift_state &= ~KB_SHIFT; + break; + case KB_ALT: + if (extended) + shift_state &= ~KB_ALTGR; + else + shift_state &= ~KB_ALT; + break; + case KB_CTL: + shift_state &= ~KB_CTL; + break; + } + } else { + /* + * make + */ + switch (scan_codes[dt].type) { + /* + * locking keys + */ + case KB_NUM: + if (shift_state & KB_NUM) + break; + shift_state |= KB_NUM; + lock_state ^= KB_NUM; + async_update(); + break; + case KB_CAPS: + if (shift_state & KB_CAPS) + break; + shift_state |= KB_CAPS; + lock_state ^= KB_CAPS; + async_update(); + break; + case KB_SCROLL: + if (shift_state & KB_SCROLL) + break; + shift_state |= KB_SCROLL; + lock_state ^= KB_SCROLL; + if ((lock_state & KB_SCROLL) == 0) + wakeup((caddr_t)&lock_state); + async_update(); + break; + /* + * non-locking keys + */ + case KB_SHIFT: + shift_state |= KB_SHIFT; + break; + case KB_ALT: + if (extended) + shift_state |= KB_ALTGR; + else + shift_state |= KB_ALT; + break; + case KB_CTL: + shift_state |= KB_CTL; + break; + case KB_ASCII: + /* control has highest priority */ + if (shift_state & KB_CTL) + capchar[0] = scan_codes[dt].ctl[0]; + else if (shift_state & KB_ALTGR) { + if (shift_state & KB_SHIFT) + capchar[0] = scan_codes[dt].shift_altgr[0]; + else + capchar[0] = scan_codes[dt].altgr[0]; + } + else { + if (shift_state & KB_SHIFT) + capchar[0] = scan_codes[dt].shift[0]; + else + capchar[0] = scan_codes[dt].unshift[0]; + } + if ((lock_state & KB_CAPS) && capchar[0] >= 'a' && + capchar[0] <= 'z') { + capchar[0] -= ('a' - 'A'); + } + capchar[0] |= (shift_state & KB_ALT); + extended = 0; + return capchar; + case KB_NONE: +printf("keycode %d\n",dt); + break; + case KB_FUNC: { + char *more_chars; + if (shift_state & KB_SHIFT) + more_chars = scan_codes[dt].shift; + else if (shift_state & KB_CTL) + more_chars = scan_codes[dt].ctl; + else + more_chars = scan_codes[dt].unshift; + extended = 0; + return more_chars; + } + case KB_KP: { + char *more_chars; + if (shift_state & (KB_SHIFT | KB_CTL) || + (lock_state & KB_NUM) == 0 || extended) + more_chars = scan_codes[dt].shift; + else + more_chars = scan_codes[dt].unshift; + extended = 0; + return more_chars; + } + } + } + + extended = 0; +loop: + if ((inb(KBSTATP) & KBS_DIB) == 0) + return 0; + goto top; +} + +int +pcmmap(dev, offset, nprot) + dev_t dev; + int offset; + int nprot; +{ + + if (offset >= 0xa0000 && offset < 0xc0000) + return pica_btop(PICA_P_LOCAL_VIDEO + offset); + if (offset >= 0x0000 && offset < 0x10000) + return pica_btop(PICA_P_LOCAL_VIDEO_CTRL + offset); + if (offset >= 0x40000000 && offset < 0x40800000) + return pica_btop(PICA_P_LOCAL_VIDEO + offset - 0x40000000); + return -1; +} + +pc_xmode_on() +{ + if (pc_xmode) + return; + pc_xmode = 1; + +#ifdef XFREE86_BUG_COMPAT + /* If still unchanged, get current shape. */ + if (cursor_shape == 0xffff) + get_cursor_shape(); +#endif +} + +pc_xmode_off() +{ + if (pc_xmode == 0) + return; + pc_xmode = 0; + +#ifdef XFREE86_BUG_COMPAT + /* XXX It would be hard to justify why the X server doesn't do this. */ + set_cursor_shape(); +#endif + async_update(); +} +/* $NetBSD: pms.c,v 1.21 1995/04/18 02:25:18 mycroft Exp $ */ + +#include <machine/mouse.h> + +/* status bits */ +#define PMS_OBUF_FULL 0x01 +#define PMS_IBUF_FULL 0x02 + +/* controller commands */ +#define PMS_INT_ENABLE 0x47 /* enable controller interrupts */ +#define PMS_INT_DISABLE 0x65 /* disable controller interrupts */ +#define PMS_AUX_ENABLE 0xa7 /* enable auxiliary port */ +#define PMS_AUX_DISABLE 0xa8 /* disable auxiliary port */ +#define PMS_MAGIC_1 0xa9 /* XXX */ + +#define PMS_8042_CMD 0x65 + +/* mouse commands */ +#define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */ +#define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */ +#define PMS_SET_RES 0xe8 /* set resolution */ +#define PMS_GET_SCALE 0xe9 /* get scaling factor */ +#define PMS_SET_STREAM 0xea /* set streaming mode */ +#define PMS_SET_SAMPLE 0xf3 /* set sampling rate */ +#define PMS_DEV_ENABLE 0xf4 /* mouse on */ +#define PMS_DEV_DISABLE 0xf5 /* mouse off */ +#define PMS_RESET 0xff /* reset */ + +#define PMS_CHUNK 128 /* chunk size for read */ +#define PMS_BSIZE 1020 /* buffer size */ + + +static inline void +pms_dev_cmd(value) + u_char value; +{ + kbd_flush_input(); + outb(KBCMDP, 0xd4); + kbd_flush_input(); + outb(KBDATAP, value); +} + +static inline void +pms_aux_cmd(value) + u_char value; +{ + kbd_flush_input(); + outb(KBCMDP, value); +} + +static inline void +pms_pit_cmd(value) + u_char value; +{ + kbd_flush_input(); + outb(KBCMDP, 0x60); + kbd_flush_input(); + outb(KBDATAP, value); +} + +int +pmsprobe(parent, probe, aux) + struct device *parent; + void *probe, *aux; +{ + struct confargs *ca = aux; + u_char x; + + /* Make shure we're looking for this type of device */ + if(!BUS_MATCHNAME(ca, "pms")) + return(0); + + pms_dev_cmd(KBC_RESET); + pms_aux_cmd(PMS_MAGIC_1); + delay(10000); + x = inb(KBDATAP); + pms_pit_cmd(PMS_INT_DISABLE); + if (x & 0x04) + return 0; + + return 1; +} + +void +pmsattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pms_softc *sc = (void *)self; + struct confargs *ca = aux; + + printf("\n"); + + /* Other initialization was done by pmsprobe. */ + sc->sc_state = 0; + + BUS_INTR_ESTABLISH(ca, pmsintr, (void *)(long)sc); +} + +int +pmsopen(dev, flag) + dev_t dev; + int flag; +{ + int unit = PMSUNIT(dev); + struct pms_softc *sc; + + if (unit >= pms_cd.cd_ndevs) + return ENXIO; + sc = pms_cd.cd_devs[unit]; + if (!sc) + return ENXIO; + + if (sc->sc_state & PMS_OPEN) + return EBUSY; + + if (clalloc(&sc->sc_q, PMS_BSIZE, 0) == -1) + return ENOMEM; + + sc->sc_state |= PMS_OPEN; + sc->sc_status = 0; + sc->sc_x = sc->sc_y = 0; + + /* Enable interrupts. */ + pms_dev_cmd(PMS_DEV_ENABLE); + pms_aux_cmd(PMS_AUX_ENABLE); + pms_dev_cmd(PMS_SET_RES); + pms_dev_cmd(3); /* 8 counts/mm */ + pms_dev_cmd(PMS_SET_SCALE21); +#if 0 + pms_dev_cmd(PMS_SET_SAMPLE); + pms_dev_cmd(100); /* 100 samples/sec */ + pms_dev_cmd(PMS_SET_STREAM); +#endif + pms_pit_cmd(PMS_INT_ENABLE); + + return 0; +} + +int +pmsclose(dev, flag) + dev_t dev; + int flag; +{ + struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)]; + + /* Disable interrupts. */ + pms_dev_cmd(PMS_DEV_DISABLE); + pms_pit_cmd(PMS_INT_DISABLE); + pms_aux_cmd(PMS_AUX_DISABLE); + + sc->sc_state &= ~PMS_OPEN; + + clfree(&sc->sc_q); + + return 0; +} + +int +pmsread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)]; + int s; + int error; + size_t length; + u_char buffer[PMS_CHUNK]; + + /* Block until mouse activity occured. */ + + s = spltty(); + while (sc->sc_q.c_cc == 0) { + if (flag & IO_NDELAY) { + splx(s); + return EWOULDBLOCK; + } + sc->sc_state |= PMS_ASLP; + if (error = tsleep((caddr_t)sc, PZERO | PCATCH, "pmsrea", 0)) { + sc->sc_state &= ~PMS_ASLP; + splx(s); + return error; + } + } + splx(s); + + /* Transfer as many chunks as possible. */ + + while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) { + length = min(sc->sc_q.c_cc, uio->uio_resid); + if (length > sizeof(buffer)) + length = sizeof(buffer); + + /* Remove a small chunk from the input queue. */ + (void) q_to_b(&sc->sc_q, buffer, length); + + /* Copy the data to the user process. */ + if (error = uiomove(buffer, length, uio)) + break; + } + + return error; +} + +int +pmsioctl(dev, cmd, addr, flag) + dev_t dev; + u_long cmd; + caddr_t addr; + int flag; +{ + struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)]; + struct mouseinfo info; + int s; + int error; + + switch (cmd) { + case MOUSEIOCREAD: + s = spltty(); + + info.status = sc->sc_status; + if (sc->sc_x || sc->sc_y) + info.status |= MOVEMENT; + + if (sc->sc_x > 127) + info.xmotion = 127; + else if (sc->sc_x < -127) + /* Bounding at -127 avoids a bug in XFree86. */ + info.xmotion = -127; + else + info.xmotion = sc->sc_x; + + if (sc->sc_y > 127) + info.ymotion = 127; + else if (sc->sc_y < -127) + info.ymotion = -127; + else + info.ymotion = sc->sc_y; + + /* Reset historical information. */ + sc->sc_x = sc->sc_y = 0; + sc->sc_status &= ~BUTCHNGMASK; + ndflush(&sc->sc_q, sc->sc_q.c_cc); + + splx(s); + error = copyout(&info, addr, sizeof(struct mouseinfo)); + break; + + default: + error = EINVAL; + break; + } + + return error; +} + +/* Masks for the first byte of a packet */ +#define PS2LBUTMASK 0x01 +#define PS2RBUTMASK 0x02 +#define PS2MBUTMASK 0x04 + +int +pmsintr(arg) + void *arg; +{ + struct pms_softc *sc = arg; + static int state = 0; + static u_char buttons; + u_char changed; + u_char mbutt; + static char dx, dy; + u_char buffer[5]; + + if ((sc->sc_state & PMS_OPEN) == 0) { + /* Interrupts are not expected. Discard the byte. */ + kbd_flush_input(); + return 0; + } + + switch (state) { + + case 0: + buttons = inb(KBDATAP); + if ((buttons & 0xc0) == 0) + ++state; + break; + + case 1: + dx = inb(KBDATAP); + /* Bounding at -127 avoids a bug in XFree86. */ + dx = (dx == -128) ? -127 : dx; + ++state; + break; + + case 2: + dy = inb(KBDATAP); + dy = (dy == -128) ? -127 : dy; + state = 0; + + mbutt = buttons; + buttons = ((buttons & PS2LBUTMASK) << 2) | + ((buttons & (PS2RBUTMASK | PS2MBUTMASK)) >> 1); + changed = ((buttons ^ sc->sc_status) & BUTSTATMASK) << 3; + sc->sc_status = buttons | (sc->sc_status & ~BUTSTATMASK) | changed; + + if (dx || dy || changed) { + /* Update accumulated movements. */ + sc->sc_x += dx; + sc->sc_y += dy; + + /* Add this event to the queue. */ + buffer[0] = 0x80 | (mbutt & BUTSTATMASK); + if(dx < 0) + buffer[0] |= 0x10; + buffer[1] = dx & 0x7f; + if(dy < 0) + buffer[0] |= 0x20; + buffer[2] = dy & 0x7f; + buffer[3] = buffer[4] = 0; + (void) b_to_q(buffer, sizeof buffer, &sc->sc_q); + + if (sc->sc_state & PMS_ASLP) { + sc->sc_state &= ~PMS_ASLP; + wakeup((caddr_t)sc); + } + selwakeup(&sc->sc_rsel); + } + + break; + } + + return -1; +} + +int +pmsselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)]; + int s; + int ret; + + if (rw == FWRITE) + return 0; + + s = spltty(); + if (!sc->sc_q.c_cc) { + selrecord(p, &sc->sc_rsel); + ret = 0; + } else + ret = 1; + splx(s); + + return ret; +} diff --git a/sys/arch/arc/dev/scsi.h b/sys/arch/arc/dev/scsi.h new file mode 100644 index 00000000000..963617add65 --- /dev/null +++ b/sys/arch/arc/dev/scsi.h @@ -0,0 +1,559 @@ +/* $OpenBSD: scsi.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)scsi.h 8.1 (Berkeley) 6/10/93 + * $Id: scsi.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ + * + * scsi.h -- + * + * Common declarations for SCSI command formaters. This file only covers + * definitions pertaining to the SCSI common command set that are + * common to all SCSI device types (ie disk, tapes, WORM, printers, etc). + * Some of the references from the proceedings of the + * 1984 Mini/Micro Northeast conference might help in understanding SCSI. + * + * from: Header: /sprite/src/kernel/dev/RCS/scsi.h, + * v 9.1 90/02/13 23:11:24 jhh Exp SPRITE (Berkeley) + * $Id: scsi.h,v 1.1 1996/06/24 09:07:19 pefo Exp $ + */ + +#ifndef _SCSI_H +#define _SCSI_H + +/* + * "Standard" SCSI Commands. + * SCSI commands are divided into 8 groups as follows: + * Group0 (0x00 - 0x1f). Basic commands. 6 bytes long + * Group1 (0x20 - 0x3f). Extended command. 10 bytes. + * Group2 (0x40 - 0x5f). Reserved. + * Group2 (0x60 - 0x7f). Reserved. + * Group2 (0x80 - 0x9f). Reserved. + * Group2 (0xa0 - 0xbf). Reserved. + * Group6 (0xc0 - 0xdf). Vendor Unique + * Group7 (0xe0 - 0xff). Vendor Unique + */ + +/* + * Scsi Group0 commands all are 6 bytes and have a format according to + * struct ScsiGroup0Cmd. + */ +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REZERO_UNIT 0x01 +#define SCSI_REWIND 0x01 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_READ_BLOCK_LIMITS 0x05 +#define SCSI_REASSIGN_BLOCKS 0x07 +#define SCSI_READ 0x08 +#define SCSI_WRITE 0x0a +#define SCSI_SEEK 0x0b +#define SCSI_TRACK_SELECT 0x0b +#define SCSI_READ_REVERSE 0x0f +#define SCSI_WRITE_EOF 0x10 +#define SCSI_SPACE 0x11 +#define SCSI_INQUIRY 0x12 +#define SCSI_VERIFY 0x13 +#define SCSI_READ_BUFFER 0x14 +#define SCSI_MODE_SELECT 0x15 +#define SCSI_RESERVE_UNIT 0x16 +#define SCSI_RELEASE_UNIT 0x17 +#define SCSI_COPY 0x18 +#define SCSI_ERASE_TAPE 0x19 +#define SCSI_MODE_SENSE 0x1a +#define SCSI_START_STOP 0x1b +#define SCSI_LOAD_UNLOAD 0x1b +#define SCSI_RECV_DIAG_RESULTS 0x1c +#define SCSI_SEND_DIAGNOSTIC 0x1d +#define SCSI_PREVENT_ALLOW 0x1e + +/* + * Group1 commands are all 10 bytes and have a format according to + * struct ScsiGroup1Cmd. + */ +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_EXT 0x28 +#define SCSI_WRITE_EXT 0x2a +#define SCSI_SEEK_EXT 0x2b +#define SCSI_WRITE_VERIFY 0x2e +#define SCSI_VERIFY_EXT 0x2f +#define SCSI_SEARCH_HIGH 0x30 +#define SCSI_SEARCH_EQUAL 0x31 +#define SCSI_SEARCH_LOW 0x32 +#define SCSI_SET_LIMITS 0x33 +#define SCSI_COMPARE 0x39 +#define SCSI_COPY_VERIFY 0x3a + +/* + * Control byte flags for Group0 and Group1 commands. + * + * SCSI_CTRL_LINK - This is used to prevent a bus free phase between commands. + * If the command terminates successfully, a SCSI_LINKED_CMD_COMPLETE + * message is returned instead of the normal SCSI_COMMAND_COMPLETE message. * The last command in a chain should not have this bit set + * (and consequently gets a normal SCSI_COMMAND_COMPLETE message). + * SCSI_CTRL_LINK_FLAG - This bit should only set when SCSI_CTRL_LINK is set and + * causes a SCSI_LINKED_FLAGED_CMD_COMPLETE to be returned instead of + * a SCSI_LINKED_CMD_COMPLETE. + */ +#define SCSI_CTRL_LINK 0x01 /* Link commands (no bus free phase) */ +#define SCSI_CTRL_LINK_INTR 0x02 /* Interrupt after linked command */ + +/* + * The standard group0 6-byte SCSI control block. Note that the + * fields between highAddr and blockCount inclusive are command dependent. + * The definitions Addr and BlockCount cover most of the commands we will + * use. + */ +typedef struct ScsiGroup0Cmd { + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ +#if BYTE_ORDER == BIG_ENDIAN + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char highAddr :5; /* High bits of address */ +#else + u_char highAddr :5; /* High bits of address */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ +#endif + u_char midAddr; /* Middle bits of address */ + u_char lowAddr; /* Low bits of address */ + u_char blockCount; /* Blocks to transfer */ + u_char control; /* See flags for common bits */ +} ScsiGroup0Cmd; + +/* + * Format of a SCSI_START_STOP command. This is a group 0 command, but + * the command contents are different. + */ +typedef struct ScsiStartStopCmd { +#if BYTE_ORDER == BIG_ENDIAN + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char pad1 :4; /* Reserved */ + u_char immed :1; /* Immediate status bit */ + u_char pad2; /* Reserved */ + u_char pad3; /* Reserved */ + u_char pad4 :6; /* Reserved */ + u_char loadEject :1; /* Load or eject medium */ + u_char start :1; /* Start or stop medium */ + u_char control; /* See flags for common bits */ +#else + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ + u_char immed :1; /* Immediate status bit */ + u_char pad1 :4; /* Reserved */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char pad2; /* Reserved */ + u_char pad3; /* Reserved */ + u_char start :1; /* Start or stop medium */ + u_char loadEject :1; /* Load or eject medium */ + u_char pad4 :6; /* Reserved */ + u_char control; /* See flags for common bits */ +#endif +} ScsiStartStopCmd; + +/* + * The standard group1 10-byte SCSI control block. Note that the + * fields between highAddr and blockCount inclusive are command dependent. + * The definitions Addr and BlockCount cover most of the commands we will + * use. + */ +typedef struct ScsiGroup1Cmd { + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ +#if BYTE_ORDER == BIG_ENDIAN + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char pad1 :5; /* Reserved */ +#else + u_char pad1 :5; /* Reserved */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ +#endif + u_char highAddr; /* High bits of address */ + u_char midHighAddr; /* Middle high bits of address */ + u_char midLowAddr; /* Middle low bits of address */ + u_char lowAddr; /* Low bits of address */ + u_char pad2; /* Reserved */ + u_char highBlockCount; /* High bits of blocks to transfer */ + u_char lowBlockCount; /* Low bits of blocks to transfer */ + u_char control; /* See flags for common bits */ +} ScsiGroup1Cmd; + +/* + * SCSI status completion information. + * This is returned by the device when a command completes. + */ +#define SCSI_STATUS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */ +#define SCSI_STATUS_CONDMET 0x04 /* Condition Met (ie., search worked) */ +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMED 0x10 /* Intermediate status sent */ +#define SCSI_STATUS_EXT 0x80 /* Extended status valid */ + +/* + * Sense information provided after some errors. This is divided into + * two kinds, classes 0-6, and class 7. This is 30 bytes big to allow + * for the drive specific sense bytes that follow the standard 4 byte header. + * + * For extended sense, this buffer may be cast into another type. Also + * The actual size of the sense data returned is used to detect what + * kind of tape drive is out there. Kludgy, but true. + */ +typedef struct ScsiClass0Sense { +#if BYTE_ORDER == BIG_ENDIAN + u_char valid :1; /* Sense data is valid */ + u_char error :7; /* 3 bits class and 4 bits code */ +#else + u_char error :7; /* 3 bits class and 4 bits code */ + u_char valid :1; /* Sense data is valid */ +#endif + u_char highAddr; /* High byte of block address */ + u_char midAddr; /* Middle byte of block address */ + u_char lowAddr; /* Low byte of block address */ + u_char sense[26]; /* Target specific sense data */ +} ScsiClass0Sense; + +/* + * Definitions for errors in the sense data. The error field is specified + * as a 3 bit class and 4 bit code, but it is easier to treat it as a + * single 7 bit field. + */ +#define SCSI_NO_SENSE_DATA 0x00 +#define SCSI_NOT_READY 0x04 +#define SCSI_NOT_LOADED 0x09 +#define SCSI_INSUF_CAPACITY 0x0a +#define SCSI_HARD_DATA_ERROR 0x11 +#define SCSI_WRITE_PROTECT 0x17 +#define SCSI_CORRECTABLE_ERROR 0x18 +#define SCSI_FILE_MARK 0x1c +#define SCSI_INVALID_COMMAND 0x20 +#define SCSI_UNIT_ATTENTION 0x30 +#define SCSI_END_OF_MEDIA 0x34 + +/* + * The standard "extended" sense data returned by SCSI devices. This + * has an error field of 0x70, for a "class 7" error. + */ +typedef struct ScsiClass7Sense { +#if BYTE_ORDER == BIG_ENDIAN + u_char valid :1; /* Sense data is valid */ + u_char error7 :7; /* == 0x70 */ + u_char pad1; /* Also "segment number" for copy */ + u_char fileMark :1; /* File mark on device */ + u_char endOfMedia :1; /* End of media reached */ + u_char badBlockLen :1; /* Block length mis-match (Exabyte) */ + u_char pad2 :1; + u_char key :4; /* Sense keys defined below */ + u_char info1; /* Information byte 1 */ + u_char info2; /* Information byte 2 */ + u_char info3; /* Information byte 3 */ + u_char info4; /* Information byte 4 */ + u_char length; /* Number of additional info bytes */ +#else + u_char error7 :7; /* == 0x70 */ + u_char valid :1; /* Sense data is valid */ + u_char pad1; /* Also "segment number" for copy */ + u_char key :4; /* Sense keys defined below */ + u_char pad2 :1; + u_char badBlockLen :1; /* Block length mis-match (Exabyte) */ + u_char endOfMedia :1; /* End of media reached */ + u_char fileMark :1; /* File mark on device */ + u_char info1; /* Information byte 1 */ + u_char info2; /* Information byte 2 */ + u_char info3; /* Information byte 3 */ + u_char info4; /* Information byte 4 */ + u_char length; /* Number of additional info bytes */ +#endif +} ScsiClass7Sense; /* 8 Bytes */ + +/* + * Key values for standardized sense class 7. + */ +#define SCSI_CLASS7_NO_SENSE 0 +#define SCSI_CLASS7_RECOVERABLE 1 +#define SCSI_CLASS7_NOT_READY 2 +#define SCSI_CLASS7_MEDIA_ERROR 3 +#define SCSI_CLASS7_HARDWARE_ERROR 4 +#define SCSI_CLASS7_ILLEGAL_REQUEST 5 + +/* + * These seem to have different meanings to different vendors.... + */ +#define SCSI_CLASS7_MEDIA_CHANGE 6 +#define SCSI_CLASS7_UNIT_ATTN 6 + +#define SCSI_CLASS7_WRITE_PROTECT 7 +#define SCSI_CLASS7_BLANK_CHECK 8 +#define SCSI_CLASS7_VENDOR 9 +#define SCSI_CLASS7_POWER_UP_FAILURE 10 +#define SCSI_CLASS7_ABORT 11 +#define SCSI_CLASS7_EQUAL 12 +#define SCSI_CLASS7_OVERFLOW 13 +#define SCSI_CLASS7_RESERVED_14 14 +#define SCSI_CLASS7_RESERVED_15 15 + +/* + * Data return by the SCSI inquiry command. + */ +typedef struct ScsiInquiryData { +#if BYTE_ORDER == BIG_ENDIAN + u_char type; /* Peripheral Device type. See below. */ + u_char rmb:1; /* Removable Medium bit. */ + u_char qualifier:7; /* Device type qualifier. */ + u_char version; /* Version info. */ + u_char reserved:4; /* reserved. */ + u_char format:4; /* Response format. */ + u_char length; /* length of data returned. */ + u_char reserved2[2]; /* Reserved */ + u_char flags; /* SCSI II flags (see below) */ + u_char vendorID[8]; /* Vendor ID (ASCII) */ + u_char productID[16]; /* Product ID (ASCII) */ + u_char revLevel[4]; /* Revision level (ASCII) */ + u_char revData[8]; /* Revision data (ASCII) */ +#else + u_char type; /* Peripheral Device type. See below. */ + u_char qualifier:7; /* Device type qualifier. */ + u_char rmb:1; /* Removable Medium bit. */ + u_char version; /* Version info. */ + u_char format:4; /* Response format. */ + u_char reserved:4; /* reserved. */ + u_char length; /* length of data returned. */ + u_char reserved2[2]; /* Reserved */ + u_char flags; /* SCSI II flags (see below) */ + u_char vendorID[8]; /* Vendor ID (ASCII) */ + u_char productID[16]; /* Product ID (ASCII) */ + u_char revLevel[4]; /* Revision level (ASCII) */ + u_char revData[8]; /* Revision data (ASCII) */ +#endif +} ScsiInquiryData; + +/* + * The SCSI Peripheral type ID codes as return by the SCSI_INQUIRY command. + * + * SCSI_DISK_TYPE - Direct Access Device. + * SCSI_TAPE_TYPE - Sequential Access Device. + * SCSI_PRINTER_TYPE - Printer Device. + * SCSI_HOST_TYPE - Processor Device. + * SCSI_WORM_TYPE - Write-Once Read-Multiple Device. + * SCSI_ROM_TYPE - Read-Only Direct Access Device. + * SCSI_SCANNER_TYPE - Scanner device. + * SCSI_OPTICAL_MEM_TYPE - Optical memory device. + * SCSI_MEDIUM_CHANGER_TYPE - Medium changer device. + * SCSI_COMMUNICATIONS_TYPE - Communications device. + * SCSI_NODEVICE_TYPE - Logical Unit not present or implemented. + * + * Note that codes 0xa-0x7e are reserved and 0x80-0xff are vendor unique. + */ +#define SCSI_DISK_TYPE 0 +#define SCSI_TAPE_TYPE 1 +#define SCSI_PRINTER_TYPE 2 +#define SCSI_HOST_TYPE 3 +#define SCSI_WORM_TYPE 4 +#define SCSI_ROM_TYPE 5 +#define SCSI_SCANNER_TYPE 6 +#define SCSI_OPTICAL_MEM_TYPE 7 +#define SCSI_MEDIUM_CHANGER_TYPE 8 +#define SCSI_COMMUNICATIONS_TYPE 9 +#define SCSI_NODEVICE_TYPE 0x7f + +/* + * The SCSI I & II inquiry flags. + * + * SCSI_REL_ADR - Relative addressing supported. + * SCSI_WIDE_32 - 32 bit wide SCSI bus transfers supported. + * SCSI_WIDE_16 - 16 bit wide SCSI bus transfers supported. + * SCSI_SYNC - Synchronous data transfers supported. + * SCSI_LINKED - Linked commands supported. + * SCSI_CMD_QUEUE - Tagged command queuing supported. + * SCSI_SOFT_RESET - Soft RESET alternative suported. + */ +#define SCSI_REL_ADR 0x80 +#define SCSI_WIDE_32 0x40 +#define SCSI_WIDE_16 0x20 +#define SCSI_SYNC 0x10 +#define SCSI_LINKED 0x08 +#define SCSI_CMD_QUEUE 0x02 +#define SCSI_SOFT_RESET 0x01 + +/* + * Standard header for SCSI_MODE_SENSE and SCSI_MODE_SELECT commands for tapes. + */ +typedef struct ScsiTapeModeSelectHdr { + u_char len; /* length */ + u_char media; /* media type */ +#if BYTE_ORDER == BIG_ENDIAN + u_char writeprot:1; /* Write protected media */ + u_char bufferedMode:3; /* Type of buffer to be done. */ + u_char speed:4; /* Drive speed. */ +#else + u_char speed:4; /* Drive speed. */ + u_char bufferedMode:3; /* Type of buffer to be done. */ + u_char writeprot:1; /* Write protected media */ +#endif + u_char length; /* Block descriptor length. */ + u_char density; /* tape density code */ + u_char blocks_2; /* number of blocks (MSB) */ + u_char blocks_1; /* number of blocks */ + u_char blocks_0; /* number of blocks (LSB) */ + u_char reserved; /* */ + u_char block_size2; /* Tape block size (MSB) */ + u_char block_size1; /* Tape block size */ + u_char block_size0; /* Tape block size (LSB) */ + u_char vendor[6]; /* vendor specific data */ +} ScsiTapeModeSelectHdr; + +/* + * Definitions of SCSI messages. + * + * SCSI_COMMAND_COMPLETE - After a command has completed, successfully + * or not, this is returned to the host from the target. + * + * SCSI_EXTENDED_MSG - Indicates that a multi-byte message is being sent. + * + * The following messages are used with connect/disconnect: + * SCSI_SAVE_DATA_POINTER - Sent from target to host to request saving + * of current DMA address and count. Indicates a pending dis-connect. + * SCSI_RESTORE_POINTER - Sent from the target to the host to request + * restoring pointers saved before a disconnect + * SCSI_DISCONNECT - Sent from the target to the host to disconnect. + * SCSI_ABORT - Sent from the host to the target to abort current request. + * SCSI_MESSAGE_REJECT - Indicates receipt, by either host or target, of + * an unimplemented message. + * SCSI_NO_OP - Sent from host to target if it has no real message to send. + * SCSI_MESSAGE_PARITY_ERROR - Sent from host to target on message parity error + * SCSI_BUS_RESET - Sent from host to target to reset all current I/O + * + * SCSI_IDENTIFY - The low order two bits of this message type indicate + * the Logical Unit of the Target which is requesting a reconnect. + * SCSI_DIS_REC_IDENTIFY - Sent from the host to a target to indicate + * is supports connect/dis-connect + * + */ +#define SCSI_COMMAND_COMPLETE 0x00 +#define SCSI_EXTENDED_MSG 0x01 +#define SCSI_SAVE_DATA_POINTER 0x02 +#define SCSI_RESTORE_POINTERS 0x03 +#define SCSI_DISCONNECT 0x04 +#define SCSI_ABORT 0x06 +#define SCSI_MESSAGE_REJECT 0x07 +#define SCSI_NO_OP 0x08 +#define SCSI_MESSAGE_PARITY_ERROR 0x09 +#define SCSI_LINKED_CMD_COMPLETE 0x0A +#define SCSI_LINKED_FLAGED_CMD_COMPLETE 0x0B +#define SCSI_BUS_RESET 0x0C + +#define SCSI_IDENTIFY 0x80 +#define SCSI_DIS_REC_IDENTIFY 0xc0 + +/* + * Extended message types (2nd byte of SCSI_EXTENDED_MSG). + */ +#define SCSI_MODIFY_DATA_PTR 0x00 +#define SCSI_SYNCHRONOUS_XFER 0x01 +#define SCSI_EXTENDED_IDENTIFY 0x02 /* only in SCSI I */ +#define SCSI_WIDE_XFER 0x03 + +/* + * Driver ioctl's for various scsi operations. + */ +#ifndef _IOCTL_ +#include <sys/ioctl.h> +#endif + +/* + * Control for SCSI "format" mode. + * + * "Format" mode allows a privileged process to issue direct SCSI + * commands to a drive (it is intended primarily to allow on-line + * formatting). SDIOCSFORMAT with a non-zero arg will put the drive + * into format mode; a zero arg will take it out. When in format + * mode, only the process that issued the SDIOCFORMAT can read or + * write the drive. + * + * In format mode, process is expected to + * - do SDIOCSCSICOMMAND to supply cdb for next SCSI op + * - do read or write as appropriate for cdb + * - if i/o error, optionally do SDIOCSENSE to get completion + * status and sense data from last scsi operation. + */ + +struct scsi_fmt_cdb { + int len; /* cdb length (in bytes) */ + u_char cdb[28]; /* cdb to use on next read/write */ +}; + +struct scsi_fmt_sense { + u_int status; /* completion status of last op */ + u_char sense[32]; /* sense data (if any) from last op */ +}; + +#define SDIOCSFORMAT _IOW('S', 0x1, int) +#define SDIOCGFORMAT _IOR('S', 0x2, int) +#define SDIOCSCSICOMMAND _IOW('S', 0x3, struct scsi_fmt_cdb) +#define SDIOCSENSE _IOR('S', 0x4, struct scsi_fmt_sense) + +#ifdef _KERNEL +/* + * Routines. + */ +extern void scsiGroup0Cmd(); +extern void scsiGroup1Cmd(); +#endif /* _KERNEL */ + +#endif /* _SCSI_H */ diff --git a/sys/arch/arc/include/ansi.h b/sys/arch/arc/include/ansi.h new file mode 100644 index 00000000000..a8ded390579 --- /dev/null +++ b/sys/arch/arc/include/ansi.h @@ -0,0 +1,75 @@ +/* $OpenBSD: ansi.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: ansi.h,v 1.5 1994/10/26 21:09:33 cgd Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)ansi.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _ANSI_H_ +#define _ANSI_H_ + +/* + * Types which are fundamental to the implementation and may appear in + * more than one standard header are defined here. Standard headers + * then use: + * #ifdef _BSD_SIZE_T_ + * typedef _BSD_SIZE_T_ size_t; + * #undef _BSD_SIZE_T_ + * #endif + */ +#define _BSD_CLOCK_T_ unsigned long /* clock() */ +#define _BSD_PTRDIFF_T_ int /* ptr1 - ptr2 */ +#define _BSD_SIZE_T_ unsigned int /* sizeof() */ +#define _BSD_SSIZE_T_ int /* byte count or error */ +#define _BSD_TIME_T_ long /* time() */ +#define _BSD_VA_LIST_ char * /* va_list */ + +/* + * Runes (wchar_t) is declared to be an ``int'' instead of the more natural + * ``unsigned long'' or ``long''. Two things are happening here. It is not + * unsigned so that EOF (-1) can be naturally assigned to it and used. Also, + * it looks like 10646 will be a 31 bit standard. This means that if your + * ints cannot hold 32 bits, you will be in trouble. The reason an int was + * chosen over a long is that the is*() and to*() routines take ints (says + * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you + * lose a bit of ANSI conformance, but your programs will still work. + * + * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t + * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains + * defined for ctype.h. + */ +#define _BSD_WCHAR_T_ int /* wchar_t */ +#define _BSD_RUNE_T_ int /* rune_t */ + +#endif /* _ANSI_H_ */ diff --git a/sys/arch/arc/include/asm.h b/sys/arch/arc/include/asm.h new file mode 100644 index 00000000000..b276c10a1f3 --- /dev/null +++ b/sys/arch/arc/include/asm.h @@ -0,0 +1,160 @@ +/* $OpenBSD: asm.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef _MACHASMDEFS +#define _MACHASMDEFS + +#include <machine/regdef.h> + +#define ABICALLS + +#define RCSID(x) + +#define _C_LABEL(x) x + +/* + * Define -pg profile entry code. + */ +#if defined(GPROF) || defined(PROF) +#define MCOUNT .set noreorder; \ + .set noat; \ + move $1,$31; \ + jal _mcount; \ + subu sp,sp,8; \ + .set reorder; \ + .set at; +#else +#define MCOUNT +#endif + +/* + * LEAF(x) + * + * Declare a leaf routine. + */ +#define LEAF(x) \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, 0, ra; \ + MCOUNT + +/* + * NLEAF(x) + * + * Declare a non-profiled leaf routine. + */ +#define NLEAF(x) \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, 0, ra + +/* + * ALEAF -- declare alternate entry to a leaf routine. + */ +#define ALEAF(x) \ + .globl x; \ +x: + +/* + * NON_LEAF(x) + * + * Declare a non-leaf routine (a routine that makes other C calls). + */ +#define NON_LEAF(x, fsize, retpc) \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, fsize, retpc; \ + MCOUNT + +/* + * NNON_LEAF(x) + * + * Declare a non-profiled non-leaf routine + * (a routine that makes other C calls). + */ +#define NNON_LEAF(x, fsize, retpc) \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, fsize, retpc + +/* + * END(x) + * + * Mark end of a procedure. + */ +#define END(x) \ + .end x + +#define STAND_FRAME_SIZE 24 +#define STAND_RA_OFFSET 20 + +/* + * Macros to panic and printf from assembly language. + */ +#define PANIC(msg) \ + la a0, 9f; \ + jal panic; \ + MSG(msg) + +#define PRINTF(msg) \ + la a0, 9f; \ + jal printf; \ + MSG(msg) + +#define MSG(msg) \ + .rdata; \ +9: .asciiz msg; \ + .text + +#define ASMSTR(str) \ + .asciiz str; \ + .align 3 + +#endif /* _MACHASMDEFS */ diff --git a/sys/arch/arc/include/autoconf.h b/sys/arch/arc/include/autoconf.h new file mode 100644 index 00000000000..650e387012d --- /dev/null +++ b/sys/arch/arc/include/autoconf.h @@ -0,0 +1,79 @@ +/* $OpenBSD: autoconf.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: autoconf.h,v 1.1 1995/02/13 23:07:31 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Machine-dependent structures of autoconfiguration + */ + +#ifndef _ARC_AUTOCONF_H_ +#define _ARC_AUTOCONF_H_ + +struct confargs; + +typedef int (*intr_handler_t) __P((void *)); + +struct abus { + struct device *ab_dv; /* back-pointer to device */ + int ab_type; /* bus type (see below) */ + void (*ab_intr_establish) /* bus's set-handler function */ + __P((struct confargs *, intr_handler_t, void *)); + void (*ab_intr_disestablish) /* bus's unset-handler function */ + __P((struct confargs *)); + caddr_t (*ab_cvtaddr) /* convert slot/offset to address */ + __P((struct confargs *)); + int (*ab_matchname) /* see if name matches driver */ + __P((struct confargs *, char *)); +}; + +#define BUS_MAIN 1 /* mainbus */ +#define BUS_PICA 2 /* PICA Bus */ +#define BUS_ISABR 3 /* ISA Bridge Bus */ + +#define BUS_INTR_ESTABLISH(ca, handler, val) \ + (*(ca)->ca_bus->ab_intr_establish)((ca), (handler), (val)) +#define BUS_INTR_DISESTABLISH(ca) \ + (*(ca)->ca_bus->ab_intr_establish)(ca) +#define BUS_CVTADDR(ca) \ + (*(ca)->ca_bus->ab_cvtaddr)(ca) +#define BUS_MATCHNAME(ca, name) \ + (*(ca)->ca_bus->ab_matchname)((ca), (name)) + +struct confargs { + char *ca_name; /* Device name. */ + int ca_slot; /* Device slot. */ + int ca_offset; /* Offset into slot. */ + struct abus *ca_bus; /* bus device resides on. */ +}; + +void set_clockintr __P((void (*)(struct clockframe *))); +void set_iointr __P((void (*)(void *, int))); +int badaddr __P((void *, u_int64_t)); + +#endif /* _ARC_AUTOCONF_H_ */ diff --git a/sys/arch/arc/include/bus.h b/sys/arch/arc/include/bus.h new file mode 100644 index 00000000000..8f9d234ac15 --- /dev/null +++ b/sys/arch/arc/include/bus.h @@ -0,0 +1,132 @@ +/* $OpenBSD: bus.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: bus.h,v 1.2 1996/04/05 23:59:37 thorpej Exp $ */ + +/* + * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. + * + * 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 Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _ARC_BUS_H_ +#define _ARC_BUS_H_ + +#include <machine/autoconf.h> +#include <machine/pio.h> + +/* + * I/O addresses (in bus space) + */ +typedef u_long bus_io_addr_t; +typedef u_long bus_io_size_t; +typedef u_long bus_io_handle_t; + +/* + * Memory addresses (in bus space) + */ +typedef u_long bus_mem_addr_t; +typedef u_long bus_mem_size_t; +typedef caddr_t bus_mem_handle_t; + +/* + * Access methods for bus resources, I/O space, and memory space. + */ +typedef +struct arc_isa_busmap { + void *isa_io_base; + void *isa_mem_base; +} *bus_chipset_tag_t; + + +#define bus_io_map(t, port, size, iohp) \ + (*iohp = (t == NULL ? port : port + (ulong)(t->isa_io_base)), 0) +#define bus_io_unmap(t, ioh, size) + +#define bus_io_read_1(t, h, o) inb((h) + (o)) +#define bus_io_read_2(t, h, o) inw((h) + (o)) +#define bus_io_read_4(t, h, o) inl((h) + (o)) +#if 0 /* Cause a link error for bus_io_read_8 */ +#define bus_io_read_8(t, h, o) !!! bus_io_read_8 unimplemented !!! +#endif + +#define bus_io_read_multi_1(t, h, o, a, c) \ + insb((h) + (o), (a), (c)) +#define bus_io_read_multi_2(t, h, o, a, c) \ + insw((h) + (o), (a), (c)) +#define bus_io_read_multi_4(t, h, o, a, c) \ + insl((h) + (o), (a), (c)) +#if 0 /* Cause a link error for bus_io_read_multi_8 */ +#define bus_io_read_multi_8(t, h, o, a, c) \ + !!! bus_io_read_multi_8 unimplemented !!! +#endif + +#define bus_io_write_1(t, h, o, v) outb((h) + (o), (v)) +#define bus_io_write_2(t, h, o, v) outw((h) + (o), (v)) +#define bus_io_write_4(t, h, o, v) outl((h) + (o), (v)) +#if 0 /* Cause a link error for bus_io_write_8 */ +#define bus_io_write_8(t, h, o, v) !!! bus_io_write_8 unimplemented !!! +#endif + +#define bus_io_write_multi_1(t, h, o, a, c) \ + outsb((h) + (o), (a), (c)) +#define bus_io_write_multi_2(t, h, o, a, c) \ + outsw((h) + (o), (a), (c)) +#define bus_io_write_multi_4(t, h, o, a, c) \ + outsl((h) + (o), (a), (c)) +#if 0 /* Cause a link error for bus_io_write_multi_8 */ +#define bus_io_write_multi_8(t, h, o, a, c) \ + !!! bus_io_write_multi_8 unimplimented !!! +#endif + +int bus_mem_map __P((bus_chipset_tag_t t, bus_mem_addr_t bpa, + bus_mem_size_t size, int cacheable, bus_mem_handle_t *mhp)); +void bus_mem_unmap __P((bus_chipset_tag_t t, bus_mem_handle_t memh, + bus_mem_size_t size)); + +#define bus_mem_read_1(t, h, o) (*(volatile u_int8_t *)((h) + (o))) +#define bus_mem_read_2(t, h, o) (*(volatile u_int16_t *)((h) + (o))) +#define bus_mem_read_4(t, h, o) (*(volatile u_int32_t *)((h) + (o))) +#define bus_mem_read_8(t, h, o) (*(volatile u_int64_t *)((h) + (o))) + +#define bus_mem_write_1(t, h, o, v) \ + ((void)(*(volatile u_int8_t *)((h) + (o)) = (v))) +#define bus_mem_write_2(t, h, o, v) \ + ((void)(*(volatile u_int16_t *)((h) + (o)) = (v))) +#define bus_mem_write_4(t, h, o, v) \ + ((void)(*(volatile u_int32_t *)((h) + (o)) = (v))) +#define bus_mem_write_8(t, h, o, v) \ + ((void)(*(volatile u_int64_t *)((h) + (o)) = (v))) + +/* These are extensions to the general NetBSD bus interface. */ +#define bus_to_host_2(t, v) (v) +#define bus_to_host_4(t, v) (v) +#define bus_to_host_8(t, v) (v) + +#define bus_from_host_2(t, v) (v) +#define bus_from_host_4(t, v) (v) +#define bus_from_host_8(t, v) (v) + +#endif /* _ARC_BUS_H_ */ diff --git a/sys/arch/arc/include/cdefs.h b/sys/arch/arc/include/cdefs.h new file mode 100644 index 00000000000..d60f7476119 --- /dev/null +++ b/sys/arch/arc/include/cdefs.h @@ -0,0 +1,39 @@ +/* $OpenBSD: cdefs.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: cdefs.h,v 1.3 1995/05/03 06:04:54 mellon Exp $ */ + +/* + * Copyright (c) 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#define _C_LABEL(x) _STRING(x) + +#define __indr_references(sym,msg) /* nothing */ +#define __warn_references(sym,msg) /* nothing */ + +#endif /* !_MACHINE_CDEFS_H_ */ diff --git a/sys/arch/arc/include/cpu.h b/sys/arch/arc/include/cpu.h new file mode 100644 index 00000000000..a15717c3374 --- /dev/null +++ b/sys/arch/arc/include/cpu.h @@ -0,0 +1,417 @@ +/* $OpenBSD: cpu.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: @(#)cpu.h 8.4 (Berkeley) 1/4/94 + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + +#define KUSEG_ADDR 0x0 +#define CACHED_MEMORY_ADDR 0x80000000 +#define UNCACHED_MEMORY_ADDR 0xa0000000 +#define KSEG2_ADDR 0xc0000000 +#define MAX_MEM_ADDR 0xbe000000 +#define RESERVED_ADDR 0xbfc80000 + +#define CACHED_TO_PHYS(x) ((unsigned)(x) & 0x1fffffff) +#define PHYS_TO_CACHED(x) ((unsigned)(x) | CACHED_MEMORY_ADDR) +#define UNCACHED_TO_PHYS(x) ((unsigned)(x) & 0x1fffffff) +#define PHYS_TO_UNCACHED(x) ((unsigned)(x) | UNCACHED_MEMORY_ADDR) +#define VA_TO_CINDEX(x) ((unsigned)(x) & 0xffffff | CACHED_MEMORY_ADDR) + +#define CODE_START 0x80080000 + +#ifdef _KERNEL +/* + * The bits in the cause register. + * + * CR_BR_DELAY Exception happened in branch delay slot. + * CR_COP_ERR Coprocessor error. + * CR_IP Interrupt pending bits defined below. + * CR_EXC_CODE The exception type (see exception codes below). + */ +#define CR_BR_DELAY 0x80000000 +#define CR_COP_ERR 0x30000000 +#define CR_EXC_CODE 0x0000007C +#define CR_IP 0x0000FF00 +#define CR_EXC_CODE_SHIFT 2 + +/* + * The bits in the status register. All bits are active when set to 1. + */ +#define SR_COP_USABILITY 0xf0000000 +#define SR_COP_0_BIT 0x10000000 +#define SR_COP_1_BIT 0x20000000 +#define SR_RP 0x08000000 +#define SR_FR_32 0x04000000 +#define SR_RE 0x02000000 +#define SR_BOOT_EXC_VEC 0x00400000 +#define SR_TLB_SHUTDOWN 0x00200000 +#define SR_SOFT_RESET 0x00100000 +#define SR_DIAG_CH 0x00040000 +#define SR_DIAG_CE 0x00020000 +#define SR_DIAG_PE 0x00010000 +#define SR_KX 0x00000080 +#define SR_SX 0x00000040 +#define SR_UX 0x00000020 +#define SR_KSU_MASK 0x00000018 +#define SR_KSU_USER 0x00000010 +#define SR_KSU_SUPER 0x00000008 +#define SR_KSU_KERNEL 0x00000000 +#define SR_ERL 0x00000004 +#define SR_EXL 0x00000002 +#define SR_INT_ENAB 0x00000001 +/*#define SR_INT_MASK 0x0000ff00*/ + +/* + * The interrupt masks. + * If a bit in the mask is 1 then the interrupt is enabled (or pending). + */ +#define INT_MASK 0x7f00 +#define INT_MASK_5 0x8000 /* Not used (on chip timer) */ +#define INT_MASK_4 0x4000 +#define INT_MASK_3 0x2000 +#define INT_MASK_2 0x1000 +#define INT_MASK_1 0x0800 +#define INT_MASK_0 0x0400 +#define HARD_INT_MASK 0x7c00 +#define SOFT_INT_MASK_1 0x0200 +#define SOFT_INT_MASK_0 0x0100 + +/* + * The bits in the context register. + */ +#define CNTXT_PTE_BASE 0xFF800000 +#define CNTXT_BAD_VPN2 0x007FFFF0 + +/* + * Location of exception vectors. + */ +#define RESET_EXC_VEC 0xBFC00000 +#define TLB_MISS_EXC_VEC 0x80000000 +#define XTLB_MISS_EXC_VEC 0x80000080 +#define CACHE_ERR_EXC_VEC 0x80000100 +#define GEN_EXC_VEC 0x80000180 + +/* + * Coprocessor 0 registers: + */ +#define COP_0_TLB_INDEX $0 +#define COP_0_TLB_RANDOM $1 +#define COP_0_TLB_LO0 $2 +#define COP_0_TLB_LO1 $3 +#define COP_0_TLB_CONTEXT $4 +#define COP_0_TLB_PG_MASK $5 +#define COP_0_TLB_WIRED $6 +#define COP_0_BAD_VADDR $8 +#define COP_0_TLB_HI $10 +#define COP_0_STATUS_REG $12 +#define COP_0_CAUSE_REG $13 +#define COP_0_EXC_PC $14 +#define COP_0_PRID $15 +#define COP_0_CONFIG $16 +#define COP_0_LLADDR $17 +#define COP_0_WATCH_LO $18 +#define COP_0_WATCH_HI $19 +#define COP_0_TLB_XCONTEXT $20 +#define COP_0_ECC $26 +#define COP_0_CACHE_ERR $27 +#define COP_0_TAG_LO $28 +#define COP_0_TAG_HI $29 +#define COP_0_ERROR_PC $30 + +/* + * Values for the code field in a break instruction. + */ +#define BREAK_INSTR 0x0000000d +#define BREAK_VAL_MASK 0x03ff0000 +#define BREAK_VAL_SHIFT 16 +#define BREAK_KDB_VAL 512 +#define BREAK_SSTEP_VAL 513 +#define BREAK_BRKPT_VAL 514 +#define BREAK_SOVER_VAL 515 +#define BREAK_KDB (BREAK_INSTR | (BREAK_KDB_VAL << BREAK_VAL_SHIFT)) +#define BREAK_SSTEP (BREAK_INSTR | (BREAK_SSTEP_VAL << BREAK_VAL_SHIFT)) +#define BREAK_BRKPT (BREAK_INSTR | (BREAK_BRKPT_VAL << BREAK_VAL_SHIFT)) +#define BREAK_SOVER (BREAK_INSTR | (BREAK_SOVER_VAL << BREAK_VAL_SHIFT)) + +/* + * Mininum and maximum cache sizes. + */ +#define MIN_CACHE_SIZE (16 * 1024) +#define MAX_CACHE_SIZE (256 * 1024) + +/* + * The floating point version and status registers. + */ +#define FPC_ID $0 +#define FPC_CSR $31 + +/* + * The floating point coprocessor status register bits. + */ +#define FPC_ROUNDING_BITS 0x00000003 +#define FPC_ROUND_RN 0x00000000 +#define FPC_ROUND_RZ 0x00000001 +#define FPC_ROUND_RP 0x00000002 +#define FPC_ROUND_RM 0x00000003 +#define FPC_STICKY_BITS 0x0000007c +#define FPC_STICKY_INEXACT 0x00000004 +#define FPC_STICKY_UNDERFLOW 0x00000008 +#define FPC_STICKY_OVERFLOW 0x00000010 +#define FPC_STICKY_DIV0 0x00000020 +#define FPC_STICKY_INVALID 0x00000040 +#define FPC_ENABLE_BITS 0x00000f80 +#define FPC_ENABLE_INEXACT 0x00000080 +#define FPC_ENABLE_UNDERFLOW 0x00000100 +#define FPC_ENABLE_OVERFLOW 0x00000200 +#define FPC_ENABLE_DIV0 0x00000400 +#define FPC_ENABLE_INVALID 0x00000800 +#define FPC_EXCEPTION_BITS 0x0003f000 +#define FPC_EXCEPTION_INEXACT 0x00001000 +#define FPC_EXCEPTION_UNDERFLOW 0x00002000 +#define FPC_EXCEPTION_OVERFLOW 0x00004000 +#define FPC_EXCEPTION_DIV0 0x00008000 +#define FPC_EXCEPTION_INVALID 0x00010000 +#define FPC_EXCEPTION_UNIMPL 0x00020000 +#define FPC_COND_BIT 0x00800000 +#define FPC_FLUSH_BIT 0x01000000 +#define FPC_MBZ_BITS 0xfe7c0000 + +/* + * Constants to determine if have a floating point instruction. + */ +#define OPCODE_SHIFT 26 +#define OPCODE_C1 0x11 + +/* + * The low part of the TLB entry. + */ +#define VMTLB_PF_NUM 0x3fffffc0 +#define VMTLB_ATTR_MASK 0x00000038 +#define VMTLB_MOD_BIT 0x00000004 +#define VMTLB_VALID_BIT 0x00000002 +#define VMTLB_GLOBAL_BIT 0x00000001 + +#define VMTLB_PHYS_PAGE_SHIFT 6 + +/* + * The high part of the TLB entry. + */ +#define VMTLB_VIRT_PAGE_NUM 0xffffe000 +#define VMTLB_PID 0x000000ff +#define VMTLB_PID_SHIFT 0 +#define VMTLB_VIRT_PAGE_SHIFT 12 + +/* + * The number of TLB entries and the first one that write random hits. + */ +#define VMNUM_TLB_ENTRIES 48 +#define VMWIRED_ENTRIES 8 + +/* + * The number of process id entries. + */ +#define VMNUM_PIDS 256 + +/* + * TLB probe return codes. + */ +#define VMTLB_NOT_FOUND 0 +#define VMTLB_FOUND 1 +#define VMTLB_FOUND_WITH_PATCH 2 +#define VMTLB_PROBE_ERROR 3 + +/* + * Kernel virtual address for user page table entries + * (i.e., the address for the context register). + */ +#define VMPTE_BASE 0xFF800000 + +#endif /* _KERNEL */ + +/* + * Exported definitions unique to pica/mips cpu support. + */ + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define COPY_SIGCODE /* copy sigcode above user stack in exec */ + +#define cpu_wait(p) /* nothing */ +#define cpu_set_init_frame(p, fp) /* nothing */ +#define cpu_swapout(p) panic("cpu_swapout: can't get here"); + +#ifndef _LOCORE +/* + * Arguments to hardclock and gatherstats encapsulate the previous + * machine state in an opaque clockframe. + */ +struct clockframe { + int pc; /* program counter at time of interrupt */ + int sr; /* status register at time of interrupt */ +}; + +#define CLKF_USERMODE(framep) ((framep)->sr & SR_KSU_USER) +#define CLKF_BASEPRI(framep) ((~(framep)->sr & (INT_MASK|SR_INT_ENAB)) == 0) +#define CLKF_PC(framep) ((framep)->pc) +#define CLKF_INTR(framep) (0) + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +#define need_resched() { want_resched = 1; aston(); } + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the PICA, request an ast to send us + * through trap, marking the proc as needing a profiling tick. + */ +#define need_proftick(p) { (p)->p_flag |= P_OWEUPC; aston(); } + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) aston() + +#define aston() (astpending = 1) + +int astpending; /* need to trap before returning to user mode */ +int want_resched; /* resched() was called */ + +/* + * CPU identification, from PRID register. + */ +union cpuprid { + int cpuprid; + struct { +#if BYTE_ORDER == BIG_ENDIAN + u_int pad1:16; /* reserved */ + u_int cp_imp:8; /* implementation identifier */ + u_int cp_majrev:4; /* major revision identifier */ + u_int cp_minrev:4; /* minor revision identifier */ +#else + u_int cp_minrev:4; /* minor revision identifier */ + u_int cp_majrev:4; /* major revision identifier */ + u_int cp_imp:8; /* implementation identifier */ + u_int pad1:16; /* reserved */ +#endif + } cpu; +}; + +/* + * CTL_MACHDEP definitions. + */ +#define CPU_CONSDEV 1 /* dev_t: console terminal device */ +#define CPU_MAXID 2 /* number of valid machdep ids */ + +#define CTL_MACHDEP_NAMES { \ + { 0, 0 }, \ + { "console_device", CTLTYPE_STRUCT }, \ +} + +#endif /* !_LOCORE */ + +/* + * MIPS CPU types (cp_imp). + */ +#define MIPS_R2000 0x01 /* MIPS R2000 CPU ISA I */ +#define MIPS_R3000 0x02 /* MIPS R3000 CPU ISA I */ +#define MIPS_R6000 0x03 /* MIPS R6000 CPU ISA II */ +#define MIPS_R4000 0x04 /* MIPS R4000/4400 CPU ISA III */ +#define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivate ISA I */ +#define MIPS_R6000A 0x06 /* MIPS R6000A CPU ISA II */ +#define MIPS_R3IDT 0x07 /* IDT R3000 derivate ISA I */ +#define MIPS_R10000 0x09 /* MIPS R10000/T5 CPU ISA IV */ +#define MIPS_R4200 0x0a /* MIPS R4200 CPU (ICE) ISA III */ +#define MIPS_UNKC1 0x0b /* unnanounced product cpu ISA III */ +#define MIPS_UNKC2 0x0c /* unnanounced product cpu ISA III */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based CPU ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based CPU ISA I */ +#define MIPS_R3NKK 0x23 /* NKK R3000 based CPU ISA I */ + +/* + * MIPS FPU types + */ +#define MIPS_SOFT 0x00 /* Software emulation ISA I */ +#define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ +#define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ +#define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ +#define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ +#define MIPS_R4010 0x05 /* MIPS R4000/R4400 FPC ISA II */ +#define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ +#define MIPS_R10010 0x09 /* MIPS R10000/T5 FPU ISA IV */ +#define MIPS_R4210 0x0a /* MIPS R4200 FPC (ICE) ISA III */ +#define MIPS_UNKF1 0x0b /* unnanounced product cpu ISA III */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based FPU ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ +#define MIPS_R3NKK 0x23 /* NKK R3000 based FPU ISA I */ + +#if defined(_KERNEL) && !defined(_LOCORE) +union cpuprid cpu_id; +union cpuprid fpu_id; +u_int machPrimaryDataCacheSize; +u_int machPrimaryInstCacheSize; +u_int machPrimaryDataCacheLSize; +u_int machPrimaryInstCacheLSize; +u_int machCacheAliasMask; +extern struct intr_tab intr_tab[]; +#endif + +/* + * Enable realtime clock (always enabled). + */ +#define enablertclock() + +#endif /* _CPU_H_ */ diff --git a/sys/arch/arc/include/disklabel.h b/sys/arch/arc/include/disklabel.h new file mode 100644 index 00000000000..eefe2733114 --- /dev/null +++ b/sys/arch/arc/include/disklabel.h @@ -0,0 +1,81 @@ +/* $OpenBSD: disklabel.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: disklabel.h,v 1.2 1995/01/18 06:37:55 mellon Exp $ */ + +/* + * Copyright (c) 1994 Christopher G. Demetriou + * All rights reserved. + * + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _MACHINE_DISKLABEL_H_ +#define _MACHINE_DISKLABEL_H_ + +#define LABELSECTOR 0 /* sector containing label */ +#define LABELOFFSET 64 /* offset of label in sector */ +#define MAXPARTITIONS 8 /* number of partitions */ +#define RAW_PART 2 /* raw partition: xx?c */ + +/* DOS partition table -- used when the system is booted from a dos + * partition. This is the case on NT systems. + */ +#define DOSBBSECTOR 0 /* DOS boot block relative sector # */ +#define DOSPARTOFF 446 +#define NDOSPART 4 + +struct dos_partition { + unsigned char dp_flag; /* bootstrap flags */ + unsigned char dp_shd; /* starting head */ + unsigned char dp_ssect; /* starting sector */ + unsigned char dp_scyl; /* starting cylinder */ + unsigned char dp_typ; /* partition type (see below) */ + unsigned char dp_ehd; /* end head */ + unsigned char dp_esect; /* end sector */ + unsigned char dp_ecyl; /* end cylinder */ + unsigned long dp_start; /* absolute starting sector number */ + unsigned long dp_size; /* partition size in sectors */ +} dos_partitions[NDOSPART]; + +/* Known DOS partition types. */ +#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */ +#define DOSPTYP_NETBSD DOSPTYP_386BSD /* NetBSD partition type (XXX) */ + +#include <sys/dkbad.h> +struct cpu_disklabel { + struct dos_partition dosparts[NDOSPART]; + struct dkbad bad; +}; + +/* Isolate the relevant bits to get sector and cylinder. */ +#define DPSECT(s) ((s) & 0x3f) +#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) + +#ifdef _KERNEL +struct disklabel; +int bounds_check_with_label __P((struct buf *, struct disklabel *, int)); +#endif + +#endif /* _MACHINE_DISKLABEL_H_ */ diff --git a/sys/arch/arc/include/display.h b/sys/arch/arc/include/display.h new file mode 100644 index 00000000000..c5e6e2f2b64 --- /dev/null +++ b/sys/arch/arc/include/display.h @@ -0,0 +1,48 @@ +/* $OpenBSD: display.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * IBM PC display definitions + * + */ + +/* Color attributes for foreground text */ + +#define FG_BLACK 0 +#define FG_BLUE 1 +#define FG_GREEN 2 +#define FG_CYAN 3 +#define FG_RED 4 +#define FG_MAGENTA 5 +#define FG_BROWN 6 +#define FG_LIGHTGREY 7 +#define FG_DARKGREY 8 +#define FG_LIGHTBLUE 9 +#define FG_LIGHTGREEN 10 +#define FG_LIGHTCYAN 11 +#define FG_LIGHTRED 12 +#define FG_LIGHTMAGENTA 13 +#define FG_YELLOW 14 +#define FG_WHITE 15 +#define FG_BLINK 0x80 +#define FG_MASK 0x8f + +/* Color attributes for text background */ + +#define BG_BLACK 0x00 +#define BG_BLUE 0x10 +#define BG_GREEN 0x20 +#define BG_CYAN 0x30 +#define BG_RED 0x40 +#define BG_MAGENTA 0x50 +#define BG_BROWN 0x60 +#define BG_LIGHTGREY 0x70 +#define BG_MASK 0x70 + +/* Monochrome attributes for foreground text */ + +#define FG_UNDERLINE 0x01 +#define FG_INTENSE 0x08 + +/* Monochrome attributes for text background */ + +#define BG_INTENSE 0x10 diff --git a/sys/arch/arc/include/ecoff.h b/sys/arch/arc/include/ecoff.h new file mode 100644 index 00000000000..9cdc5c61277 --- /dev/null +++ b/sys/arch/arc/include/ecoff.h @@ -0,0 +1,90 @@ +/* $OpenBSD: ecoff.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: ecoff.h,v 1.4 1995/06/16 02:07:33 mellon Exp $ */ + +/* + * Copyright (c) 1994 Adam Glass + * All rights reserved. + * + * 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 Adam Glass. + * 4. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam Glass ``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 Adam Glass 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. + */ + +#define ECOFF_LDPGSZ 4096 + +#define ECOFF_PAD + +#define ECOFF_MACHDEP \ + u_long ea_gprmask; \ + u_long ea_cprmask[4]; \ + u_long ea_gp_value + +#define ECOFF_MAGIC_MIPSEL 0x0162 +#define ECOFF_BADMAG(ex) ((ex)->f.f_magic != ECOFF_MAGIC_MIPSEL) + +#define ECOFF_SEGMENT_ALIGNMENT(eap) ((eap)->ea_vstamp < 23 ? 8 : 16) + +struct ecoff_symhdr { + int16_t sh_magic; + int16_t sh_vstamp; + int32_t sh_linemax; + int32_t sh_densenummax; + int32_t sh_procmax; + int32_t sh_lsymmax; + int32_t sh_optsymmax; + int32_t sh_auxxymmax; + int32_t sh_lstrmax; + int32_t sh_estrmax; + int32_t sh_fdmax; + int32_t sh_rfdmax; + int32_t sh_esymmax; + long sh_linesize; + long sh_lineoff; + long sh_densenumoff; + long sh_procoff; + long sh_lsymoff; + long sh_optsymoff; + long sh_auxsymoff; + long sh_lstroff; + long sh_estroff; + long sh_fdoff; + long sh_rfdoff; + long sh_esymoff; +}; + +struct ecoff_extsym { + long es_value; + int es_strindex; + unsigned es_type:6; + unsigned es_class:5; + unsigned :1; + unsigned es_symauxindex:20; + unsigned es_jmptbl:1; + unsigned es_cmain:1; + unsigned es_weakext:1; + unsigned :29; + int es_indexfld; +}; + diff --git a/sys/arch/arc/include/elf.h b/sys/arch/arc/include/elf.h new file mode 100644 index 00000000000..c66e2005e3d --- /dev/null +++ b/sys/arch/arc/include/elf.h @@ -0,0 +1,138 @@ +/* $OpenBSD: elf.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: elf.h,v 1.2 1995/03/28 18:19:14 jtc Exp $ */ + +/* + * Copyright (c) 1994 Ted Lemon + * + * 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. + * + */ + +#ifndef __MACHINE_ELF_H__ +#define __MACHINE_ELF_H__ + +/* ELF executable header... */ +struct ehdr { + char elf_magic [4]; /* Elf magic number... */ + unsigned long magic [3]; /* Magic number... */ + unsigned short type; /* Object file type... */ + unsigned short machine; /* Machine ID... */ + unsigned long version; /* File format version... */ + unsigned long entry; /* Entry point... */ + unsigned long phoff; /* Program header table offset... */ + unsigned long shoff; /* Section header table offset... */ + unsigned long flags; /* Processor-specific flags... */ + unsigned short ehsize; /* Elf header size in bytes... */ + unsigned short phsize; /* Program header size... */ + unsigned short phcount; /* Program header count... */ + unsigned short shsize; /* Section header size... */ + unsigned short shcount; /* Section header count... */ + unsigned short shstrndx; /* Section header string table index... */ +}; + +/* Program header... */ +struct phdr { + unsigned long type; /* Segment type... */ + unsigned long offset; /* File offset... */ + unsigned long vaddr; /* Virtual address... */ + unsigned long paddr; /* Physical address... */ + unsigned long filesz; /* Size of segment in file... */ + unsigned long memsz; /* Size of segment in memory... */ + unsigned long flags; /* Segment flags... */ + unsigned long align; /* Alighment, file and memory... */ +}; + +/* Section header... */ +struct shdr { + unsigned long name; /* Offset into string table of section name */ + unsigned long type; /* Type of section... */ + unsigned long flags; /* Section flags... */ + unsigned long addr; /* Section virtual address at execution... */ + unsigned long offset; /* Section file offset... */ + unsigned long size; /* Section size... */ + unsigned long link; /* Link to another section... */ + unsigned long info; /* Additional section info... */ + unsigned long align; /* Section alignment... */ + unsigned long esize; /* Entry size if section holds table... */ +}; + +/* Symbol table entry... */ +struct sym { + unsigned long name; /* Index into strtab of symbol name. */ + unsigned long value; /* Section offset, virt addr or common align. */ + unsigned long size; /* Size of object referenced. */ + unsigned type : 4; /* Symbol type (e.g., function, data)... */ + unsigned binding : 4; /* Symbol binding (e.g., global, local)... */ + unsigned char other; /* Unused. */ + unsigned short shndx; /* Section containing symbol. */ +}; + +/* Values for program header type field */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_LOPROC 0x70000000 /* Processor-specific */ +#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */ +#define PT_MIPS_REGINFO PT_LOPROC /* Mips reginfo section... */ + +/* Program segment permissions, in program header flags field */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */ + +/* Reserved section indices... */ +#define SHN_UNDEF 0 +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_MIPS_ACOMMON 0xfff0 + +/* Symbol bindings... */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +/* Symbol types... */ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +#define ELF_HDR_SIZE (sizeof (struct ehdr)) +#ifdef _KERNEL +int pmax_elf_makecmds __P((struct proc *, struct exec_package *)); +#endif /* _KERNEL */ +#endif /* __MACHINE_ELF_H__ */ diff --git a/sys/arch/arc/include/endian.h b/sys/arch/arc/include/endian.h new file mode 100644 index 00000000000..b03f0c5c78d --- /dev/null +++ b/sys/arch/arc/include/endian.h @@ -0,0 +1,95 @@ +/* $OpenBSD: endian.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: endian.h,v 1.4 1994/10/26 21:09:38 cgd Exp $ */ + +/* + * Copyright (c) 1987, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)endian.h 8.1 (Berkeley) 6/11/93 + */ + +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +/* + * Define _NOQUAD if the compiler does NOT support 64-bit integers. + */ +/* #define _NOQUAD */ + +/* + * Define the order of 32-bit words in 64-bit words. + */ +#define _QUAD_HIGHWORD 1 +#define _QUAD_LOWWORD 0 + +#ifndef _POSIX_SOURCE +/* + * Definitions for byte order, according to byte significance from low + * address to high. + */ +#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ +#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ + +#define BYTE_ORDER LITTLE_ENDIAN /* ``... Beautiful SPIIIIM!'' */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +unsigned long htonl __P((unsigned long)); +unsigned short htons __P((unsigned short)); +unsigned long ntohl __P((unsigned long)); +unsigned short ntohs __P((unsigned short)); +__END_DECLS + +/* + * Macros for network/external number representation conversion. + */ +#if BYTE_ORDER == BIG_ENDIAN && !defined(lint) +#define ntohl(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define htons(x) (x) + +#define NTOHL(x) (x) +#define NTOHS(x) (x) +#define HTONL(x) (x) +#define HTONS(x) (x) + +#else + +#define NTOHL(x) (x) = ntohl((u_long)x) +#define NTOHS(x) (x) = ntohs((u_short)x) +#define HTONL(x) (x) = htonl((u_long)x) +#define HTONS(x) (x) = htons((u_short)x) +#endif +#endif /* ! _POSIX_SOURCE */ +#endif /* !_ENDIAN_H_ */ diff --git a/sys/arch/arc/include/exec.h b/sys/arch/arc/include/exec.h new file mode 100644 index 00000000000..d4f4e03159f --- /dev/null +++ b/sys/arch/arc/include/exec.h @@ -0,0 +1,57 @@ +/* $OpenBSD: exec.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: exec.h,v 1.5 1994/10/26 21:09:39 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)exec.h 8.1 (Berkeley) 6/10/93 + */ + +#define __LDPGSZ 4096 + +/* + * Define what exec "formats" we should handle. + */ +#define NATIVE_EXEC_ELF +#define EXEC_SCRIPT + +#define ELF_TARG_CLASS ELFCLASS32 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_MIPS + +/* + * This is what we want nlist(3) to handle. + */ +#define DO_AOUT /* support a.out */ +#define DO_ELF /* support ELF */ +#define DO_ECOFF /* support ECOFF */ + diff --git a/sys/arch/arc/include/float.h b/sys/arch/arc/include/float.h new file mode 100644 index 00000000000..db2c3da071f --- /dev/null +++ b/sys/arch/arc/include/float.h @@ -0,0 +1,81 @@ +/* $OpenBSD: float.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: float.h,v 1.7 1995/06/20 20:45:50 jtc Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)float.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _PMAX_FLOAT_H_ +#define _PMAX_FLOAT_H_ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +extern int __flt_rounds(); +__END_DECLS + +#define FLT_RADIX 2 /* b */ +#define FLT_ROUNDS __flt_rounds() + +#define FLT_MANT_DIG 24 /* p */ +#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */ +#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */ +#define FLT_MIN_EXP -125 /* emin */ +#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */ +#define FLT_MIN_10_EXP -37 /* ceil(log10(b**(emin-1))) */ +#define FLT_MAX_EXP 128 /* emax */ +#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */ +#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */ + +#define DBL_MANT_DIG 53 +#define DBL_EPSILON 2.2204460492503131E-16 +#define DBL_DIG 15 +#define DBL_MIN_EXP -1021 +#define DBL_MIN 2.225073858507201E-308 +#define DBL_MIN_10_EXP -307 +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.797693134862316E+308 +#define DBL_MAX_10_EXP 308 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP + +#endif /* _PMAX_FLOAT_H_ */ diff --git a/sys/arch/arc/include/ieeefp.h b/sys/arch/arc/include/ieeefp.h new file mode 100644 index 00000000000..898094c474a --- /dev/null +++ b/sys/arch/arc/include/ieeefp.h @@ -0,0 +1,25 @@ +/* $OpenBSD: ieeefp.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#ifndef _MIPS_IEEEFP_H_ +#define _MIPS_IEEEFP_H_ + +typedef int fp_except; +#define FP_X_IMP 0x01 /* imprecise (loss of precision) */ +#define FP_X_UFL 0x02 /* underflow exception */ +#define FP_X_OFL 0x04 /* overflow exception */ +#define FP_X_DZ 0x08 /* divide-by-zero exception */ +#define FP_X_INV 0x10 /* invalid operation exception */ + +typedef enum { + FP_RN=0, /* round to nearest representable number */ + FP_RZ=1, /* round to zero (truncate) */ + FP_RP=2, /* round toward positive infinity */ + FP_RM=3 /* round toward negative infinity */ +} fp_rnd; + +#endif /* _MIPS_IEEEFP_H_ */ diff --git a/sys/arch/arc/include/intr.h b/sys/arch/arc/include/intr.h new file mode 100644 index 00000000000..67e7ad75ff1 --- /dev/null +++ b/sys/arch/arc/include/intr.h @@ -0,0 +1,164 @@ +/* $NetBSD: intr.h,v 1.5 1996/05/13 06:11:28 mycroft Exp $ */ + +/* + * Copyright (c) 1996 Charles M. Hannum. All rights reserved. + * + * 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _ARC_INTR_H_ +#define _ARC_INTR_H_ + +/* Interrupt priority `levels'; not mutually exclusive. */ +#define IPL_BIO 0 /* block I/O */ +#define IPL_NET 1 /* network */ +#define IPL_TTY 2 /* terminal */ +#define IPL_CLOCK 3 /* clock */ +#define IPL_IMP 4 /* memory allocation */ +#define IPL_NONE 5 /* nothing */ +#define IPL_HIGH 6 /* everything */ + +/* Interrupt sharing types. */ +#define IST_NONE 0 /* none */ +#define IST_PULSE 1 /* pulsed */ +#define IST_EDGE 2 /* edge-triggered */ +#define IST_LEVEL 3 /* level-triggered */ + +/* Soft interrupt masks. */ +#define SIR_CLOCK 31 +#define SIR_CLOCKMASK ((1 << SIR_CLOCK)) +#define SIR_NET 30 +#define SIR_NETMASK ((1 << SIR_NET) | SIR_CLOCKMASK) +#define SIR_TTY 29 +#define SIR_TTYMASK ((1 << SIR_TTY) | SIR_CLOCKMASK) +#define SIR_ALLMASK (SIR_CLOCKMASK | SIR_NETMASK | SIR_TTYMASK) + +#ifndef _LOCORE + +volatile int cpl, ipending, astpending; +int imask[7]; + +#if 0 +extern void Xspllower __P((void)); + +static __inline int splraise __P((int)); +static __inline int spllower __P((int)); +static __inline void splx __P((int)); +static __inline void softintr __P((int)); + +/* + * Add a mask to cpl, and return the old value of cpl. + */ +static __inline int +splraise(ncpl) + register int ncpl; +{ + register int ocpl = cpl; + + cpl = ocpl | ncpl; + return (ocpl); +} + +/* + * Restore a value to cpl (unmasking interrupts). If any unmasked + * interrupts are pending, call Xspllower() to process them. + */ +static __inline void +splx(ncpl) + register int ncpl; +{ + + cpl = ncpl; + if (ipending & ~ncpl) + Xspllower(); +} + +/* + * Same as splx(), but we return the old value of spl, for the + * benefit of some splsoftclock() callers. + */ +static __inline int +spllower(ncpl) + register int ncpl; +{ + register int ocpl = cpl; + + cpl = ncpl; + if (ipending & ~ncpl) + Xspllower(); + return (ocpl); +} +#endif + +/* + * Hardware interrupt masks + */ +#if 0 +#define splbio() splraise(imask[IPL_BIO]) +#define splnet() splraise(imask[IPL_NET]) +#define spltty() splraise(imask[IPL_TTY]) +#define splclock() splraise(imask[IPL_CLOCK]) +#define splimp() splraise(imask[IPL_IMP]) +#define splstatclock() splclock() + +/* + * Software interrupt masks + * + * NOTE: splsoftclock() is used by hardclock() to lower the priority from + * clock to softclock before it calls softclock(). + */ +#define splsoftclock() spllower(SIR_CLOCKMASK) +#define splsoftnet() splraise(SIR_NETMASK) +#define splsofttty() splraise(SIR_TTYMASK) + +/* + * Miscellaneous + */ +#define splhigh() splraise(-1) +#define spl0() spllower(0) + +#endif +/* + * Software interrupt registration + * + * We hand-code this to ensure that it's atomic. + */ +static __inline void +softintr(mask) + register int mask; +{ + + __asm __volatile("orl %0,_ipending" : : "ir" (mask)); +} + +#define setsoftast() (astpending = 1) +#define setsoftclock() softintr(1 << SIR_CLOCK) +#define setsoftnet() softintr(1 << SIR_NET) +#define setsofttty() softintr(1 << SIR_TTY) + +#endif /* _LOCORE */ + +#endif /* _ARC_INTR_H_ */ diff --git a/sys/arch/arc/include/kbdreg.h b/sys/arch/arc/include/kbdreg.h new file mode 100644 index 00000000000..36f7c430398 --- /dev/null +++ b/sys/arch/arc/include/kbdreg.h @@ -0,0 +1,53 @@ +/* $OpenBSD: kbdreg.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * Keyboard definitions + * + */ + +#define KBSTATP (PICA_SYS_KBD + 0x61) /* controller status port (I) */ +#define KBS_DIB 0x01 /* data in buffer */ +#define KBS_IBF 0x02 /* input buffer low */ +#define KBS_WARM 0x04 /* input buffer low */ +#define KBS_OCMD 0x08 /* output buffer has command */ +#define KBS_NOSEC 0x10 /* security lock not engaged */ +#define KBS_TERR 0x20 /* transmission error */ +#define KBS_RERR 0x40 /* receive error */ +#define KBS_PERR 0x80 /* parity error */ + +#define KBCMDP (PICA_SYS_KBD + 0x61) /* controller port (O) */ +#define KBDATAP (PICA_SYS_KBD + 0x60) /* data port (I) */ +#define KBOUTP (PICA_SYS_KBD + 0x60) /* data port (O) */ + +#define K_RDCMDBYTE 0x20 +#define K_LDCMDBYTE 0x60 + +#define KC8_TRANS 0x40 /* convert to old scan codes */ +#define KC8_MDISABLE 0x20 /* disable mouse */ +#define KC8_KDISABLE 0x10 /* disable keyboard */ +#define KC8_IGNSEC 0x08 /* ignore security lock */ +#define KC8_CPU 0x04 /* exit from protected mode reset */ +#define KC8_MENABLE 0x02 /* enable mouse interrupt */ +#define KC8_KENABLE 0x01 /* enable keyboard interrupt */ +#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) + +/* keyboard commands */ +#define KBC_RESET 0xFF /* reset the keyboard */ +#define KBC_RESEND 0xFE /* request the keyboard resend the last byte */ +#define KBC_SETDEFAULT 0xF6 /* resets keyboard to its power-on defaults */ +#define KBC_DISABLE 0xF5 /* as per KBC_SETDEFAULT, but also disable key scanning */ +#define KBC_ENABLE 0xF4 /* enable key scanning */ +#define KBC_TYPEMATIC 0xF3 /* set typematic rate and delay */ +#define KBC_SETTABLE 0xF0 /* set scancode translation table */ +#define KBC_MODEIND 0xED /* set mode indicators (i.e. LEDs) */ +#define KBC_ECHO 0xEE /* request an echo from the keyboard */ + +/* keyboard responses */ +#define KBR_EXTENDED 0xE0 /* extended key sequence */ +#define KBR_RESEND 0xFE /* needs resend of command */ +#define KBR_ACK 0xFA /* received a valid command */ +#define KBR_OVERRUN 0x00 /* flooded */ +#define KBR_FAILURE 0xFD /* diagnosic failure */ +#define KBR_BREAK 0xF0 /* break code prefix - sent on key release */ +#define KBR_RSTDONE 0xAA /* reset complete */ +#define KBR_ECHO 0xEE /* echo response */ diff --git a/sys/arch/arc/include/kcore.h b/sys/arch/arc/include/kcore.h new file mode 100644 index 00000000000..ce62986fe0e --- /dev/null +++ b/sys/arch/arc/include/kcore.h @@ -0,0 +1,45 @@ +/* $OpenBSD: kcore.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: kcore.h,v 1.1 1996/03/10 21:55:18 leo Exp $ */ + +/* + * Copyright (c) 1996 Leo Weppelman. + * All rights reserved. + * + * 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 Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _MIPS_KCORE_H_ +#define _MIPS_KCORE_H_ + +#define NPHYS_RAM_SEGS 8 + +typedef struct cpu_kcore_hdr { + vm_offset_t kernel_pa; /* Phys. address of kernel VA 0 */ + int mmutype; + phys_ram_seg_t ram_segs[NPHYS_RAM_SEGS]; +} cpu_kcore_hdr_t; + +#endif /* _MIPS_KCORE_H_ */ diff --git a/sys/arch/arc/include/kdbparam.h b/sys/arch/arc/include/kdbparam.h new file mode 100644 index 00000000000..511ab733778 --- /dev/null +++ b/sys/arch/arc/include/kdbparam.h @@ -0,0 +1,75 @@ +/* $OpenBSD: kdbparam.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: kdbparam.h,v 1.4 1994/10/26 21:09:42 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)kdbparam.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent definitions for kdb. + */ + +#if BYTE_ORDER == LITTLE_ENDIAN +#define kdbshorten(w) ((w) & 0xFFFF) +#define kdbbyte(w) ((w) & 0xFF) +#define kdbitol(a,b) ((long)(((b) << 16) | ((a) & 0xFFFF))) +#define kdbbtol(a) ((long)(a)) +#endif + +#define LPRMODE "%R" +#define OFFMODE "+%R" + +#define SETBP(ins) BREAK_BRKPT + +/* return the program counter value modified if we are in a delay slot */ +#define kdbgetpc(pcb) (kdbvar[kdbvarchk('t')] < 0 ? \ + (pcb).pcb_regs[34] + 4 : (pcb).pcb_regs[34]) +#define kdbishiddenreg(p) ((p) >= &kdbreglist[33]) +#define kdbisbreak(type) (((type) & CR_EXC_CODE) == 0x24) + +/* check for address wrap around */ +#define kdbaddrwrap(addr,newaddr) (((addr)^(newaddr)) >> 31) + +/* declare machine dependent routines defined in kadb.c */ +void kdbprinttrap __P((unsigned, unsigned)); +void kdbsetsstep __P((void)); +void kdbclrsstep __P((void)); +void kdbreadc __P((char *)); +void kdbwrite __P((char *, int)); +void kdbprintins __P((int, long)); +void kdbstacktrace __P((int)); +char *kdbmalloc __P((int)); diff --git a/sys/arch/arc/include/limits.h b/sys/arch/arc/include/limits.h new file mode 100644 index 00000000000..92211965129 --- /dev/null +++ b/sys/arch/arc/include/limits.h @@ -0,0 +1,101 @@ +/* $OpenBSD: limits.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: limits.h,v 1.8 1995/03/28 18:19:16 jtc Exp $ */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)limits.h 8.3 (Berkeley) 1/4/94 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define MB_LEN_MAX 6 /* Allow 31 bit UTF2 */ + +#ifdef _KERNEL +#define CLK_TCK 100 /* ticks per second */ +#endif + +/* + * According to ANSI (section 2.2.4.2), the values below must be usable by + * #if preprocessing directives. Additionally, the expression must have the + * same type as would an expression that is an object of the corresponding + * type converted according to the integral promotions. The subtraction for + * INT_MIN and LONG_MIN is so the value is not unsigned; 2147483648 is an + * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). + * These numbers work for pcc as well. The UINT_MAX and ULONG_MAX values + * are written as hex so that GCC will be quiet about large integer constants. + */ +#define SCHAR_MAX 127 /* min value for a signed char */ +#define SCHAR_MIN (-128) /* max value for a signed char */ + +#define UCHAR_MAX 255 /* max value for an unsigned char */ +#define CHAR_MAX 127 /* max value for a char */ +#define CHAR_MIN (-128) /* min value for a char */ + +#define USHRT_MAX 65535 /* max value for an unsigned short */ +#define SHRT_MAX 32767 /* max value for a short */ +#define SHRT_MIN (-32768) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 2147483647 /* max value for an int */ +#define INT_MIN (-2147483647-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 2147483647 /* max value for a long */ +#define LONG_MIN (-2147483647-1) /* min value for a long */ + +#if !defined(_ANSI_SOURCE) +#define SSIZE_MAX INT_MAX /* max value for a ssize_t */ + +#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE) +#define SIZE_T_MAX UINT_MAX /* max value for a size_t */ + +/* GCC requires that quad constants be written as expressions. */ +#define UQUAD_MAX ((u_quad_t)0-1) /* max value for a uquad_t */ + /* max value for a quad_t */ +#define QUAD_MAX ((quad_t)(UQUAD_MAX >> 1)) +#define QUAD_MIN (-QUAD_MAX-1) /* min value for a quad_t */ + +#endif /* !_POSIX_SOURCE && !_XOPEN_SOURCE */ +#endif /* !_ANSI_SOURCE */ + +#if (!defined(_ANSI_SOURCE)&&!defined(_POSIX_SOURCE)) || defined(_XOPEN_SOURCE) +#define LONG_BIT 32 +#define WORD_BIT 32 + +#define DBL_DIG 15 +#define DBL_MAX 1.797693134862316E+308 +#define DBL_MIN 2.225073858507201E-308 + +#define FLT_DIG 6 +#define FLT_MAX 3.40282347E+38F +#define FLT_MIN 1.17549435E-38F +#endif diff --git a/sys/arch/arc/include/mips_opcode.h b/sys/arch/arc/include/mips_opcode.h new file mode 100644 index 00000000000..5af5668d88c --- /dev/null +++ b/sys/arch/arc/include/mips_opcode.h @@ -0,0 +1,260 @@ +/* $OpenBSD: mips_opcode.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)mips_opcode.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Define the instruction formats and opcode values for the + * MIPS instruction set. + */ + +/* + * Define the instruction formats. + */ +typedef union { + unsigned word; + +#if BYTE_ORDER == LITTLE_ENDIAN + struct { + unsigned imm: 16; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } IType; + + struct { + unsigned target: 26; + unsigned op: 6; + } JType; + + struct { + unsigned func: 6; + unsigned shamt: 5; + unsigned rd: 5; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } RType; + + struct { + unsigned func: 6; + unsigned fd: 5; + unsigned fs: 5; + unsigned ft: 5; + unsigned fmt: 4; + unsigned : 1; /* always '1' */ + unsigned op: 6; /* always '0x11' */ + } FRType; +#endif +} InstFmt; + +/* + * Values for the 'op' field. + */ +#define OP_SPECIAL 000 +#define OP_BCOND 001 +#define OP_J 002 +#define OP_JAL 003 +#define OP_BEQ 004 +#define OP_BNE 005 +#define OP_BLEZ 006 +#define OP_BGTZ 007 + +#define OP_ADDI 010 +#define OP_ADDIU 011 +#define OP_SLTI 012 +#define OP_SLTIU 013 +#define OP_ANDI 014 +#define OP_ORI 015 +#define OP_XORI 016 +#define OP_LUI 017 + +#define OP_COP0 020 +#define OP_COP1 021 +#define OP_COP2 022 +#define OP_COP3 023 +#define OP_BEQL 024 +#define OP_BNEL 025 +#define OP_BLEZL 026 +#define OP_BGTZL 027 + +#define OP_DADDI 030 +#define OP_DADDIU 031 +#define OP_LDL 032 +#define OP_LDR 033 + +#define OP_LB 040 +#define OP_LH 041 +#define OP_LWL 042 +#define OP_LW 043 +#define OP_LBU 044 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LWU 047 + +#define OP_SB 050 +#define OP_SH 051 +#define OP_SWL 052 +#define OP_SW 053 +#define OP_SDL 054 +#define OP_SDR 055 +#define OP_SWR 056 +#define OP_CACHE 057 + +#define OP_LL 060 +#define OP_LWC1 061 +#define OP_LWC2 062 +#define OP_LWC3 063 +#define OP_LLD 064 +#define OP_LD 067 + +#define OP_SC 070 +#define OP_SWC1 071 +#define OP_SWC2 072 +#define OP_SWC3 073 +#define OP_SCD 074 +#define OP_SD 077 + +/* + * Values for the 'func' field when 'op' == OP_SPECIAL. + */ +#define OP_SLL 000 +#define OP_SRL 002 +#define OP_SRA 003 +#define OP_SLLV 004 +#define OP_SRLV 006 +#define OP_SRAV 007 + +#define OP_JR 010 +#define OP_JALR 011 +#define OP_SYSCALL 014 +#define OP_BREAK 015 +#define OP_SYNC 017 + +#define OP_MFHI 020 +#define OP_MTHI 021 +#define OP_MFLO 022 +#define OP_MTLO 023 +#define OP_DSLLV 024 +#define OP_DSRLV 026 +#define OP_DSRAV 027 + +#define OP_MULT 030 +#define OP_MULTU 031 +#define OP_DIV 032 +#define OP_DIVU 033 +#define OP_DMULT 034 +#define OP_DMULTU 035 +#define OP_DDIV 036 +#define OP_DDIVU 037 + + +#define OP_ADD 040 +#define OP_ADDU 041 +#define OP_SUB 042 +#define OP_SUBU 043 +#define OP_AND 044 +#define OP_OR 045 +#define OP_XOR 046 +#define OP_NOR 047 + +#define OP_SLT 052 +#define OP_SLTU 053 +#define OP_DADD 054 +#define OP_DADDU 055 +#define OP_DSUB 056 +#define OP_DSUBU 057 + +#define OP_TGE 060 +#define OP_TGEU 061 +#define OP_TLT 062 +#define OP_TLTU 063 +#define OP_TEQ 064 +#define OP_TNE 066 + +#define OP_DSLL 070 +#define OP_DSRL 072 +#define OP_DSRA 073 +#define OP_DSLL32 074 +#define OP_DSRL32 076 +#define OP_DSRA32 077 + +/* + * Values for the 'func' field when 'op' == OP_BCOND. + */ +#define OP_BLTZ 000 +#define OP_BGEZ 001 +#define OP_BLTZL 002 +#define OP_BGEZL 003 + +#define OP_TGEI 010 +#define OP_TGEIU 011 +#define OP_TLTI 012 +#define OP_TLTIU 013 +#define OP_TEQI 014 +#define OP_TNEI 016 + +#define OP_BLTZAL 020 +#define OP_BLTZAL 020 +#define OP_BGEZAL 021 +#define OP_BLTZALL 022 +#define OP_BGEZALL 023 + +/* + * Values for the 'rs' field when 'op' == OP_COPz. + */ +#define OP_MF 000 +#define OP_DMF 001 +#define OP_MT 004 +#define OP_DMT 005 +#define OP_BCx 010 +#define OP_BCy 014 +#define OP_CF 002 +#define OP_CT 006 + +/* + * Values for the 'rt' field when 'op' == OP_COPz. + */ +#define COPz_BC_TF_MASK 0x01 +#define COPz_BC_TRUE 0x01 +#define COPz_BC_FALSE 0x00 +#define COPz_BCL_TF_MASK 0x02 +#define COPz_BCL_TRUE 0x02 +#define COPz_BCL_FALSE 0x00 diff --git a/sys/arch/arc/include/mouse.h b/sys/arch/arc/include/mouse.h new file mode 100644 index 00000000000..29d4423f83b --- /dev/null +++ b/sys/arch/arc/include/mouse.h @@ -0,0 +1,50 @@ +/* $OpenBSD: mouse.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: mouse.h,v 1.4 1994/10/27 04:16:10 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 Erik Forsberg. + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY ``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 I 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. + */ + +#ifndef _MOUSE_H_ +#define _MOUSE_H_ + +struct mouseinfo { + unsigned char status; + char xmotion, ymotion; +}; + +#define BUTSTATMASK 0x07 /* Any mouse button down if any bit set */ +#define BUTCHNGMASK 0x38 /* Any mouse button changed if any bit set */ + +#define BUT3STAT 0x01 /* Button 3 down if set */ +#define BUT2STAT 0x02 /* Button 2 down if set */ +#define BUT1STAT 0x04 /* Button 1 down if set */ +#define BUT3CHNG 0x08 /* Button 3 changed if set */ +#define BUT2CHNG 0x10 /* Button 2 changed if set */ +#define BUT1CHNG 0x20 /* Button 1 changed if set */ +#define MOVEMENT 0x40 /* Mouse movement detected */ + +/* Ioctl definitions */ + +#define MOUSEIOC ('M'<<8) +#define MOUSEIOCREAD (MOUSEIOC|60) + +#endif /* !_MOUSE_H_ */ diff --git a/sys/arch/arc/include/param.h b/sys/arch/arc/include/param.h new file mode 100644 index 00000000000..a24f4b327c4 --- /dev/null +++ b/sys/arch/arc/include/param.h @@ -0,0 +1,166 @@ +/* $OpenBSD: param.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: machparam.h 1.11 89/08/14 + * from: @(#)param.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent constants for Acer Labs PICA_61. + */ +#define MACHINE "arc" +#define MACHINE_ARCH "mips" +#define MID_PICA MID_PMAX /* For the moment */ +#define MID_MACHINE MID_PICA + +/* + * Round p (pointer or byte index) up to a correctly-aligned value for all + * data types (int, long, ...). The result is u_int and must be cast to + * any desired pointer type. + */ +#define ALIGNBYTES 7 +#define ALIGN(p) (((u_int)(p) + ALIGNBYTES) &~ ALIGNBYTES) + +#define NBPG 4096 /* bytes/page */ +#define PGOFSET (NBPG-1) /* byte offset into page */ +#define PGSHIFT 12 /* LOG2(NBPG) */ +#define NPTEPG (NBPG/4) + +#define NBSEG 0x400000 /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ + +#define KERNBASE 0x80000000 /* start of kernel virtual */ +#define KERNTEXTOFF 0x80080000 /* start of kernel text for kvm_mkdb */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define DEV_BSIZE 512 +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define BLKDEV_IOSIZE 2048 +#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */ + +#define CLSIZE 1 +#define CLSIZELOG2 0 + +/* NOTE: SSIZE, SINCR and UPAGES must be multiples of CLSIZE */ +#define SSIZE 1 /* initial stack size/NBPG */ +#define SINCR 1 /* increment of stack/NBPG */ + +#define UPAGES 2 /* pages of u-area */ +#define UADDR 0xffffc000 /* address of u */ +#define USPACE (UPAGES*NBPG) /* size of u-area in bytes */ +#define UVPN (UADDR>>PGSHIFT)/* virtual page number of u */ +#define KERNELSTACK (UADDR+UPAGES*NBPG) /* top of kernel stack */ + +/* + * Constants related to network buffer management. + * MCLBYTES must be no larger than CLBYTES (the software page size), and, + * on machines that exchange pages of input or output buffers with mbuf + * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple + * of the hardware page size. + */ +#define MSIZE 128 /* size of an mbuf */ +#define MCLBYTES 2048 /* enough for whole Ethernet packet */ +#define MCLSHIFT 10 +#define MCLOFSET (MCLBYTES - 1) +#ifndef NMBCLUSTERS +#ifdef GATEWAY +#define NMBCLUSTERS 2048 /* map size, max cluster allocation */ +#else +#define NMBCLUSTERS 1024 /* map size, max cluster allocation */ +#endif +#endif + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (512*1024/CLBYTES) +#endif + +/* pages ("clicks") (4096 bytes) to disk blocks */ +#define ctod(x) ((x) << (PGSHIFT - DEV_BSHIFT)) +#define dtoc(x) ((x) >> (PGSHIFT - DEV_BSHIFT)) + +/* pages to bytes */ +#define ctob(x) ((x) << PGSHIFT) +#define btoc(x) (((x) + PGOFSET) >> PGSHIFT) + +/* bytes to disk blocks */ +#define btodb(x) ((x) >> DEV_BSHIFT) +#define dbtob(x) ((x) << DEV_BSHIFT) + +/* + * Map a ``block device block'' to a file system block. + * This should be device dependent, and should use the bsize + * field from the disk label. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE)) + +/* + * Mach derived conversion macros + */ +#define pica_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1)) +#define pica_trunc_page(x) ((unsigned)(x) & ~(NBPG-1)) +#define pica_btop(x) ((unsigned)(x) >> PGSHIFT) +#define pica_ptob(x) ((unsigned)(x) << PGSHIFT) + +#ifdef _KERNEL +#ifndef _LOCORE +extern int (*Mach_splnet)(), (*Mach_splbio)(), (*Mach_splimp)(), + (*Mach_spltty)(), (*Mach_splclock)(), (*Mach_splstatclock)(); +#define splnet() ((*Mach_splnet)()) +#define splbio() ((*Mach_splbio)()) +#define splimp() ((*Mach_splimp)()) +#define spltty() ((*Mach_spltty)()) +#define splclock() ((*Mach_splclock)()) +#define splstatclock() ((*Mach_splstatclock)()) + +/* + * Delay is based on an assumtion that each time in the loop + * takes 3 clocks. Three is for branch and subtract in the delay slot. + */ +extern int cpuspeed; +#define DELAY(n) { register int N = cpuspeed * (n); while ((N -= 3) > 0); } +#endif + +#else /* !_KERNEL */ +#define DELAY(n) { register int N = (n); while (--N > 0); } +#endif /* !_KERNEL */ diff --git a/sys/arch/arc/include/pcb.h b/sys/arch/arc/include/pcb.h new file mode 100644 index 00000000000..8181602c1ab --- /dev/null +++ b/sys/arch/arc/include/pcb.h @@ -0,0 +1,61 @@ +/* $OpenBSD: pcb.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: pcb.h 1.13 89/04/23 + * from: @(#)pcb.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * PICA process control block + */ +struct pcb +{ + int pcb_regs[71]; /* saved CPU and floating point registers */ + label_t pcb_context; /* kernel context for resume */ + int pcb_onfault; /* for copyin/copyout faults */ + void *pcb_segtab; /* copy of pmap pm_segtab */ +}; + +/* + * The pcb is augmented with machine-dependent additional data for + * core dumps. For the PICA, there is nothing to add. + */ +struct md_coredump { + long md_pad[8]; +}; diff --git a/sys/arch/arc/include/pccons.h b/sys/arch/arc/include/pccons.h new file mode 100644 index 00000000000..df988c0da17 --- /dev/null +++ b/sys/arch/arc/include/pccons.h @@ -0,0 +1,45 @@ +/* $OpenBSD: pccons.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: pccons.h,v 1.4 1996/02/02 18:06:06 mycroft Exp $ */ + +/* + * pccons.h -- pccons ioctl definitions + */ + +#ifndef _PCCONS_H_ +#define _PCCONS_H_ + +#include <sys/ioctl.h> + +/* key types -- warning: pccons.c depends on most values */ + +#define KB_SCROLL 0x0001 /* stop output */ +#define KB_NUM 0x0002 /* numeric shift cursors vs. numeric */ +#define KB_CAPS 0x0004 /* caps shift -- swaps case of letter */ +#define KB_SHIFT 0x0008 /* keyboard shift */ +#define KB_CTL 0x0010 /* control shift -- allows ctl function */ +#define KB_ASCII 0x0020 /* ascii code for this key */ +#define KB_ALTGR 0x0040 /* alternate graphics shift */ +#define KB_ALT 0x0080 /* alternate shift -- alternate chars */ +#define KB_FUNC 0x0100 /* function key */ +#define KB_KP 0x0200 /* Keypad keys */ +#define KB_NONE 0x0400 /* no function */ + +#define KB_CODE_SIZE 4 /* Use a max of 4 for now... */ +#define KB_NUM_KEYS 128 /* Number of scan codes */ +typedef struct { + u_short type; + char unshift[KB_CODE_SIZE]; + char shift[KB_CODE_SIZE]; + char ctl[KB_CODE_SIZE]; + char altgr[KB_CODE_SIZE]; + char shift_altgr[KB_CODE_SIZE]; +} keymap_t; + +#define CONSOLE_X_MODE_ON _IO('t',121) +#define CONSOLE_X_MODE_OFF _IO('t',122) +#define CONSOLE_X_BELL _IOW('t',123,int[2]) +#define CONSOLE_SET_TYPEMATIC_RATE _IOW('t',124,u_char) +#define CONSOLE_GET_KEYMAP _IOR('t',128,keymap_t[KB_NUM_KEYS]) +#define CONSOLE_SET_KEYMAP _IOW('t',129,keymap_t[KB_NUM_KEYS]) + +#endif /* _PCCONS_H_ */ diff --git a/sys/arch/arc/include/pio.h b/sys/arch/arc/include/pio.h new file mode 100644 index 00000000000..04db5b11f34 --- /dev/null +++ b/sys/arch/arc/include/pio.h @@ -0,0 +1,46 @@ +/* $OpenBSD: pio.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * Copyright (c) 1995 Per Fogelstrom. All rights reserved. + * + * 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * I/O macros. + */ + +#define outb(a,v) (*(volatile unsigned char*)(a) = (v)) +#define outw(a,v) (*(volatile unsigned short*)(a) = (v)) +#define out16(a,v) outw(a,v) +#define outl(a,v) (*(volatile unsigned int*)(a) = (v)) +#define out32(a,v) outl(a,v) +#define inb(a) (*(volatile unsigned char*)(a)) +#define inw(a) (*(volatile unsigned short*)(a)) +#define in16(a) inw(a) +#define inl(a) (*(volatile unsigned int*)(a)) +#define in32(a) inl(a) + diff --git a/sys/arch/arc/include/pmap.h b/sys/arch/arc/include/pmap.h new file mode 100644 index 00000000000..6582b7b13ba --- /dev/null +++ b/sys/arch/arc/include/pmap.h @@ -0,0 +1,109 @@ +/* $OpenBSD: pmap.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ + +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)pmap.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _PMAP_MACHINE_ +#define _PMAP_MACHINE_ + +/* + * The user address space is 2Gb (0x0 - 0x80000000). + * User programs are laid out in memory as follows: + * address + * USRTEXT 0x00001000 + * USRDATA USRTEXT + text_size + * USRSTACK 0x7FFFFFFF + * + * The user address space is mapped using a two level structure where + * virtual address bits 30..22 are used to index into a segment table which + * points to a page worth of PTEs (4096 page can hold 1024 PTEs). + * Bits 21..12 are then used to index a PTE which describes a page within + * a segment. + * + * The wired entries in the TLB will contain the following: + * 0-1 (UPAGES) for curproc user struct and kernel stack. + * + * Note: The kernel doesn't use the same data structures as user programs. + * All the PTE entries are stored in a single array in Sysmap which is + * dynamically allocated at boot time. + */ + +#define pica_trunc_seg(x) ((vm_offset_t)(x) & ~SEGOFSET) +#define pica_round_seg(x) (((vm_offset_t)(x) + SEGOFSET) & ~SEGOFSET) +#define pmap_segmap(m, v) ((m)->pm_segtab->seg_tab[((v) >> SEGSHIFT)]) + +#define PMAP_SEGTABSIZE 512 + +union pt_entry; + +struct segtab { + union pt_entry *seg_tab[PMAP_SEGTABSIZE]; +}; + +/* + * Machine dependent pmap structure. + */ +typedef struct pmap { + int pm_count; /* pmap reference count */ + simple_lock_data_t pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + int pm_tlbpid; /* address space tag */ + u_int pm_tlbgen; /* TLB PID generation number */ + struct segtab *pm_segtab; /* pointers to pages of PTEs */ +} *pmap_t; + +/* + * Defines for pmap_attributes[phys_mach_page]; + */ +#define PMAP_ATTR_MOD 0x01 /* page has been modified */ +#define PMAP_ATTR_REF 0x02 /* page has been referenced */ + +#ifdef _KERNEL +extern char *pmap_attributes; /* reference and modify bits */ +extern struct pmap kernel_pmap_store; + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) +#define pmap_kernel() (&kernel_pmap_store) + +#define PMAP_PREFER(pa, va) pmap_prefer((pa), (va)) + +#endif /* _KERNEL */ + +#endif /* _PMAP_MACHINE_ */ diff --git a/sys/arch/arc/include/proc.h b/sys/arch/arc/include/proc.h new file mode 100644 index 00000000000..b9b2b81c76d --- /dev/null +++ b/sys/arch/arc/include/proc.h @@ -0,0 +1,54 @@ +/* $OpenBSD: proc.h,v 1.1 1996/06/24 09:07:17 pefo Exp $ */ +/* $NetBSD: proc.h,v 1.4 1994/10/26 21:09:52 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)proc.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine-dependent part of the proc structure for DEC Station. + */ +struct mdproc { + int *md_regs; /* registers on current frame */ + int md_flags; /* machine-dependent flags */ + int md_upte[UPAGES]; /* ptes for mapping u page */ + int md_ss_addr; /* single step address for ptrace */ + int md_ss_instr; /* single step instruction for ptrace */ +}; + +/* md_flags */ +#define MDP_FPUSED 0x0001 /* floating point coprocessor used */ diff --git a/sys/arch/arc/include/profile.h b/sys/arch/arc/include/profile.h new file mode 100644 index 00000000000..911da1370f9 --- /dev/null +++ b/sys/arch/arc/include/profile.h @@ -0,0 +1,79 @@ +/* $OpenBSD: profile.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)profile.h 8.1 (Berkeley) 6/10/93 + */ + +#define _MCOUNT_DECL static void ___mcount + +#define MCOUNT \ + __asm(".globl _mcount;" \ + "_mcount:;" \ + ".set noreorder;" \ + ".set noat;" \ + "sw $4,8($29);" \ + "sw $5,12($29);" \ + "sw $6,16($29);" \ + "sw $7,20($29);" \ + "sw $1,0($29);" \ + "sw $31,4($29);" \ + "move $5,$31;" \ + "jal ___mcount;" \ + "move $4,$1;" \ + "lw $4,8($29);" \ + "lw $5,12($29);" \ + "lw $6,16($29);" \ + "lw $7,20($29);" \ + "lw $31,4($29);" \ + "lw $1,0($29);" \ + "addu $29,$29,8;" \ + "j $31;" \ + "move $31,$1;" \ + ".set reorder;" \ + ".set at"); + +#ifdef _KERNEL +/* + * The following two macros do splhigh and splx respectively. + * They have to be defined this way because these are real + * functions on the PICA, and we do not want to invoke mcount + * recursively. + */ +#define MCOUNT_ENTER s = _splhigh() + +#define MCOUNT_EXIT _splx(s) +#endif /* _KERNEL */ diff --git a/sys/arch/arc/include/psl.h b/sys/arch/arc/include/psl.h new file mode 100644 index 00000000000..e1109ebbb54 --- /dev/null +++ b/sys/arch/arc/include/psl.h @@ -0,0 +1,69 @@ +/* $OpenBSD: psl.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * from: @(#)psl.h 8.1 (Berkeley) 6/10/93 + */ + +#include <machine/cpu.h> + +#define PSL_LOWIPL (INT_MASK | SR_INT_ENAB) + +#define PSL_USERSET ( \ + SR_KSU_USER | \ + SR_INT_ENAB | \ + SR_EXL | \ + INT_MASK) + +#define PSL_USERCLR ( \ + SR_COP_USABILITY | \ + SR_BOOT_EXC_VEC | \ + SR_TLB_SHUTDOWN | \ + SR_PARITY_ERR | \ + SR_CACHE_MISS | \ + SR_PARITY_ZERO | \ + SR_SWAP_CACHES | \ + SR_ISOL_CACHES | \ + SR_KU_CUR | \ + SR_INT_ENA_CUR | \ + SR_MBZ) + +/* + * Macros to decode processor status word. + */ +#define USERMODE(ps) (((ps) & SR_KSU_MASK) == SR_KSU_USER) +#define BASEPRI(ps) (((ps) & (INT_MASK | SR_INT_ENA_PREV)) \ + == (INT_MASK | SR_INT_ENA_PREV)) diff --git a/sys/arch/arc/include/pte.h b/sys/arch/arc/include/pte.h new file mode 100644 index 00000000000..a5e6ee48054 --- /dev/null +++ b/sys/arch/arc/include/pte.h @@ -0,0 +1,134 @@ +/* $OpenBSD: pte.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: pte.h 1.11 89/09/03 + * from: @(#)pte.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * R4000 hardware page table entry + */ + +#ifndef _LOCORE +struct pte { +#if BYTE_ORDER == BIG_ENDIAN +unsigned int pg_prot:2, /* SW: access control */ + pg_pfnum:24, /* HW: core page frame number or 0 */ + pg_attr:3, /* HW: cache attribute */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_v:1, /* HW: valid bit */ + pg_g:1; /* HW: ignore pid bit */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +unsigned int pg_g:1, /* HW: ignore pid bit */ + pg_v:1, /* HW: valid bit */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_attr:3, /* HW: cache attribute */ + pg_pfnum:24, /* HW: core page frame number or 0 */ + pg_prot:2; /* SW: access control */ +#endif +}; + +/* + * Structure defining an tlb entry data set. + */ + +struct tlb { + int tlb_mask; + int tlb_hi; + int tlb_lo0; + int tlb_lo1; +}; + +typedef union pt_entry { + unsigned int pt_entry; /* for copying, etc. */ + struct pte pt_pte; /* for getting to bits by name */ +} pt_entry_t; /* Mach page table entry */ +#endif /* _LOCORE */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) + +#define PG_WIRED 0x80000000 /* SW */ +#define PG_RO 0x40000000 /* SW */ + +#define PG_SVPN 0xfffff000 /* Software page no mask */ +#define PG_HVPN 0xffffe000 /* Hardware page no mask */ +#define PG_ODDPG 0x00001000 /* Odd even pte entry */ +#define PG_ASID 0x000000ff /* Address space ID */ +#define PG_G 0x00000001 /* HW */ +#define PG_V 0x00000002 +#define PG_NV 0x00000000 +#define PG_M 0x00000004 +#define PG_ATTR 0x0000003f +#define PG_UNCACHED 0x00000010 +#define PG_CACHED 0x00000018 +#define PG_CACHEMODE 0x00000038 +#define PG_ROPAGE (PG_V | PG_RO | PG_CACHED) /* Write protected */ +#define PG_RWPAGE (PG_V | PG_M | PG_CACHED) /* Not wr-prot not clean */ +#define PG_CWPAGE (PG_V | PG_CACHED) /* Not wr-prot but clean */ +#define PG_IOPAGE (PG_G | PG_V | PG_M | PG_UNCACHED) +#define PG_FRAME 0x3fffffc0 +#define PG_SHIFT 6 +#define vad_to_pfn(x) (((unsigned)(x) >> PG_SHIFT) & PG_FRAME) +#define pfn_to_vad(x) (((x) & PG_FRAME) << PG_SHIFT) +#define vad_to_vpn(x) ((unsigned)(x) & PG_SVPN) +#define vpn_to_vad(x) ((x) & PG_SVPN) +/* User viritual to pte page entry */ +#define uvtopte(adr) (((adr) >> PGSHIFT) & (NPTEPG -1)) + +#define PG_SIZE_4K 0x00000000 +#define PG_SIZE_16K 0x00006000 +#define PG_SIZE_64K 0x0001e000 +#define PG_SIZE_256K 0x0007e000 +#define PG_SIZE_1M 0x001fe000 +#define PG_SIZE_4M 0x007fe000 +#define PG_SIZE_16M 0x01ffe000 + +#if defined(_KERNEL) && !defined(_LOCORE) +/* + * Kernel virtual address to page table entry and visa versa. + */ +#define kvtopte(va) \ + (Sysmap + (((vm_offset_t)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT)) +#define ptetokv(pte) \ + ((((pt_entry_t *)(pte) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) + +extern pt_entry_t *Sysmap; /* kernel pte table */ +extern u_int Sysmapsize; /* number of pte's in Sysmap */ +#endif diff --git a/sys/arch/arc/include/ptrace.h b/sys/arch/arc/include/ptrace.h new file mode 100644 index 00000000000..987d48b285b --- /dev/null +++ b/sys/arch/arc/include/ptrace.h @@ -0,0 +1,45 @@ +/* $OpenBSD: ptrace.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * from: @(#)ptrace.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent trace commands. + * + */ + +#define PT_GETREGS (PT_FIRSTMACH+0) +#define PT_SETREGS (PT_FIRSTMACH+1) +#define PT_STEP (PT_FIRSTMACH+2) diff --git a/sys/arch/arc/include/reg.h b/sys/arch/arc/include/reg.h new file mode 100644 index 00000000000..d1a7a2b76e1 --- /dev/null +++ b/sys/arch/arc/include/reg.h @@ -0,0 +1,62 @@ +/* $OpenBSD: reg.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: reg.h,v 1.6 1995/12/20 02:00:27 jonathan Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: reg.h 1.1 90/07/09 + * @(#)reg.h 8.2 (Berkeley) 1/11/94 + */ + +#ifndef _MACHINE_REG_H_ +#define _MACHINE_REG_H_ +/* + * Location of the users' stored + * registers relative to ZERO. + * Usage is p->p_regs[XX]. + * + * must be visible to assembly code. + */ +#include <machine/regnum.h> + +/* + * Register set accessible via /proc/$pid/reg + */ +struct reg { + int r_regs[71]; /* numbered as above */ +}; +#endif /*_MACHINE_REG_H_*/ diff --git a/sys/arch/arc/include/regdef.h b/sys/arch/arc/include/regdef.h new file mode 100644 index 00000000000..def7c6ef1a1 --- /dev/null +++ b/sys/arch/arc/include/regdef.h @@ -0,0 +1,74 @@ +/* $OpenBSD: regdef.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: regdef.h,v 1.4 1994/10/26 21:09:58 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. This file is derived from the MIPS RISC + * Architecture book by Gerry Kane. + * + * 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. + * + * @(#)regdef.h 8.1 (Berkeley) 6/10/93 + */ + +#define zero $0 /* always zero */ +#define AT $at /* assembler temp */ +#define v0 $2 /* return value */ +#define v1 $3 +#define a0 $4 /* argument registers */ +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 /* temp registers (not saved across subroutine calls) */ +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 /* saved across subroutine calls (callee saved) */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* two more temp registers */ +#define t9 $25 +#define k0 $26 /* kernel temporary */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define s8 $30 /* one more callee saved */ +#define ra $31 /* return address */ diff --git a/sys/arch/arc/include/regnum.h b/sys/arch/arc/include/regnum.h new file mode 100644 index 00000000000..b0cc92e6d9b --- /dev/null +++ b/sys/arch/arc/include/regnum.h @@ -0,0 +1,136 @@ +/* $OpenBSD: regnum.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: reg.h,v 1.5 1995/01/18 06:40:12 mellon Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: reg.h 1.1 90/07/09 + * @(#)reg.h 8.2 (Berkeley) 1/11/94 + */ + +/* + * Location of the users' stored + * registers relative to ZERO. + * Usage is p->p_regs[XX]. + */ +#define ZERO 0 +#define AST 1 +#define V0 2 +#define V1 3 +#define A0 4 +#define A1 5 +#define A2 6 +#define A3 7 +#define T0 8 +#define T1 9 +#define T2 10 +#define T3 11 +#define T4 12 +#define T5 13 +#define T6 14 +#define T7 15 +#define S0 16 +#define S1 17 +#define S2 18 +#define S3 19 +#define S4 20 +#define S5 21 +#define S6 22 +#define S7 23 +#define T8 24 +#define T9 25 +#define K0 26 +#define K1 27 +#define GP 28 +#define SP 29 +#define S8 30 +#define RA 31 +#define SR 32 +#define PS SR /* alias for SR */ +#define MULLO 33 +#define MULHI 34 +#define BADVADDR 35 +#define CAUSE 36 +#define PC 37 + +#define FPBASE 38 +#define F0 (FPBASE+0) +#define F1 (FPBASE+1) +#define F2 (FPBASE+2) +#define F3 (FPBASE+3) +#define F4 (FPBASE+4) +#define F5 (FPBASE+5) +#define F6 (FPBASE+6) +#define F7 (FPBASE+7) +#define F8 (FPBASE+8) +#define F9 (FPBASE+9) +#define F10 (FPBASE+10) +#define F11 (FPBASE+11) +#define F12 (FPBASE+12) +#define F13 (FPBASE+13) +#define F14 (FPBASE+14) +#define F15 (FPBASE+15) +#define F16 (FPBASE+16) +#define F17 (FPBASE+17) +#define F18 (FPBASE+18) +#define F19 (FPBASE+19) +#define F20 (FPBASE+20) +#define F21 (FPBASE+21) +#define F22 (FPBASE+22) +#define F23 (FPBASE+23) +#define F24 (FPBASE+24) +#define F25 (FPBASE+25) +#define F26 (FPBASE+26) +#define F27 (FPBASE+27) +#define F28 (FPBASE+28) +#define F29 (FPBASE+29) +#define F30 (FPBASE+30) +#define F31 (FPBASE+31) +#define FSR (FPBASE+32) + +#ifdef IPCREG +#define NIPCREG (FSR + 1) +int ipcreg[NIPCREG] = { + ZERO, AST, V0, V1, A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, T6, T7, + S0, S1, S2, S3, S4, S5, S6, S7, T8, T9, K0, K1, GP, SP, S8, RA, + SR, MULLO, MULHI, BADVADDR, CAUSE, PC, + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, FSR, +}; +#endif diff --git a/sys/arch/arc/include/reloc.h b/sys/arch/arc/include/reloc.h new file mode 100644 index 00000000000..bba5426b18a --- /dev/null +++ b/sys/arch/arc/include/reloc.h @@ -0,0 +1,75 @@ +/* $OpenBSD: reloc.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * from: @(#)reloc.h 8.1 (Berkeley) 6/10/93 + * from: Header: reloc.h,v 1.6 92/06/20 09:59:37 torek Exp + */ + +#if 0 +/* + * MIPS relocation types. + */ +enum reloc_type { + MIPS_RELOC_32, /* 32-bit absolute */ + MIPS_RELOC_JMP, /* 26-bit absolute << 2 | high 4 bits of pc */ + MIPS_RELOC_WDISP16, /* 16-bit signed pc-relative << 2 */ + MIPS_RELOC_HI16, /* 16-bit absolute << 16 */ + MIPS_RELOC_HI16_S, /* 16-bit absolute << 16 (+1 if needed) */ + MIPS_RELOC_LO16, /* 16-bit absolute */ +}; + +/* + * MIPS relocation info. + * + * Symbol-relative relocation is done by: + * 1. start with the value r_addend, + * 2. locate the appropriate symbol and if defined, add symbol value, + * 3. if pc relative, subtract pc, + * 4. if the reloc_type is MIPS_RELOC_HI16_S and the result bit 15 is set, + * add 0x00010000, + * 5. shift down 2 or 16 if necessary. + * The resulting value is then to be stuffed into the appropriate bits + * in the object (the low 16, or the low 26 bits). + */ +struct reloc_info_pica { + u_long r_address; /* relocation addr (offset in segment) */ + u_int r_index:24, /* segment (r_extern==0) or symbol index */ + r_extern:1, /* if set, r_index is symbol index */ + :2; /* unused */ + enum reloc_type r_type:5; /* relocation type, from above */ + long r_addend; /* value to add to symbol value */ +}; + +#define relocation_info reloc_info_pica +#endif diff --git a/sys/arch/arc/include/setjmp.h b/sys/arch/arc/include/setjmp.h new file mode 100644 index 00000000000..0c31feea29b --- /dev/null +++ b/sys/arch/arc/include/setjmp.h @@ -0,0 +1,8 @@ +/* $OpenBSD: setjmp.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: setjmp.h,v 1.1 1994/12/20 10:37:05 cgd Exp $ */ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + */ + +#define _JBLEN 83 /* size, in longs, of a jmp_buf */ diff --git a/sys/arch/arc/include/signal.h b/sys/arch/arc/include/signal.h new file mode 100644 index 00000000000..8051144c5a3 --- /dev/null +++ b/sys/arch/arc/include/signal.h @@ -0,0 +1,68 @@ +/* $OpenBSD: signal.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: signal.h,v 1.6 1995/01/18 06:42:01 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)signal.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine-dependent signal definitions + */ + +typedef int sig_atomic_t; + +#ifndef _ANSI_SOURCE +/* + * Information pushed on stack when a signal is delivered. + * This is used by the kernel to restore state following + * execution of the signal handler. It is also made available + * to the handler to allow it to restore state properly if + * a non-standard exit is performed. + */ +struct sigcontext { + int sc_onstack; /* sigstack state to restore */ + int sc_mask; /* signal mask to restore */ + int sc_pc; /* pc at time of signal */ + int sc_regs[32]; /* processor regs 0 to 31 */ + int mullo, mulhi; /* mullo and mulhi registers... */ + int sc_fpused; /* fp has been used */ + int sc_fpregs[33]; /* fp regs 0 to 31 and csr */ + int sc_fpc_eir; /* floating point exception instruction reg */ + int xxx[8]; /* XXX reserved */ +}; + +#endif /* !_ANSI_SOURCE */ diff --git a/sys/arch/arc/include/stdarg.h b/sys/arch/arc/include/stdarg.h new file mode 100644 index 00000000000..f2416324434 --- /dev/null +++ b/sys/arch/arc/include/stdarg.h @@ -0,0 +1,65 @@ +/* $OpenBSD: stdarg.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: stdarg.h,v 1.7 1995/03/28 18:19:28 jtc Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)stdarg.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _PMAX_STDARG_H_ +#define _PMAX_STDARG_H_ + +#include <machine/ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define __va_promote(type) \ + (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int)) + +#define va_start(ap, last) \ + (ap = ((char *)&(last) + __va_promote(last))) + +#ifdef _KERNEL +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type)))[-1] +#else +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type) == sizeof(int) ? sizeof(type) : \ + sizeof(type) > sizeof(int) ? \ + (-(int)(ap) & (sizeof(type) - 1)) + sizeof(type) : \ + (abort(), 0)))[-1] +#endif + +#define va_end(ap) ((void) 0) + +#endif /* !_PMAX_STDARG_H_ */ diff --git a/sys/arch/arc/include/trap.h b/sys/arch/arc/include/trap.h new file mode 100644 index 00000000000..b134df761f0 --- /dev/null +++ b/sys/arch/arc/include/trap.h @@ -0,0 +1,68 @@ +/* $OpenBSD: trap.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: trap.h 1.1 90/07/09 + * from: @(#)trap.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Trap codes + * also known in trap.c for name strings + */ + +#define T_INT 0 /* Interrupt pending */ +#define T_TLB_MOD 1 /* TLB modified fault */ +#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */ +#define T_TLB_ST_MISS 3 /* TLB miss on a store */ +#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */ +#define T_ADDR_ERR_ST 5 /* Address error on a store */ +#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */ +#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */ +#define T_SYSCALL 8 /* System call */ +#define T_BREAK 9 /* Breakpoint */ +#define T_RES_INST 10 /* Reserved instruction exception */ +#define T_COP_UNUSABLE 11 /* Coprocessor unusable */ +#define T_OVFLOW 12 /* Arithmetic overflow */ +#define T_TRAP 13 /* Trap instruction */ +#define T_VCEI 14 /* Viritual coherency instruction */ +#define T_FPE 15 /* Floating point exception */ +#define T_WATCH 23 /* Watch address reference */ +#define T_VCED 31 /* Viritual coherency data */ + +#define T_USER 0x20 /* user-mode flag or'ed with type */ diff --git a/sys/arch/arc/include/types.h b/sys/arch/arc/include/types.h new file mode 100644 index 00000000000..e847a7f4f8f --- /dev/null +++ b/sys/arch/arc/include/types.h @@ -0,0 +1,82 @@ +/* $OpenBSD: types.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: types.h,v 1.10 1995/07/06 03:39:43 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)types.h 8.3 (Berkeley) 1/5/94 + */ + +#ifndef _MACHTYPES_H_ +#define _MACHTYPES_H_ + +#include <sys/cdefs.h> + +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +typedef struct _physadr { + int r[1]; +} *physadr; + +typedef struct label_t { + int val[12]; +} label_t; +#endif + +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_t; + +/* + * Basic integral types. Omit the typedef if + * not possible for a machine/compiler combination. + */ +#define __BIT_TYPES_DEFINED__ +typedef __signed char int8_t; +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +/* LONGLONG */ +typedef long long int64_t; +/* LONGLONG */ +typedef unsigned long long u_int64_t; + +typedef int32_t register_t; + +#define __BDEVSW_DUMP_OLD_TYPE +#define __SWAP_BROKEN +#define __FORK_BRAINDAMAGE + +#endif /* _MACHTYPES_H_ */ diff --git a/sys/arch/arc/include/varargs.h b/sys/arch/arc/include/varargs.h new file mode 100644 index 00000000000..eca413161e8 --- /dev/null +++ b/sys/arch/arc/include/varargs.h @@ -0,0 +1,69 @@ +/* $OpenBSD: varargs.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: varargs.h,v 1.8 1995/03/28 18:19:30 jtc Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * + * @(#)varargs.h 8.2 (Berkeley) 3/22/94 + */ + +#ifndef _PMAX_VARARGS_H_ +#define _PMAX_VARARGS_H_ + +#include <machine/ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define va_dcl int va_alist; ... + +#define va_start(ap) \ + ap = (char *)&va_alist + +#ifdef _KERNEL +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type)))[-1] +#else +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type) == sizeof(int) ? sizeof(type) : \ + sizeof(type) > sizeof(int) ? \ + (-(int)(ap) & (sizeof(type) - 1)) + sizeof(type) : \ + (abort(), 0)))[-1] +#endif + +#define va_end(ap) ((void) 0) + +#endif /* !_PMAX_VARARGS_H_ */ diff --git a/sys/arch/arc/include/vmparam.h b/sys/arch/arc/include/vmparam.h new file mode 100644 index 00000000000..539b024441d --- /dev/null +++ b/sys/arch/arc/include/vmparam.h @@ -0,0 +1,238 @@ +/* $OpenBSD: vmparam.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: vmparam.h,v 1.5 1994/10/26 21:10:10 cgd Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * 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. + * + * from: Utah Hdr: vmparam.h 1.16 91/01/18 + * @(#)vmparam.h 8.2 (Berkeley) 4/22/94 + */ + +/* + * Machine dependent constants for DEC Station 3100. + */ +/* + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. LOWPAGES and HIGHPAGES are + * the number of pages from the beginning of the P0 region to the + * beginning of the text and from the beginning of the P1 region to the + * beginning of the stack respectively. + */ +#define USRTEXT 0x00001000 +#define USRSTACK 0x80000000 /* Start of user stack */ +#define BTOPUSRSTACK 0x80000 /* btop(USRSTACK) */ +#define LOWPAGES 0x00001 +#define HIGHPAGES 0 + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ (24*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ (32*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (32*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ MAXDSIZ /* max stack size */ +#endif + +/* + * Default sizes of swap allocation chunks (see dmap.h). + * The actual values may be changed in vminit() based on MAXDSIZ. + * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024. + * DMMIN should be at least ctod(1) so that vtod() works. + * vminit() insures this. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ + +/* + * Sizes of the system and user portions of the system page table. + */ +/* SYSPTSIZE IS SILLY; (really number of buffers for I/O) */ +#define SYSPTSIZE 1228 +#define USRPTSIZE 1024 + +/* + * PTEs for mapping user space into the kernel for phyio operations. + * 16 pte's are enough to cover 8 disks * MAXBSIZE. + */ +#ifndef USRIOSIZE +#define USRIOSIZE 32 +#endif + +/* + * PTEs for system V style shared memory. + * This is basically slop for kmempt which we actually allocate (malloc) from. + */ +#ifndef SHMMAXPGS +#define SHMMAXPGS 1024 /* 4mb */ +#endif + +/* + * Boundary at which to place first MAPMEM segment if not explicitly + * specified. Should be a power of two. This allows some slop for + * the data segment to grow underneath the first mapped segment. + */ +#define MMSEG 0x200000 + +/* + * The size of the clock loop. + */ +#define LOOPPAGES (maxfree - firstfree) + +/* + * The time for a process to be blocked before being very swappable. + * This is a number of seconds which the system takes as being a non-trivial + * amount of real time. You probably shouldn't change this; + * it is used in subtle ways (fractions and multiples of it are, that is, like + * half of a ``long time'', almost a long time, etc.) + * It is related to human patience and other factors which don't really + * change over time. + */ +#define MAXSLP 20 + +/* + * A swapped in process is given a small amount of core without being bothered + * by the page replacement algorithm. Basically this says that if you are + * swapped in you deserve some resources. We protect the last SAFERSS + * pages against paging and will just swap you out rather than paging you. + * Note that each process has at least UPAGES+CLSIZE pages which are not + * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this + * number just means a swapped in process is given around 25k bytes. + * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81), + * so we loan each swapped in process memory worth 100$, or just admit + * that we don't consider it worthwhile and swap it out to disk which costs + * $30/mb or about $0.75. + */ +#define SAFERSS 4 /* nominal ``small'' resident set size + protected against replacement */ + +/* + * DISKRPM is used to estimate the number of paging i/o operations + * which one can expect from a single disk controller. + */ +#define DISKRPM 60 + +/* + * Klustering constants. Klustering is the gathering + * of pages together for pagein/pageout, while clustering + * is the treatment of hardware page size as though it were + * larger than it really is. + * + * KLMAX gives maximum cluster size in CLSIZE page (cluster-page) + * units. Note that ctod(KLMAX*CLSIZE) must be <= DMMIN in dmap.h. + * ctob(KLMAX) should also be less than MAXPHYS (in vm_swp.c) + * unless you like "big push" panics. + */ + +#ifdef notdef /* XXX */ +#define KLMAX (4/CLSIZE) +#define KLSEQL (2/CLSIZE) /* in klust if vadvise(VA_SEQL) */ +#define KLIN (4/CLSIZE) /* default data/stack in klust */ +#define KLTXT (4/CLSIZE) /* default text in klust */ +#define KLOUT (4/CLSIZE) +#else +#define KLMAX (1/CLSIZE) +#define KLSEQL (1/CLSIZE) +#define KLIN (1/CLSIZE) +#define KLTXT (1/CLSIZE) +#define KLOUT (1/CLSIZE) +#endif + +/* + * KLSDIST is the advance or retard of the fifo reclaim for sequential + * processes data space. + */ +#define KLSDIST 3 /* klusters advance/retard for seq. fifo */ + +/* + * Paging thresholds (see vm_sched.c). + * Strategy of 1/19/85: + * lotsfree is 512k bytes, but at most 1/4 of memory + * desfree is 200k bytes, but at most 1/8 of memory + */ +#define LOTSFREE (512 * 1024) +#define LOTSFREEFRACT 4 +#define DESFREE (200 * 1024) +#define DESFREEFRACT 8 + +/* + * There are two clock hands, initially separated by HANDSPREAD bytes + * (but at most all of user memory). The amount of time to reclaim + * a page once the pageout process examines it increases with this + * distance and decreases as the scan rate rises. + */ +#define HANDSPREAD (2 * 1024 * 1024) + +/* + * The number of times per second to recompute the desired paging rate + * and poke the pagedaemon. + */ +#define RATETOSCHEDPAGING 4 + +/* + * Believed threshold (in megabytes) for which interleaved + * swapping area is desirable. + */ +#define LOTSOFMEM 2 + +#define mapin(pte, v, pfnum, prot) \ + (*(int *)(pte) = ((pfnum) << PG_SHIFT) | (prot), MachTLBFlushAddr(v)) + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0x00000000) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0x80000000) +#define VM_MAX_ADDRESS ((vm_offset_t)0x80000000) +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xC0000000) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFFFFC000) + +/* virtual sizes (bytes) for various kernel submaps */ +#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES) +#define VM_KMEM_SIZE (NKMEMCLUSTERS*CLBYTES) +#define VM_PHYS_SIZE (USRIOSIZE*CLBYTES) diff --git a/sys/arch/arc/isa/isa_machdep.h b/sys/arch/arc/isa/isa_machdep.h new file mode 100644 index 00000000000..24c104c3deb --- /dev/null +++ b/sys/arch/arc/isa/isa_machdep.h @@ -0,0 +1,72 @@ +/* $OpenBSD: isa_machdep.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * All rights reserved. + * + * 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 Per Fogelstrom + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ +#ifndef _ISA_MACHDEP_H_ +#define _ISA_MACHDEP_H_ + +typedef struct arc_isa_bus *isa_chipset_tag_t; + +struct arc_isa_bus { + void *ic_data; + + void (*ic_attach_hook) __P((struct device *, struct device *, + struct isabus_attach_args *)); + void *(*ic_intr_establish) __P((isa_chipset_tag_t, int, int, int, + int (*)(void *), void *, char *)); + void (*ic_intr_disestablish) __P((isa_chipset_tag_t, void *)); +}; + + +/* + * Functions provided to machine-independent ISA code. + */ +#define isa_attach_hook(p, s, a) /* \ + (*(a)->iba_ic->ic_attach_hook)((p), (s), (a)) */ +#define isa_intr_establish(c, i, t, l, f, a, w) \ + (*(c)->ic_intr_establish)((c)->ic_data, (i), (t), (l), (f), (a), (w)) +#define isa_intr_disestablish(c, h) \ + (*(c)->ic_intr_disestablish)((c)->ic_data, (h)) + +/* + * Interrupt control struct used to control the ICU setup. + */ + +struct intrhand { + struct intrhand *ih_next; + int (*ih_fun) __P((void *)); + void *ih_arg; + u_long ih_count; + int ih_level; + int ih_irq; + char *ih_what; +}; + +#endif /* _ISA_MACHDEP_H_ */ diff --git a/sys/arch/arc/isa/isabus.c b/sys/arch/arc/isa/isabus.c new file mode 100644 index 00000000000..75f69270954 --- /dev/null +++ b/sys/arch/arc/isa/isabus.c @@ -0,0 +1,490 @@ +/* $OpenBSD: isabus.c,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp $ */ + +/*- + * Copyright (c) 1995 Per Fogelstrom + * Copyright (c) 1993, 1994 Charles Hannum. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * 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. + * + * @(#)isa.c 7.2 (Berkeley) 5/12/91 + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN 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/systm.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> +#include <machine/intr.h> + +#include <arc/arc/arctype.h> +#include <arc/pica/pica.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <arc/isa/timerreg.h> +#include <arc/isa/spkrreg.h> +#include <arc/isa/isa_machdep.h> + +extern int isa_io_base; /* Base address for ISA I/O space */ +extern int isa_mem_base; /* Base address for ISA MEM space */ + +static int beeping; + +/* + * I/O macros to access isa bus ports/memory. + * At the first glance theese macros may seem inefficient. + * However, the cpu executes an instruction every 7.5ns + * so the bus is much slower so it doesn't matter, really. + */ +#define isa_outb(x,y) outb(isa_io_base + (x), y) +#define isa_inb(x) inb(isa_io_base + (x)) + +#define IRQ_SLAVE 2 +#define ICU_LEN 16 + +struct isabr_softc { + struct device sc_dv; + struct arc_isa_bus arc_isa_cs; + struct arc_isa_busmap arc_isa_map; + struct abus sc_bus; +}; + +/* Definition of the driver for autoconfig. */ +int isabrmatch(struct device *, void *, void *); +void isabrattach(struct device *, struct device *, void *); +int isabrprint(void *, char *); + +struct cfattach isabr_ca = { + sizeof(struct isabr_softc), isabrmatch, isabrattach +}; +struct cfdriver isabr_cd = { + NULL, "isabr", DV_DULL, NULL, 0 +}; + +void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int, + int (*)(void *), void *, char *)); +void isabr_intr_disestablish __P((isa_chipset_tag_t, void*)); +int isabr_iointr __P((void *)); +void isabr_initicu(); + +extern int cputype; + + +int +isabrmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* Make sure that we're looking for a ISABR. */ + if (strcmp(ca->ca_name, isabr_cd.cd_name) != 0) + return (0); + + return (1); +} + +void +isabrattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct isabr_softc *sc = (struct isabr_softc *)self; + struct isabus_attach_args iba; + + printf("\n"); + + /* Initialize interrupt controller */ + isabr_initicu(); + + /* set up interrupt handlers */ + switch(cputype) { + case ACER_PICA_61: + set_intr(INT_MASK_2, isabr_iointr, 3); + break; + default: + panic("isabrattach: unkown cputype!"); + } + +/*XXX we may remove the abus part of the softc struct... */ + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_ISABR; + + sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish; + sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish; + sc->arc_isa_map.isa_io_base = (void *)isa_io_base; + sc->arc_isa_map.isa_mem_base = (void *)isa_mem_base; + + iba.iba_busname = "isa"; + iba.iba_bc = &sc->arc_isa_map; + iba.iba_ic = &sc->arc_isa_cs; + config_found(self, &iba, isabrprint); +} + +int +isabrprint(aux, pnp) + void *aux; + char *pnp; +{ + struct confargs *ca = aux; + + if (pnp) + printf("%s at %s", ca->ca_name, pnp); + printf(" I/O base 0x%lx Mem base 0x%lx", isa_io_base, isa_mem_base); + return (UNCONF); +} + + +/* + * Interrupt system driver code + * ============================ + */ +#define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2) + +int imen; +int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN]; +struct intrhand *intrhand[ICU_LEN]; + +int fakeintr(void *arg) {return 0;} + +/* + * Recalculate the interrupt masks from scratch. + * We could code special registry and deregistry versions of this function that + * would be faster, but the code would be nastier, and we don't expect this to + * happen very much anyway. + */ +void +intr_calculatemasks() +{ + int irq, level; + struct intrhand *q; + + /* First, figure out which levels each IRQ uses. */ + for (irq = 0; irq < ICU_LEN; irq++) { + register int levels = 0; + for (q = intrhand[irq]; q; q = q->ih_next) + levels |= 1 << q->ih_level; + intrlevel[irq] = levels; + } + + /* Then figure out which IRQs use each level. */ + for (level = 0; level < 5; level++) { + register int irqs = 0; + for (irq = 0; irq < ICU_LEN; irq++) + if (intrlevel[irq] & (1 << level)) + irqs |= 1 << irq; + imask[level] = irqs | SIR_ALLMASK; + } + + /* + * There are tty, network and disk drivers that use free() at interrupt + * time, so imp > (tty | net | bio). + */ + imask[IPL_IMP] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO]; + + /* + * Enforce a hierarchy that gives slow devices a better chance at not + * dropping data. + */ + imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO]; + imask[IPL_NET] |= imask[IPL_BIO]; + + /* + * These are pseudo-levels. + */ + imask[IPL_NONE] = 0x00000000; + imask[IPL_HIGH] = 0xffffffff; + + /* And eventually calculate the complete masks. */ + for (irq = 0; irq < ICU_LEN; irq++) { + register int irqs = 1 << irq; + for (q = intrhand[irq]; q; q = q->ih_next) + irqs |= imask[q->ih_level]; + intrmask[irq] = irqs | SIR_ALLMASK; + } + + /* Lastly, determine which IRQs are actually in use. */ + { + register int irqs = 0; + for (irq = 0; irq < ICU_LEN; irq++) + if (intrhand[irq]) + irqs |= 1 << irq; + if (irqs >= 0x100) /* any IRQs >= 8 in use */ + irqs |= 1 << IRQ_SLAVE; + imen = ~irqs; + isa_outb(IO_ICU1 + 1, imen); + isa_outb(IO_ICU2 + 1, imen >> 8); + } +} + +/* + * Establish a ISA bus interrupt. + */ +void * +isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what) + isa_chipset_tag_t ic; + int irq; + int type; + int level; + int (*ih_fun) __P((void *)); + void *ih_arg; + char *ih_what; +{ + struct intrhand **p, *q, *ih; + static struct intrhand fakehand = {NULL, fakeintr}; + extern int cold; + + /* no point in sleeping unless someone can free memory. */ + ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) + panic("isa_intr_establish: can't malloc handler info"); + + if (!LEGAL_IRQ(irq) || type == IST_NONE) + panic("intr_establish: bogus irq or type"); + + switch (intrtype[irq]) { + case IST_EDGE: + case IST_LEVEL: + if (type == intrtype[irq]) + break; + case IST_PULSE: + if (type != IST_NONE) + panic("intr_establish: can't share %s with %s", + isa_intr_typename(intrtype[irq]), + isa_intr_typename(type)); + break; + } + + /* + * Figure out where to put the handler. + * This is O(N^2), but we want to preserve the order, and N is + * generally small. + */ + for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + ; + + /* + * Actually install a fake handler momentarily, since we might be doing + * this with interrupts enabled and don't want the real routine called + * until masking is set up. + */ + fakehand.ih_level = level; + *p = &fakehand; + + intr_calculatemasks(); + + /* + * Poke the real handler in now. + */ + ih->ih_fun = ih_fun; + ih->ih_arg = ih_arg; + ih->ih_count = 0; + ih->ih_next = NULL; + ih->ih_level = level; + ih->ih_irq = irq; + ih->ih_what = ih_what; + *p = ih; + + return (ih); +} + +void +isabr_intr_disestablish(ic, arg) + isa_chipset_tag_t ic; + void *arg; +{ + +} + +/* + * Process an interrupt from the ISA bus ACER PICA style. + */ +int +isabr_iointr(ca) + void *ca; /* XXX */ +{ + struct intrhand *ih; + int isa_vector; + int o_imen; + + isa_vector = in32(PICA_SYS_ISA_VECTOR) & (ICU_LEN - 1); + + o_imen = imen; + imen |= 1 << (isa_vector & (ICU_LEN - 1)); + if(isa_vector & 0x08) { + isa_inb(IO_ICU2 + 1); + isa_outb(IO_ICU2 + 1, imen >> 8); + isa_outb(IO_ICU2, 0x60 + (isa_vector & 7)); + isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE); + } + else { + isa_inb(IO_ICU1 + 1); + isa_outb(IO_ICU1 + 1, imen); + isa_outb(IO_ICU1, 0x60 + isa_vector); + } + ih = intrhand[isa_vector]; + while(ih) { + (*ih->ih_fun)(ih->ih_arg); + ih = ih->ih_next; + } + imen = o_imen; + isa_inb(IO_ICU1 + 1); + isa_inb(IO_ICU2 + 1); + isa_outb(IO_ICU1 + 1, imen); + isa_outb(IO_ICU2 + 1, imen >> 8); + + return(~0); /* Dont reenable */ +} + + +/* + * Initialize the Interrupt controller logic. + */ +void +isabr_initicu() +{ + + isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ + isa_outb(IO_ICU1+1, 0); /* starting at this vector index */ + isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */ + isa_outb(IO_ICU1+1, 1); /* 8086 mode */ + isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ + isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */ + isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */ +#ifdef REORDER_IRQ + isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ +#endif + + isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ + isa_outb(IO_ICU2+1, 8); /* staring at this vector index */ + isa_outb(IO_ICU2+1, IRQ_SLAVE); + isa_outb(IO_ICU2+1, 1); /* 8086 mode */ + isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ + isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */ + isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */ +} + + +/* + * SPEAKER BEEPER... + */ +void +sysbeepstop(arg) + void *arg; +{ + int s; + + /* disable counter 2 */ + s = splhigh(); + isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR); + splx(s); + beeping = 0; +} + +void +sysbeep(pitch, period) + int pitch, period; +{ + static int last_pitch, last_period; + int s; + + if (beeping) + untimeout(sysbeepstop, 0); + if (!beeping || last_pitch != pitch) { + s = splhigh(); + isa_outb(TIMER_MODE, TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); + isa_outb(TIMER_CNTR2, TIMER_DIV(pitch) % 256); + isa_outb(TIMER_CNTR2, TIMER_DIV(pitch) / 256); + isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR); + splx(s); + } + last_pitch = pitch; + beeping = last_period = period; + timeout(sysbeepstop, 0, period); +} diff --git a/sys/arch/arc/isa/isadma.c b/sys/arch/arc/isa/isadma.c new file mode 100644 index 00000000000..95cdfbe475f --- /dev/null +++ b/sys/arch/arc/isa/isadma.c @@ -0,0 +1,317 @@ +/* $OpenBSD: isadma.c,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: isadma.c,v 1.19 1996/04/29 20:03:26 christos Exp $ */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/file.h> +#include <sys/buf.h> +#include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/uio.h> + +#include <vm/vm.h> + +#include <machine/pio.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> +#include <arch/arc/isa/isadmareg.h> /*XXX*/ + +struct dma_info { + int flags; + int active; + caddr_t addr; + vm_size_t nbytes; + struct isadma_seg phys[1]; +}; + +static struct isadma_softc *isadma_sc; /*XXX ugly */ +static struct dma_info dma_info[8]; +static u_int8_t dma_finished; + +/* high byte of address is stored in this port for i-th dma channel */ +static int dmapageport[2][4] = { + {0x87, 0x83, 0x81, 0x82}, + {0x8f, 0x8b, 0x89, 0x8a} +}; + +static u_int8_t dmamode[4] = { + DMA37MD_READ | DMA37MD_SINGLE, + DMA37MD_WRITE | DMA37MD_SINGLE, + DMA37MD_READ | DMA37MD_LOOP, + DMA37MD_WRITE | DMA37MD_LOOP +}; + +int isadmamatch __P((struct device *, void *, void *)); +void isadmaattach __P((struct device *, struct device *, void *)); +int isadmaprint __P((void *, char *)); + +struct isadma_softc { + struct device sc_dev; + bus_chipset_tag_t sc_bc; + bus_io_handle_t sc_ioh1; + bus_io_handle_t sc_ioh2; +} + +struct cfattach isadma_ca = { + sizeof(struct isadma_softc), isadmamatch, isadmaattach +}; + +struct cfdriver isadma_cd = { + NULL, "isadma", DV_DULL, 1 +}; + +isadmamatch(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct isa_attach_args *ia = aux; + + /* Sure we exist */ + ia->ia_iosize = 0; + return (1); +} + +void +isadmaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isadma_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + + printf("\n"); + + bc = sc->sc_bc = ia->ia_bc; + if (bus_io_map(bc, IO_DMA1, DMA_NREGS, &ioh)) + panic("isadmaattach: couldn't map I/O ports"); + sc->sc_ioh1 = ioh; + if (bus_io_map(bc, IO_DMA2, DMA_NREGS*2, &ioh)) + panic("isadmaattach: couldn't map I/O ports"); + sc->sc_ioh2 = ioh; + isadma_sc = sc; +} + +/* + * isadma_cascade(): program 8237 DMA controller channel to accept + * external dma control by a board. + */ +void +isadma_cascade(chan) + int chan; +{ + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7) + panic("isadma_cascade: impossible request"); +#endif + + /* set dma channel mode, and set dma channel mode */ + if ((chan & 4) == 0) { + bus_io_write_1(bc, sc->sc_ioh1, DMA1_MODE, chan | DMA37MD_CASCADE); + bus_io_write_1(bc, sc->sc_ioh1, DMA1_SMSK, chan); + } else { + chan &= 3; + + bus_io_write_1(bc, sc->sc_ioh2, DMA2_MODE, chan | DMA37MD_CASCADE); + bus_io_write_1(bc, sc->sc_ioh2, DMA2_SMSK, chan); + } +} + +/* + * isadma_start(): program 8237 DMA controller channel, avoid page alignment + * problems by using a bounce buffer. + */ +void +isadma_start(addr, nbytes, chan, flags) + caddr_t addr; + vm_size_t nbytes; + int chan; + int flags; +{ + struct dma_info *di; + int waport; + int mflags; + vm_size_t size; + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7 || + (((flags & DMAMODE_READ) != 0) + ((flags & DMAMODE_WRITE) != 0) + + ((flags & DMAMODE_LOOP) != 0) != 1) || + ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) : + (nbytes >= (1<<16)))) + panic("isadma_start: impossible request"); +#endif + + di = dma_info+chan; + if (di->active) { + log(LOG_ERR,"isadma_start: old request active on %d\n",chan); + isadma_abort(chan); + } + + di->flags = flags; + di->active = 1; + di->addr = addr; + di->nbytes = nbytes; + + mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_BOUNCE | ISADMA_MAP_CONTIG; + mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT; + + if (isadma_map(addr, nbytes, di->phys, mflags) != 1) + panic("isadma_start: cannot map"); + + /* XXX Will this do what we want with DMAMODE_LOOP? */ + if ((flags & DMAMODE_READ) == 0) + isadma_copytobuf(addr, nbytes, 1, di->phys); + + dma_finished &= ~(1 << chan); + + if ((chan & 4) == 0) { + ioh = sc->sc_ioh1; + /* + * Program one of DMA channels 0..3. These are + * byte mode channels. + */ + /* set dma channel mode, and reset address ff */ + bus_io_write_1(bc, ioh, DMA1_MODE, chan | dmamode[flags]); + bus_io_write_1(bc, ioh, DMA1_FFC, 0); + + /* send start address */ + waport = DMA1_CHN(chan); + outb(dmapageport[0][chan], di->phys[0].addr>>16); + outb(waport, di->phys[0].addr); + outb(waport, di->phys[0].addr>>8); + + /* send count */ + outb(waport + 1, --nbytes); + outb(waport + 1, nbytes>>8); + + /* unmask channel */ + bus_io_write_1(bc, ioh, DMA1_SMSK, chan | DMA37SM_CLEAR); + } else { + ioh = sc->sc_ioh2; + /* + * Program one of DMA channels 4..7. These are + * word mode channels. + */ + /* set dma channel mode, and reset address ff */ + bus_io_write_1(bc, ioh, DMA2_MODE, (chan & 3) | dmamode[flags]); + bus_io_write_1(bc, ioh, DMA2_FFC, 0); + + /* send start address */ + waport = DMA2_CHN(chan & 3); + outb(dmapageport[1][chan], di->phys[0].addr>>16); + outb(waport, di->phys[0].addr>>1); + outb(waport, di->phys[0].addr>>9); + + /* send count */ + nbytes >>= 1; + outb(waport + 2, --nbytes); + outb(waport + 2, nbytes>>8); + + /* unmask channel */ + bus_io_write_1(bc, ioh, DMA2_SMSK, (chan & 3) | DMA37SM_CLEAR); + } +} + +void +isadma_abort(chan) + int chan; +{ + struct dma_info *di; + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7) + panic("isadma_abort: impossible request"); +#endif + + di = dma_info+chan; + if (! di->active) { + log(LOG_ERR,"isadma_abort: no request active on %d\n",chan); + return; + } + + /* mask channel */ + if ((chan & 4) == 0) + bus_io_write_1(bc, sc->sc_ioh1, DMA1_SMSK, DMA37SM_SET | chan); + else + bus_io_write_1(bc, sc->sc_ioh2, DMA2_SMSK, DMA37SM_SET | (chan & 3)); + + isadma_unmap(di->addr, di->nbytes, 1, di->phys); + di->active = 0; +} + +int +isadma_finished(chan) + int chan; +{ + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7) + panic("isadma_finished: impossible request"); +#endif + + /* check that the terminal count was reached */ + if ((chan & 4) == 0) + dma_finished |= bus_io_read_1(bc, sc->sc_ioh1, DMA1_SR) & 0x0f; + else + dma_finished |= (bus_io_read_1(bc, sc->sc_ioh2, DMA2_SR) & 0x0f) << 4; + + return ((dma_finished & (1 << chan)) != 0); +} + +void +isadma_done(chan) + int chan; +{ + struct dma_info *di; + u_char tc; + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef DIAGNOSTIC + if (chan < 0 || chan > 7) + panic("isadma_done: impossible request"); +#endif + + di = dma_info+chan; + if (! di->active) { + log(LOG_ERR,"isadma_done: no request active on %d\n",chan); + return; + } + + /* check that the terminal count was reached */ + if ((chan & 4) == 0) + tc = bus_io_read_1(bc, sc->sc_ioh1, DMA1_SR) & (1 << chan); + else + tc = bus_io_read_1(bc, sc->sc_ioh2, DMA2_SR) & (1 << (chan & 3)); + if (tc == 0) + /* XXX probably should panic or something */ + log(LOG_ERR, "dma channel %d not finished\n", chan); + + /* mask channel */ + if ((chan & 4) == 0) + bus_io_write_1(bc, sc->sc_ioh1, DMA1_SMSK, DMA37SM_SET | chan); + else + bus_io_write_1(bc, sc->sc_ioh2, DMA2_SMSK, DMA37SM_SET | (chan & 3)); + + /* XXX Will this do what we want with DMAMODE_LOOP? */ + if (di->flags & DMAMODE_READ) + isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys); + + isadma_unmap(di->addr, di->nbytes, 1, di->phys); + di->active = 0; +} diff --git a/sys/arch/arc/isa/isadmareg.h b/sys/arch/arc/isa/isadmareg.h new file mode 100644 index 00000000000..185016060f2 --- /dev/null +++ b/sys/arch/arc/isa/isadmareg.h @@ -0,0 +1,22 @@ +/* $NetBSD: isadmareg.h,v 1.4 1995/06/28 04:31:48 cgd Exp $ */ + +#include <dev/ic/i8237reg.h> + +#define DMA_NREG 16 +/* + * Register definitions for DMA controller 1 (channels 0..3): + */ +#define DMA1_CHN(c) (1*(2*(c))) /* addr reg for channel c */ +#define DMA1_SR (1*8) /* status register */ +#define DMA1_SMSK (1*10) /* single mask register */ +#define DMA1_MODE (1*11) /* mode register */ +#define DMA1_FFC (1*12) /* clear first/last FF */ + +/* + * Register definitions for DMA controller 2 (channels 4..7): + */ +#define DMA2_CHN(c) (2*(2*(c))) /* addr reg for channel c */ +#define DMA2_SR (2*8) /* status register */ +#define DMA2_SMSK (2*10) /* single mask register */ +#define DMA2_MODE (2*11) /* mode register */ +#define DMA2_FFC (2*12) /* clear first/last FF */ diff --git a/sys/arch/arc/isa/spkrreg.h b/sys/arch/arc/isa/spkrreg.h new file mode 100644 index 00000000000..af1df50e2ad --- /dev/null +++ b/sys/arch/arc/isa/spkrreg.h @@ -0,0 +1,11 @@ +/* $NetBSD: spkrreg.h,v 1.2 1994/10/27 04:18:16 cgd Exp $ */ + +/* + * PIT port addresses and speaker control values + */ + +#define PITAUX_PORT 0x61 /* port of Programmable Peripheral Interface */ +#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */ +#define PIT_SPKRDATA 0x02 /* Direct to speaker */ + +#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA) diff --git a/sys/arch/arc/isa/timerreg.h b/sys/arch/arc/isa/timerreg.h new file mode 100644 index 00000000000..996834cadca --- /dev/null +++ b/sys/arch/arc/isa/timerreg.h @@ -0,0 +1,100 @@ +/* $NetBSD: timerreg.h,v 1.4 1994/10/27 04:18:17 cgd Exp $ */ + +/*- + * Copyright (c) 1993 The Regents of the University of California. + * All rights reserved. + * + * 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. + */ + +/* + * Register definitions for the Intel 8253 Programmable Interval Timer. + * + * This chip has three independent 16-bit down counters that can be + * read on the fly. There are three mode registers and three countdown + * registers. The countdown registers are addressed directly, via the + * first three I/O ports. The three mode registers are accessed via + * the fourth I/O port, with two bits in the mode byte indicating the + * register. (Why are hardware interfaces always so braindead?). + * + * To write a value into the countdown register, the mode register + * is first programmed with a command indicating the which byte of + * the two byte register is to be modified. The three possibilities + * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then + * msb (TMR_MR_BOTH). + * + * To read the current value ("on the fly") from the countdown register, + * you write a "latch" command into the mode register, then read the stable + * value from the corresponding I/O port. For example, you write + * TMR_MR_LATCH into the corresponding mode register. Presumably, + * after doing this, a write operation to the I/O port would result + * in undefined behavior (but hopefully not fry the chip). + * Reading in this manner has no side effects. + * + * The outputs of the three timers are connected as follows: + * + * timer 0 -> irq 0 + * timer 1 -> dma chan 0 (for dram refresh) + * timer 2 -> speaker (via keyboard controller) + * + * Timer 0 is used to call hardclock. + * Timer 2 is used to generate console beeps. + */ + +/* + * Frequency of all three count-down timers; (TIMER_FREQ/freq) is the + * appropriate count to generate a frequency of freq hz. + */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 +#endif +#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) + +/* + * Macros for specifying values to be written into a mode register. + */ +#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */ +#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */ +#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */ +#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */ +#define TIMER_SEL0 0x00 /* select counter 0 */ +#define TIMER_SEL1 0x40 /* select counter 1 */ +#define TIMER_SEL2 0x80 /* select counter 2 */ +#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */ +#define TIMER_ONESHOT 0x02 /* mode 1, one shot */ +#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */ +#define TIMER_SQWAVE 0x06 /* mode 3, square wave */ +#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */ +#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */ +#define TIMER_LATCH 0x00 /* latch counter for reading */ +#define TIMER_LSB 0x10 /* r/w counter LSB */ +#define TIMER_MSB 0x20 /* r/w counter MSB */ +#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */ +#define TIMER_BCD 0x01 /* count in BCD */ + diff --git a/sys/arch/arc/pica/pica.h b/sys/arch/arc/pica/pica.h new file mode 100644 index 00000000000..454e674f81f --- /dev/null +++ b/sys/arch/arc/pica/pica.h @@ -0,0 +1,168 @@ +/* $OpenBSD */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University, + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * from: @(#)pica.h 8.1 (Berkeley) 6/10/93 + * $Id: pica.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ + */ + +/* + * HISTORY + * Log: pica.h,v + * Created, from the ALI specs: + */ +/* + * File: pica.h + * Author: Per Fogelstrom + * Date: 1/95 + * + */ + +#ifndef _PICA_H_ +#define _PICA_H_ 1 + +/* + * PICA's Physical address space + */ + +#define PICA_PHYS_MIN 0x00000000 /* 256 Meg */ +#define PICA_PHYS_MAX 0x0fffffff + +/* + * Memory map + */ + +#define PICA_PHYS_MEMORY_START 0x00000000 +#define PICA_PHYS_MEMORY_END 0x0fffffff /* 256 Meg in 8 slots */ + +#define PICA_MEMORY_SIZE_REG 0xe00fffe0 /* Memory size register */ +#define PICA_CONFIG_REG 0xe00ffff0 /* Hardware config reg */ + +/* + * I/O map + */ + +#define PICA_P_LOCAL_IO_BASE 0x80000000 /* I/O Base address */ +#define PICA_V_LOCAL_IO_BASE 0xe0000000 +#define PICA_S_LOCAL_IO_BASE 0x00040000 /* Size */ +#define PVLB PICA_V_LOCAL_IO_BASE +#define PICA_SYS_TL_BASE (PVLB+0x0018) /* DMA transl. table base */ +#define PICA_SYS_TL_LIMIT (PVLB+0x0020) /* DMA transl. table limit */ +#define PICA_SYS_TL_IVALID (PVLB+0x0028) /* DMA transl. cache inval */ +#define PICA_SYS_DMA0_REGS (PVLB+0x0100) /* DMA ch0 base address */ +#define PICA_SYS_DMA1_REGS (PVLB+0x0120) /* DMA ch0 base address */ +#define PICA_SYS_DMA2_REGS (PVLB+0x0140) /* DMA ch0 base address */ +#define PICA_SYS_DMA3_REGS (PVLB+0x0160) /* DMA ch0 base address */ +#define PICA_SYS_IT_VALUE (PVLB+0x0228) /* Interval timer reload */ +#define PICA_SYS_IT_STAT (PVLB+0x0230) /* Interval timer count */ +#define PICA_SYS_ISA_VECTOR (PVLB+0x0238) /* ISA Interrupt vector */ +#define PICA_SYS_EXT_IMASK (PVLB+0x00e8) /* External int enable mask */ +#define PICA_SYS_SONIC (PVLB+0x1000) /* SONIC base address */ +#define PICA_SYS_SCSI (PVLB+0x2000) /* SCSI base address */ +#define PICA_SYS_FLOPPY (PVLB+0x3000) /* Floppy base address */ +#define PICA_SYS_CLOCK (PVLB+0x4000) /* Clock base address */ +#define PICA_SYS_KBD (PVLB+0x5000) /* Keybrd/mouse base address */ +#define PICA_SYS_COM1 (PVLB+0x6000) /* Com port 1 */ +#define PICA_SYS_COM2 (PVLB+0x7000) /* Com port 2 */ +#define PICA_SYS_PAR1 (PVLB+0x8000) /* Parallel port 1 */ +#define PICA_SYS_NVRAM (PVLB+0x9000) /* Unprotected NV-ram */ +#define PICA_SYS_PNVRAM (PVLB+0xa000) /* Protected NV-ram */ +#define PICA_SYS_NVPROM (PVLB+0xb000) /* Read only NV-ram */ +#define PICA_SYS_SOUND (PVLB+0xc000) /* Sound port */ + +#define PICA_SYS_ISA_AS (PICA_V_ISA_IO+0x70) + +#define PICA_P_DRAM_CONF 0x800e0000 /* Dram config registers */ +#define PICA_V_DRAM_CONF 0xe00e0000 +#define PICA_S_DRAM_CONF 0x00020000 + +#define PICA_P_INT_SOURCE 0xf0000000 /* Interrupt src registers */ +#define PICA_V_INT_SOURCE PICA_V_LOCAL_IO_BASE+PICA_S_LOCAL_IO_BASE +#define PICA_S_INT_SOURCE 0x00001000 +#define PVIS PICA_V_INT_SOURCE +#define PICA_SYS_LB_IS (PVIS+0x0000) /* Local bus int source */ +#define PICA_SYS_LB_IE (PVIS+0x0002) /* Local bus int enables */ +#define PICA_SYS_LB_IE_PAR1 0x0001 /* Parallel port enable */ +#define PICA_SYS_LB_IE_FLOPPY 0x0002 /* Floppy ctrl enable */ +#define PICA_SYS_LB_IE_SOUND 0x0004 /* Sound port enable */ +#define PICA_SYS_LB_IE_VIDEO 0x0008 /* Video int enable */ +#define PICA_SYS_LB_IE_SONIC 0x0010 /* Ethernet ctrl enable */ +#define PICA_SYS_LB_IE_SCSI 0x0020 /* Scsi crtl enable */ +#define PICA_SYS_LB_IE_KBD 0x0040 /* Keyboard ctrl enable */ +#define PICA_SYS_LB_IE_MOUSE 0x0080 /* Mouse ctrl enable */ +#define PICA_SYS_LB_IE_COM1 0x0100 /* Serial port 1 enable */ +#define PICA_SYS_LB_IE_COM2 0x0200 /* Serial port 2 enable */ + +#define PICA_P_LOCAL_VIDEO_CTRL 0x60000000 /* Local video control */ +#define PICA_V_LOCAL_VIDEO_CTRL 0xe0200000 +#define PICA_S_LOCAL_VIDEO_CTRL 0x00200000 + +#define PICA_P_EXTND_VIDEO_CTRL 0x60200000 /* Extended video control */ +#define PICA_V_EXTND_VIDEO_CTRL 0xe0400000 +#define PICA_S_EXTND_VIDEO_CTRL 0x00200000 + +#define PICA_P_LOCAL_VIDEO 0x40000000 /* Local video memory */ +#define PICA_V_LOCAL_VIDEO 0xe0800000 +#define PICA_S_LOCAL_VIDEO 0x00800000 + +#define PICA_P_ISA_IO 0x90000000 /* ISA I/O control */ +#define PICA_V_ISA_IO 0xe2000000 +#define PICA_S_ISA_IO 0x01000000 + +#define PICA_P_ISA_MEM 0x91000000 /* ISA Memory control */ +#define PICA_V_ISA_MEM 0xe3000000 +#define PICA_S_ISA_MEM 0x01000000 + +/* + * Addresses used by various display drivers. + */ +#define MONO_BASE (PICA_V_LOCAL_VIDEO_CTRL + 0x3B4) +#define MONO_BUF (PICA_V_LOCAL_VIDEO + 0xB0000) +#define CGA_BASE (PICA_V_LOCAL_VIDEO_CTRL + 0x3D4) +#define CGA_BUF (PICA_V_LOCAL_VIDEO + 0xB8000) + +/* + * Interrupt vector descriptor for device on pica bus. + */ +struct pica_int_desc { + int int_mask; /* Mask used in PICA_SYS_LB_IE */ + intr_handler_t int_hand; /* Interrupt handler */ + void *param; /* Parameter to send to handler */ + int spl_mask; /* Spl mask for interrupt */ +}; + +int pica_intrnull __P((void *)); +#endif /* _PICA_H_ */ diff --git a/sys/arch/arc/pica/picabus.c b/sys/arch/arc/pica/picabus.c new file mode 100644 index 00000000000..f6058cf8b4d --- /dev/null +++ b/sys/arch/arc/pica/picabus.c @@ -0,0 +1,323 @@ +/* $OpenBSD: picabus.c,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: tc.c,v 1.2 1995/03/08 00:39:05 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * Author: Per Fogelstrom. (Mips R4x00) + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/device.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> + +#include <arc/pica/pica.h> +#include <arc/arc/arctype.h> + +struct pica_softc { + struct device sc_dv; + struct abus sc_bus; + struct pica_dev *sc_devs; +}; + +/* Definition of the driver for autoconfig. */ +int picamatch(struct device *, void *, void *); +void picaattach(struct device *, struct device *, void *); +int picaprint(void *, char *); + +struct cfattach pica_ca = { + sizeof(struct pica_softc), picamatch, picaattach +}; +struct cfdriver pica_cd = { + NULL, "pica", DV_DULL, NULL, 0 +}; + +void pica_intr_establish __P((struct confargs *, int (*)(void *), void *)); +void pica_intr_disestablish __P((struct confargs *)); +caddr_t pica_cvtaddr __P((struct confargs *)); +int pica_matchname __P((struct confargs *, char *)); +int pica_iointr __P((void *)); +int pica_clkintr __P((unsigned, unsigned, unsigned, unsigned)); + +extern int cputype; + +/* + * Interrupt dispatch table. + */ +struct pica_int_desc int_table[] = { + {0, pica_intrnull, (void *)NULL, 0 }, /* 0 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 1 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 2 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 3 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 4 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 5 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 6 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 7 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 8 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 9 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 10 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 11 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 12 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 13 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 14 */ + {0, pica_intrnull, (void *)NULL, 0 }, /* 15 */ +}; + +struct pica_dev { + struct confargs ps_ca; + u_int ps_mask; + intr_handler_t ps_handler; + void *ps_base; +}; +#ifdef ACER_PICA_61 +struct pica_dev acer_pica_61_cpu[] = { + {{ "dallas_rtc",0, 0, }, + 0, pica_intrnull, (void *)PICA_SYS_CLOCK, }, + {{ "lpt", 1, 0, }, + PICA_SYS_LB_IE_PAR1, pica_intrnull, (void *)PICA_SYS_PAR1, }, + {{ "fdc", 2, 0, }, + PICA_SYS_LB_IE_FLOPPY,pica_intrnull, (void *)PICA_SYS_FLOPPY, }, + {{ NULL, 3, NULL, }, + 0, pica_intrnull, (void *)NULL, }, + {{ NULL, 4, NULL, }, + 0, pica_intrnull, (void *)NULL, }, + {{ "sonic", 5, 0, }, + PICA_SYS_LB_IE_SONIC, pica_intrnull, (void *)PICA_SYS_SONIC, }, + {{ "asc", 6, 0, }, + PICA_SYS_LB_IE_SCSI, pica_intrnull, (void *)PICA_SYS_SCSI, }, + {{ "pc", 7, 0, }, + PICA_SYS_LB_IE_KBD, pica_intrnull, (void *)PICA_SYS_KBD, }, + {{ "pms", 8, NULL, }, + PICA_SYS_LB_IE_MOUSE, pica_intrnull, (void *)PICA_SYS_KBD, }, + {{ "com", 9, 0, }, + PICA_SYS_LB_IE_COM1, pica_intrnull, (void *)PICA_SYS_COM1, }, + {{ "com", 10, 0, }, + PICA_SYS_LB_IE_COM2, pica_intrnull, (void *)PICA_SYS_COM2, }, + {{ NULL, -1, NULL, }, + 0, NULL, (void *)NULL, }, +}; +#endif + +struct pica_dev *pica_cpu_devs[] = { + NULL, /* Unused */ +#ifdef ACER_PICA_61 + acer_pica_61_cpu, /* Acer PICA */ +#else + NULL, +#endif +}; +int npica_cpu_devs = sizeof pica_cpu_devs / sizeof pica_cpu_devs[0]; + +int local_int_mask = 0; /* Local interrupt enable mask */ + +int +picamatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* Make sure that we're looking for a PICA. */ + if (strcmp(ca->ca_name, pica_cd.cd_name) != 0) + return (0); + + /* Make sure that unit exists. */ + if (cf->cf_unit != 0 || + cputype > npica_cpu_devs || pica_cpu_devs[cputype] == NULL) + return (0); + + return (1); +} + +void +picaattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct pica_softc *sc = (struct pica_softc *)self; + struct confargs *nca; + int i; + + printf("\n"); + + /* keep our CPU device description handy */ + sc->sc_devs = pica_cpu_devs[cputype]; + + /* set up interrupt handlers */ + set_intr(INT_MASK_1, pica_iointr, 2); + + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_PICA; + sc->sc_bus.ab_intr_establish = pica_intr_establish; + sc->sc_bus.ab_intr_disestablish = pica_intr_disestablish; + sc->sc_bus.ab_cvtaddr = pica_cvtaddr; + sc->sc_bus.ab_matchname = pica_matchname; + + /* Initialize PICA Dma */ + picaDmaInit(); + + /* Try to configure each PICA attached device */ + for (i = 0; sc->sc_devs[i].ps_ca.ca_slot >= 0; i++) { + + if(sc->sc_devs[i].ps_ca.ca_name == NULL) + continue; /* Empty slot */ + + nca = &sc->sc_devs[i].ps_ca; + nca->ca_bus = &sc->sc_bus; + + /* Tell the autoconfig machinery we've found the hardware. */ + config_found(self, nca, picaprint); + } +} + +int +picaprint(aux, pnp) + void *aux; + char *pnp; +{ + struct confargs *ca = aux; + + if (pnp) + printf("%s at %s", ca->ca_name, pnp); + printf(" slot %ld offset 0x%lx", ca->ca_slot, ca->ca_offset); + return (UNCONF); +} + +caddr_t +pica_cvtaddr(ca) + struct confargs *ca; +{ + struct pica_softc *sc = pica_cd.cd_devs[0]; + + return(sc->sc_devs[ca->ca_slot].ps_base + ca->ca_offset); + +} + +void +pica_intr_establish(ca, handler, val) + struct confargs *ca; + intr_handler_t handler; + void *val; +{ + struct pica_softc *sc = pica_cd.cd_devs[0]; + + int slot; + + slot = ca->ca_slot; + if(slot == 0) { /* Slot 0 is special, clock */ + set_intr(INT_MASK_4, pica_clkintr, 1); + } + + if(int_table[slot].int_mask != 0) { + panic("pica intr already set"); + } + else { + int_table[slot].int_mask = sc->sc_devs[slot].ps_mask;; + local_int_mask |= int_table[slot].int_mask; + int_table[slot].int_hand = handler; + int_table[slot].param = val; + } + out16(PICA_SYS_LB_IE, local_int_mask); +} + +void +pica_intr_disestablish(ca) + struct confargs *ca; +{ + struct pica_softc *sc = pica_cd.cd_devs[0]; + + int slot; + + slot = ca->ca_slot; + if(slot = 0) { /* Slot 0 is special, clock */ + } + else { + local_int_mask &= ~int_table[slot].int_mask; + int_table[slot].int_mask = 0; + int_table[slot].int_hand = pica_intrnull; + int_table[slot].param = (void *)NULL; + } +} + +int +pica_matchname(ca, name) + struct confargs *ca; + char *name; +{ + return (strcmp(name, ca->ca_name) == 0); +} + +int +pica_intrnull(val) + void *val; +{ + panic("uncaught PICA intr for slot %d\n", val); +} + +/* + * Handle pica i/o interrupt. + */ +int +pica_iointr(val) + void *val; +{ + int vector; + + while((vector = inb(PVIS) >> 2) != 0) { + (*int_table[vector].int_hand)(int_table[vector].param); + } + return(~0); /* Dont reenable */ +} + +/* + * Handle pica interval clock interrupt. + */ +int +pica_clkintr(mask, pc, statusReg, causeReg) + unsigned mask; + unsigned pc; + unsigned statusReg; + unsigned causeReg; +{ + struct clockframe cf; + int temp; + + temp = inw(PICA_SYS_IT_STAT); + cf.pc = pc; + cf.sr = statusReg; + hardclock(&cf); + + /* Re-enable clock interrupts */ + splx(INT_MASK_4 | SR_INT_ENAB); + + return(~INT_MASK_4); /* Keep clock interrupts enabled */ +} + diff --git a/sys/arch/arc/stand/Makefile b/sys/arch/arc/stand/Makefile new file mode 100644 index 00000000000..a7dd6383200 --- /dev/null +++ b/sys/arch/arc/stand/Makefile @@ -0,0 +1,96 @@ +# $NetBSD: Makefile,v 1.5 1995/01/18 06:53:36 mellon Exp $ +# @(#)Makefile 8.3 (Berkeley) 2/16/94 + +DESTDIR= +STAND= ../../stand +#VPATH= ${STAND} + +# RELOC=80200000 allows for boot prog up to 1D0000 (1900544) bytes long +RELOC= 80200000 + +S= ../../.. + +DEFS= -DSTANDALONE -DDEBUG +CFLAGS= -O2 ${INCPATH} ${DEFS} +AFLAGS= -O2 ${INCPATH} ${DEFS} -DLOCORE + +.PATH: ${S}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} +.PATH: ${S}/stand ${S}/lib/libsa + +#INCPATH=-I. -I/sys +INCPATH=-I${.CURDIR} -I${.CURDIR}/../.. -I${S} -I${S}/lib/libsa + +### find out what to use for libkern +.include "$S/lib/libkern/Makefile.inc" +LIBKERN= ${KERNLIB} +#KERNLIB= ${.CURDIR}/../compile/libkern.a + +.include "$S/lib/libsa/Makefile.inc" +LIBSA= ${SA_LIB} + +# not yet: need to write libsa/Makefile.inc first +LIBS= ${.OBJDIR}/libdrive.a ${.CURDIR}/libsa/libsa.a ${KERNLIB} +#LIBS= libdrive.a libsa/libsa.a ../../libkern/obj/libkern.a + +DRIVERS= rz.c +SRCS= ${DRIVERS} +#STUFF= callvec.c devopen.c getenv.c gets.c strcmp.c +STUFF= + +ALL= boot + +.s.o: + ${CPP} -E ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \ + ${AS} -o ${.TARGET} + +all: ${ALL} + +boot: ${LIBS} + +#libsa/libsa.a:: +# cd libsa; make + +${.OBJDIR}/libdrive.a: conf.o ${DRIVERS:.c=.o} + ar crv $@ $? + ranlib $@ + +# depend on DEFS + +#before other deps on bootconf.o +bootconf.o: conf.o + rm -f bootconf.c + ln -s ${.CURDIR}/conf.c bootconf.c + ${CC} -c ${CFLAGS} -DBOOT bootconf.c + rm -f bootconf.c + + +# bootable from real disks + +boot: start.o boot.o bootconf.o filesystem.o ${LIBS} + /usr/gnu/ld -N -Ttext ${RELOC} -e __start start.o boot.o bootconf.o filesystem.o ${LIBS} -o boot.elf + elf2ecoff boot.elf boot + +start.o: ${.CURDIR}/start.S + +# ${CPP} -E ${CFLAGS:M-[ID]*} -DLOCORE ${AINC} ${.IMPSRC} | \ +# ${AS} -o ${.TARGET} + +mkboot: ${.CURDIR}/mkboot.c + ${CC} ${CFLAGS} -o mkboot ${.CURDIR}/mkboot.c + +# utilities + +clean:: + rm -f .depend *.o *.exe *.i errs make.out core* + rm -f a.out ${ALL} + rm -f libdrive.a + cd libsa; make cleandir + +install: + +depend: ${SRCS} + mkdep ${INCPATH} ${DEFS} ${SRCS} + cd libsa; make depend + +.include <bsd.dep.mk> +.include <bsd.obj.mk> diff --git a/sys/arch/arc/stand/boot.c b/sys/arch/arc/stand/boot.c new file mode 100644 index 00000000000..170f6f923de --- /dev/null +++ b/sys/arch/arc/stand/boot.c @@ -0,0 +1,114 @@ +/* $NetBSD: boot.c,v 1.6 1995/06/28 10:22:32 jonathan Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)boot.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/exec.h> +#include <stand.h> + + +char line[1024]; + +/* + * This gets arguments from the PROM, calls other routines to open + * and load the program to boot, and then transfers execution to that + * new program. + * Argv[0] should be something like "rz(0,0,0)vmunix" on a DECstation 3100. + * Argv[0,1] should be something like "boot 5/rz0/vmunix" on a DECstation 5000. + * The argument "-a" means vmunix should do an automatic reboot. + */ +int +main(argc, argv) + int argc; + char **argv; +{ + char *cp; + int ask, entry; + int i; + + ask = 1; + + for(i = 0; i < argc; i++) + printf("Arg %d:%s\n",i,argv[i]); + + do { + printf("Boot: "); + if (ask) { + gets(line); + cp = line; + argv[0] = cp; + argc = 1; + } else + printf("%s\n", cp); + } while(ask && line[0] == '\0'); + + entry = loadfile(cp); + if (entry == -1) { + gets(line); + return 0; + } + + printf("Starting at 0x%x\n\n", entry); + ((void (*)())entry)(argc, argv, 0, 0); +} + +/* + * Open 'filename', read in program and return the entry point or -1 if error. + */ +loadfile(fname) + register char *fname; +{ + struct devices *dp; + int fd, i, n; + struct exec aout; + + if ((fd = open(fname, 0)) < 0) { + printf("open(%s) failed: %d\n", fname, errno); + goto err; + } + + /* read the exec header */ + i = read(fd, (char *)&aout, sizeof(aout)); + +cerr: + (void) close(fd); +err: + printf("Can't boot '%s'\n", fname); + return (-1); +} diff --git a/sys/arch/arc/stand/conf.c b/sys/arch/arc/stand/conf.c new file mode 100644 index 00000000000..cecbc70b64c --- /dev/null +++ b/sys/arch/arc/stand/conf.c @@ -0,0 +1,70 @@ +/* $NetBSD: conf.c,v 1.5 1995/01/18 06:53:39 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)conf.c 8.1 (Berkeley) 6/10/93 + */ + +#include <stand.h> + +int errno; + +extern void nullsys(); +extern int nodev(), noioctl(); + +int rzstrategy(), rzopen(); +#ifdef SMALL +#define rzclose 0 +#else /*!SMALL*/ +int rzclose(); +#endif /*!SMALL*/ + +#define rzioctl noioctl + +#ifndef BOOT +int tzstrategy(), tzopen(), tzclose(); +#endif +#define tzioctl noioctl + + +struct devsw devsw[] = { + { "rz", rzstrategy, rzopen, rzclose, rzioctl }, /*0*/ +#ifndef BOOT + { "tz", tzstrategy, tzopen, tzclose, tzioctl }, /*1*/ +#endif +}; + +int ndevs = (sizeof(devsw)/sizeof(devsw[0])); diff --git a/sys/arch/arc/stand/filesystem.c b/sys/arch/arc/stand/filesystem.c new file mode 100644 index 00000000000..514e6e809bf --- /dev/null +++ b/sys/arch/arc/stand/filesystem.c @@ -0,0 +1,44 @@ +/* $NetBSD: filesystem.c,v 1.2 1995/02/16 02:33:05 cgd Exp $ */ + +/* + * Copyright (c) 1993 Philip A. Nelson. + * All rights reserved. + * + * 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 Philip A. Nelson. + * 4. The name of Philip A. Nelson may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY PHILIP NELSON ``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 PHILIP NELSON 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. + * + * filesystem.c + */ + +#include <lib/libsa/stand.h> +#include <lib/libsa/ufs.h> + +struct fs_ops file_system[] = { + { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat }, +}; + +int nfsys = sizeof(file_system)/sizeof(struct fs_ops); + diff --git a/sys/arch/arc/stand/libsa/Makefile b/sys/arch/arc/stand/libsa/Makefile new file mode 100644 index 00000000000..d147171311d --- /dev/null +++ b/sys/arch/arc/stand/libsa/Makefile @@ -0,0 +1,14 @@ +# $NetBSD: Makefile,v 1.5 1995/01/18 06:53:51 mellon Exp $ +# @(#)Makefile 8.2 (Berkeley) 2/16/94 + +LIB= sa +SRCS= alloc.c bcopy.c bzero.c close.c dev.c disklabel.c getfile.c \ + getputchar.c ioctl.c lseek.c open.c printf.c read.c ufs.c write.c \ + devopen.c getenv.c gets.c strcat.c strcmp.c strcpy.c strlen.c + +.PATH: ../../../../lib/libsa ../../../../lib/libkern +NOPROFILE=noprofile + +.include <bsd.lib.mk> + +CFLAGS=-O2 -I../../include -I/sys -DSMALL diff --git a/sys/arch/arc/stand/libsa/devopen.c b/sys/arch/arc/stand/libsa/devopen.c new file mode 100644 index 00000000000..79b35f8f595 --- /dev/null +++ b/sys/arch/arc/stand/libsa/devopen.c @@ -0,0 +1,128 @@ +/* $NetBSD: devopen.c,v 1.5 1995/01/18 06:53:54 mellon Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)devopen.c 8.1 (Berkeley) 6/10/93 + */ + +#include <lib/libsa/stand.h> + +/* + * Decode the string 'fname', open the device and return the remaining + * file name if any. + */ +devopen(f, fname, file) + struct open_file *f; + const char *fname; + char **file; /* out */ +{ + register char *cp; + register char *ncp; + register struct devsw *dp; + register int c, i; + int ctlr = 0, unit = 0, part = 0; + char namebuf[20]; + int rc; + + cp = fname; + ncp = namebuf; + + /* expect a string like 'rz(0,0,0)vmunix' */ + while ((c = *cp) != '\0') { + if (c == '(') { + cp++; + break; + } + if (ncp < namebuf + sizeof(namebuf) - 1) + *ncp++ = c; + cp++; + } + + /* get controller number */ + if ((c = *cp) >= '0' && c <= '9') { + ctlr = c - '0'; + c = *++cp; + } + + if (c == ',') { + /* get SCSI device number */ + if ((c = *++cp) >= '0' && c <= '9') { + unit = c - '0'; + c = *++cp; + } + + if (c == ',') { + /* get partition number */ + if ((c = *++cp) >= '0' && c <= '9') { + part = c - '0'; + c = *++cp; + } + } + } + if (c != ')') + return (ENXIO); + cp++; + *ncp = '\0'; + +#ifdef SMALL + if (strcmp (namebuf, "rz")) { + printf ("Unknown device: %s\n", namebuf); + return ENXIO; + } + dp = devsw; + i = 0; +#else + for (dp = devsw, i = 0; i < ndevs; dp++, i++) + if (dp->dv_name && strcmp(namebuf, dp->dv_name) == 0) + goto fnd; + printf("Unknown device '%s'\nKnown devices are:", namebuf); + for (dp = devsw, i = 0; i < ndevs; dp++, i++) + if (dp->dv_name) + printf(" %s", dp->dv_name); + printf("\n"); + return (ENXIO); + +fnd: +#endif + rc = (dp->dv_open)(f, ctlr, unit, part); + if (rc) + return (rc); + + f->f_dev = dp; + if (file && *cp != '\0') + *file = cp; + return (0); +} diff --git a/sys/arch/arc/stand/libsa/getenv.c b/sys/arch/arc/stand/libsa/getenv.c new file mode 100644 index 00000000000..7e063cd4ad5 --- /dev/null +++ b/sys/arch/arc/stand/libsa/getenv.c @@ -0,0 +1,45 @@ +/* $NetBSD: getenv.c,v 1.5 1995/01/18 06:53:55 mellon Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)getenv.c 8.1 (Berkeley) 6/10/93 + */ + +char * +getenv(s) + char *s; +{ +} diff --git a/sys/arch/arc/stand/libsa/getputchar.c b/sys/arch/arc/stand/libsa/getputchar.c new file mode 100644 index 00000000000..dbfae22d4d6 --- /dev/null +++ b/sys/arch/arc/stand/libsa/getputchar.c @@ -0,0 +1,69 @@ +/* $NetBSD: getenv.c,v 1.5 1995/01/18 06:53:55 mellon Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + * @(#)getenv.c 8.1 (Berkeley) 6/10/93 + */ + +getchar() +{ + char buf[4]; + int cnt; + + if(Bios_Read(0, &buf, 1, &cnt) != 0) + return(-1); + return(buf[0] & 255); +} + +putchar(c) +char c; +{ + char buf[4]; + int cnt; + + if(c == '\n') { + buf[0] = '\r'; + buf[1] = c; + cnt = 2; + } + else { + buf[0] = c; + cnt = 1; + } + if(Bios_Write(1, &buf, cnt, &cnt) != 0) + return(-1); + return(0); +} diff --git a/sys/arch/arc/stand/rz.c b/sys/arch/arc/stand/rz.c new file mode 100644 index 00000000000..1094aef4705 --- /dev/null +++ b/sys/arch/arc/stand/rz.c @@ -0,0 +1,174 @@ +/* $NetBSD: rz.c,v 1.6 1995/06/28 10:22:35 jonathan Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell. + * + * 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. + * + * @(#)rz.c 8.1 (Berkeley) 6/10/93 + */ + +#include <stdarg.h> + +#include <stand.h> +#include <sys/param.h> +#include <sys/disklabel.h> + +struct rz_softc { + int sc_fd; /* PROM file id */ + int sc_ctlr; /* controller number */ + int sc_unit; /* disk unit number */ + int sc_part; /* disk partition number */ + struct disklabel sc_label; /* disk label for this disk */ +}; + +int +rzstrategy(devdata, rw, bn, reqcnt, addr, cnt) + void *devdata; + int rw; + daddr_t bn; + u_int reqcnt; + char *addr; + u_int *cnt; /* out: number of bytes transfered */ +{ + register struct rz_softc *sc = (struct rz_softc *)devdata; + register int part = sc->sc_part; + register struct partition *pp = &sc->sc_label.d_partitions[part]; + register int s; + long offset; + + offset = bn * DEV_BSIZE; + +#ifdef DEBUG +/*XXX*/printf("rz:%x %d\n", offset, reqcnt); +#endif + + /* + * Partial-block transfers not handled. + */ + if (reqcnt & (DEV_BSIZE - 1)) { + *cnt = 0; + return (EINVAL); + } + + offset += pp->p_offset * DEV_BSIZE; + + if (Bios_Seek(sc->sc_fd, &offset, 0) != 0) + return (EIO); + s = Bios_Read(sc->sc_fd, addr, reqcnt, &reqcnt); + if (s != 0) + return (EIO); + + *cnt = reqcnt; + return (0); +} + +int +rzopen(struct open_file *f, ...) +{ + int ctlr, unit, part; + + struct rz_softc *sc; + struct disklabel *lp; + int i, fd; + char *msg; + char buf[DEV_BSIZE]; + int cnt; + static char device[] = "scsi()disk(0)rdisk()"; + va_list ap; + + va_start(ap, f); + + ctlr = va_arg(ap, int); + unit = va_arg(ap, int); + part = va_arg(ap, int); + if (unit >= 8 || part >= 8) + return (ENXIO); +#if 0 + device[5] = '0' + unit; +#endif + /* NOTE: only support reads for now */ + + i = Bios_Open(device, 0, &fd); + if (i != 0) { + printf("boot init failed error code %d\n", i); + return (ENXIO); + } + + sc = alloc(sizeof(struct rz_softc)); + bzero(sc, sizeof(struct rz_softc)); + f->f_devdata = (void *)sc; + + sc->sc_fd = fd; + sc->sc_ctlr = ctlr; + sc->sc_unit = unit; + sc->sc_part = part; + + /* try to read disk label and partition table information */ + lp = &sc->sc_label; + lp->d_secsize = DEV_BSIZE; + lp->d_secpercyl = 1; + lp->d_npartitions = MAXPARTITIONS; + lp->d_partitions[part].p_offset = 0; + lp->d_partitions[part].p_size = 0x7fffffff; + i = rzstrategy(sc, F_READ, (daddr_t)LABELSECTOR, DEV_BSIZE, buf, &cnt); + if (i || cnt != DEV_BSIZE) { + printf("rz%d: error reading disk label\n", unit); + goto bad; + } else { + msg = getdisklabel(buf, lp); + if (msg) { + printf("rz%d: %s\n", unit, msg); + goto bad; + } + } + + if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) { + bad: +#ifndef SMALL + free(sc, sizeof(struct rz_softc)); +#endif + return (ENXIO); + } + return (0); +} + +#ifndef SMALL +rzclose(f) + struct open_file *f; +{ + free(f->f_devdata, sizeof(struct rz_softc)); + f->f_devdata = (void *)0; + return (0); +} +#endif diff --git a/sys/arch/arc/stand/start.S b/sys/arch/arc/stand/start.S new file mode 100644 index 00000000000..09114a91b7e --- /dev/null +++ b/sys/arch/arc/stand/start.S @@ -0,0 +1,129 @@ +/* $NetBSD: start.S,v 1.1 1995/01/18 06:19:01 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * 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. + * + */ + +/* + * start.S - + * + * Contains code that is the first executed at boot time. + */ + +#include <machine/regdef.h> +#include <machine/cpu.h> +#include <machine/asm.h> + +/* + * Frame required for the debugger (if we have any) + */ +#define START_FRAME ((4 * 4) + 4 + 4) + + .globl __start +__start: + .set noreorder +#ifdef __GP_SUPPORT__ + la gp, _C_LABEL (_gp) +#endif + la sp, __start - START_FRAME # Stack below program + sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger + sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger + move s0, a0 # save argc + move s1, a1 # save argv + + la a0, _C_LABEL (edata) # clear BSS + la a1, _C_LABEL (end) + jal _C_LABEL(bzero) # bzero(edata, end - edata) + subu a1, a1, a0 + + move a0, s0 # restore argc + jal _C_LABEL(main) # main(argc, argv) + move a1, s1 # restore argv + + j _C_LABEL(Bios_Restart) # restart... + nop + +/* dummy routine for gcc2 */ + .globl _C_LABEL(__main) +_C_LABEL(__main): + j ra + nop + +#define Bios_Call(Name,Offset) \ +LEAF(Name); \ + lw v0,0x80001020; \ + lw v0,Offset(v0); \ + jr v0 ; \ + nop ; \ + END(Name) + +Bios_Call(Bios_Load, 0x00) +Bios_Call(Bios_Invoke, 0x04) +Bios_Call(Bios_Execute, 0x08) +Bios_Call(Bios_Halt, 0x0c) +Bios_Call(Bios_PowerDown, 0x10) +Bios_Call(Bios_Restart, 0x14) +Bios_Call(Bios_Reboot, 0x18) +Bios_Call(Bios_EnterInteractiveMode, 0x1c) +Bios_Call(Bios_Unused1, 0x20) +Bios_Call(Bios_GetPeer, 0x24) +Bios_Call(Bios_GetChild, 0x28) +Bios_Call(Bios_GetParent, 0x2c) +Bios_Call(Bios_GetConfigurationData, 0x30) +Bios_Call(Bios_AddChild, 0x34) +Bios_Call(Bios_DeleteComponent, 0x38) +Bios_Call(Bios_GetComponent, 0x3c) +Bios_Call(Bios_SaveConfiguration, 0x40) +Bios_Call(Bios_GetSystemId, 0x44) +Bios_Call(Bios_GetMemoryDescriptor, 0x48) +Bios_Call(Bios_Unused2, 0x4c) +Bios_Call(Bios_GetTime, 0x50) +Bios_Call(Bios_GetRelativeTime, 0x54) +Bios_Call(Bios_GetDirectoryEntry, 0x58) +Bios_Call(Bios_Open, 0x5c) +Bios_Call(Bios_Close, 0x60) +Bios_Call(Bios_Read, 0x64) +Bios_Call(Bios_GetReadStatus, 0x68) +Bios_Call(Bios_Write, 0x6c) +Bios_Call(Bios_Seek, 0x70) +Bios_Call(Bios_Mount, 0x74) +Bios_Call(Bios_GetEnvironmentVariable, 0x78) +Bios_Call(Bios_SetEnvironmentVariable, 0x7c) +Bios_Call(Bios_GetFileInformation, 0x80) +Bios_Call(Bios_SetFileInformation, 0x84) +Bios_Call(Bios_FlushAllCaches, 0x88) +Bios_Call(Bios_TestUnicodeCharacter, 0x8c) +Bios_Call(Bios_GetDisplayStatus, 0x90) |