diff options
author | Per Fogelstrom <pefo@cvs.openbsd.org> | 1996-06-24 09:07:22 +0000 |
---|---|---|
committer | Per Fogelstrom <pefo@cvs.openbsd.org> | 1996-06-24 09:07:22 +0000 |
commit | b0da6d46ce9cdb2877c41fbbfbfb2471130e1101 (patch) | |
tree | 6bae40ed3bba9f5ebcdfa64519398b7d93149363 | |
parent | 3dd058744292725ea73c1c76b15e1bd7f2e9fd6b (diff) |
Next try. ARC tree import. "New" Mips (spim) ARC compliant systems tree.
This tree will eventually suport viritualy all ARC compliant Mips systems,
that is all we can lay our hands on for porting/testing. It will supersede
the pica tree which will be removed shortly when this tree is functioning.
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) |